From e1cd5bd9ffc6baf66e81741c4a3a8f21cd2acfcd Mon Sep 17 00:00:00 2001 From: "copilot-cli-release-app[bot]" Date: Fri, 9 Oct 2026 00:45:12 +0000 Subject: [PATCH 1/9] Update SDK snapshot for Copilot CLI 1.0.95-1 --- nodejs/package.json | 2 +- nodejs/src/cliVersion.ts | 2 +- .../e2e/multi_provider_registry.e2e.test.ts | 18 +- .../websocket_fallback_recovery.e2e.test.ts | 277 ++++++++++++++++++ 4 files changed, 293 insertions(+), 6 deletions(-) create mode 100644 nodejs/test/e2e/websocket_fallback_recovery.e2e.test.ts diff --git a/nodejs/package.json b/nodejs/package.json index bf0b7222c8..279202c5bc 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -5,7 +5,7 @@ "url": "https://github.com/github/copilot-sdk.git" }, "version": "0.0.0-dev", - "copilotCliVersion": "1.0.95-0", + "copilotCliVersion": "1.0.95-1", "description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC", "main": "./dist/cjs/index.js", "types": "./dist/index.d.ts", diff --git a/nodejs/src/cliVersion.ts b/nodejs/src/cliVersion.ts index ff5a2eeb37..785341144b 100644 --- a/nodejs/src/cliVersion.ts +++ b/nodejs/src/cliVersion.ts @@ -1,3 +1,3 @@ -export const COPILOT_CLI_VERSION = "1.0.95-0"; +export const COPILOT_CLI_VERSION = "1.0.95-1"; export const COPILOT_CLI_USE_NPM_PACKAGE = false; diff --git a/nodejs/test/e2e/multi_provider_registry.e2e.test.ts b/nodejs/test/e2e/multi_provider_registry.e2e.test.ts index cd0eb53169..49b4a3618c 100644 --- a/nodejs/test/e2e/multi_provider_registry.e2e.test.ts +++ b/nodejs/test/e2e/multi_provider_registry.e2e.test.ts @@ -137,7 +137,8 @@ describe("Multi-provider BYOK registry", async () => { async function assertRouting( selectionId: string, expectedWireModel: string, - expectedProviderHeader: string + expectedProviderHeader: string, + expectedOutputCap?: number ): Promise { // Two OpenAI-compatible providers, both pointed at the replay proxy so // their /chat/completions traffic is captured. They are distinguished on @@ -162,7 +163,12 @@ describe("Multi-provider BYOK registry", async () => { }, ]; const models: ProviderModelConfig[] = [ - { id: "sonnet", provider: "alpha", wireModel: "byok-gpt-4o" }, + { + id: "sonnet", + provider: "alpha", + wireModel: "byok-gpt-4o", + maxOutputTokens: 16_384, + }, { id: "haiku", provider: "alpha", wireModel: "byok-gpt-4o-mini" }, { id: "turbo", provider: "delta", wireModel: "byok-gpt-4-turbo" }, ]; @@ -175,7 +181,8 @@ describe("Multi-provider BYOK registry", async () => { }); try { - await session.sendAndWait({ prompt: "What is 5+5?" }); + const response = await session.sendAndWait({ prompt: "What is 5+5?" }); + expect(response?.data.content).toContain("10"); const exchanges = await waitForExchanges(); expect(exchanges.length).toBe(1); const exchange = exchanges[0]; @@ -183,6 +190,9 @@ describe("Multi-provider BYOK registry", async () => { // The wire model sent to the provider is the selected model's // wireModel, not its provider-qualified selection id. expect(exchange.request.model).toBe(expectedWireModel); + expect(exchange.request.max_tokens).toBe(expectedOutputCap); + expect(exchange.request.max_completion_tokens).toBeUndefined(); + expect("max_output_tokens" in exchange.request).toBe(false); // The request carried the owning provider's custom header, proving // the turn was dispatched against the correct provider connection. @@ -200,7 +210,7 @@ describe("Multi-provider BYOK registry", async () => { } it("should route alpha sonnet turn to its provider and wire model", async () => { - await assertRouting("alpha/sonnet", "byok-gpt-4o", "alpha"); + await assertRouting("alpha/sonnet", "byok-gpt-4o", "alpha", 16_384); }); it("should route alpha haiku turn to its provider and wire model", async () => { diff --git a/nodejs/test/e2e/websocket_fallback_recovery.e2e.test.ts b/nodejs/test/e2e/websocket_fallback_recovery.e2e.test.ts new file mode 100644 index 0000000000..671c7549bd --- /dev/null +++ b/nodejs/test/e2e/websocket_fallback_recovery.e2e.test.ts @@ -0,0 +1,277 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import http from "node:http"; +import { afterAll, describe, expect, it } from "vitest"; +import { WebSocketServer } from "ws"; +import { approveAll, defineTool, type SessionEvent } from "../../src/index.js"; +import { withTestCleanup } from "../helpers/withTestCleanup.js"; +import { createSdkTestContext, DEFAULT_GITHUB_TOKEN } from "./harness/sdkTestContext.js"; + +const FINAL_TEXT = "WS_FALLBACK_RECOVERY_DONE"; +const TOOL_NAME = "fallback_recovery_step"; + +type Transport = "ws" | "http"; +type ProviderRequest = { transport: Transport; connectionId?: number; body: ProviderBody }; +type ProviderBody = { + input?: Array<{ type?: string; call_id?: string; output?: unknown }>; + previous_response_id?: string; + stream?: boolean; +}; + +/** + * Scripts one agent loop: two tool rounds, then a final answer. The reply depends + * only on how many tool results the request carries, so either transport can + * serve any step and the assertions observe which transport the runtime chose. + */ +function responseEvents(body: ProviderBody, id: string): Array> { + const toolResults = (body.input ?? []).filter((item) => item.type === "function_call_output"); + const created = { + type: "response.created", + response: { id, object: "response", status: "in_progress", output: [] }, + }; + if (toolResults.length < 2) { + const call = { + type: "function_call", + id: `fc-${toolResults.length + 1}`, + call_id: `call-${toolResults.length + 1}`, + name: TOOL_NAME, + arguments: JSON.stringify({ step: toolResults.length + 1 }), + status: "completed", + }; + return [ + created, + { type: "response.output_item.added", output_index: 0, item: call }, + { type: "response.output_item.done", output_index: 0, item: call }, + { + type: "response.completed", + response: { id, object: "response", status: "completed", output: [call] }, + }, + ]; + } + const message = { + id: "msg-final", + type: "message", + role: "assistant", + content: [{ type: "output_text", text: FINAL_TEXT, annotations: [] }], + }; + return [ + created, + { + type: "response.output_item.added", + output_index: 0, + item: { ...message, content: [] }, + }, + { + type: "response.content_part.added", + output_index: 0, + content_index: 0, + part: { type: "output_text", text: "" }, + }, + { + type: "response.output_text.delta", + output_index: 0, + content_index: 0, + delta: FINAL_TEXT, + }, + { type: "response.output_text.done", output_index: 0, content_index: 0, text: FINAL_TEXT }, + { type: "response.output_item.done", output_index: 0, item: message }, + { + type: "response.completed", + response: { id, object: "response", status: "completed", output: [message] }, + }, + ]; +} + +/** An OpenAI-compatible provider whose first WebSocket request fails before any output. */ +async function startProvider() { + const requests: ProviderRequest[] = []; + const errors: unknown[] = []; + let connectionCount = 0; + let wsRequestCount = 0; + const server = http.createServer((req, res) => { + void (async () => { + if (req.method !== "POST" || req.url !== "/v1/responses") { + throw new Error(`Unexpected provider request: ${req.method} ${req.url}`); + } + req.setEncoding("utf8"); + let raw = ""; + for await (const chunk of req) raw += chunk; + const body = JSON.parse(raw) as ProviderBody; + if (body.stream !== true) { + // Session title generation is a one-shot request outside the agent loop. + res.writeHead(200, { "content-type": "application/json" }); + res.end( + JSON.stringify({ + id: "resp-title", + object: "response", + status: "completed", + output: [ + { + id: "msg-title", + type: "message", + role: "assistant", + content: [{ type: "output_text", text: "Title", annotations: [] }], + }, + ], + }) + ); + return; + } + requests.push({ transport: "http", body }); + res.writeHead(200, { "content-type": "text/event-stream" }); + for (const event of responseEvents(body, `resp-http-${requests.length}`)) { + res.write(`data: ${JSON.stringify(event)}\n\n`); + } + res.end(); + })().catch((error: unknown) => { + errors.push(error); + res.destroy(error instanceof Error ? error : new Error(String(error))); + }); + }); + const sockets = new WebSocketServer({ server, path: "/v1/responses" }); + sockets.on("connection", (socket) => { + const connectionId = ++connectionCount; + socket.on("error", (error) => errors.push(error)); + socket.on("message", (raw) => { + const body = JSON.parse(raw.toString()) as ProviderBody; + requests.push({ transport: "ws", connectionId, body }); + const events = + ++wsRequestCount === 1 + ? [ + { + type: "error", + error: { + code: "service_unavailable", + type: "websocket_error", + message: "Controlled transient WebSocket failure", + }, + }, + ] + : responseEvents(body, `resp-ws-${wsRequestCount}`); + for (const event of events) socket.send(JSON.stringify(event)); + }); + }); + await new Promise((resolve, reject) => { + server.once("error", reject); + server.listen(0, "127.0.0.1", resolve); + }); + const address = server.address(); + if (address === null || typeof address === "string") { + throw new Error("Expected a bound TCP address for the provider."); + } + return { + baseUrl: `http://127.0.0.1:${address.port}/v1`, + requests, + connectionCount: () => connectionCount, + async stop() { + for (const socket of sockets.clients) socket.terminate(); + await new Promise((resolve) => sockets.close(() => resolve())); + server.closeAllConnections(); + await new Promise((resolve, reject) => + server.close((error) => (error ? reject(error) : resolve())) + ); + if (errors.length > 0) throw new AggregateError(errors, "Provider fixture failed."); + }, + }; +} + +// The dispatcher's fallback state lives for one run (one user message's agent +// loop), so recovery is only observable across the model calls of one send. +describe.each([ + { recovery: true, transports: ["ws", "http", "http", "ws"] }, + { recovery: false, transports: ["ws", "http", "http", "http"] }, +])("WebSocket fallback recovery=$recovery", async ({ recovery, transports }) => { + const provider = await startProvider(); + // Register first so the SDK context stops its client before this provider. + afterAll(() => provider.stop()); + const flag = String(recovery); + const { copilotClient: client } = await createSdkTestContext({ + useStdio: true, + copilotClientOptions: { + gitHubToken: DEFAULT_GITHUB_TOKEN, + env: { + COPILOT_CLI_DISABLE_WEBSOCKET_RESPONSES: "false", + WEBSOCKET_FALLBACK_RECOVERY: flag, + COPILOT_EXP_COPILOT_CLI_WEBSOCKET_FALLBACK_RECOVERY: flag, + }, + }, + }); + + it(`${recovery ? "returns to" : "stays off"} the socket after a transient failure within one run`, async () => { + const toolCalls: number[] = []; + const session = await client.createSession({ + model: "gpt-5-responses", + streaming: true, + provider: { + type: "openai", + baseUrl: provider.baseUrl, + apiKey: "test-provider-key", + wireApi: "responses", + transport: "websockets", + }, + tools: [ + defineTool<{ step: number }>(TOOL_NAME, { + description: "Records one step of the controlled agent loop", + parameters: { + type: "object", + properties: { step: { type: "number" } }, + required: ["step"], + }, + defer: "never", + handler: ({ step }) => { + toolCalls.push(step); + return `STEP_${step}_RESULT`; + }, + }), + ], + onPermissionRequest: approveAll, + }); + const events: SessionEvent[] = []; + const unsubscribe = session.on((event) => events.push(event)); + await withTestCleanup( + async () => { + const answer = await session.sendAndWait({ prompt: "Run the two steps." }); + // Validate the final assistant response arrived (guards against truncated captures) + expect(answer?.data.content).toBe(FINAL_TEXT); + + const { requests } = provider; + expect(requests.map((request) => request.transport)).toEqual(transports); + // The failed socket request is replayed once over HTTP, then each + // tool runs exactly once whichever transport carried its turn. + expect(toolCalls).toEqual([1, 2]); + expect(events.filter((event) => event.type === "session.error")).toEqual([]); + const deltas = events.flatMap((event) => + event.type === "assistant.message_delta" ? [event.data.deltaContent] : [] + ); + expect(deltas.join("")).toBe(FINAL_TEXT); + + const last = requests.at(-1)!; + const results = (last.body.input ?? []).filter( + (item) => item.type === "function_call_output" + ); + expect(results.map((item) => item.call_id)).toEqual(["call-1", "call-2"]); + expect(JSON.stringify(results)).toContain("STEP_1_RESULT"); + expect(JSON.stringify(results)).toContain("STEP_2_RESULT"); + if (recovery) { + // A fresh socket carries the full history, not a continuation + // of the response it never produced. + expect(last.connectionId).toBe(2); + expect(last.body.previous_response_id).toBeUndefined(); + expect(provider.connectionCount()).toBe(2); + } else { + expect(provider.connectionCount()).toBe(1); + } + }, + unsubscribe, + () => session.disconnect(), + async () => { + const errors = await client.stop(); + if (errors.length > 0) { + throw new AggregateError(errors, "Client cleanup failed"); + } + } + ); + }); +}); From 341a526b26ccc170f6a1c6c5651b51f4ba9d3691 Mon Sep 17 00:00:00 2001 From: "copilot-cli-release-app[bot]" Date: Fri, 9 Oct 2026 02:43:18 +0000 Subject: [PATCH 2/9] Update SDK snapshot for Copilot CLI 1.0.95-2 --- docs/features/plugin-directories.md | 57 ++++ dotnet/src/Client.cs | 4 + dotnet/src/Generated/Rpc.cs | 139 ++++++++++ dotnet/src/Types.cs | 20 ++ .../test/Unit/ClientSessionLifetimeTests.cs | 34 +++ go/client.go | 2 + go/image_generation_test.go | 48 ++++ go/rpc/zrpc.go | 84 ++++++ go/types.go | 18 ++ .../rpc/ManagedPluginRetryEntry.java | 35 +++ .../rpc/ManagedPluginRetryStatus.java | 47 ++++ .../generated/rpc/SessionPluginsApi.java | 29 ++ .../rpc/SessionPluginsRetryManagedParams.java | 33 +++ .../rpc/SessionPluginsRetryManagedResult.java | 31 +++ .../github/copilot/SessionRequestBuilder.java | 2 + .../copilot/rpc/CreateSessionRequest.java | 16 ++ .../copilot/rpc/ImageGenerationConfig.java | 46 ++++ .../copilot/rpc/ResumeSessionConfig.java | 25 ++ .../copilot/rpc/ResumeSessionRequest.java | 16 ++ .../com/github/copilot/rpc/SessionConfig.java | 25 ++ .../copilot/ImageGenerationConfigTest.java | 50 ++++ nodejs/package.json | 2 +- nodejs/src/cliVersion.ts | 2 +- nodejs/src/client.ts | 2 + nodejs/src/extension.ts | 6 +- nodejs/src/generated/rpc.ts | 68 +++++ nodejs/src/index.ts | 1 + nodejs/src/types.ts | 21 ++ nodejs/test/e2e/harness/sdkTestContext.ts | 9 +- nodejs/test/e2e/image_generation.e2e.test.ts | 254 ++++++++++++++++++ .../test/e2e/rpc_surface_coverage.e2e.test.ts | 27 +- nodejs/test/extension.test.ts | 18 +- nodejs/test/image-generation.test.ts | 78 ++++++ python/copilot/__init__.py | 2 + python/copilot/client.py | 11 + python/copilot/generated/rpc.py | 108 +++++++- python/copilot/session.py | 14 + python/test_image_generation.py | 47 ++++ rust/src/generated/api_types.rs | 87 ++++++ rust/src/generated/rpc.rs | 58 ++++ rust/src/types.rs | 51 ++++ rust/src/types/tests.rs | 47 +++- rust/src/wire.rs | 10 +- 43 files changed, 1668 insertions(+), 16 deletions(-) create mode 100644 go/image_generation_test.go create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPluginRetryEntry.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPluginRetryStatus.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsRetryManagedParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsRetryManagedResult.java create mode 100644 java/sdk/src/main/java/com/github/copilot/rpc/ImageGenerationConfig.java create mode 100644 java/sdk/src/test/java/com/github/copilot/ImageGenerationConfigTest.java create mode 100644 nodejs/test/e2e/image_generation.e2e.test.ts create mode 100644 nodejs/test/image-generation.test.ts create mode 100644 python/test_image_generation.py diff --git a/docs/features/plugin-directories.md b/docs/features/plugin-directories.md index 456ef88e7f..393fc4c048 100644 --- a/docs/features/plugin-directories.md +++ b/docs/features/plugin-directories.md @@ -422,6 +422,63 @@ for (const plugin of plugins.plugins) { Plugins loaded via `--plugin-dir` appear in this list with their cache path set to the directory you provided. Marketplace installs are tagged with their registry source. +## Retrying plugins required by managed settings + +When managed settings require plugins through `enabledPlugins`, the runtime installs or updates them before chat messages. If that fails, the session emits a `session.warning` with `warningType: "managed_plugins"` and waits an hour, or until the managed settings change, before trying again. The experimental `session.rpc.plugins.retryManaged()` tries again right away, for example from a Retry action next to that warning. + +Call it with no arguments to retry every plugin the managed settings require, or pass `plugin@marketplace` specs in `plugins` to retry only those. The result has one entry per plugin with a `status`: `installed`, `updated`, `already_present`, `failed`, `deferred`, or `not_required`. `failed` and `deferred` entries include an `error`. The session also emits the usual `session.info` progress and `session.warning` failure events. + +
+Node.js / TypeScript + + +```typescript +import { CopilotClient } from "@github/copilot-sdk"; + +async function main() { + const client = new CopilotClient(); + await client.start(); + const session = await client.createSession({ + onPermissionRequest: async () => ({ kind: "approve-once" }), + }); + + // Retry every plugin the managed settings require, for example from a Retry action. + const result = await session.rpc.plugins.retryManaged(); + for (const entry of result.plugins) { + console.log(`${entry.spec}: ${entry.status}${entry.error ? ` (${entry.error})` : ""}`); + } + + // Or retry only the required plugins that are still missing. + const { plugins } = await session.rpc.plugins.list(); + const missing = plugins + .filter((plugin) => plugin.managedDesiredEnabled === true && plugin.installed === false) + .map((plugin) => `${plugin.name}@${plugin.marketplace}`); + await session.rpc.plugins.retryManaged({ plugins: missing }); +} + +main(); +``` + + +```typescript +// Retry every plugin the managed settings require, for example from a Retry action. +const result = await session.rpc.plugins.retryManaged(); +for (const entry of result.plugins) { + console.log(`${entry.spec}: ${entry.status}${entry.error ? ` (${entry.error})` : ""}`); +} + +// Or retry only the required plugins that are still missing. +const { plugins } = await session.rpc.plugins.list(); +const missing = plugins + .filter((plugin) => plugin.managedDesiredEnabled === true && plugin.installed === false) + .map((plugin) => `${plugin.name}@${plugin.marketplace}`); +await session.rpc.plugins.retryManaged({ plugins: missing }); +``` + +
+ +Runtimes that do not prepare managed plugins for the session reject the call. + ## Troubleshooting * **"no plugin.json or SKILL.md found in <dir>"** — the directory exists but doesn't qualify as a plugin. Add a `plugin.json` manifest at the root (or under `.github/`), or include a top-level `SKILL.md`. diff --git a/dotnet/src/Client.cs b/dotnet/src/Client.cs index 7fcfbfef99..d22e329428 100644 --- a/dotnet/src/Client.cs +++ b/dotnet/src/Client.cs @@ -1347,6 +1347,7 @@ public async Task CreateSessionAsync(SessionConfig config, Cance DisabledMcpServers: config.DisabledMcpServers, LargeOutput: config.LargeOutput, ToolSearch: config.ToolSearch, + ImageGeneration: config.ImageGeneration, Memory: config.Memory, Canvases: config.Canvases, RequestCanvasRenderer: config.RequestCanvasRenderer, @@ -1619,6 +1620,7 @@ public async Task ResumeSessionAsync(string sessionId, ResumeSes DisabledMcpServers: config.DisabledMcpServers, LargeOutput: config.LargeOutput, ToolSearch: config.ToolSearch, + ImageGeneration: config.ImageGeneration, Memory: config.Memory, Canvases: config.Canvases, RequestCanvasRenderer: config.RequestCanvasRenderer, @@ -3273,6 +3275,7 @@ internal record CreateSessionRequest( [property: JsonPropertyName("disabledMcpServers")] IList? DisabledMcpServers = null, LargeToolOutputConfig? LargeOutput = null, ToolSearchConfig? ToolSearch = null, + ImageGenerationConfig? ImageGeneration = null, MemoryConfiguration? Memory = null, #pragma warning disable GHCP001 IList? Canvases = null, @@ -3395,6 +3398,7 @@ internal record ResumeSessionRequest( [property: JsonPropertyName("disabledMcpServers")] IList? DisabledMcpServers = null, LargeToolOutputConfig? LargeOutput = null, ToolSearchConfig? ToolSearch = null, + ImageGenerationConfig? ImageGeneration = null, MemoryConfiguration? Memory = null, #pragma warning disable GHCP001 IList? Canvases = null, diff --git a/dotnet/src/Generated/Rpc.cs b/dotnet/src/Generated/Rpc.cs index b21d884f1d..6ab5009adc 100644 --- a/dotnet/src/Generated/Rpc.cs +++ b/dotnet/src/Generated/Rpc.cs @@ -19333,6 +19333,54 @@ internal sealed class SessionPluginsReloadRequestWithSession public string SessionId { get; set; } = string.Empty; } +/// Retry outcome for one plugin required by managed settings. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ManagedPluginRetryEntry +{ + /// Why the plugin was not prepared. Present when `status` is `failed` or `deferred`. + [JsonPropertyName("error")] + public string? Error { get; set; } + + /// Plugin spec in "plugin@marketplace" form. + [JsonPropertyName("spec")] + public string Spec { get; set; } = string.Empty; + + /// What the retry did for this plugin. + [JsonPropertyName("status")] + public ManagedPluginRetryStatus Status { get; set; } +} + +/// Per-plugin outcomes of retrying the plugins required by the session's managed settings. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionPluginsRetryManagedResult +{ + /// One entry per requested plugin, in request order. When no plugins were requested, one entry per plugin the managed settings require. + [JsonPropertyName("plugins")] + public IList Plugins { get => field ??= []; set; } +} + +/// RPC data type for SessionPluginsRetryManaged operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionPluginsRetryManagedRequest +{ + /// "plugin@marketplace" specs to retry. Omit to retry every plugin the session's managed settings require. + [JsonPropertyName("plugins")] + public IList? Plugins { get; set; } +} + +/// RPC data type for SessionPluginsRetryManagedRequestWithSession operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionPluginsRetryManagedRequestWithSession +{ + /// "plugin@marketplace" specs to retry. Omit to retry every plugin the session's managed settings require. + [JsonPropertyName("plugins")] + public IList? Plugins { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] internal sealed class SessionPluginsMarketplacesListRequest @@ -39292,6 +39340,81 @@ public override void Write(Utf8JsonWriter writer, ConnectorMcpStatus value, Json } +/// What retrying did for one plugin required by managed settings. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ManagedPluginRetryStatus : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ManagedPluginRetryStatus(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// The plugin was missing and is now installed. + public static ManagedPluginRetryStatus Installed { get; } = new("installed"); + + /// An update was available and is now installed. + public static ManagedPluginRetryStatus Updated { get; } = new("updated"); + + /// The plugin was already installed and current, so nothing was done. + public static ManagedPluginRetryStatus AlreadyPresent { get; } = new("already_present"); + + /// Checking, installing, or updating the plugin failed. See `error`. + public static ManagedPluginRetryStatus Failed { get; } = new("failed"); + + /// The plugin was not prepared because another session was changing plugins or the managed settings changed during the retry. It is prepared again before a later message. + public static ManagedPluginRetryStatus Deferred { get; } = new("deferred"); + + /// The session's managed settings do not require this plugin, so nothing was done. + public static ManagedPluginRetryStatus NotRequired { get; } = new("not_required"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedPluginRetryStatus left, ManagedPluginRetryStatus right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedPluginRetryStatus left, ManagedPluginRetryStatus right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ManagedPluginRetryStatus other && Equals(other); + + /// + public bool Equals(ManagedPluginRetryStatus other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ManagedPluginRetryStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ManagedPluginRetryStatus value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedPluginRetryStatus)); + } + } +} + + /// Allowed values for the `OptionsUpdateAdditionalContentExclusionPolicyScope` enumeration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] @@ -49223,6 +49346,18 @@ public async Task ReloadAsync(SessionPluginsReloadRequest? request = null, Cance await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.plugins.reload", [rpcRequest], cancellationToken); } + /// Installs or updates the plugins the session's managed settings require now, without waiting for the next automatic attempt after a failure, then reloads plugins. Reports progress and failures with the same `session.info` and `session.warning` events as automatic preparation. Fails when the runtime does not prepare managed plugins for the session. + /// Plugins required by the session's managed settings to install or update again. + /// The to monitor for cancellation requests. The default is . + /// Per-plugin outcomes of retrying the plugins required by the session's managed settings. + public async Task RetryManagedAsync(SessionPluginsRetryManagedRequest? request = null, CancellationToken cancellationToken = default) + { + _session.ThrowIfDisposed(); + + var rpcRequest = new SessionPluginsRetryManagedRequestWithSession { SessionId = _session.SessionId, Plugins = request?.Plugins }; + return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.plugins.retryManaged", [rpcRequest], cancellationToken); + } + /// Marketplaces APIs. public PluginsMarketplacesApi Marketplaces => field ?? @@ -52719,6 +52854,7 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(LogResult))] [JsonSerializable(typeof(LoggedInUser))] [JsonSerializable(typeof(LspInitializeRequest))] +[JsonSerializable(typeof(ManagedPluginRetryEntry))] [JsonSerializable(typeof(ManagedSettingMeta))] [JsonSerializable(typeof(ManagedSettingsComposeLayer))] [JsonSerializable(typeof(ManagedSettingsComposeRequest))] @@ -53297,6 +53433,9 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(SessionPluginsMarketplacesRefreshRequestWithSession))] [JsonSerializable(typeof(SessionPluginsReloadRequest))] [JsonSerializable(typeof(SessionPluginsReloadRequestWithSession))] +[JsonSerializable(typeof(SessionPluginsRetryManagedRequest))] +[JsonSerializable(typeof(SessionPluginsRetryManagedRequestWithSession))] +[JsonSerializable(typeof(SessionPluginsRetryManagedResult))] [JsonSerializable(typeof(SessionProviderGetEndpointRequest))] [JsonSerializable(typeof(SessionProviderGetEndpointRequestWithSession))] [JsonSerializable(typeof(SessionProvidersGetCatalogRequest))] diff --git a/dotnet/src/Types.cs b/dotnet/src/Types.cs index f4ba58fe4b..c836a095dc 100644 --- a/dotnet/src/Types.cs +++ b/dotnet/src/Types.cs @@ -3276,6 +3276,21 @@ public sealed class LargeToolOutputConfig public string? OutputDirectory { get; set; } } +/// Non-persisted opt-in to image generation. +/// Experimental. This API may change or be removed in a future release. +[Experimental(Diagnostics.Experimental)] +public sealed class ImageGenerationConfig +{ + /// + /// Opt in to an authorized Copilot image model. False disables image generation. + /// Omission disables on create/cold resume and preserves resident resume state. + /// Not persisted: re-supply after runtime restart. Policy, permissions, offline + /// mode, and tool filters still apply. BYOK image generation is not supported. + /// + [JsonPropertyName("enabled")] + public bool? Enabled { get; set; } +} + /// /// Overrides the runtime's built-in tool-search behavior. /// Defers tools to keep the model's active tool set small. @@ -3630,6 +3645,7 @@ protected SessionConfigBase(SessionConfigBase? other) InfiniteSessions = other.InfiniteSessions; LargeOutput = other.LargeOutput; ToolSearch = other.ToolSearch; + ImageGeneration = other.ImageGeneration; Memory = other.Memory; McpServers = other.McpServers is not null ? (other.McpServers is Dictionary dict @@ -4137,6 +4153,10 @@ protected SessionConfigBase(SessionConfigBase? other) /// public ToolSearchConfig? ToolSearch { get; set; } + /// Non-persisted image generation opt-in. Re-supply after runtime restart. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + public ImageGenerationConfig? ImageGeneration { get; set; } + /// /// Configuration for session memory. When set, controls whether the /// session can read and write persistent memory. diff --git a/dotnet/test/Unit/ClientSessionLifetimeTests.cs b/dotnet/test/Unit/ClientSessionLifetimeTests.cs index 5beb89ae05..c3ea694395 100644 --- a/dotnet/test/Unit/ClientSessionLifetimeTests.cs +++ b/dotnet/test/Unit/ClientSessionLifetimeTests.cs @@ -24,6 +24,40 @@ public sealed partial class ClientSessionLifetimeTests { private sealed record RpcRequestRecord(string Method, JsonElement Params); + [Theory] + [InlineData(false, true)] + [InlineData(false, false)] + [InlineData(false, null)] + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(true, null)] + public async Task ImageGeneration_ForwardsCreateAndResumeOptIn(bool resume, bool? enabled) + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url) }); + var imageGeneration = enabled is null ? null : new ImageGenerationConfig { Enabled = enabled }; + await using var session = resume + ? await client.ResumeSessionAsync("image-test", new ResumeSessionConfig + { + OnPermissionRequest = PermissionHandler.ApproveAll, + ImageGeneration = imageGeneration + }.Clone()) + : await client.CreateSessionAsync(new SessionConfig + { + OnPermissionRequest = PermissionHandler.ApproveAll, + ImageGeneration = imageGeneration + }.Clone()); + var request = Assert.Single(server.Requests, r => r.Method == (resume ? "session.resume" : "session.create")).Params; + if (enabled is null) + { + Assert.False(request.TryGetProperty("imageGeneration", out _), request.ToString()); + } + else + { + Assert.Equal(enabled.Value, request.GetProperty("imageGeneration").GetProperty("enabled").GetBoolean()); + } + } + [Theory] [InlineData(CopilotClientMode.CopilotCli, null, null)] [InlineData(CopilotClientMode.Empty, null, null)] diff --git a/go/client.go b/go/client.go index b924a9b6c2..aa8659fd4b 100644 --- a/go/client.go +++ b/go/client.go @@ -984,6 +984,7 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses req.InfiniteSessions = config.InfiniteSessions req.LargeOutput = config.LargeOutput req.ToolSearch = config.ToolSearch + req.ImageGeneration = config.ImageGeneration req.Memory = config.Memory req.GitHubToken = config.GitHubToken req.GitHubTokenProviderRegistrationID = registrationID @@ -1464,6 +1465,7 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string, req.InfiniteSessions = config.InfiniteSessions req.LargeOutput = config.LargeOutput req.ToolSearch = config.ToolSearch + req.ImageGeneration = config.ImageGeneration req.Memory = config.Memory req.GitHubToken = config.GitHubToken req.GitHubTokenProviderRegistrationID = registrationID diff --git a/go/image_generation_test.go b/go/image_generation_test.go new file mode 100644 index 0000000000..1c6586692c --- /dev/null +++ b/go/image_generation_test.go @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. + +package copilot + +import ( + "encoding/json" + "testing" +) + +func TestImageGenerationSerialization(t *testing.T) { + for _, enabled := range []*bool{Bool(true), Bool(false), nil} { + var config *ImageGenerationConfig + if enabled != nil { + config = &ImageGenerationConfig{Enabled: enabled} + } + for _, request := range []any{ + createSessionRequest{ImageGeneration: config}, + resumeSessionRequest{SessionID: "image-test", ImageGeneration: config}, + } { + data, err := json.Marshal(request) + if err != nil { + t.Fatal(err) + } + var payload map[string]json.RawMessage + if err := json.Unmarshal(data, &payload); err != nil { + t.Fatal(err) + } + value, present := payload["imageGeneration"] + if enabled == nil { + if present { + t.Fatalf("expected omitted imageGeneration, got %s", data) + } + } else { + expected, err := json.Marshal(map[string]bool{"enabled": *enabled}) + if err != nil { + t.Fatal(err) + } + if string(value) != string(expected) { + t.Fatalf("imageGeneration = %s, want %s", value, expected) + } + } + } + } + data, err := json.Marshal(ImageGenerationConfig{}) + if err != nil || string(data) != "{}" { + t.Fatalf("unset enabled = %s, err = %v", data, err) + } +} diff --git a/go/rpc/zrpc.go b/go/rpc/zrpc.go index 9ac9b92597..7f341d8b5f 100644 --- a/go/rpc/zrpc.go +++ b/go/rpc/zrpc.go @@ -6787,6 +6787,18 @@ type ManagedMCPServerConfig struct { URL string `json:"url"` } +// Retry outcome for one plugin required by managed settings. +// Experimental: ManagedPluginRetryEntry is part of an experimental API and may change or be +// removed. +type ManagedPluginRetryEntry struct { + // Why the plugin was not prepared. Present when `status` is `failed` or `deferred`. + Error *string `json:"error,omitempty"` + // Plugin spec in "plugin@marketplace" form. + Spec string `json:"spec"` + // What the retry did for this plugin. + Status ManagedPluginRetryStatus `json:"status"` +} + // Lock state and provenance of one managed setting. // Experimental: ManagedSettingMeta is part of an experimental API and may change or be // removed. @@ -17067,6 +17079,23 @@ type SessionPluginsReloadRequest struct { type SessionPluginsReloadResult struct { } +// Experimental: SessionPluginsRetryManagedRequest is part of an experimental API and may +// change or be removed. +type SessionPluginsRetryManagedRequest struct { + // "plugin@marketplace" specs to retry. Omit to retry every plugin the session's managed + // settings require. + Plugins []string `json:"plugins,omitzero"` +} + +// Per-plugin outcomes of retrying the plugins required by the session's managed settings. +// Experimental: SessionPluginsRetryManagedResult is part of an experimental API and may +// change or be removed. +type SessionPluginsRetryManagedResult struct { + // One entry per requested plugin, in request order. When no plugins were requested, one + // entry per plugin the managed settings require. + Plugins []ManagedPluginRetryEntry `json:"plugins"` +} + // Experimental: SessionPluginsUninstallResult is part of an experimental API and may change // or be removed. type SessionPluginsUninstallResult struct { @@ -24551,6 +24580,27 @@ const ( LoginProviderKindProxima LoginProviderKind = "proxima" ) +// What retrying did for one plugin required by managed settings. +// Experimental: ManagedPluginRetryStatus is part of an experimental API and may change or +// be removed. +type ManagedPluginRetryStatus string + +const ( + // The plugin was already installed and current, so nothing was done. + ManagedPluginRetryStatusAlreadyPresent ManagedPluginRetryStatus = "already_present" + // The plugin was not prepared because another session was changing plugins or the managed + // settings changed during the retry. It is prepared again before a later message. + ManagedPluginRetryStatusDeferred ManagedPluginRetryStatus = "deferred" + // Checking, installing, or updating the plugin failed. See `error`. + ManagedPluginRetryStatusFailed ManagedPluginRetryStatus = "failed" + // The plugin was missing and is now installed. + ManagedPluginRetryStatusInstalled ManagedPluginRetryStatus = "installed" + // The session's managed settings do not require this plugin, so nothing was done. + ManagedPluginRetryStatusNotRequired ManagedPluginRetryStatus = "not_required" + // An update was available and is now installed. + ManagedPluginRetryStatusUpdated ManagedPluginRetryStatus = "updated" +) + // A channel accepted by managedSettings.compose. // Experimental: ManagedSettingsChannel is part of an experimental API and may change or be // removed. @@ -35891,6 +35941,40 @@ func (a *PluginsAPI) Reload(ctx context.Context, params ...*SessionPluginsReload return &result, nil } +// RetryManaged installs or updates the plugins the session's managed settings require now, +// without waiting for the next automatic attempt after a failure, then reloads plugins. +// Reports progress and failures with the same `session.info` and `session.warning` events +// as automatic preparation. Fails when the runtime does not prepare managed plugins for the +// session. +// +// RPC method: session.plugins.retryManaged. +// +// Parameters: Plugins required by the session's managed settings to install or update again. +// +// Returns: Per-plugin outcomes of retrying the plugins required by the session's managed +// settings. +func (a *PluginsAPI) RetryManaged(ctx context.Context, params ...*SessionPluginsRetryManagedRequest) (*SessionPluginsRetryManagedResult, error) { + var requestParams *SessionPluginsRetryManagedRequest + if len(params) > 0 { + requestParams = params[0] + } + req := map[string]any{"sessionId": a.sessionID} + if requestParams != nil { + if requestParams.Plugins != nil { + req["plugins"] = requestParams.Plugins + } + } + raw, err := a.client.Request(ctx, "session.plugins.retryManaged", req) + if err != nil { + return nil, err + } + var result SessionPluginsRetryManagedResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // Uninstalls a plugin when permitted by the live session's retained managed policy. // // RPC method: session.plugins.uninstall. diff --git a/go/types.go b/go/types.go index 19b263f7f0..cdeae3b404 100644 --- a/go/types.go +++ b/go/types.go @@ -1323,6 +1323,16 @@ type LargeToolOutputConfig struct { OutputDirectory string `json:"outputDir,omitempty"` } +// ImageGenerationConfig opts in to an authorized Copilot image model. +// Experimental: this API may change or be removed in a future release. +// Omission disables on create/cold resume and preserves resident resume state. +// Not persisted: re-supply after runtime restart. Policy, permissions, offline +// mode, and tool filters still apply. BYOK image generation is not supported. +type ImageGenerationConfig struct { + // Enabled opts in when true and disables image generation when false. + Enabled *bool `json:"enabled,omitempty"` +} + // ToolSearchConfig allows to configure tool search behavior. // Tool search defers tools to keep the model's active tool set small. // To override the tool-search tool's implementation, register a @@ -1693,6 +1703,9 @@ type SessionConfig struct { // defers rarely used tools behind a searchable index. When nil, the runtime // default applies. ToolSearch *ToolSearchConfig + // ImageGeneration is the non-persisted image generation opt-in. + // Experimental: this API may change or be removed in a future release. + ImageGeneration *ImageGenerationConfig // Memory configures the memory feature for the session. When omitted, the // runtime default applies. Memory *MemoryConfiguration @@ -2292,6 +2305,9 @@ type ResumeSessionConfig struct { // defers rarely used tools behind a searchable index. When nil, the runtime // default applies. ToolSearch *ToolSearchConfig + // ImageGeneration is the non-persisted image generation opt-in. + // Experimental: this API may change or be removed in a future release. + ImageGeneration *ImageGenerationConfig // Memory configures the memory feature for the session. When omitted, the // runtime default applies. Memory *MemoryConfiguration @@ -2900,6 +2916,7 @@ type createSessionRequest struct { InfiniteSessions *InfiniteSessionConfig `json:"infiniteSessions,omitempty"` LargeOutput *LargeToolOutputConfig `json:"largeOutput,omitempty"` ToolSearch *ToolSearchConfig `json:"toolSearch,omitempty"` + ImageGeneration *ImageGenerationConfig `json:"imageGeneration,omitempty"` Memory *MemoryConfiguration `json:"memory,omitempty"` Commands []wireCommand `json:"commands,omitempty"` RequestElicitation *bool `json:"requestElicitation,omitempty"` @@ -3006,6 +3023,7 @@ type resumeSessionRequest struct { InfiniteSessions *InfiniteSessionConfig `json:"infiniteSessions,omitempty"` LargeOutput *LargeToolOutputConfig `json:"largeOutput,omitempty"` ToolSearch *ToolSearchConfig `json:"toolSearch,omitempty"` + ImageGeneration *ImageGenerationConfig `json:"imageGeneration,omitempty"` Memory *MemoryConfiguration `json:"memory,omitempty"` Commands []wireCommand `json:"commands,omitempty"` RequestElicitation *bool `json:"requestElicitation,omitempty"` diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPluginRetryEntry.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPluginRetryEntry.java new file mode 100644 index 0000000000..9fb16e5a55 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPluginRetryEntry.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Retry outcome for one plugin required by managed settings. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ManagedPluginRetryEntry( + /** Plugin spec in "plugin@marketplace" form. */ + @JsonProperty("spec") String spec, + /** What the retry did for this plugin. */ + @JsonProperty("status") ManagedPluginRetryStatus status, + /** Why the plugin was not prepared. Present when `status` is `failed` or `deferred`. */ + @JsonProperty("error") String error +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPluginRetryStatus.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPluginRetryStatus.java new file mode 100644 index 0000000000..43a46d2625 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPluginRetryStatus.java @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * What retrying did for one plugin required by managed settings. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ManagedPluginRetryStatus { + /** The {@code installed} variant. */ + INSTALLED("installed"), + /** The {@code updated} variant. */ + UPDATED("updated"), + /** The {@code already_present} variant. */ + ALREADY_PRESENT("already_present"), + /** The {@code failed} variant. */ + FAILED("failed"), + /** The {@code deferred} variant. */ + DEFERRED("deferred"), + /** The {@code not_required} variant. */ + NOT_REQUIRED("not_required"); + + private final String value; + ManagedPluginRetryStatus(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ManagedPluginRetryStatus fromValue(String value) { + for (ManagedPluginRetryStatus v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ManagedPluginRetryStatus value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsApi.java index e041a149c1..3235108161 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsApi.java @@ -154,4 +154,33 @@ public CompletableFuture reload(SessionPluginsReloadParams params) { return caller.invoke("session.plugins.reload", _p, Void.class); } + /** + * Installs or updates the plugins the session's managed settings require now, without waiting for the next automatic attempt after a failure, then reloads plugins. Reports progress and failures with the same `session.info` and `session.warning` events as automatic preparation. Fails when the runtime does not prepare managed plugins for the session. + *

+ * Invokes the method with no params, applying the runtime defaults. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture retryManaged() { + return retryManaged(null); + } + + /** + * Installs or updates the plugins the session's managed settings require now, without waiting for the next automatic attempt after a failure, then reloads plugins. Reports progress and failures with the same `session.info` and `session.warning` events as automatic preparation. Fails when the runtime does not prepare managed plugins for the session. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture retryManaged(SessionPluginsRetryManagedParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = params == null ? MAPPER.createObjectNode() : MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.plugins.retryManaged", _p, SessionPluginsRetryManagedResult.class); + } + } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsRetryManagedParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsRetryManagedParams.java new file mode 100644 index 0000000000..24b687ca75 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsRetryManagedParams.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Request parameters for the {@code session.plugins.retryManaged} RPC method. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionPluginsRetryManagedParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** "plugin@marketplace" specs to retry. Omit to retry every plugin the session's managed settings require. */ + @JsonProperty("plugins") List plugins +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsRetryManagedResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsRetryManagedResult.java new file mode 100644 index 0000000000..f2fc9b73cb --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionPluginsRetryManagedResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Per-plugin outcomes of retrying the plugins required by the session's managed settings. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionPluginsRetryManagedResult( + /** One entry per requested plugin, in request order. When no plugins were requested, one entry per plugin the managed settings require. */ + @JsonProperty("plugins") List plugins +) { +} diff --git a/java/sdk/src/main/java/com/github/copilot/SessionRequestBuilder.java b/java/sdk/src/main/java/com/github/copilot/SessionRequestBuilder.java index 8d77086746..71cf2fcded 100644 --- a/java/sdk/src/main/java/com/github/copilot/SessionRequestBuilder.java +++ b/java/sdk/src/main/java/com/github/copilot/SessionRequestBuilder.java @@ -200,6 +200,7 @@ static CreateSessionRequest buildCreateRequest(SessionConfig config, String sess request.setPluginDirectories(config.getPluginDirectories()); request.setLargeOutput(config.getLargeOutput()); request.setToolSearch(config.getToolSearch()); + request.setImageGeneration(config.getImageGeneration()); request.setMemory(config.getMemory()); request.setDisabledSkills(config.getDisabledSkills()); request.setDisabledMcpServers(config.getDisabledMcpServers()); @@ -366,6 +367,7 @@ static ResumeSessionRequest buildResumeRequest(String sessionId, ResumeSessionCo request.setPluginDirectories(config.getPluginDirectories()); request.setLargeOutput(config.getLargeOutput()); request.setToolSearch(config.getToolSearch()); + request.setImageGeneration(config.getImageGeneration()); request.setMemory(config.getMemory()); request.setDisabledSkills(config.getDisabledSkills()); request.setDisabledMcpServers(config.getDisabledMcpServers()); diff --git a/java/sdk/src/main/java/com/github/copilot/rpc/CreateSessionRequest.java b/java/sdk/src/main/java/com/github/copilot/rpc/CreateSessionRequest.java index d18de07fb1..fa5e7d3e16 100644 --- a/java/sdk/src/main/java/com/github/copilot/rpc/CreateSessionRequest.java +++ b/java/sdk/src/main/java/com/github/copilot/rpc/CreateSessionRequest.java @@ -159,6 +159,9 @@ public final class CreateSessionRequest { @JsonProperty("toolSearch") private ToolSearchConfig toolSearch; + @JsonProperty("imageGeneration") + private ImageGenerationConfig imageGeneration; + @JsonProperty("memory") private MemoryConfiguration memory; @@ -757,6 +760,19 @@ public ToolSearchConfig getToolSearch() { return toolSearch; } + /** Gets image generation config. @return the image generation config */ + public ImageGenerationConfig getImageGeneration() { + return imageGeneration; + } + + /** + * Sets image generation config. @param imageGeneration the image generation + * config + */ + public void setImageGeneration(ImageGenerationConfig imageGeneration) { + this.imageGeneration = imageGeneration; + } + /** Sets tool-search config. @param toolSearch the tool-search config */ public void setToolSearch(ToolSearchConfig toolSearch) { this.toolSearch = toolSearch; diff --git a/java/sdk/src/main/java/com/github/copilot/rpc/ImageGenerationConfig.java b/java/sdk/src/main/java/com/github/copilot/rpc/ImageGenerationConfig.java new file mode 100644 index 0000000000..79b336b4da --- /dev/null +++ b/java/sdk/src/main/java/com/github/copilot/rpc/ImageGenerationConfig.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + */ + +package com.github.copilot.rpc; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; + +/** + * Experimental. This API may change or be removed in a future + * release. Opt in to image generation through an authorized Copilot image + * model. Omission disables on create/cold resume and preserves resident resume + * state. Not persisted: re-supply after runtime restart. Policy, permissions, + * offline mode, and tool filters still apply. BYOK image generation is not + * supported. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +@CopilotExperimental +public class ImageGenerationConfig { + @JsonProperty("enabled") + private Boolean enabled; + + /** + * Gets the image generation opt-in. + * + * @return true to opt in, false to disable, or null when unset + */ + public Boolean getEnabled() { + return enabled; + } + + /** + * Enables or disables image generation. + * + * @param enabled + * the opt-in, or null when unset + * @return this config for method chaining + */ + public ImageGenerationConfig setEnabled(Boolean enabled) { + this.enabled = enabled; + return this; + } +} diff --git a/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionConfig.java b/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionConfig.java index 927aa9555d..44c965bab0 100644 --- a/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionConfig.java +++ b/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionConfig.java @@ -102,6 +102,7 @@ public class ResumeSessionConfig { private List pluginDirectories; private LargeToolOutputConfig largeOutput; private ToolSearchConfig toolSearch; + private ImageGenerationConfig imageGeneration; private MemoryConfiguration memory; private List disabledSkills; private List disabledMcpServers; @@ -1773,6 +1774,29 @@ public ToolSearchConfig getToolSearch() { return toolSearch; } + /** + * Gets the non-persisted image generation opt-in. + * + * @return the image generation config, or null when unset + */ + @CopilotExperimental + public ImageGenerationConfig getImageGeneration() { + return imageGeneration; + } + + /** + * Sets the image generation opt-in. Re-supply after runtime restart. + * + * @param imageGeneration + * the image generation config + * @return this config for method chaining + */ + @CopilotExperimental + public ResumeSessionConfig setImageGeneration(ImageGenerationConfig imageGeneration) { + this.imageGeneration = imageGeneration; + return this; + } + /** * Sets the tool-search configuration. * @@ -2320,6 +2344,7 @@ public ResumeSessionConfig clone() { copy.pluginDirectories = this.pluginDirectories != null ? new ArrayList<>(this.pluginDirectories) : null; copy.largeOutput = this.largeOutput; copy.toolSearch = this.toolSearch; + copy.imageGeneration = this.imageGeneration; copy.memory = this.memory; copy.disabledSkills = this.disabledSkills != null ? new ArrayList<>(this.disabledSkills) : null; copy.disabledMcpServers = this.disabledMcpServers != null ? new ArrayList<>(this.disabledMcpServers) : null; diff --git a/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionRequest.java b/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionRequest.java index 2d6e2474b6..4a5e2a9a7c 100644 --- a/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionRequest.java +++ b/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionRequest.java @@ -209,6 +209,9 @@ public final class ResumeSessionRequest { @JsonProperty("toolSearch") private ToolSearchConfig toolSearch; + @JsonProperty("imageGeneration") + private ImageGenerationConfig imageGeneration; + @JsonProperty("memory") private MemoryConfiguration memory; @@ -1030,6 +1033,19 @@ public ToolSearchConfig getToolSearch() { return toolSearch; } + /** Gets image generation config. @return the image generation config */ + public ImageGenerationConfig getImageGeneration() { + return imageGeneration; + } + + /** + * Sets image generation config. @param imageGeneration the image generation + * config + */ + public void setImageGeneration(ImageGenerationConfig imageGeneration) { + this.imageGeneration = imageGeneration; + } + /** Sets tool-search config. @param toolSearch the tool-search config */ public void setToolSearch(ToolSearchConfig toolSearch) { this.toolSearch = toolSearch; diff --git a/java/sdk/src/main/java/com/github/copilot/rpc/SessionConfig.java b/java/sdk/src/main/java/com/github/copilot/rpc/SessionConfig.java index 926706872b..e912527abc 100644 --- a/java/sdk/src/main/java/com/github/copilot/rpc/SessionConfig.java +++ b/java/sdk/src/main/java/com/github/copilot/rpc/SessionConfig.java @@ -89,6 +89,7 @@ public class SessionConfig { private List pluginDirectories; private LargeToolOutputConfig largeOutput; private ToolSearchConfig toolSearch; + private ImageGenerationConfig imageGeneration; private MemoryConfiguration memory; private List disabledSkills; private List disabledMcpServers; @@ -1353,6 +1354,29 @@ public ToolSearchConfig getToolSearch() { return toolSearch; } + /** + * Gets the non-persisted image generation opt-in. + * + * @return the image generation config, or null when unset + */ + @CopilotExperimental + public ImageGenerationConfig getImageGeneration() { + return imageGeneration; + } + + /** + * Sets the image generation opt-in. Re-supply after runtime restart. + * + * @param imageGeneration + * the image generation config + * @return this config for method chaining + */ + @CopilotExperimental + public SessionConfig setImageGeneration(ImageGenerationConfig imageGeneration) { + this.imageGeneration = imageGeneration; + return this; + } + /** * Sets the tool-search override configuration. When {@code null}, the runtime * default tool-search behavior applies. @@ -2408,6 +2432,7 @@ public SessionConfig clone() { copy.pluginDirectories = this.pluginDirectories != null ? new ArrayList<>(this.pluginDirectories) : null; copy.largeOutput = this.largeOutput; copy.toolSearch = this.toolSearch; + copy.imageGeneration = this.imageGeneration; copy.memory = this.memory; copy.disabledSkills = this.disabledSkills != null ? new ArrayList<>(this.disabledSkills) : null; copy.disabledMcpServers = this.disabledMcpServers != null ? new ArrayList<>(this.disabledMcpServers) : null; diff --git a/java/sdk/src/test/java/com/github/copilot/ImageGenerationConfigTest.java b/java/sdk/src/test/java/com/github/copilot/ImageGenerationConfigTest.java new file mode 100644 index 0000000000..5acace1e7a --- /dev/null +++ b/java/sdk/src/test/java/com/github/copilot/ImageGenerationConfigTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + */ + +package com.github.copilot; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.copilot.rpc.ImageGenerationConfig; +import com.github.copilot.rpc.ResumeSessionConfig; +import com.github.copilot.rpc.SessionConfig; + +class ImageGenerationConfigTest { + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void createAndResumeForwardExplicitOptIn(boolean enabled) { + var imageGeneration = new ImageGenerationConfig().setEnabled(enabled); + var createConfig = new SessionConfig().setImageGeneration(imageGeneration).clone(); + var resumeConfig = new ResumeSessionConfig().setImageGeneration(imageGeneration).clone(); + assertSame(imageGeneration, createConfig.getImageGeneration()); + assertSame(imageGeneration, resumeConfig.getImageGeneration()); + var create = SessionRequestBuilder.buildCreateRequest(createConfig, "image-test"); + var resume = SessionRequestBuilder.buildResumeRequest("image-test", resumeConfig); + for (Object request : new Object[]{create, resume}) { + JsonNode json = JsonRpcClient.getObjectMapper().valueToTree(request); + assertEquals(enabled, json.get("imageGeneration").get("enabled").booleanValue()); + assertEquals(1, json.get("imageGeneration").size()); + } + } + + @Test + void createAndResumeOmitUnsetOptIn() { + var create = SessionRequestBuilder.buildCreateRequest(new SessionConfig(), "image-test"); + var resume = SessionRequestBuilder.buildResumeRequest("image-test", new ResumeSessionConfig()); + for (Object request : new Object[]{create, resume}) { + JsonNode json = JsonRpcClient.getObjectMapper().valueToTree(request); + assertFalse(json.has("imageGeneration")); + } + JsonNode empty = JsonRpcClient.getObjectMapper().valueToTree(new ImageGenerationConfig()); + assertEquals(0, empty.size()); + } +} diff --git a/nodejs/package.json b/nodejs/package.json index 279202c5bc..5af5d28093 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -5,7 +5,7 @@ "url": "https://github.com/github/copilot-sdk.git" }, "version": "0.0.0-dev", - "copilotCliVersion": "1.0.95-1", + "copilotCliVersion": "1.0.95-2", "description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC", "main": "./dist/cjs/index.js", "types": "./dist/index.d.ts", diff --git a/nodejs/src/cliVersion.ts b/nodejs/src/cliVersion.ts index 785341144b..833739e796 100644 --- a/nodejs/src/cliVersion.ts +++ b/nodejs/src/cliVersion.ts @@ -1,3 +1,3 @@ -export const COPILOT_CLI_VERSION = "1.0.95-1"; +export const COPILOT_CLI_VERSION = "1.0.95-2"; export const COPILOT_CLI_USE_NPM_PACKAGE = false; diff --git a/nodejs/src/client.ts b/nodejs/src/client.ts index 2f00114da9..fd82d52ada 100644 --- a/nodejs/src/client.ts +++ b/nodejs/src/client.ts @@ -1806,6 +1806,7 @@ export class CopilotClient { isTerminal: tool.isTerminal, })), toolSearch: config.toolSearch, + imageGeneration: config.imageGeneration, canvases: config.canvases?.map((canvas) => canvas.declaration), requestCanvasRenderer: config.requestCanvasRenderer, requestExtensions: config.requestExtensions, @@ -2119,6 +2120,7 @@ export class CopilotClient { isTerminal: tool.isTerminal, })), toolSearch: config.toolSearch, + imageGeneration: config.imageGeneration, canvases: config.canvases?.map((canvas) => canvas.declaration), workflows: workflows?.map((workflow) => workflow.meta), requestCanvasRenderer: config.requestCanvasRenderer, diff --git a/nodejs/src/extension.ts b/nodejs/src/extension.ts index 99a1c0a3be..f6adc32745 100644 --- a/nodejs/src/extension.ts +++ b/nodejs/src/extension.ts @@ -24,7 +24,7 @@ export { export type JoinSessionConfig = Omit< ResumeSessionConfig, - "onPermissionRequest" | "extensionSdkPath" | "skillProvider" + "onPermissionRequest" | "extensionSdkPath" | "skillProvider" | "imageGeneration" > & { onPermissionRequest?: PermissionHandler; /** @@ -130,15 +130,19 @@ export async function joinSession(config: JoinSessionConfig = {}): Promise => connection.sendRequest("session.plugins.reload", { ...params, sessionId }), + /** + * Installs or updates the plugins the session's managed settings require now, without waiting for the next automatic attempt after a failure, then reloads plugins. Reports progress and failures with the same `session.info` and `session.warning` events as automatic preparation. Fails when the runtime does not prepare managed plugins for the session. + * + * @param params Plugins required by the session's managed settings to install or update again. + * + * @returns Per-plugin outcomes of retrying the plugins required by the session's managed settings. + */ + retryManaged: async (params?: SessionPluginsRetryManagedRequest): Promise => + connection.sendRequest("session.plugins.retryManaged", { ...params, sessionId }), }, /** @experimental */ provider: { diff --git a/nodejs/src/index.ts b/nodejs/src/index.ts index ef91cd9689..ad9e427287 100644 --- a/nodejs/src/index.ts +++ b/nodejs/src/index.ts @@ -245,6 +245,7 @@ export type { ToolTelemetry, ToolResultObject, ToolSearchConfig, + ImageGenerationConfig, TypedSessionEventHandler, TypedSessionLifecycleHandler, ZodSchema, diff --git a/nodejs/src/types.ts b/nodejs/src/types.ts index 5a807c8896..80588c2627 100644 --- a/nodejs/src/types.ts +++ b/nodejs/src/types.ts @@ -863,6 +863,21 @@ export function defineTool( return { name, ...config }; } +/** + * Non-persisted opt-in to image generation. + * @experimental This API may change or be removed in a future release. + */ +export interface ImageGenerationConfig { + /** + * Opt in to image generation through an authorized Copilot image model. + * False disables it; omission defaults to disabled on create/cold resume and + * preserves the setting on resident resume. Not persisted: re-supply after + * runtime restart. Policy, permissions, offline mode, and tool filters still + * apply. BYOK image generation is not supported. + */ + enabled?: boolean; +} + /** * SDK-supplied override for the runtime's built-in tool-search behavior. * @@ -2628,6 +2643,12 @@ export interface SessionConfigBase { */ toolSearch?: ToolSearchConfig; + /** + * Image generation opt-in. Re-supply after runtime restart. + * @experimental This API may change or be removed in a future release. + */ + imageGeneration?: ImageGenerationConfig; + /** * List of tool names to allow. When specified, only these tools will be available. * diff --git a/nodejs/test/e2e/harness/sdkTestContext.ts b/nodejs/test/e2e/harness/sdkTestContext.ts index 1bbc4ab19e..633fd4aa0a 100644 --- a/nodejs/test/e2e/harness/sdkTestContext.ts +++ b/nodejs/test/e2e/harness/sdkTestContext.ts @@ -16,6 +16,7 @@ import { formatError, retry } from "./sdkTestHelper"; import { resolvePreparedRuntimePath } from "../../../scripts/prepare-runtime.js"; import { testBackend, withTestBackend } from "./testBackend"; import { readDiagnosticTail } from "../../../../test/harness/sdk-diagnostics.mjs"; +import type { ReplayBackend } from "../../../../test/harness/replayingCapiProxy"; export const isCI = process.env.GITHUB_ACTIONS === "true"; export const DEFAULT_GITHUB_TOKEN = "fake-token-for-e2e-tests"; @@ -65,6 +66,7 @@ export async function createSdkTestContext({ copilotClientOptions, replayOnly = process.env.COPILOT_SDK_E2E_REPLAY_ONLY === "true", modelNames, + backend = testBackend, }: { logLevel?: "error" | "none" | "warning" | "info" | "debug" | "all"; cliPath?: string; @@ -72,6 +74,8 @@ export async function createSdkTestContext({ copilotClientOptions?: CopilotClientOptions; replayOnly?: boolean; modelNames?: Record; + /** Pin a provider-specific contract instead of inheriting the CI backend matrix. */ + backend?: ReplayBackend; } = {}) { const homeDir = realpathSync(fs.mkdtempSync(join(os.tmpdir(), "copilot-test-config-"))); const copilotHomeDir = realpathSync(fs.mkdtempSync(join(os.tmpdir(), "copilot-test-home-"))); @@ -170,11 +174,11 @@ export async function createSdkTestContext({ class TestClient extends CopilotClient { override createSession(config: SessionConfig) { - return super.createSession(withTestBackend(config, testBackend, proxyUrl)); + return super.createSession(withTestBackend(config, backend, proxyUrl)); } override resumeSession(sessionId: string, config: ResumeSessionConfig) { - return super.resumeSession(sessionId, withTestBackend(config, testBackend, proxyUrl)); + return super.resumeSession(sessionId, withTestBackend(config, backend, proxyUrl)); } } @@ -309,6 +313,7 @@ export async function createSdkTestContext({ } await openAiEndpoint.updateConfig({ + backend, replayOnly, filePath: getTrafficCapturePath(testContext), workDir, diff --git a/nodejs/test/e2e/image_generation.e2e.test.ts b/nodejs/test/e2e/image_generation.e2e.test.ts new file mode 100644 index 0000000000..2473d39127 --- /dev/null +++ b/nodejs/test/e2e/image_generation.e2e.test.ts @@ -0,0 +1,254 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import { describe, expect, it } from "vitest"; +import { + approveAll, + CopilotRequestHandler, + RuntimeConnection, + type CopilotRequestContext, + type CopilotSession, +} from "../../src/index.js"; +import { createSdkTestContext } from "./harness/sdkTestContext.js"; +import { withTestBackend } from "./harness/testBackend.js"; + +const IMAGE_MODEL = "gpt-image-2.5-sunburst"; +const IMAGE_ENDPOINT = "/v1/images/generations"; +const PNG = + "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAABHNCSVQICAgIfAhkiAAAAAFzUkdCAK7OHOkAAAANSURBVAiZY2BgYPgPAAEEAQB9ssjfAAAAAElFTkSuQmCC"; + +class ImageService extends CopilotRequestHandler { + readonly imageRequests: unknown[] = []; + readonly chatToolNames: string[][] = []; + + constructor(private readonly modelAvailable = true) { + super(); + } + + protected override async sendRequest( + request: Request, + context: CopilotRequestContext + ): Promise { + const pathname = new URL(request.url).pathname; + if (pathname.endsWith("/chat/completions") && request.method === "POST") { + const body = (await request.json()) as { + model: string; + stream?: boolean; + tools?: Array<{ function: { name: string } }>; + }; + this.chatToolNames.push(body.tools?.map((tool) => tool.function.name) ?? []); + const message = { role: "assistant", content: "IMAGE_CONSENT_TURN_COMPLETE" }; + const response = { + id: "image-consent-turn", + created: 123, + model: body.model, + usage: { prompt_tokens: 5, completion_tokens: 1, total_tokens: 6 }, + }; + if (!body.stream) { + return Response.json({ + ...response, + object: "chat.completion", + choices: [{ index: 0, message, finish_reason: "stop" }], + }); + } + return new Response( + `data: ${JSON.stringify({ + ...response, + object: "chat.completion.chunk", + choices: [{ index: 0, delta: message, finish_reason: "stop" }], + })}\n\ndata: [DONE]\n\n`, + { headers: { "content-type": "text/event-stream" } } + ); + } + if (pathname === IMAGE_ENDPOINT) { + this.imageRequests.push(await request.json()); + return Response.json({ + created: 123, + data: [{ b64_json: PNG }], + output_format: "png", + }); + } + const response = await super.sendRequest(request, context); + if (pathname !== "/models" || !response.ok) { + return response; + } + const catalog = (await response.json()) as { data: unknown[] }; + if (this.modelAvailable) { + catalog.data.push({ + id: IMAGE_MODEL, + name: "SDK test image model", + capabilities: { type: "image" }, + supported_endpoints: [IMAGE_ENDPOINT], + model_picker_enabled: false, + policy: { state: "enabled" }, + }); + } + return Response.json(catalog); + } +} + +async function imageToolOffered(session: CopilotSession): Promise { + await session.rpc.tools.initializeAndValidate(); + const { tools } = await session.rpc.tools.getCurrentMetadata(); + return tools.some((tool) => tool.name === "image_generation"); +} + +describe("Native image generation consent", async () => { + // Native image inference is CAPI-only, independent of the chat-provider CI matrix. + const { createClient, openAiEndpoint } = await createSdkTestContext({ + replayOnly: true, + backend: "capi", + }); + + it("requires SDK consent and CAPI access regardless of the CLI rollout flag", async () => { + for (const flag of [false, true]) { + for (const enabled of [undefined, false, true]) { + const service = new ImageService(); + await using client = createClient({ requestHandler: service }); + await using session = await client.createSession({ + onPermissionRequest: approveAll, + featureFlags: { IMAGE_GENERATION_TOOL: flag }, + imageGeneration: enabled === undefined ? undefined : { enabled }, + }); + expect(await imageToolOffered(session)).toBe(enabled === true); + expect(service.imageRequests).toEqual([]); + } + } + }); + + it("executes an opted-in CAPI image tool while the rollout flag is off", async () => { + const service = new ImageService(); + await using client = createClient({ requestHandler: service }); + await using session = await client.createSession({ + onPermissionRequest: approveAll, + featureFlags: { IMAGE_GENERATION_TOOL: false }, + imageGeneration: { enabled: true }, + }); + expect(await imageToolOffered(session)).toBe(true); + const result = await session.rpc.tools.execute({ + name: "image_generation", + arguments: { prompt: "A watercolor fox" }, + toolCallId: "sdk-image", + }); + expect(result).toMatchObject({ + resultType: "success", + contents: [{ type: "image", mimeType: "image/png", data: PNG }], + }); + expect(service.imageRequests).toEqual([ + { + model: IMAGE_MODEL, + prompt: "A watercolor fox", + n: 1, + output_format: "png", + stream: false, + }, + ]); + }); + + it("still requires an image model from CAPI", async () => { + const service = new ImageService(false); + await using client = createClient({ requestHandler: service }); + await using session = await client.createSession({ + onPermissionRequest: approveAll, + imageGeneration: { enabled: true }, + featureFlags: { IMAGE_GENERATION_TOOL: true }, + }); + expect(await imageToolOffered(session)).toBe(false); + expect(service.imageRequests).toEqual([]); + }); + + it("preserves resident consent but applies an explicit opt-out", async () => { + await using client = createClient({ requestHandler: new ImageService() }); + await using session = await client.createSession({ + onPermissionRequest: approveAll, + imageGeneration: { enabled: true }, + featureFlags: { IMAGE_GENERATION_TOOL: false }, + }); + expect(await imageToolOffered(session)).toBe(true); + await using resumed = await client.resumeSession(session.sessionId, { + onPermissionRequest: approveAll, + }); + expect(await imageToolOffered(resumed)).toBe(true); + await using disabled = await client.resumeSession(session.sessionId, { + onPermissionRequest: approveAll, + imageGeneration: { enabled: false }, + featureFlags: { IMAGE_GENERATION_TOOL: true }, + }); + expect(await imageToolOffered(disabled)).toBe(false); + }); + + it("requires renewed consent after a runtime restart", async () => { + // Separate stdio runtimes prove that consent is not restored from disk. + const firstService = new ImageService(); + await using first = createClient({ + requestHandler: firstService, + connection: RuntimeConnection.forStdio(), + }); + const original = await first.createSession({ + model: "claude-sonnet-5", + onPermissionRequest: approveAll, + imageGeneration: { enabled: true }, + }); + expect(await imageToolOffered(original)).toBe(true); + // A session with no user activity is deliberately not persisted. + const response = await original.sendAndWait({ + prompt: "Acknowledge this message without using tools.", + }); + expect(response?.data.content).toBe("IMAGE_CONSENT_TURN_COMPLETE"); + expect(firstService.chatToolNames.some((names) => names.includes("image_generation"))).toBe( + true + ); + const sessionId = original.sessionId; + await first.rpc.sessions.save({ sessionId }); + await original.disconnect(); + await first.stop(); + + const secondService = new ImageService(); + await using second = createClient({ + requestHandler: secondService, + connection: RuntimeConnection.forStdio(), + }); + await using resumed = await second.resumeSession(sessionId, { + onPermissionRequest: approveAll, + featureFlags: { IMAGE_GENERATION_TOOL: true }, + }); + expect(await imageToolOffered(resumed)).toBe(false); + const resumedResponse = await resumed.sendAndWait({ + prompt: "Acknowledge again without using tools.", + }); + expect(resumedResponse?.data.content).toBe("IMAGE_CONSENT_TURN_COMPLETE"); + expect(secondService.chatToolNames.length).toBeGreaterThan(0); + expect( + secondService.chatToolNames.every((names) => !names.includes("image_generation")) + ).toBe(true); + await using optedIn = await second.resumeSession(sessionId, { + onPermissionRequest: approveAll, + imageGeneration: { enabled: true }, + featureFlags: { IMAGE_GENERATION_TOOL: false }, + }); + expect(await imageToolOffered(optedIn)).toBe(true); + }); + + it.each(["anthropic-messages", "openai-responses", "openai-completions"] as const)( + "does not expose image generation for %s without CAPI image-model access", + async (backend) => { + const service = new ImageService(false); + await using client = createClient({ requestHandler: service }); + await using session = await client.createSession( + withTestBackend( + { + model: "claude-sonnet-5", + onPermissionRequest: approveAll, + imageGeneration: { enabled: true }, + featureFlags: { IMAGE_GENERATION_TOOL: true }, + }, + backend, + openAiEndpoint.url + ) + ); + expect(await imageToolOffered(session)).toBe(false); + expect(service.imageRequests).toEqual([]); + } + ); +}); diff --git a/nodejs/test/e2e/rpc_surface_coverage.e2e.test.ts b/nodejs/test/e2e/rpc_surface_coverage.e2e.test.ts index 9888df8a7b..9d6836f631 100644 --- a/nodejs/test/e2e/rpc_surface_coverage.e2e.test.ts +++ b/nodejs/test/e2e/rpc_surface_coverage.e2e.test.ts @@ -327,7 +327,7 @@ describe("Generated RPC surface coverage", () => { ...collectRuntimeFunctions(session.rpc, "session"), ]); - expect(inventory).toHaveLength(404); + expect(inventory).toHaveLength(405); expect(inventory.filter((method) => method.wireMethod === "host.listSessions")).toEqual([ expect.objectContaining({ scope: "server", path: "host.listSessions" }), ]); @@ -341,6 +341,15 @@ describe("Generated RPC surface coverage", () => { path: "extensions.reconcile", parameterCount: 0, }); + expect( + inventory.filter((method) => method.wireMethod === "session.plugins.retryManaged") + ).toEqual([ + expect.objectContaining({ + scope: "session", + path: "plugins.retryManaged", + parameterCount: 1, + }), + ]); const sessionProviderMethods = [ "providers.getCatalog", "providers.discover", @@ -467,6 +476,7 @@ describe("Generated RPC surface coverage", () => { expect((await session.rpc.customizations.reload()).outcomes).toEqual([ { subsystem: "instructions", status: "reloaded" }, ]); + await session.rpc.plugins.retryManaged(); await expect( client.rpc.ping({ message: "error", __forceError: true } as never) @@ -496,5 +506,20 @@ describe("Generated RPC surface coverage", () => { { method: wireMethod, params: { sessionId: "rpc-surface-session" } }, ]); } + expect( + captured.filter((request) => request.method === "session.plugins.retryManaged") + ).toEqual([ + { + method: "session.plugins.retryManaged", + params: { + __coveragePath: "session.plugins.retryManaged", + sessionId: "rpc-surface-session", + }, + }, + { + method: "session.plugins.retryManaged", + params: { sessionId: "rpc-surface-session" }, + }, + ]); }); }); diff --git a/nodejs/test/extension.test.ts b/nodejs/test/extension.test.ts index 9bb6b11ae9..132f5a8fc7 100644 --- a/nodejs/test/extension.test.ts +++ b/nodejs/test/extension.test.ts @@ -1,6 +1,6 @@ import { afterEach, describe, expect, it, vi } from "vitest"; import { CopilotClient } from "../src/client.js"; -import { approveAll } from "../src/index.js"; +import { approveAll, type CopilotSession } from "../src/index.js"; import { createCanvas, defineWorkflow, joinSession } from "../src/extension.js"; import { defaultJoinSessionPermissionHandler } from "../src/types.js"; @@ -111,6 +111,22 @@ describe("joinSession", () => { }); }); + it.each([true, false])( + "strips image generation consent (%s) from extension joins", + async (enabled) => { + process.env.SESSION_ID = "session-123"; + const resumeForExtension = vi + .spyOn(CopilotClient.prototype, "resumeSessionForExtension") + .mockResolvedValue({} as CopilotSession); + + const config = { tools: [], imageGeneration: { enabled } }; + await joinSession(config); + + const [, forwarded] = resumeForExtension.mock.calls[0]!; + expect(forwarded).not.toHaveProperty("imageGeneration"); + } + ); + it("exports the canvas helper from the extension surface", () => { const canvas = createCanvas({ id: "counter", diff --git a/nodejs/test/image-generation.test.ts b/nodejs/test/image-generation.test.ts new file mode 100644 index 0000000000..93e5a4d71b --- /dev/null +++ b/nodejs/test/image-generation.test.ts @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. + +import { once } from "node:events"; +import { createServer } from "node:net"; +import { describe, expect, it, onTestFinished } from "vitest"; +import { + createMessageConnection, + StreamMessageReader, + StreamMessageWriter, + type MessageConnection, +} from "vscode-jsonrpc/node.js"; +import { + approveAll, + CopilotClient, + RuntimeConnection, + type ImageGenerationConfig, +} from "../src/index.js"; +import { getSdkProtocolVersion } from "../src/sdkProtocolVersion.js"; + +describe("image generation request serialization", () => { + it.each([undefined, {}, { enabled: true }, { enabled: false }] satisfies ( + | ImageGenerationConfig + | undefined + )[])("forwards %j on create and resume", async (imageGeneration) => { + const requests = new Map>(); + const connections: MessageConnection[] = []; + const server = createServer((socket) => { + const connection = createMessageConnection( + new StreamMessageReader(socket), + new StreamMessageWriter(socket) + ); + connections.push(connection); + connection.onRequest((method, params) => { + if (method === "connect") { + return { ok: true, protocolVersion: getSdkProtocolVersion(), version: "test" }; + } + if (method === "session.create" || method === "session.resume") { + const payload = params as Record; + requests.set(method, payload); + return { sessionId: payload.sessionId }; + } + return {}; + }); + connection.listen(); + }); + onTestFinished(async () => { + for (const connection of connections) connection.dispose(); + await new Promise((resolve, reject) => + server.close((error) => (error ? reject(error) : resolve())) + ); + }); + server.listen(0, "127.0.0.1"); + await once(server, "listening"); + const address = server.address(); + if (!address || typeof address === "string") throw new Error("Missing TCP address"); + const client = new CopilotClient({ + connection: RuntimeConnection.forUri(`127.0.0.1:${address.port}`), + }); + onTestFinished(() => client.forceStop()); + const session = await client.createSession({ + onPermissionRequest: approveAll, + imageGeneration, + }); + await client.resumeSession(session.sessionId, { + onPermissionRequest: approveAll, + imageGeneration, + }); + for (const method of ["session.create", "session.resume"]) { + const payload = requests.get(method); + expect(payload).toBeDefined(); + if (imageGeneration === undefined) { + expect(payload).not.toHaveProperty("imageGeneration"); + } else { + expect(payload?.imageGeneration).toEqual(imageGeneration); + } + } + }); +}); diff --git a/python/copilot/__init__.py b/python/copilot/__init__.py index 9e9a9fa8bf..ae3aa7e7ac 100644 --- a/python/copilot/__init__.py +++ b/python/copilot/__init__.py @@ -157,6 +157,7 @@ ExitPlanModeRequest, ExitPlanModeResult, GitHubMcpToolConfig, + ImageGenerationConfig, InfiniteSessionConfig, InputOptions, LargeToolOutputConfig, @@ -464,6 +465,7 @@ "ToolResult", "ToolResultType", "ToolSearchConfig", + "ImageGenerationConfig", "ToolSet", "UriRuntimeConnection", "UserInputHandler", diff --git a/python/copilot/client.py b/python/copilot/client.py index 2d0230023c..fc9ea41718 100644 --- a/python/copilot/client.py +++ b/python/copilot/client.py @@ -114,6 +114,7 @@ ElicitationHandler, ExitPlanModeHandler, GitHubMcpToolConfig, + ImageGenerationConfig, InfiniteSessionConfig, LargeToolOutputConfig, McpAuthHandler, @@ -2359,6 +2360,7 @@ async def create_session( tools: list[Tool] | None = None, system_message: SystemMessageConfig | None = None, tool_search: ToolSearchConfig | None = None, + image_generation: ImageGenerationConfig | None = None, available_tools: list[str] | ToolSet | None = None, excluded_tools: list[str] | ToolSet | None = None, on_user_input_request: UserInputHandler | None = None, @@ -2568,6 +2570,8 @@ async def create_session( already running. This does not change global MCP settings. infinite_sessions: Infinite session configuration. memory: Session memory configuration. + image_generation: **Experimental.** Image generation opt-in. Not persisted; re-supply + after runtime restart. See :class:`ImageGenerationConfig`. cloud: Creates a remote session in the cloud instead of a local session. Optionally associates repository metadata with the cloud session. @@ -2715,6 +2719,8 @@ async def create_session( if tool_search is not None: payload["toolSearch"] = _tool_search_to_wire(tool_search) + if image_generation is not None: + payload["imageGeneration"] = dict(image_generation) if available_tools is not None: payload["availableTools"] = available_tools @@ -3239,6 +3245,7 @@ async def resume_session( tools: list[Tool] | None = None, system_message: SystemMessageConfig | None = None, tool_search: ToolSearchConfig | None = None, + image_generation: ImageGenerationConfig | None = None, available_tools: list[str] | ToolSet | None = None, excluded_tools: list[str] | ToolSet | None = None, on_user_input_request: UserInputHandler | None = None, @@ -3444,6 +3451,8 @@ async def resume_session( already running. This does not change global MCP settings. infinite_sessions: Infinite session configuration. memory: Session memory configuration. + image_generation: **Experimental.** Image generation opt-in. Omission preserves a + resident session's setting; re-supply after runtime restart. on_event: Callback for session events. enable_mcp_apps: **Experimental.** Opt into MCP Apps (SEP-1865) UI passthrough on resume. This parameter is part of an experimental @@ -3589,6 +3598,8 @@ async def resume_session( payload["systemMessage"] = wire_system_message if tool_search is not None: payload["toolSearch"] = _tool_search_to_wire(tool_search) + if image_generation is not None: + payload["imageGeneration"] = dict(image_generation) if available_tools is not None: payload["availableTools"] = available_tools if excluded_tools is not None: diff --git a/python/copilot/generated/rpc.py b/python/copilot/generated/rpc.py index c4010c7315..e496e3addf 100644 --- a/python/copilot/generated/rpc.py +++ b/python/copilot/generated/rpc.py @@ -6483,6 +6483,19 @@ def to_dict(self) -> dict: result["tools"] = from_union([lambda x: from_list(from_str, x), from_none], self.tools) return result +# Experimental: this type is part of an experimental API and may change or be removed. +class ManagedPluginRetryStatus(Enum): + """What the retry did for this plugin. + + What retrying did for one plugin required by managed settings. + """ + ALREADY_PRESENT = "already_present" + DEFERRED = "deferred" + FAILED = "failed" + INSTALLED = "installed" + NOT_REQUIRED = "not_required" + UPDATED = "updated" + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class ManagedSettingMeta: @@ -14664,6 +14677,26 @@ def to_dict(self) -> dict: result["reloadMcp"] = from_union([from_bool, from_none], self.reload_mcp) return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SessionPluginsRetryManagedRequest: + plugins: list[str] | None = None + """"plugin@marketplace" specs to retry. Omit to retry every plugin the session's managed + settings require. + """ + + @staticmethod + def from_dict(obj: Any) -> 'SessionPluginsRetryManagedRequest': + assert isinstance(obj, dict) + plugins = from_union([lambda x: from_list(from_str, x), from_none], obj.get("plugins")) + return SessionPluginsRetryManagedRequest(plugins) + + def to_dict(self) -> dict: + result: dict = {} + if self.plugins is not None: + result["plugins"] = from_union([lambda x: from_list(from_str, x), from_none], self.plugins) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class SessionPruneResult: @@ -28105,6 +28138,36 @@ def to_dict(self) -> dict: result["version"] = from_union([from_str, from_none], self.version) return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class ManagedPluginRetryEntry: + """Retry outcome for one plugin required by managed settings.""" + + spec: str + """Plugin spec in "plugin@marketplace" form.""" + + status: ManagedPluginRetryStatus + """What the retry did for this plugin.""" + + error: str | None = None + """Why the plugin was not prepared. Present when `status` is `failed` or `deferred`.""" + + @staticmethod + def from_dict(obj: Any) -> 'ManagedPluginRetryEntry': + assert isinstance(obj, dict) + spec = from_str(obj.get("spec")) + status = ManagedPluginRetryStatus(obj.get("status")) + error = from_union([from_str, from_none], obj.get("error")) + return ManagedPluginRetryEntry(spec, status, error) + + def to_dict(self) -> dict: + result: dict = {} + result["spec"] = from_str(self.spec) + result["status"] = to_enum(ManagedPluginRetryStatus, self.status) + if self.error is not None: + result["error"] = from_union([from_str, from_none], self.error) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class MarketplacePluginInfo: @@ -37457,6 +37520,27 @@ def to_dict(self) -> dict: result["plugins"] = from_list(lambda x: to_class(InstalledPluginInfo, x), self.plugins) return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SessionPluginsRetryManagedResult: + """Per-plugin outcomes of retrying the plugins required by the session's managed settings.""" + + plugins: list[ManagedPluginRetryEntry] + """One entry per requested plugin, in request order. When no plugins were requested, one + entry per plugin the managed settings require. + """ + + @staticmethod + def from_dict(obj: Any) -> 'SessionPluginsRetryManagedResult': + assert isinstance(obj, dict) + plugins = from_list(ManagedPluginRetryEntry.from_dict, obj.get("plugins")) + return SessionPluginsRetryManagedResult(plugins) + + def to_dict(self) -> dict: + result: dict = {} + result["plugins"] = from_list(lambda x: to_class(ManagedPluginRetryEntry, x), self.plugins) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class MarketplaceBrowseResult: @@ -50164,6 +50248,8 @@ class RPC: log_result: LogResult lsp_initialize_request: LspInitializeRequest managed_mcp_server_config: ManagedMCPServerConfig + managed_plugin_retry_entry: ManagedPluginRetryEntry + managed_plugin_retry_status: ManagedPluginRetryStatus managed_setting_meta: ManagedSettingMeta managed_settings_channel: ManagedSettingsChannel managed_settings_compose_layer: ManagedSettingsComposeLayer @@ -50893,6 +50979,8 @@ class RPC: session_plugins_install_request: SessionPluginsInstallRequest session_plugins_marketplaces_refresh_request: SessionPluginsMarketplacesRefreshRequest session_plugins_reload_request: SessionPluginsReloadRequest + session_plugins_retry_managed_request: SessionPluginsRetryManagedRequest + session_plugins_retry_managed_result: SessionPluginsRetryManagedResult session_provider_get_endpoint_request: SessionProviderGetEndpointRequest session_prune_result: SessionPruneResult session_quota_delegate_warning: SessionQuotaDelegateWarning @@ -51760,6 +51848,8 @@ def from_dict(obj: Any) -> 'RPC': log_result = LogResult.from_dict(obj.get("LogResult")) lsp_initialize_request = LspInitializeRequest.from_dict(obj.get("LspInitializeRequest")) managed_mcp_server_config = ManagedMCPServerConfig.from_dict(obj.get("ManagedMcpServerConfig")) + managed_plugin_retry_entry = ManagedPluginRetryEntry.from_dict(obj.get("ManagedPluginRetryEntry")) + managed_plugin_retry_status = ManagedPluginRetryStatus(obj.get("ManagedPluginRetryStatus")) managed_setting_meta = ManagedSettingMeta.from_dict(obj.get("ManagedSettingMeta")) managed_settings_channel = ManagedSettingsChannel(obj.get("ManagedSettingsChannel")) managed_settings_compose_layer = ManagedSettingsComposeLayer.from_dict(obj.get("ManagedSettingsComposeLayer")) @@ -52489,6 +52579,8 @@ def from_dict(obj: Any) -> 'RPC': session_plugins_install_request = SessionPluginsInstallRequest.from_dict(obj.get("SessionPluginsInstallRequest")) session_plugins_marketplaces_refresh_request = SessionPluginsMarketplacesRefreshRequest.from_dict(obj.get("SessionPluginsMarketplacesRefreshRequest")) session_plugins_reload_request = SessionPluginsReloadRequest.from_dict(obj.get("SessionPluginsReloadRequest")) + session_plugins_retry_managed_request = SessionPluginsRetryManagedRequest.from_dict(obj.get("SessionPluginsRetryManagedRequest")) + session_plugins_retry_managed_result = SessionPluginsRetryManagedResult.from_dict(obj.get("SessionPluginsRetryManagedResult")) session_provider_get_endpoint_request = SessionProviderGetEndpointRequest.from_dict(obj.get("SessionProviderGetEndpointRequest")) session_prune_result = SessionPruneResult.from_dict(obj.get("SessionPruneResult")) session_quota_delegate_warning = SessionQuotaDelegateWarning.from_dict(obj.get("SessionQuotaDelegateWarning")) @@ -52864,7 +52956,7 @@ def from_dict(obj: Any) -> 'RPC': subagent_settings = from_union([SubagentSettings.from_dict, from_none], obj.get("SubagentSettings")) task_progress = from_union([TaskProgress.from_dict, from_none], obj.get("TaskProgress")) workspace_summary = from_union([WorkspaceSummary.from_dict, from_none], obj.get("WorkspaceSummary")) - return RPC(abort_request, abort_result, accepted_enqueue_command_result, account_all_users, account_auth_info, account_get_all_users_result, account_get_current_auth_result, account_get_quota_request, account_get_quota_result, account_kind, account_login_request, account_login_result, account_logout_request, account_logout_result, account_quota_snapshot, accounts_enumerate_request, accounts_get_request, accounts_set_request, account_status, adaptive_thinking_support, agent_discovery_path, agent_discovery_path_list, agent_discovery_path_scope, agent_get_current_result, agent_info, agent_info_source, agent_list, agent_list_request, agent_registry_live_target_entry, agent_registry_live_target_entry_attention_kind, agent_registry_live_target_entry_kind, agent_registry_live_target_entry_last_terminal_event, agent_registry_live_target_entry_status, agent_registry_log_capture, agent_registry_log_capture_open_error_reason, agent_registry_spawn_error, agent_registry_spawn_permission_mode, agent_registry_spawn_registry_timeout, agent_registry_spawn_request, agent_registry_spawn_result, agent_registry_spawn_spawned, agent_registry_spawn_validation_error, agent_registry_spawn_validation_error_field, agent_registry_spawn_validation_error_reason, agent_reload_result, agents_custom_agent_initial_model_decision_params, agents_custom_agent_initial_model_decision_result, agents_discover_request, agent_select_request, agent_select_result, agent_set_prompt_request, agents_get_available_builtins_request, agents_get_available_builtins_result, agents_get_builtin_definition_request, agents_get_builtin_definition_result, agents_get_builtin_listing_definition_request, agents_get_builtin_listing_definition_result, agents_get_builtins_result, agents_get_discovery_paths_request, api_key_auth_info, auth_enumerate_query, auth_enumerate_value, auth_identity, auth_identity_metadata, auth_info, auth_info_type, auth_login_account, auth_login_advance_request, auth_login_begin_request, auth_login_begun, auth_login_cancel_request, auth_login_result_dto, auth_login_result_status, auth_login_step, auth_read_query, auth_read_value, auth_status_dto, auth_validation_error, auth_validation_errors, auth_write, auth_write_result, autopilot_objective_credit_limit, autopilot_objective_get_state_result, autopilot_objective_state, autopilot_objective_status, auto_tier_descriptor, auto_tier_metadata, auto_tier_status, builtin_agent_summary, built_in_model_catalog, built_in_model_catalog_entry, builtin_tool_descriptor, builtin_tool_format, builtin_tool_format_type, builtin_tool_input_schema, builtin_tool_input_schema_type, builtin_tool_safe_for_telemetry, builtin_tool_safe_telemetry_fields, cancel_user_requested_shell_command_result, canvas_action, canvas_action_invoke_request, canvas_action_invoke_result, canvas_close_request, canvas_host_context, canvas_host_context_capabilities, canvas_json_schema, canvas_list, canvas_list_open_result, canvas_open_request, canvas_provider_close_request, canvas_provider_invoke_action_request, canvas_provider_open_request, canvas_provider_open_result, canvas_provider_register_request, canvas_provider_unregister_request, canvas_session_context, capi_session_options, card_digest, card_digest_algorithm, card_digest_value, catalog_agent_plugin_candidate, catalog_agent_plugin_candidate_kind, catalog_agent_plugin_candidate_provenance, catalog_agent_plugin_compatibility_tag, catalog_agent_plugin_media_type, catalog_ai_skill_candidate, catalog_ai_skill_candidate_kind, catalog_ai_skill_candidate_provenance, catalog_ai_skill_installability, catalog_ai_skill_media_type, catalog_authentication_required_error, catalog_authentication_required_reason, catalog_candidate, catalog_candidate_kind, catalog_candidate_source, catalog_candidate_source_embedded, catalog_candidate_source_url, catalog_capability, catalog_capability_id, catalog_client_contract, catalog_contract_violation_error, catalog_contract_violation_reason, catalog_handle_rejected_error, catalog_handle_rejection_reason, catalog_handle_type, catalog_invalid_request_error, catalog_invalid_request_field, catalog_malformed_card_error, catalog_malformed_card_reason, catalog_mcp_server_candidate, catalog_mcp_server_candidate_kind, catalog_mcp_server_candidate_provenance, catalog_mcp_server_installability, catalog_media_type, catalog_negotiated_contract, catalog_negotiation_refused_error, catalog_negotiation_refused_reason, catalog_network_failure_error, catalog_network_failure_reason, catalog_not_installable_error, catalog_not_installable_reason, catalog_plugin_repository_source, catalog_policy_rejected_error, catalog_resource_identity, catalog_resource_version, catalog_search_page, catalog_search_pagination, catalog_search_request, catalog_search_result, catalog_search_succeeded, catalog_search_total_count_relation, catalog_selection_cancelled, catalog_selection_decision, catalog_selection_declined, catalog_selection_foreign, catalog_selection_invalid, catalog_selection_replayed, catalog_selection_request, catalog_selection_result, catalog_selection_selected, catalog_selection_stale, catalog_selection_timed_out, catalog_selection_wrong_kind, catalog_trust_eligibility, catalog_trust_provenance, catalog_trust_snapshot, catalog_trust_snapshot_absent, catalog_trust_snapshot_absent_status, catalog_trust_snapshot_current, catalog_trust_snapshot_current_status, catalog_trust_snapshot_downgraded, catalog_trust_snapshot_downgraded_status, catalog_trust_snapshot_malformed, catalog_trust_snapshot_malformed_status, catalog_trust_snapshot_revoked, catalog_trust_snapshot_revoked_status, catalog_trust_snapshot_schema_version, catalog_trust_snapshot_stale, catalog_trust_snapshot_stale_status, catalog_trust_snapshot_unsupported, catalog_trust_snapshot_unsupported_status, catalog_trust_source, catalog_trust_tier, catalog_unavailable_error, catalog_unavailable_reason, catalog_unavailable_transport_error, catalog_unavailable_transport_reason, catalog_unsafe_retrieval_error, catalog_unsafe_retrieval_reason, catalog_unsupported_kind_error, client_metadata, client_task_cancel_reason, client_task_cancel_request, client_task_cancel_result, command_list, commands_finalize_invocation_effect_request, commands_finalize_invocation_effect_result, commands_handle_pending_command_request, commands_handle_pending_command_result, commands_invocation_effect_outcome, commands_invocation_origin, commands_invoke_request, commands_list_request, commands_respond_to_queued_command_request, commands_respond_to_queued_command_result, completions_get_trigger_characters_result, completions_request_request, completions_request_result, configure_session_extensions_params, connect_client_info, connected_remote_session_metadata, connected_remote_session_metadata_kind, connected_remote_session_metadata_repository, connector_account_request, connector_authorization_requirement, connector_authorization_scope, connector_availability, connector_capabilities, connector_catalog_entry, connector_catalog_result, connector_catalog_status, connector_connect_request, connector_connect_result, connector_continue_request, connector_disconnect_result, connector_discovery_account, connector_discovery_account_list, connector_discovery_account_request, connector_discovery_auth_info, connector_discovery_availability, connector_discovery_capabilities, connector_discovery_catalog_entry, connector_discovery_catalog_result, connector_mcp_status, connector_reconcile_request, connector_runtime_status, connector_session_account, connector_status, connect_remote_session_params, connect_request, connect_result, content_exclusion_check_paths_request, content_exclusion_check_paths_result, content_exclusion_path_check, content_filter_mode, context_heaviest_message, copilot_api_token_auth_info, copilot_user_response, copilot_user_response_endpoints, copilot_user_response_quota_snapshots, copilot_user_response_quota_snapshots_chat, copilot_user_response_quota_snapshots_completions, copilot_user_response_quota_snapshots_premium_interactions, current_model, current_tool_metadata, customization_reload_outcome, customization_reload_status, customization_reload_subsystem, customizations_reload_result, debug_collect_logs_collected_entry, debug_collect_logs_destination, debug_collect_logs_entry, debug_collect_logs_entry_kind, debug_collect_logs_include, debug_collect_logs_redaction, debug_collect_logs_request, debug_collect_logs_result, debug_collect_logs_result_kind, debug_collect_logs_skipped_entry, debug_collect_logs_source, diagnostic_cursor_status, diagnostic_entry, diagnostic_log_level, diagnostics_configuration, diagnostics_configure_request, diagnostic_severity, diagnostic_source, diagnostic_sources_configuration, diagnostics_read_request, diagnostics_read_result, discovered_canvas, discovered_extension, discovered_extension_mode, discovered_extension_plugin, discovered_extensions, discovered_extensions_disable_request, discovered_extensions_enable_request, discovered_extension_source, discovered_hook, discovered_mcp_server, discovered_mcp_server_type, discovered_model, discovered_model_list, enqueue_command_params, enqueue_command_result, env_auth_info, environment_capabilities, environment_kind, environments_delete_request, environments_delete_result, environments_get_request, environments_get_result, environments_list_request, environments_list_result, event_log_read_request, event_log_release_interest_result, event_log_tail_result, event_log_types, events_agent_scope, events_cursor_status, events_read_direction, events_read_result, execute_command_params, execute_command_result, extension, extension_context_push_input, extension_launch_profile, extension_launch_provider_resolve_request, extension_launch_provider_resolve_result, extension_list, extensions_disable_request, extensions_enable_request, extension_source, extension_status, external_tool_result, external_tool_text_result_for_llm, external_tool_text_result_for_llm_binary_results_for_llm, external_tool_text_result_for_llm_binary_results_for_llm_type, external_tool_text_result_for_llm_content, external_tool_text_result_for_llm_content_audio, external_tool_text_result_for_llm_content_image, external_tool_text_result_for_llm_content_resource, external_tool_text_result_for_llm_content_resource_details, external_tool_text_result_for_llm_content_resource_link, external_tool_text_result_for_llm_content_resource_link_icon, external_tool_text_result_for_llm_content_resource_link_icon_theme, external_tool_text_result_for_llm_content_shell_exit, external_tool_text_result_for_llm_content_terminal, external_tool_text_result_for_llm_content_text, filter_mapping, fleet_start_request, fleet_start_result, folder_trust_add_params, folder_trust_check_params, folder_trust_check_result, gh_cli_auth_info, git_current_branch_remote_result, git_cwd_request, git_hub_environment, git_hub_owner_option, git_hub_owners_cancel_request, git_hub_owners_cancel_result, git_hub_owners_list_request, git_hub_owners_list_result, git_hub_owners_request_id_result, git_hub_repository_at_path_request, git_hub_repository_at_path_result, git_hub_repository_identity, git_hub_telemetry_client_info, git_hub_telemetry_event, git_hub_telemetry_notification, git_hub_token_acquire_reason, git_hub_token_acquire_request, git_hub_token_acquire_result, git_remote_repository, git_repos_from_remotes_request, git_repos_from_remotes_result, global_state_load_for_config_dir_request, global_state_load_result, global_state_write_key_request, handle_pending_tool_call_request, handle_pending_tool_call_result, history_abort_manual_compaction_result, history_cancel_background_compaction_result, history_clear_context_request, history_clear_context_result, history_compact_context_window, history_compact_request, history_compact_result, history_file_restore_skip_reason, history_list_rewind_points_result, history_preview_rewind_request, history_preview_rewind_result, history_rewind_change_type, history_rewind_file_preview, history_rewind_mode, history_rewind_outcome, history_rewind_point, history_rewind_request, history_rewind_result, history_rewind_unavailable_reason, history_skipped_file_restore, history_summarize_for_handoff_result, history_truncate_request, history_truncate_result, hmac_auth_info, hook_invoke_request, hook_invoke_response, hook_origin, hooks_discover_request, hooks_discover_result, hook_type, host_configuration, host_dispose_request, host_empty_result, host_environment_credentials, host_exited_notification, host_exit_reason, host_git_hub_environment_options, host_list_sessions_request, host_list_sessions_result, host_local_server_configuration, host_local_server_options, host_publish_session_request, host_publish_session_result, host_ready_request, host_register_session_request, host_session_create_callback, host_session_create_request, host_session_create_result, host_session_released_notification, host_session_release_request, host_session_summary, host_start_request, host_start_result, installation_catalogue_identity, installation_confirmation_request, installation_confirmation_response, installation_decision, installation_review, installed_plugin, installed_plugin_info, installed_plugin_source, installed_plugin_source_git_hub, installed_plugin_source_local, installed_plugin_source_url, instruction_discovery_path, instruction_discovery_path_kind, instruction_discovery_path_list, instruction_discovery_path_location, instructions_discover_request, instructions_get_discovery_paths_request, instructions_get_sources_result, instruction_source, instruction_source_location, instruction_source_type, interrupt_main_turn_request, interrupt_main_turn_result, json_schema_response_format, llm_inference_headers, llm_inference_http_request_chunk_request, llm_inference_http_request_chunk_result, llm_inference_http_request_start_request, llm_inference_http_request_start_result, llm_inference_http_request_start_transport, llm_inference_http_response_chunk_error, llm_inference_http_response_chunk_request, llm_inference_http_response_chunk_result, llm_inference_http_response_start_request, llm_inference_http_response_start_result, llm_inference_set_provider_result, local_session_metadata_value, logged_in_user, login_provider_kind, log_request, log_result, lsp_initialize_request, managed_mcp_server_config, managed_setting_meta, managed_settings_channel, managed_settings_compose_layer, managed_settings_compose_request, managed_settings_compose_result, managed_settings_diagnostic, managed_settings_diagnostic_severity, managed_settings_layer, managed_settings_meta, managed_settings_read_result, managed_settings_resolved_data, managed_settings_resolve_request, managed_settings_resolve_result, managed_settings_schema_result, managed_settings_validate_request, managed_settings_validate_result, managed_settings_values, marketplace_add_result, marketplace_browse_result, marketplace_info, marketplace_list_result, marketplace_plugin_info, marketplace_refresh_entry, marketplace_refresh_result, marketplace_remove_result, mcp_allowed_server, mcp_apply_install_request, mcp_apply_uninstall_request, mcp_apps_call_tool_request, mcp_apps_diagnose_capability, mcp_apps_diagnose_request, mcp_apps_diagnose_result, mcp_apps_diagnose_server, mcp_apps_host_context, mcp_apps_host_context_details, mcp_apps_host_context_details_available_display_mode, mcp_apps_host_context_details_display_mode, mcp_apps_host_context_details_platform, mcp_apps_host_context_details_theme, mcp_apps_list_tools_request, mcp_apps_list_tools_result, mcp_apps_read_resource_request, mcp_apps_read_resource_result, mcp_apps_resource_content, mcp_apps_set_host_context_details, mcp_apps_set_host_context_details_available_display_mode, mcp_apps_set_host_context_details_display_mode, mcp_apps_set_host_context_details_platform, mcp_apps_set_host_context_details_theme, mcp_apps_set_host_context_request, mcp_cancel_sampling_execution_params, mcp_cancel_sampling_execution_result, mcp_config_add_request, mcp_config_disable_request, mcp_config_enable_request, mcp_config_list, mcp_config_remove_request, mcp_config_update_request, mcp_configured_server, mcp_configured_server_list, mcp_configured_server_state, mcp_configure_git_hub_request, mcp_configure_git_hub_result, mcp_diagnostic_details, mcp_diagnostic_direction, mcp_diagnostic_kind, mcp_diagnostic_source_configuration, mcp_disable_request, mcp_discover_request, mcp_discover_result, mcp_elicitation_form_mode, mcp_enable_request, mcp_execute_sampling_params, mcp_execute_sampling_request, mcp_execute_sampling_result, mcp_failed_server, mcp_filtered_server, mcp_headers_handle_pending_headers_refresh_request, mcp_headers_handle_pending_headers_refresh_request_request, mcp_headers_handle_pending_headers_refresh_request_result, mcp_host_state, mcp_installation_failure_reason, mcp_installation_input, mcp_installation_management_outcome, mcp_installation_management_result, mcp_installation_operation_request, mcp_installation_operation_status, mcp_installation_outcome, mcp_installation_remote_configuration, mcp_installation_result, mcp_installation_review, mcp_installation_secret, mcp_installation_secret_storage, mcp_installations_request, mcp_installation_state, mcp_installation_summary, mcp_install_plan, mcp_is_server_running_request, mcp_is_server_running_result, mcp_list_tools_request, mcp_list_tools_result, mcp_oauth_authentication_state_changed_request, mcp_oauth_cancel_login_request, mcp_oauth_cancel_login_result, mcp_oauth_complete_request, mcp_oauth_handle_pending_request, mcp_oauth_handle_pending_result, mcp_oauth_login_grant_type, mcp_oauth_login_request, mcp_oauth_login_result, mcp_oauth_pending_request_response, mcp_oauth_prepare_login_request, mcp_oauth_prepare_login_result, mcp_oauth_probe_needs_auth_reason, mcp_oauth_probe_request, mcp_oauth_probe_result, mcp_oauth_respond_request, mcp_oauth_respond_result, mcp_owned_oauth_login_status, mcp_plan_configuration_change, mcp_plan_configuration_operation, mcp_plan_enum_value_type, mcp_plan_install_planned, mcp_plan_install_request, mcp_plan_install_result, mcp_plan_install_source, mcp_plan_install_source_candidate, mcp_plan_install_source_candidate_kind, mcp_plan_install_source_card, mcp_plan_install_source_card_kind, mcp_plan_package_install_method, mcp_plan_package_transport, mcp_plan_policy_decision, mcp_plan_policy_result, mcp_plan_policy_source, mcp_plan_provenance, mcp_plan_remote_install_method, mcp_plan_remote_transport, mcp_plan_required_value, mcp_plan_required_value_enum, mcp_plan_required_value_enum_kind, mcp_plan_required_value_scalar, mcp_plan_required_value_scalar_kind, mcp_plan_resource_identity, mcp_plan_scalar_value_type, mcp_plan_scope, mcp_plan_secret_placeholder, mcp_plan_secret_reference, mcp_plan_target, mcp_plan_transport_choice, mcp_plan_transport_choice_package, mcp_plan_transport_choice_remote, mcp_plan_uninstall_request, mcp_plan_value_category, mcp_prepared_install, mcp_prepare_install_request, mcp_prompt, mcp_prompt_argument, mcp_prompt_icon, mcp_prompt_message, mcp_prompt_role, mcp_prompts_get_request, mcp_prompts_get_result, mcp_prompts_list_request, mcp_prompts_list_result, mcp_register_external_client_request, mcp_reload_config, mcp_reload_with_config_request, mcp_remove_git_hub_result, mcp_resource, mcp_resource_annotations, mcp_resource_content, mcp_resource_icon, mcp_resources_list_request, mcp_resources_list_result, mcp_resources_list_templates_request, mcp_resources_list_templates_result, mcp_resources_read_request, mcp_resources_read_result, mcp_resource_template, mcp_restart_server_request, mcp_safe_for_telemetry, mcp_safe_for_telemetry_fields, mcp_sampling_execution_action, mcp_sampling_execution_result, mcp_serializable_server_config, mcp_server, mcp_server_auth_config, mcp_server_auth_config_redirect_port, mcp_server_card_embedded, mcp_server_card_embedded_kind, mcp_server_card_media_type, mcp_server_card_reference, mcp_server_card_url, mcp_server_card_url_kind, mcp_server_config, mcp_server_config_defer_tools, mcp_server_config_http, mcp_server_config_http_oauth_grant_type, mcp_server_config_http_type, mcp_server_config_memory, mcp_server_config_memory_type, mcp_server_config_stdio, mcp_server_config_stdio_type, mcp_server_failure_info, mcp_server_list, mcp_server_needs_auth_info, mcp_server_ownership, mcp_set_env_value_mode_details, mcp_set_env_value_mode_params, mcp_set_env_value_mode_result, mcp_source_file, mcp_source_plugin, mcp_source_ref, mcp_start_server_request, mcp_start_servers_result, mcp_stop_server_request, mcp_task_metadata, mcp_tools, mcp_tool_ui, mcp_tool_ui_visibility, mcp_uninstall_plan, mcp_unregister_external_client_request, memory_configuration, metadata_context_attribution_result, metadata_context_heaviest_messages_request, metadata_context_heaviest_messages_result, metadata_context_info_request, metadata_context_info_result, metadata_is_processing_result, metadata_recompute_context_tokens_request, metadata_recompute_context_tokens_result, metadata_record_context_change_request, metadata_record_context_change_result, metadata_set_working_directory_request, metadata_set_working_directory_result, metadata_snapshot_current_mode, metadata_snapshot_remote_metadata, metadata_snapshot_remote_metadata_repository, metadata_snapshot_remote_metadata_task_type, metadata_update_client_metadata_request, model, model_apply_startup_overlay_request, model_artifact_details, model_billing, model_billing_promo, model_billing_token_prices, model_billing_token_prices_long_context, model_capabilities, model_capabilities_limits, model_capabilities_limits_vision, model_capabilities_override, model_capabilities_override_limits, model_capabilities_override_limits_vision, model_capabilities_override_supports, model_capabilities_supports, model_clear_startup_seed_request, model_clear_startup_seed_result, model_list, model_list_request, model_message, model_picker_category, model_picker_persistence_request, model_picker_price_category, model_picker_settings_context, model_policy, model_policy_state, model_provider_adapter_catalog, model_provider_adapter_descriptor, model_provider_adapter_operation_descriptor, model_provider_attribution, model_provider_automatic_discovery_mode, model_provider_automatic_discovery_policy, model_provider_configuration_disposition, model_provider_configuration_plan, model_provider_descriptor, model_provider_discover_request, model_provider_discover_result, model_provider_discovery_network_scope, model_provider_get_status_request, model_provider_instance, model_provider_instance_reference, model_provider_models_list_request, model_provider_operation_outcome, model_provider_operation_outcome_code, model_provider_prepare_configuration_request, model_provider_provenance, model_provider_provenance_source, model_provider_status, model_provider_warning, model_set_allowed_models_request, model_set_allowed_models_result, model_set_reasoning_effort_request, model_set_reasoning_effort_result, models_list_request, model_switch_auto_tier_request, model_switch_auto_tier_result, model_switch_auto_tier_status, model_switch_confirmation, model_switch_to_request, model_switch_to_result, model_warning_text, mode_set_request, mode_set_result, move_mcp_loading_to_background_result, named_provider_config, name_get_result, name_set_auto_request, name_set_auto_result, name_set_request, open_canvas_instance, options_update_additional_content_exclusion_policy, options_update_additional_content_exclusion_policy_rule, options_update_additional_content_exclusion_policy_rule_source, options_update_additional_content_exclusion_policy_scope, options_update_context_tier, options_update_env_value_mode, options_update_reasoning_summary, options_update_tool_filter_precedence, pending_external_tool_request, pending_external_tool_request_list, pending_permission_request, pending_permission_request_list, permission_decision, permission_decision_approved, permission_decision_approved_for_location, permission_decision_approved_for_session, permission_decision_approve_for_location, permission_decision_approve_for_location_approval, permission_decision_approve_for_location_approval_commands, permission_decision_approve_for_location_approval_custom_tool, permission_decision_approve_for_location_approval_extension_env_access, permission_decision_approve_for_location_approval_extension_management, permission_decision_approve_for_location_approval_extension_permission_access, permission_decision_approve_for_location_approval_mcp, permission_decision_approve_for_location_approval_mcp_sampling, permission_decision_approve_for_location_approval_memory, permission_decision_approve_for_location_approval_read, permission_decision_approve_for_location_approval_workflow, permission_decision_approve_for_location_approval_write, permission_decision_approve_for_session, permission_decision_approve_for_session_approval, permission_decision_approve_for_session_approval_commands, permission_decision_approve_for_session_approval_custom_tool, permission_decision_approve_for_session_approval_extension_env_access, permission_decision_approve_for_session_approval_extension_management, permission_decision_approve_for_session_approval_extension_permission_access, permission_decision_approve_for_session_approval_mcp, permission_decision_approve_for_session_approval_mcp_sampling, permission_decision_approve_for_session_approval_memory, permission_decision_approve_for_session_approval_read, permission_decision_approve_for_session_approval_workflow, permission_decision_approve_for_session_approval_write, permission_decision_approve_once, permission_decision_approve_permanently, permission_decision_approve_read_only_for_session, permission_decision_cancelled, permission_decision_context, permission_decision_denied_by_content_exclusion_policy, permission_decision_denied_by_permission_request_hook, permission_decision_denied_by_rules, permission_decision_denied_interactively_by_user, permission_decision_denied_no_approval_rule_and_could_not_request_from_user, permission_decision_outcome, permission_decision_reject, permission_decision_request, permission_decision_surface, permission_decision_user_not_available, permission_location_add_tool_approval_params, permission_location_apply_params, permission_location_apply_result, permission_location_resolve_params, permission_location_resolve_result, permission_location_type, permission_mode_source, permission_paths_add_params, permission_paths_allowed_check_params, permission_paths_allowed_check_result, permission_paths_config, permission_paths_list, permission_paths_update_primary_params, permission_paths_workspace_check_params, permission_paths_workspace_check_result, permission_prompt_shown_notification, permission_request_result, permission_response_capability, permission_rules_set, permissions_configure_additional_content_exclusion_policy, permissions_configure_additional_content_exclusion_policy_rule, permissions_configure_additional_content_exclusion_policy_rule_source, permissions_configure_additional_content_exclusion_policy_scope, permissions_configure_params, permissions_configure_result, permissions_folder_trust_add_trusted_result, permissions_get_mode_request, permissions_get_mode_result, permissions_locations_add_tool_approval_details, permissions_locations_add_tool_approval_details_commands, permissions_locations_add_tool_approval_details_custom_tool, permissions_locations_add_tool_approval_details_extension_env_access, permissions_locations_add_tool_approval_details_extension_management, permissions_locations_add_tool_approval_details_extension_permission_access, permissions_locations_add_tool_approval_details_mcp, permissions_locations_add_tool_approval_details_mcp_sampling, permissions_locations_add_tool_approval_details_memory, permissions_locations_add_tool_approval_details_read, permissions_locations_add_tool_approval_details_workflow, permissions_locations_add_tool_approval_details_write, permissions_locations_add_tool_approval_result, permissions_modify_rules_params, permissions_modify_rules_result, permissions_modify_rules_scope, permissions_notify_prompt_shown_result, permissions_paths_add_result, permissions_paths_list_request, permissions_paths_update_primary_result, permissions_pending_requests_request, permissions_reset_session_approvals_request, permissions_reset_session_approvals_result, permissions_set_approve_all_request, permissions_set_approve_all_result, permissions_set_approve_all_source, permissions_set_mode_request, permissions_set_mode_result, permissions_set_required_request, permissions_set_required_result, permissions_urls_set_unrestricted_mode_result, permission_urls_config, permission_urls_set_unrestricted_mode_params, ping_request, ping_result, plan_read_result, plan_read_sql_todos_result, plan_read_sql_todos_with_dependencies_result, plan_sql_todo_dependency, plan_sql_todos_row, plan_update_request, plugin, plugin_install_result, plugin_install_staging_mode, plugin_list, plugin_list_result, plugins_builtin_set_request, plugins_disable_request, plugins_enable_request, plugins_install_request, plugins_marketplaces_add_request, plugins_marketplaces_browse_request, plugins_marketplaces_refresh_request, plugins_marketplaces_remove_request, plugins_reload_request, plugins_uninstall_request, plugins_update_request, plugin_update_all_entry, plugin_update_all_result, plugin_update_result, protocol_append_mode, protocol_customize_mode, protocol_external_tool_defer, protocol_external_tool_definition, protocol_marker_section_override, protocol_replace_mode, protocol_section_override, protocol_static_section_action, protocol_static_section_override, protocol_system_message_append_config, protocol_system_message_config, protocol_system_message_customize_config, protocol_system_message_replace_config, provider_add_request, provider_add_result, provider_config, provider_config_azure, provider_config_model_provider, provider_config_transport, provider_config_type, provider_config_wire_api, provider_descriptor, provider_endpoint, provider_endpoint_transport, provider_endpoint_type, provider_endpoint_wire_api, provider_get_endpoint_request, provider_model_config, provider_session_token, provider_sync_request, provider_sync_result, provider_token_acquire_request, provider_token_acquire_result, provider_withdraw_request, provider_withdraw_result, push_attachment, push_attachment_blob, push_attachment_directory, push_attachment_file, push_attachment_file_line_range, push_attachment_git_hub_actions_job, push_attachment_git_hub_commit, push_attachment_git_hub_file, push_attachment_git_hub_file_diff, push_attachment_git_hub_file_diff_side, push_attachment_git_hub_reference, push_attachment_git_hub_reference_type, push_attachment_git_hub_release, push_attachment_git_hub_repository, push_attachment_git_hub_snippet, push_attachment_git_hub_tree_comparison, push_attachment_git_hub_tree_comparison_side, push_attachment_git_hub_url, push_attachment_selection, push_attachment_selection_details, push_attachment_selection_details_end, push_attachment_selection_details_start, push_git_hub_repo_ref, queue_append_steering_request, queue_begin_deferred_idle_drain_request, queue_begin_deferred_idle_drain_result, queue_consume_system_notifications_request, queued_command_handled, queued_command_not_handled, queued_command_result, queue_defer_session_idle_request, queue_duplicate_at_request, queue_duplicate_at_result, queue_enqueue_resume_pending_result, queue_finish_deferred_idle_drain_request, queue_finish_deferred_idle_drain_result, queue_has_pending_result, queue_insert_at_request, queue_insert_at_result, queue_insert_message, queue_move_item_request, queue_move_item_result, queue_pending_items, queue_pending_items_kind, queue_pending_items_result, queue_remove_at_request, queue_remove_at_result, queue_remove_most_recent_result, queue_send_now_request, queue_send_now_result, queue_set_drain_paused_request, queue_snapshot_result, queue_update_text_request, queue_update_text_result, queue_withdraw_message_request, queue_withdraw_message_result, quota_take_warnings_result, quota_warning_projection, register_event_interest_params, register_event_interest_result, release_event_interest_params, remote_control_config, remote_control_config_existing_mc_session, remote_control_status, remote_control_status_active, remote_control_status_connecting, remote_control_status_error, remote_control_status_off, remote_control_status_result, remote_control_stop_result, remote_control_transfer_result, remote_enable_request, remote_enable_result, remote_notify_steerable_changed_request, remote_notify_steerable_changed_result, remote_session_connection_result, remote_session_host_status, remote_session_metadata_repository, remote_session_metadata_task_type, remote_session_metadata_value, remote_session_mode, remote_session_repository, response_format, sandbox_config, sandbox_config_auth, sandbox_config_source, sandbox_config_user_policy, sandbox_config_user_policy_experimental, sandbox_config_user_policy_experimental_seatbelt, sandbox_config_user_policy_filesystem, sandbox_config_user_policy_network, sandbox_config_user_policy_network_proxy, sandbox_config_user_policy_seatbelt, sandbox_credentials_config, sandbox_disable_for_session_request, sandbox_disable_for_session_result, sandbox_enforcement_status, sandbox_grant_path_for_request_request, sandbox_grant_path_for_request_result, sandbox_host_capability, sandbox_host_capability_name, sandbox_host_support, sandbox_masked_env_var, sandbox_proxy_ca_create_result, sandbox_proxy_ca_request, sandbox_proxy_ca_state, sandbox_proxy_ca_status, sandbox_session_change, schedule_add_at_request, schedule_add_cron_request, schedule_add_request, schedule_add_result, schedule_add_self_paced_request, schedule_entry, schedule_has_self_paced_result, schedule_list, schedule_rearm_self_paced_request, schedule_stop_request, schedule_stop_result, secrets_add_filter_values_request, secrets_add_filter_values_result, send_agent_mode, send_attachments_to_message_params, send_message_item, send_messages_request, send_messages_result, send_mode, send_request, send_result, send_system_notification_request, server_agent_list, server_instruction_source_list, server_skill, server_skill_list, session_activity, session_agent_list_request, session_auth_login_request, session_auth_logout_user_request, session_auth_status, session_auth_switch_request, session_bulk_delete_result, session_cancel_all_background_agents_result, session_capability, session_commands_list_request, session_completion_item, session_connected_ide_info, session_context, session_context_host_type, session_enrich_metadata_result, session_fs_append_file_request, session_fs_error, session_fs_error_code, session_fs_exists_request, session_fs_exists_result, session_fs_mkdir_request, session_fs_readdir_request, session_fs_readdir_result, session_fs_readdir_with_types_entry, session_fs_readdir_with_types_entry_type, session_fs_readdir_with_types_request, session_fs_readdir_with_types_result, session_fs_read_file_bytes_request, session_fs_read_file_bytes_result, session_fs_read_file_request, session_fs_read_file_result, session_fs_rename_request, session_fs_rm_request, session_fs_set_provider_capabilities, session_fs_set_provider_conventions, session_fs_set_provider_request, session_fs_set_provider_result, session_fs_sqlite_exists_request, session_fs_sqlite_exists_result, session_fs_sqlite_query_request, session_fs_sqlite_query_result, session_fs_sqlite_query_type, session_fs_sqlite_transaction_error, session_fs_sqlite_transaction_error_class, session_fs_sqlite_transaction_request, session_fs_sqlite_transaction_result, session_fs_sqlite_transaction_statement, session_fs_stat_request, session_fs_stat_result, session_fs_write_file_bytes_request, session_fs_write_file_request, session_git_hub_auth_get_all_auth_available_result, session_git_hub_auth_logout_result, session_git_hub_auth_logout_user_result, session_history_compact_request, session_installed_plugin, session_installed_plugin_source, session_installed_plugin_source_git_hub, session_installed_plugin_source_local, session_installed_plugin_source_url, session_limit_prediction_baseline_data, session_limit_prediction_client_type, session_limit_prediction_details, session_limit_prediction_predict_request, session_limit_prediction_request, session_limit_prediction_result, session_limit_prediction_source, session_limit_prediction_tier, session_limit_prediction_tier_option, session_limit_prediction_unavailable_reason, session_list, session_list_entry, session_list_filter, session_load_deferred_repo_hooks_result, session_log_level, session_managed_permissions, session_managed_settings, session_mcp_apps_call_tool_result, session_mcp_oauth_cancel_login_request, session_mcp_oauth_cancel_login_result, session_mcp_oauth_prepare_login_request, session_mcp_oauth_prepare_login_result, session_mcp_set_connected_ide_info_params, session_metadata_snapshot, session_mode, session_model_clear_startup_seed_request, session_model_clear_startup_seed_result, session_model_list, session_model_list_request, session_model_price_category, session_open_options, session_open_options_additional_content_exclusion_policy, session_open_options_additional_content_exclusion_policy_rule, session_open_options_additional_content_exclusion_policy_rule_source, session_open_options_additional_content_exclusion_policy_scope, session_open_options_env_value_mode, session_open_options_reasoning_summary, session_open_params, session_open_result, session_plugins_disable_request, session_plugins_enable_request, session_plugins_install_request, session_plugins_marketplaces_refresh_request, session_plugins_reload_request, session_provider_get_endpoint_request, session_prune_result, session_quota_delegate_warning, session_quota_get_result, session_quota_plan_tier, session_quota_projection, session_quota_refresh_result, session_quota_snapshot, session_quota_take_warnings_result, sessions_bulk_delete_request, sessions_check_in_use_request, sessions_check_in_use_result, sessions_client_metadata_entry, sessions_close_request, sessions_close_result, sessions_create_workspace_request, sessions_create_workspace_result, sessions_delete_request, sessions_enrich_metadata_request, session_set_credentials_params, session_set_credentials_result, session_settings_built_in_tool_availability_snapshot, session_settings_evaluate_predicate_request, session_settings_evaluate_predicate_result, session_settings_job_snapshot, session_settings_model_snapshot, session_settings_online_evaluation_snapshot, session_settings_predicate_name, session_settings_repo_snapshot, session_settings_snapshot, session_settings_validation_snapshot, sessions_find_by_prefix_request, sessions_find_by_prefix_result, sessions_find_by_task_id_request, sessions_find_by_task_id_result, sessions_fork_request, sessions_fork_result, sessions_get_board_entry_count_request, sessions_get_board_entry_count_result, sessions_get_client_metadata_request, sessions_get_client_metadata_result, sessions_get_event_file_path_request, sessions_get_event_file_path_result, sessions_get_last_for_context_request, sessions_get_last_for_context_result, sessions_get_metadata_request, sessions_get_metadata_result, sessions_get_persisted_remote_steerable_request, sessions_get_persisted_remote_steerable_result, session_sizes, sessions_list_non_empty_session_ids_request, sessions_list_non_empty_session_ids_result, sessions_list_request, sessions_load_deferred_repo_hooks_request, sessions_load_workspace_request, sessions_load_workspace_result, sessions_open_attach, sessions_open_cloud, sessions_open_create, sessions_open_handoff, sessions_open_handoff_task_type, sessions_open_progress, sessions_open_progress_status, sessions_open_progress_step, sessions_open_remote, sessions_open_resume, sessions_open_resume_last, sessions_open_status, session_source, sessions_prune_old_request, sessions_read_persisted_events_request, sessions_release_lock_request, sessions_release_lock_result, sessions_reload_plugin_hooks_request, sessions_reload_plugin_hooks_result, sessions_save_request, sessions_save_result, sessions_set_additional_plugins_request, sessions_set_additional_plugins_result, sessions_set_remote_control_steering_request, sessions_start_remote_control_request, sessions_stop_remote_control_request, sessions_transfer_remote_control_request, sessions_update_workspace_fields_request, sessions_update_workspace_fields_result, session_telemetry_engagement, session_update_options_params, session_update_options_result, session_usage_set_code_changes_request, session_visibility_status, session_workflow_pause_at_checkpoint_result, session_working_directory_context, session_working_directory_context_host_type, session_working_directory_context_with_client, settable_auth_info, settable_token_auth_info, shell_cancel_user_requested_request, shell_credentials, shell_exec_request, shell_exec_result, shell_execute_user_requested_request, shell_init_profile, shell_init_script, shell_init_script_shell, shell_kill_request, shell_kill_result, shell_kill_signal, shell_options, shutdown_request, skill, skill_apply_install_request, skill_apply_uninstall_request, skill_discovery_path, skill_discovery_path_list, skill_discovery_scope, skill_installation_failure_reason, skill_installation_file_review, skill_installation_location, skill_installation_management_outcome, skill_installation_management_result, skill_installation_operation_request, skill_installation_operation_status, skill_installation_outcome, skill_installation_ownership_state, skill_installation_result, skill_installation_review, skill_installation_scope, skill_installation_session_state, skill_installation_source, skill_installations_request, skill_installation_summary, skill_install_plan, skill_list, skill_plan_install_request, skill_plan_uninstall_request, skill_provider_descriptor, skill_provider_list_request, skill_provider_list_result, skill_provider_read_request, skill_provider_read_result, skills_config_set_disabled_skills_request, skills_config_set_skill_disabled_request, skills_disable_request, skills_discover_request, skills_enable_request, skill_set_enabled_request, skills_get_discovery_paths_request, skills_get_invoked_result, skills_invoked_skill, skills_load_diagnostics, skill_uninstall_plan, slash_command_add_timeline_entry_result, slash_command_agent_prompt_result, slash_command_completed_result, slash_command_info, slash_command_input, slash_command_input_choice, slash_command_input_completion, slash_command_invocation_result, slash_command_kind, slash_command_model_picker_dialog, slash_command_select_subcommand_option, slash_command_select_subcommand_result, slash_command_set_model_result, slash_command_set_plan_model_result, slash_command_show_dialog_result, slash_command_text_result, slash_command_timeline_entry, subagent_settings_entry, subagent_settings_entry_context_tier, system_message_block, task_agent_info, task_agent_progress, task_client_active_status, task_client_execution_mode, task_client_info, task_client_owner, task_client_owner_kind, task_client_owner_presence, task_client_progress, task_client_status, task_client_type, task_client_update, task_complete_data, task_completion_decision, task_execution_mode, task_info, task_kind, task_list, task_progress_line, tasks_cancel_request, tasks_cancel_result, tasks_get_current_promotable_result, tasks_get_progress_request, tasks_get_progress_result, task_shell_info, task_shell_info_attachment_mode, task_shell_progress, tasks_promote_current_to_background_result, tasks_promote_to_background_request, tasks_promote_to_background_result, tasks_refresh_result, tasks_register_request, tasks_register_result, tasks_remove_request, tasks_remove_result, tasks_send_message_request, tasks_send_message_result, tasks_start_agent_request, tasks_start_agent_result, task_status, tasks_update_request, tasks_update_result, tasks_wait_for_pending_result, telemetry_set_feature_overrides_request, token_auth_info, token_provider_auth_info, tool, tool_list, tool_result, tool_result_expanded, tool_result_new_message, tool_result_type, tools_execute_request, tools_get_builtin_descriptors_request, tools_get_builtin_descriptors_result, tools_get_current_metadata_result, tools_initialize_and_validate_result, tools_list_pending_requests_request, tools_list_request, tools_set_request, tools_set_result, tools_shell_descriptor_config, tools_task_complete_event_data_request, tools_update_subagent_settings_result, ui_auto_mode_switch_response, ui_elicitation_array_any_of_field, ui_elicitation_array_any_of_field_items, ui_elicitation_array_any_of_field_items_any_of, ui_elicitation_array_enum_field, ui_elicitation_array_enum_field_items, ui_elicitation_field_value, ui_elicitation_request, ui_elicitation_response, ui_elicitation_response_action, ui_elicitation_response_content, ui_elicitation_result, ui_elicitation_schema, ui_elicitation_schema_property, ui_elicitation_schema_property_boolean, ui_elicitation_schema_property_number, ui_elicitation_schema_property_number_type, ui_elicitation_schema_property_string, ui_elicitation_schema_property_string_format, ui_elicitation_string_enum_field, ui_elicitation_string_one_of_field, ui_elicitation_string_one_of_field_one_of, ui_ephemeral_query_request, ui_ephemeral_query_result, ui_exit_plan_mode_action, ui_exit_plan_mode_response, ui_handle_pending_auto_mode_switch_request, ui_handle_pending_elicitation_request, ui_handle_pending_exit_plan_mode_request, ui_handle_pending_result, ui_handle_pending_sampling_request, ui_handle_pending_sampling_response, ui_handle_pending_session_limits_exhausted_request, ui_handle_pending_user_input_request, ui_register_direct_auto_mode_switch_handler_result, ui_session_limits_exhausted_response, ui_session_limits_exhausted_response_action, ui_unregister_direct_auto_mode_switch_handler_request, ui_unregister_direct_auto_mode_switch_handler_result, ui_user_input_response, unsupported_enqueue_command_result, update_subagent_settings_request, usage_get_metrics_result, usage_set_code_changes_request, user_auth_info, user_requested_shell_command_result, user_setting_metadata, user_settings_get_result, user_settings_set_request, visibility_get_result, visibility_set_request, visibility_set_result, workflow_abort_request, workflow_ack_result, workflow_agent_options, workflow_agent_request, workflow_agent_result, workflow_agent_summary, workflow_cancel_request, workflow_current_phase, workflow_declared_limits, workflow_durable_operation, workflow_execute_request, workflow_execute_result, workflow_get_run_progress_request, workflow_get_run_request, workflow_journal_get_request, workflow_journal_get_result, workflow_journal_put_request, workflow_list_runs_request, workflow_list_runs_result, workflow_log_line, workflow_log_line_kind, workflow_log_request, workflow_pause_checkpoint_action, workflow_pause_checkpoint_request, workflow_pause_checkpoint_result, workflow_pause_info, workflow_pause_request, workflow_phase_observation, workflow_phase_status, workflow_progress_line, workflow_progress_page, workflow_resume_request, workflow_resume_result, workflow_run_consumed, workflow_run_detail, workflow_run_failure, workflow_run_failure_kind, workflow_run_limits, workflow_run_options, workflow_run_request, workflow_run_result, workflow_run_status, workflow_run_summary, workflow_run_terminal, workflow_tool_resume_request, workflow_tool_run_options, workflow_tool_run_request, workspace_diff_contents, workspace_diff_file_change, workspace_diff_file_change_type, workspace_diff_mode, workspace_diff_result, workspaces_add_summary_request, workspaces_add_summary_result, workspaces_autopilot_objective_exists_result, workspaces_checkpoints, workspaces_create_directory_request, workspaces_create_file_request, workspaces_delete_autopilot_objective_result, workspaces_diff_request, workspaces_ensure_request, workspaces_get_workspace_result, workspaces_list_checkpoints_result, workspaces_list_files_result, workspaces_read_autopilot_objective_result, workspaces_read_checkpoint_request, workspaces_read_checkpoint_result, workspaces_read_file_request, workspaces_read_file_result, workspaces_remove_path_request, workspaces_rename_path_request, workspaces_save_large_paste_request, workspaces_save_large_paste_result, workspaces_stat_file_request, workspaces_stat_file_result, workspaces_truncate_summaries_request, workspace_summary_host_type, workspaces_update_metadata_request, workspaces_workspace_details_host_type, workspaces_write_autopilot_objective_request, workspaces_write_autopilot_objective_result, connector_session_account_result, session_auth_info_result, session_context_attribution, session_context_info, subagent_settings, task_progress, workspace_summary) + return RPC(abort_request, abort_result, accepted_enqueue_command_result, account_all_users, account_auth_info, account_get_all_users_result, account_get_current_auth_result, account_get_quota_request, account_get_quota_result, account_kind, account_login_request, account_login_result, account_logout_request, account_logout_result, account_quota_snapshot, accounts_enumerate_request, accounts_get_request, accounts_set_request, account_status, adaptive_thinking_support, agent_discovery_path, agent_discovery_path_list, agent_discovery_path_scope, agent_get_current_result, agent_info, agent_info_source, agent_list, agent_list_request, agent_registry_live_target_entry, agent_registry_live_target_entry_attention_kind, agent_registry_live_target_entry_kind, agent_registry_live_target_entry_last_terminal_event, agent_registry_live_target_entry_status, agent_registry_log_capture, agent_registry_log_capture_open_error_reason, agent_registry_spawn_error, agent_registry_spawn_permission_mode, agent_registry_spawn_registry_timeout, agent_registry_spawn_request, agent_registry_spawn_result, agent_registry_spawn_spawned, agent_registry_spawn_validation_error, agent_registry_spawn_validation_error_field, agent_registry_spawn_validation_error_reason, agent_reload_result, agents_custom_agent_initial_model_decision_params, agents_custom_agent_initial_model_decision_result, agents_discover_request, agent_select_request, agent_select_result, agent_set_prompt_request, agents_get_available_builtins_request, agents_get_available_builtins_result, agents_get_builtin_definition_request, agents_get_builtin_definition_result, agents_get_builtin_listing_definition_request, agents_get_builtin_listing_definition_result, agents_get_builtins_result, agents_get_discovery_paths_request, api_key_auth_info, auth_enumerate_query, auth_enumerate_value, auth_identity, auth_identity_metadata, auth_info, auth_info_type, auth_login_account, auth_login_advance_request, auth_login_begin_request, auth_login_begun, auth_login_cancel_request, auth_login_result_dto, auth_login_result_status, auth_login_step, auth_read_query, auth_read_value, auth_status_dto, auth_validation_error, auth_validation_errors, auth_write, auth_write_result, autopilot_objective_credit_limit, autopilot_objective_get_state_result, autopilot_objective_state, autopilot_objective_status, auto_tier_descriptor, auto_tier_metadata, auto_tier_status, builtin_agent_summary, built_in_model_catalog, built_in_model_catalog_entry, builtin_tool_descriptor, builtin_tool_format, builtin_tool_format_type, builtin_tool_input_schema, builtin_tool_input_schema_type, builtin_tool_safe_for_telemetry, builtin_tool_safe_telemetry_fields, cancel_user_requested_shell_command_result, canvas_action, canvas_action_invoke_request, canvas_action_invoke_result, canvas_close_request, canvas_host_context, canvas_host_context_capabilities, canvas_json_schema, canvas_list, canvas_list_open_result, canvas_open_request, canvas_provider_close_request, canvas_provider_invoke_action_request, canvas_provider_open_request, canvas_provider_open_result, canvas_provider_register_request, canvas_provider_unregister_request, canvas_session_context, capi_session_options, card_digest, card_digest_algorithm, card_digest_value, catalog_agent_plugin_candidate, catalog_agent_plugin_candidate_kind, catalog_agent_plugin_candidate_provenance, catalog_agent_plugin_compatibility_tag, catalog_agent_plugin_media_type, catalog_ai_skill_candidate, catalog_ai_skill_candidate_kind, catalog_ai_skill_candidate_provenance, catalog_ai_skill_installability, catalog_ai_skill_media_type, catalog_authentication_required_error, catalog_authentication_required_reason, catalog_candidate, catalog_candidate_kind, catalog_candidate_source, catalog_candidate_source_embedded, catalog_candidate_source_url, catalog_capability, catalog_capability_id, catalog_client_contract, catalog_contract_violation_error, catalog_contract_violation_reason, catalog_handle_rejected_error, catalog_handle_rejection_reason, catalog_handle_type, catalog_invalid_request_error, catalog_invalid_request_field, catalog_malformed_card_error, catalog_malformed_card_reason, catalog_mcp_server_candidate, catalog_mcp_server_candidate_kind, catalog_mcp_server_candidate_provenance, catalog_mcp_server_installability, catalog_media_type, catalog_negotiated_contract, catalog_negotiation_refused_error, catalog_negotiation_refused_reason, catalog_network_failure_error, catalog_network_failure_reason, catalog_not_installable_error, catalog_not_installable_reason, catalog_plugin_repository_source, catalog_policy_rejected_error, catalog_resource_identity, catalog_resource_version, catalog_search_page, catalog_search_pagination, catalog_search_request, catalog_search_result, catalog_search_succeeded, catalog_search_total_count_relation, catalog_selection_cancelled, catalog_selection_decision, catalog_selection_declined, catalog_selection_foreign, catalog_selection_invalid, catalog_selection_replayed, catalog_selection_request, catalog_selection_result, catalog_selection_selected, catalog_selection_stale, catalog_selection_timed_out, catalog_selection_wrong_kind, catalog_trust_eligibility, catalog_trust_provenance, catalog_trust_snapshot, catalog_trust_snapshot_absent, catalog_trust_snapshot_absent_status, catalog_trust_snapshot_current, catalog_trust_snapshot_current_status, catalog_trust_snapshot_downgraded, catalog_trust_snapshot_downgraded_status, catalog_trust_snapshot_malformed, catalog_trust_snapshot_malformed_status, catalog_trust_snapshot_revoked, catalog_trust_snapshot_revoked_status, catalog_trust_snapshot_schema_version, catalog_trust_snapshot_stale, catalog_trust_snapshot_stale_status, catalog_trust_snapshot_unsupported, catalog_trust_snapshot_unsupported_status, catalog_trust_source, catalog_trust_tier, catalog_unavailable_error, catalog_unavailable_reason, catalog_unavailable_transport_error, catalog_unavailable_transport_reason, catalog_unsafe_retrieval_error, catalog_unsafe_retrieval_reason, catalog_unsupported_kind_error, client_metadata, client_task_cancel_reason, client_task_cancel_request, client_task_cancel_result, command_list, commands_finalize_invocation_effect_request, commands_finalize_invocation_effect_result, commands_handle_pending_command_request, commands_handle_pending_command_result, commands_invocation_effect_outcome, commands_invocation_origin, commands_invoke_request, commands_list_request, commands_respond_to_queued_command_request, commands_respond_to_queued_command_result, completions_get_trigger_characters_result, completions_request_request, completions_request_result, configure_session_extensions_params, connect_client_info, connected_remote_session_metadata, connected_remote_session_metadata_kind, connected_remote_session_metadata_repository, connector_account_request, connector_authorization_requirement, connector_authorization_scope, connector_availability, connector_capabilities, connector_catalog_entry, connector_catalog_result, connector_catalog_status, connector_connect_request, connector_connect_result, connector_continue_request, connector_disconnect_result, connector_discovery_account, connector_discovery_account_list, connector_discovery_account_request, connector_discovery_auth_info, connector_discovery_availability, connector_discovery_capabilities, connector_discovery_catalog_entry, connector_discovery_catalog_result, connector_mcp_status, connector_reconcile_request, connector_runtime_status, connector_session_account, connector_status, connect_remote_session_params, connect_request, connect_result, content_exclusion_check_paths_request, content_exclusion_check_paths_result, content_exclusion_path_check, content_filter_mode, context_heaviest_message, copilot_api_token_auth_info, copilot_user_response, copilot_user_response_endpoints, copilot_user_response_quota_snapshots, copilot_user_response_quota_snapshots_chat, copilot_user_response_quota_snapshots_completions, copilot_user_response_quota_snapshots_premium_interactions, current_model, current_tool_metadata, customization_reload_outcome, customization_reload_status, customization_reload_subsystem, customizations_reload_result, debug_collect_logs_collected_entry, debug_collect_logs_destination, debug_collect_logs_entry, debug_collect_logs_entry_kind, debug_collect_logs_include, debug_collect_logs_redaction, debug_collect_logs_request, debug_collect_logs_result, debug_collect_logs_result_kind, debug_collect_logs_skipped_entry, debug_collect_logs_source, diagnostic_cursor_status, diagnostic_entry, diagnostic_log_level, diagnostics_configuration, diagnostics_configure_request, diagnostic_severity, diagnostic_source, diagnostic_sources_configuration, diagnostics_read_request, diagnostics_read_result, discovered_canvas, discovered_extension, discovered_extension_mode, discovered_extension_plugin, discovered_extensions, discovered_extensions_disable_request, discovered_extensions_enable_request, discovered_extension_source, discovered_hook, discovered_mcp_server, discovered_mcp_server_type, discovered_model, discovered_model_list, enqueue_command_params, enqueue_command_result, env_auth_info, environment_capabilities, environment_kind, environments_delete_request, environments_delete_result, environments_get_request, environments_get_result, environments_list_request, environments_list_result, event_log_read_request, event_log_release_interest_result, event_log_tail_result, event_log_types, events_agent_scope, events_cursor_status, events_read_direction, events_read_result, execute_command_params, execute_command_result, extension, extension_context_push_input, extension_launch_profile, extension_launch_provider_resolve_request, extension_launch_provider_resolve_result, extension_list, extensions_disable_request, extensions_enable_request, extension_source, extension_status, external_tool_result, external_tool_text_result_for_llm, external_tool_text_result_for_llm_binary_results_for_llm, external_tool_text_result_for_llm_binary_results_for_llm_type, external_tool_text_result_for_llm_content, external_tool_text_result_for_llm_content_audio, external_tool_text_result_for_llm_content_image, external_tool_text_result_for_llm_content_resource, external_tool_text_result_for_llm_content_resource_details, external_tool_text_result_for_llm_content_resource_link, external_tool_text_result_for_llm_content_resource_link_icon, external_tool_text_result_for_llm_content_resource_link_icon_theme, external_tool_text_result_for_llm_content_shell_exit, external_tool_text_result_for_llm_content_terminal, external_tool_text_result_for_llm_content_text, filter_mapping, fleet_start_request, fleet_start_result, folder_trust_add_params, folder_trust_check_params, folder_trust_check_result, gh_cli_auth_info, git_current_branch_remote_result, git_cwd_request, git_hub_environment, git_hub_owner_option, git_hub_owners_cancel_request, git_hub_owners_cancel_result, git_hub_owners_list_request, git_hub_owners_list_result, git_hub_owners_request_id_result, git_hub_repository_at_path_request, git_hub_repository_at_path_result, git_hub_repository_identity, git_hub_telemetry_client_info, git_hub_telemetry_event, git_hub_telemetry_notification, git_hub_token_acquire_reason, git_hub_token_acquire_request, git_hub_token_acquire_result, git_remote_repository, git_repos_from_remotes_request, git_repos_from_remotes_result, global_state_load_for_config_dir_request, global_state_load_result, global_state_write_key_request, handle_pending_tool_call_request, handle_pending_tool_call_result, history_abort_manual_compaction_result, history_cancel_background_compaction_result, history_clear_context_request, history_clear_context_result, history_compact_context_window, history_compact_request, history_compact_result, history_file_restore_skip_reason, history_list_rewind_points_result, history_preview_rewind_request, history_preview_rewind_result, history_rewind_change_type, history_rewind_file_preview, history_rewind_mode, history_rewind_outcome, history_rewind_point, history_rewind_request, history_rewind_result, history_rewind_unavailable_reason, history_skipped_file_restore, history_summarize_for_handoff_result, history_truncate_request, history_truncate_result, hmac_auth_info, hook_invoke_request, hook_invoke_response, hook_origin, hooks_discover_request, hooks_discover_result, hook_type, host_configuration, host_dispose_request, host_empty_result, host_environment_credentials, host_exited_notification, host_exit_reason, host_git_hub_environment_options, host_list_sessions_request, host_list_sessions_result, host_local_server_configuration, host_local_server_options, host_publish_session_request, host_publish_session_result, host_ready_request, host_register_session_request, host_session_create_callback, host_session_create_request, host_session_create_result, host_session_released_notification, host_session_release_request, host_session_summary, host_start_request, host_start_result, installation_catalogue_identity, installation_confirmation_request, installation_confirmation_response, installation_decision, installation_review, installed_plugin, installed_plugin_info, installed_plugin_source, installed_plugin_source_git_hub, installed_plugin_source_local, installed_plugin_source_url, instruction_discovery_path, instruction_discovery_path_kind, instruction_discovery_path_list, instruction_discovery_path_location, instructions_discover_request, instructions_get_discovery_paths_request, instructions_get_sources_result, instruction_source, instruction_source_location, instruction_source_type, interrupt_main_turn_request, interrupt_main_turn_result, json_schema_response_format, llm_inference_headers, llm_inference_http_request_chunk_request, llm_inference_http_request_chunk_result, llm_inference_http_request_start_request, llm_inference_http_request_start_result, llm_inference_http_request_start_transport, llm_inference_http_response_chunk_error, llm_inference_http_response_chunk_request, llm_inference_http_response_chunk_result, llm_inference_http_response_start_request, llm_inference_http_response_start_result, llm_inference_set_provider_result, local_session_metadata_value, logged_in_user, login_provider_kind, log_request, log_result, lsp_initialize_request, managed_mcp_server_config, managed_plugin_retry_entry, managed_plugin_retry_status, managed_setting_meta, managed_settings_channel, managed_settings_compose_layer, managed_settings_compose_request, managed_settings_compose_result, managed_settings_diagnostic, managed_settings_diagnostic_severity, managed_settings_layer, managed_settings_meta, managed_settings_read_result, managed_settings_resolved_data, managed_settings_resolve_request, managed_settings_resolve_result, managed_settings_schema_result, managed_settings_validate_request, managed_settings_validate_result, managed_settings_values, marketplace_add_result, marketplace_browse_result, marketplace_info, marketplace_list_result, marketplace_plugin_info, marketplace_refresh_entry, marketplace_refresh_result, marketplace_remove_result, mcp_allowed_server, mcp_apply_install_request, mcp_apply_uninstall_request, mcp_apps_call_tool_request, mcp_apps_diagnose_capability, mcp_apps_diagnose_request, mcp_apps_diagnose_result, mcp_apps_diagnose_server, mcp_apps_host_context, mcp_apps_host_context_details, mcp_apps_host_context_details_available_display_mode, mcp_apps_host_context_details_display_mode, mcp_apps_host_context_details_platform, mcp_apps_host_context_details_theme, mcp_apps_list_tools_request, mcp_apps_list_tools_result, mcp_apps_read_resource_request, mcp_apps_read_resource_result, mcp_apps_resource_content, mcp_apps_set_host_context_details, mcp_apps_set_host_context_details_available_display_mode, mcp_apps_set_host_context_details_display_mode, mcp_apps_set_host_context_details_platform, mcp_apps_set_host_context_details_theme, mcp_apps_set_host_context_request, mcp_cancel_sampling_execution_params, mcp_cancel_sampling_execution_result, mcp_config_add_request, mcp_config_disable_request, mcp_config_enable_request, mcp_config_list, mcp_config_remove_request, mcp_config_update_request, mcp_configured_server, mcp_configured_server_list, mcp_configured_server_state, mcp_configure_git_hub_request, mcp_configure_git_hub_result, mcp_diagnostic_details, mcp_diagnostic_direction, mcp_diagnostic_kind, mcp_diagnostic_source_configuration, mcp_disable_request, mcp_discover_request, mcp_discover_result, mcp_elicitation_form_mode, mcp_enable_request, mcp_execute_sampling_params, mcp_execute_sampling_request, mcp_execute_sampling_result, mcp_failed_server, mcp_filtered_server, mcp_headers_handle_pending_headers_refresh_request, mcp_headers_handle_pending_headers_refresh_request_request, mcp_headers_handle_pending_headers_refresh_request_result, mcp_host_state, mcp_installation_failure_reason, mcp_installation_input, mcp_installation_management_outcome, mcp_installation_management_result, mcp_installation_operation_request, mcp_installation_operation_status, mcp_installation_outcome, mcp_installation_remote_configuration, mcp_installation_result, mcp_installation_review, mcp_installation_secret, mcp_installation_secret_storage, mcp_installations_request, mcp_installation_state, mcp_installation_summary, mcp_install_plan, mcp_is_server_running_request, mcp_is_server_running_result, mcp_list_tools_request, mcp_list_tools_result, mcp_oauth_authentication_state_changed_request, mcp_oauth_cancel_login_request, mcp_oauth_cancel_login_result, mcp_oauth_complete_request, mcp_oauth_handle_pending_request, mcp_oauth_handle_pending_result, mcp_oauth_login_grant_type, mcp_oauth_login_request, mcp_oauth_login_result, mcp_oauth_pending_request_response, mcp_oauth_prepare_login_request, mcp_oauth_prepare_login_result, mcp_oauth_probe_needs_auth_reason, mcp_oauth_probe_request, mcp_oauth_probe_result, mcp_oauth_respond_request, mcp_oauth_respond_result, mcp_owned_oauth_login_status, mcp_plan_configuration_change, mcp_plan_configuration_operation, mcp_plan_enum_value_type, mcp_plan_install_planned, mcp_plan_install_request, mcp_plan_install_result, mcp_plan_install_source, mcp_plan_install_source_candidate, mcp_plan_install_source_candidate_kind, mcp_plan_install_source_card, mcp_plan_install_source_card_kind, mcp_plan_package_install_method, mcp_plan_package_transport, mcp_plan_policy_decision, mcp_plan_policy_result, mcp_plan_policy_source, mcp_plan_provenance, mcp_plan_remote_install_method, mcp_plan_remote_transport, mcp_plan_required_value, mcp_plan_required_value_enum, mcp_plan_required_value_enum_kind, mcp_plan_required_value_scalar, mcp_plan_required_value_scalar_kind, mcp_plan_resource_identity, mcp_plan_scalar_value_type, mcp_plan_scope, mcp_plan_secret_placeholder, mcp_plan_secret_reference, mcp_plan_target, mcp_plan_transport_choice, mcp_plan_transport_choice_package, mcp_plan_transport_choice_remote, mcp_plan_uninstall_request, mcp_plan_value_category, mcp_prepared_install, mcp_prepare_install_request, mcp_prompt, mcp_prompt_argument, mcp_prompt_icon, mcp_prompt_message, mcp_prompt_role, mcp_prompts_get_request, mcp_prompts_get_result, mcp_prompts_list_request, mcp_prompts_list_result, mcp_register_external_client_request, mcp_reload_config, mcp_reload_with_config_request, mcp_remove_git_hub_result, mcp_resource, mcp_resource_annotations, mcp_resource_content, mcp_resource_icon, mcp_resources_list_request, mcp_resources_list_result, mcp_resources_list_templates_request, mcp_resources_list_templates_result, mcp_resources_read_request, mcp_resources_read_result, mcp_resource_template, mcp_restart_server_request, mcp_safe_for_telemetry, mcp_safe_for_telemetry_fields, mcp_sampling_execution_action, mcp_sampling_execution_result, mcp_serializable_server_config, mcp_server, mcp_server_auth_config, mcp_server_auth_config_redirect_port, mcp_server_card_embedded, mcp_server_card_embedded_kind, mcp_server_card_media_type, mcp_server_card_reference, mcp_server_card_url, mcp_server_card_url_kind, mcp_server_config, mcp_server_config_defer_tools, mcp_server_config_http, mcp_server_config_http_oauth_grant_type, mcp_server_config_http_type, mcp_server_config_memory, mcp_server_config_memory_type, mcp_server_config_stdio, mcp_server_config_stdio_type, mcp_server_failure_info, mcp_server_list, mcp_server_needs_auth_info, mcp_server_ownership, mcp_set_env_value_mode_details, mcp_set_env_value_mode_params, mcp_set_env_value_mode_result, mcp_source_file, mcp_source_plugin, mcp_source_ref, mcp_start_server_request, mcp_start_servers_result, mcp_stop_server_request, mcp_task_metadata, mcp_tools, mcp_tool_ui, mcp_tool_ui_visibility, mcp_uninstall_plan, mcp_unregister_external_client_request, memory_configuration, metadata_context_attribution_result, metadata_context_heaviest_messages_request, metadata_context_heaviest_messages_result, metadata_context_info_request, metadata_context_info_result, metadata_is_processing_result, metadata_recompute_context_tokens_request, metadata_recompute_context_tokens_result, metadata_record_context_change_request, metadata_record_context_change_result, metadata_set_working_directory_request, metadata_set_working_directory_result, metadata_snapshot_current_mode, metadata_snapshot_remote_metadata, metadata_snapshot_remote_metadata_repository, metadata_snapshot_remote_metadata_task_type, metadata_update_client_metadata_request, model, model_apply_startup_overlay_request, model_artifact_details, model_billing, model_billing_promo, model_billing_token_prices, model_billing_token_prices_long_context, model_capabilities, model_capabilities_limits, model_capabilities_limits_vision, model_capabilities_override, model_capabilities_override_limits, model_capabilities_override_limits_vision, model_capabilities_override_supports, model_capabilities_supports, model_clear_startup_seed_request, model_clear_startup_seed_result, model_list, model_list_request, model_message, model_picker_category, model_picker_persistence_request, model_picker_price_category, model_picker_settings_context, model_policy, model_policy_state, model_provider_adapter_catalog, model_provider_adapter_descriptor, model_provider_adapter_operation_descriptor, model_provider_attribution, model_provider_automatic_discovery_mode, model_provider_automatic_discovery_policy, model_provider_configuration_disposition, model_provider_configuration_plan, model_provider_descriptor, model_provider_discover_request, model_provider_discover_result, model_provider_discovery_network_scope, model_provider_get_status_request, model_provider_instance, model_provider_instance_reference, model_provider_models_list_request, model_provider_operation_outcome, model_provider_operation_outcome_code, model_provider_prepare_configuration_request, model_provider_provenance, model_provider_provenance_source, model_provider_status, model_provider_warning, model_set_allowed_models_request, model_set_allowed_models_result, model_set_reasoning_effort_request, model_set_reasoning_effort_result, models_list_request, model_switch_auto_tier_request, model_switch_auto_tier_result, model_switch_auto_tier_status, model_switch_confirmation, model_switch_to_request, model_switch_to_result, model_warning_text, mode_set_request, mode_set_result, move_mcp_loading_to_background_result, named_provider_config, name_get_result, name_set_auto_request, name_set_auto_result, name_set_request, open_canvas_instance, options_update_additional_content_exclusion_policy, options_update_additional_content_exclusion_policy_rule, options_update_additional_content_exclusion_policy_rule_source, options_update_additional_content_exclusion_policy_scope, options_update_context_tier, options_update_env_value_mode, options_update_reasoning_summary, options_update_tool_filter_precedence, pending_external_tool_request, pending_external_tool_request_list, pending_permission_request, pending_permission_request_list, permission_decision, permission_decision_approved, permission_decision_approved_for_location, permission_decision_approved_for_session, permission_decision_approve_for_location, permission_decision_approve_for_location_approval, permission_decision_approve_for_location_approval_commands, permission_decision_approve_for_location_approval_custom_tool, permission_decision_approve_for_location_approval_extension_env_access, permission_decision_approve_for_location_approval_extension_management, permission_decision_approve_for_location_approval_extension_permission_access, permission_decision_approve_for_location_approval_mcp, permission_decision_approve_for_location_approval_mcp_sampling, permission_decision_approve_for_location_approval_memory, permission_decision_approve_for_location_approval_read, permission_decision_approve_for_location_approval_workflow, permission_decision_approve_for_location_approval_write, permission_decision_approve_for_session, permission_decision_approve_for_session_approval, permission_decision_approve_for_session_approval_commands, permission_decision_approve_for_session_approval_custom_tool, permission_decision_approve_for_session_approval_extension_env_access, permission_decision_approve_for_session_approval_extension_management, permission_decision_approve_for_session_approval_extension_permission_access, permission_decision_approve_for_session_approval_mcp, permission_decision_approve_for_session_approval_mcp_sampling, permission_decision_approve_for_session_approval_memory, permission_decision_approve_for_session_approval_read, permission_decision_approve_for_session_approval_workflow, permission_decision_approve_for_session_approval_write, permission_decision_approve_once, permission_decision_approve_permanently, permission_decision_approve_read_only_for_session, permission_decision_cancelled, permission_decision_context, permission_decision_denied_by_content_exclusion_policy, permission_decision_denied_by_permission_request_hook, permission_decision_denied_by_rules, permission_decision_denied_interactively_by_user, permission_decision_denied_no_approval_rule_and_could_not_request_from_user, permission_decision_outcome, permission_decision_reject, permission_decision_request, permission_decision_surface, permission_decision_user_not_available, permission_location_add_tool_approval_params, permission_location_apply_params, permission_location_apply_result, permission_location_resolve_params, permission_location_resolve_result, permission_location_type, permission_mode_source, permission_paths_add_params, permission_paths_allowed_check_params, permission_paths_allowed_check_result, permission_paths_config, permission_paths_list, permission_paths_update_primary_params, permission_paths_workspace_check_params, permission_paths_workspace_check_result, permission_prompt_shown_notification, permission_request_result, permission_response_capability, permission_rules_set, permissions_configure_additional_content_exclusion_policy, permissions_configure_additional_content_exclusion_policy_rule, permissions_configure_additional_content_exclusion_policy_rule_source, permissions_configure_additional_content_exclusion_policy_scope, permissions_configure_params, permissions_configure_result, permissions_folder_trust_add_trusted_result, permissions_get_mode_request, permissions_get_mode_result, permissions_locations_add_tool_approval_details, permissions_locations_add_tool_approval_details_commands, permissions_locations_add_tool_approval_details_custom_tool, permissions_locations_add_tool_approval_details_extension_env_access, permissions_locations_add_tool_approval_details_extension_management, permissions_locations_add_tool_approval_details_extension_permission_access, permissions_locations_add_tool_approval_details_mcp, permissions_locations_add_tool_approval_details_mcp_sampling, permissions_locations_add_tool_approval_details_memory, permissions_locations_add_tool_approval_details_read, permissions_locations_add_tool_approval_details_workflow, permissions_locations_add_tool_approval_details_write, permissions_locations_add_tool_approval_result, permissions_modify_rules_params, permissions_modify_rules_result, permissions_modify_rules_scope, permissions_notify_prompt_shown_result, permissions_paths_add_result, permissions_paths_list_request, permissions_paths_update_primary_result, permissions_pending_requests_request, permissions_reset_session_approvals_request, permissions_reset_session_approvals_result, permissions_set_approve_all_request, permissions_set_approve_all_result, permissions_set_approve_all_source, permissions_set_mode_request, permissions_set_mode_result, permissions_set_required_request, permissions_set_required_result, permissions_urls_set_unrestricted_mode_result, permission_urls_config, permission_urls_set_unrestricted_mode_params, ping_request, ping_result, plan_read_result, plan_read_sql_todos_result, plan_read_sql_todos_with_dependencies_result, plan_sql_todo_dependency, plan_sql_todos_row, plan_update_request, plugin, plugin_install_result, plugin_install_staging_mode, plugin_list, plugin_list_result, plugins_builtin_set_request, plugins_disable_request, plugins_enable_request, plugins_install_request, plugins_marketplaces_add_request, plugins_marketplaces_browse_request, plugins_marketplaces_refresh_request, plugins_marketplaces_remove_request, plugins_reload_request, plugins_uninstall_request, plugins_update_request, plugin_update_all_entry, plugin_update_all_result, plugin_update_result, protocol_append_mode, protocol_customize_mode, protocol_external_tool_defer, protocol_external_tool_definition, protocol_marker_section_override, protocol_replace_mode, protocol_section_override, protocol_static_section_action, protocol_static_section_override, protocol_system_message_append_config, protocol_system_message_config, protocol_system_message_customize_config, protocol_system_message_replace_config, provider_add_request, provider_add_result, provider_config, provider_config_azure, provider_config_model_provider, provider_config_transport, provider_config_type, provider_config_wire_api, provider_descriptor, provider_endpoint, provider_endpoint_transport, provider_endpoint_type, provider_endpoint_wire_api, provider_get_endpoint_request, provider_model_config, provider_session_token, provider_sync_request, provider_sync_result, provider_token_acquire_request, provider_token_acquire_result, provider_withdraw_request, provider_withdraw_result, push_attachment, push_attachment_blob, push_attachment_directory, push_attachment_file, push_attachment_file_line_range, push_attachment_git_hub_actions_job, push_attachment_git_hub_commit, push_attachment_git_hub_file, push_attachment_git_hub_file_diff, push_attachment_git_hub_file_diff_side, push_attachment_git_hub_reference, push_attachment_git_hub_reference_type, push_attachment_git_hub_release, push_attachment_git_hub_repository, push_attachment_git_hub_snippet, push_attachment_git_hub_tree_comparison, push_attachment_git_hub_tree_comparison_side, push_attachment_git_hub_url, push_attachment_selection, push_attachment_selection_details, push_attachment_selection_details_end, push_attachment_selection_details_start, push_git_hub_repo_ref, queue_append_steering_request, queue_begin_deferred_idle_drain_request, queue_begin_deferred_idle_drain_result, queue_consume_system_notifications_request, queued_command_handled, queued_command_not_handled, queued_command_result, queue_defer_session_idle_request, queue_duplicate_at_request, queue_duplicate_at_result, queue_enqueue_resume_pending_result, queue_finish_deferred_idle_drain_request, queue_finish_deferred_idle_drain_result, queue_has_pending_result, queue_insert_at_request, queue_insert_at_result, queue_insert_message, queue_move_item_request, queue_move_item_result, queue_pending_items, queue_pending_items_kind, queue_pending_items_result, queue_remove_at_request, queue_remove_at_result, queue_remove_most_recent_result, queue_send_now_request, queue_send_now_result, queue_set_drain_paused_request, queue_snapshot_result, queue_update_text_request, queue_update_text_result, queue_withdraw_message_request, queue_withdraw_message_result, quota_take_warnings_result, quota_warning_projection, register_event_interest_params, register_event_interest_result, release_event_interest_params, remote_control_config, remote_control_config_existing_mc_session, remote_control_status, remote_control_status_active, remote_control_status_connecting, remote_control_status_error, remote_control_status_off, remote_control_status_result, remote_control_stop_result, remote_control_transfer_result, remote_enable_request, remote_enable_result, remote_notify_steerable_changed_request, remote_notify_steerable_changed_result, remote_session_connection_result, remote_session_host_status, remote_session_metadata_repository, remote_session_metadata_task_type, remote_session_metadata_value, remote_session_mode, remote_session_repository, response_format, sandbox_config, sandbox_config_auth, sandbox_config_source, sandbox_config_user_policy, sandbox_config_user_policy_experimental, sandbox_config_user_policy_experimental_seatbelt, sandbox_config_user_policy_filesystem, sandbox_config_user_policy_network, sandbox_config_user_policy_network_proxy, sandbox_config_user_policy_seatbelt, sandbox_credentials_config, sandbox_disable_for_session_request, sandbox_disable_for_session_result, sandbox_enforcement_status, sandbox_grant_path_for_request_request, sandbox_grant_path_for_request_result, sandbox_host_capability, sandbox_host_capability_name, sandbox_host_support, sandbox_masked_env_var, sandbox_proxy_ca_create_result, sandbox_proxy_ca_request, sandbox_proxy_ca_state, sandbox_proxy_ca_status, sandbox_session_change, schedule_add_at_request, schedule_add_cron_request, schedule_add_request, schedule_add_result, schedule_add_self_paced_request, schedule_entry, schedule_has_self_paced_result, schedule_list, schedule_rearm_self_paced_request, schedule_stop_request, schedule_stop_result, secrets_add_filter_values_request, secrets_add_filter_values_result, send_agent_mode, send_attachments_to_message_params, send_message_item, send_messages_request, send_messages_result, send_mode, send_request, send_result, send_system_notification_request, server_agent_list, server_instruction_source_list, server_skill, server_skill_list, session_activity, session_agent_list_request, session_auth_login_request, session_auth_logout_user_request, session_auth_status, session_auth_switch_request, session_bulk_delete_result, session_cancel_all_background_agents_result, session_capability, session_commands_list_request, session_completion_item, session_connected_ide_info, session_context, session_context_host_type, session_enrich_metadata_result, session_fs_append_file_request, session_fs_error, session_fs_error_code, session_fs_exists_request, session_fs_exists_result, session_fs_mkdir_request, session_fs_readdir_request, session_fs_readdir_result, session_fs_readdir_with_types_entry, session_fs_readdir_with_types_entry_type, session_fs_readdir_with_types_request, session_fs_readdir_with_types_result, session_fs_read_file_bytes_request, session_fs_read_file_bytes_result, session_fs_read_file_request, session_fs_read_file_result, session_fs_rename_request, session_fs_rm_request, session_fs_set_provider_capabilities, session_fs_set_provider_conventions, session_fs_set_provider_request, session_fs_set_provider_result, session_fs_sqlite_exists_request, session_fs_sqlite_exists_result, session_fs_sqlite_query_request, session_fs_sqlite_query_result, session_fs_sqlite_query_type, session_fs_sqlite_transaction_error, session_fs_sqlite_transaction_error_class, session_fs_sqlite_transaction_request, session_fs_sqlite_transaction_result, session_fs_sqlite_transaction_statement, session_fs_stat_request, session_fs_stat_result, session_fs_write_file_bytes_request, session_fs_write_file_request, session_git_hub_auth_get_all_auth_available_result, session_git_hub_auth_logout_result, session_git_hub_auth_logout_user_result, session_history_compact_request, session_installed_plugin, session_installed_plugin_source, session_installed_plugin_source_git_hub, session_installed_plugin_source_local, session_installed_plugin_source_url, session_limit_prediction_baseline_data, session_limit_prediction_client_type, session_limit_prediction_details, session_limit_prediction_predict_request, session_limit_prediction_request, session_limit_prediction_result, session_limit_prediction_source, session_limit_prediction_tier, session_limit_prediction_tier_option, session_limit_prediction_unavailable_reason, session_list, session_list_entry, session_list_filter, session_load_deferred_repo_hooks_result, session_log_level, session_managed_permissions, session_managed_settings, session_mcp_apps_call_tool_result, session_mcp_oauth_cancel_login_request, session_mcp_oauth_cancel_login_result, session_mcp_oauth_prepare_login_request, session_mcp_oauth_prepare_login_result, session_mcp_set_connected_ide_info_params, session_metadata_snapshot, session_mode, session_model_clear_startup_seed_request, session_model_clear_startup_seed_result, session_model_list, session_model_list_request, session_model_price_category, session_open_options, session_open_options_additional_content_exclusion_policy, session_open_options_additional_content_exclusion_policy_rule, session_open_options_additional_content_exclusion_policy_rule_source, session_open_options_additional_content_exclusion_policy_scope, session_open_options_env_value_mode, session_open_options_reasoning_summary, session_open_params, session_open_result, session_plugins_disable_request, session_plugins_enable_request, session_plugins_install_request, session_plugins_marketplaces_refresh_request, session_plugins_reload_request, session_plugins_retry_managed_request, session_plugins_retry_managed_result, session_provider_get_endpoint_request, session_prune_result, session_quota_delegate_warning, session_quota_get_result, session_quota_plan_tier, session_quota_projection, session_quota_refresh_result, session_quota_snapshot, session_quota_take_warnings_result, sessions_bulk_delete_request, sessions_check_in_use_request, sessions_check_in_use_result, sessions_client_metadata_entry, sessions_close_request, sessions_close_result, sessions_create_workspace_request, sessions_create_workspace_result, sessions_delete_request, sessions_enrich_metadata_request, session_set_credentials_params, session_set_credentials_result, session_settings_built_in_tool_availability_snapshot, session_settings_evaluate_predicate_request, session_settings_evaluate_predicate_result, session_settings_job_snapshot, session_settings_model_snapshot, session_settings_online_evaluation_snapshot, session_settings_predicate_name, session_settings_repo_snapshot, session_settings_snapshot, session_settings_validation_snapshot, sessions_find_by_prefix_request, sessions_find_by_prefix_result, sessions_find_by_task_id_request, sessions_find_by_task_id_result, sessions_fork_request, sessions_fork_result, sessions_get_board_entry_count_request, sessions_get_board_entry_count_result, sessions_get_client_metadata_request, sessions_get_client_metadata_result, sessions_get_event_file_path_request, sessions_get_event_file_path_result, sessions_get_last_for_context_request, sessions_get_last_for_context_result, sessions_get_metadata_request, sessions_get_metadata_result, sessions_get_persisted_remote_steerable_request, sessions_get_persisted_remote_steerable_result, session_sizes, sessions_list_non_empty_session_ids_request, sessions_list_non_empty_session_ids_result, sessions_list_request, sessions_load_deferred_repo_hooks_request, sessions_load_workspace_request, sessions_load_workspace_result, sessions_open_attach, sessions_open_cloud, sessions_open_create, sessions_open_handoff, sessions_open_handoff_task_type, sessions_open_progress, sessions_open_progress_status, sessions_open_progress_step, sessions_open_remote, sessions_open_resume, sessions_open_resume_last, sessions_open_status, session_source, sessions_prune_old_request, sessions_read_persisted_events_request, sessions_release_lock_request, sessions_release_lock_result, sessions_reload_plugin_hooks_request, sessions_reload_plugin_hooks_result, sessions_save_request, sessions_save_result, sessions_set_additional_plugins_request, sessions_set_additional_plugins_result, sessions_set_remote_control_steering_request, sessions_start_remote_control_request, sessions_stop_remote_control_request, sessions_transfer_remote_control_request, sessions_update_workspace_fields_request, sessions_update_workspace_fields_result, session_telemetry_engagement, session_update_options_params, session_update_options_result, session_usage_set_code_changes_request, session_visibility_status, session_workflow_pause_at_checkpoint_result, session_working_directory_context, session_working_directory_context_host_type, session_working_directory_context_with_client, settable_auth_info, settable_token_auth_info, shell_cancel_user_requested_request, shell_credentials, shell_exec_request, shell_exec_result, shell_execute_user_requested_request, shell_init_profile, shell_init_script, shell_init_script_shell, shell_kill_request, shell_kill_result, shell_kill_signal, shell_options, shutdown_request, skill, skill_apply_install_request, skill_apply_uninstall_request, skill_discovery_path, skill_discovery_path_list, skill_discovery_scope, skill_installation_failure_reason, skill_installation_file_review, skill_installation_location, skill_installation_management_outcome, skill_installation_management_result, skill_installation_operation_request, skill_installation_operation_status, skill_installation_outcome, skill_installation_ownership_state, skill_installation_result, skill_installation_review, skill_installation_scope, skill_installation_session_state, skill_installation_source, skill_installations_request, skill_installation_summary, skill_install_plan, skill_list, skill_plan_install_request, skill_plan_uninstall_request, skill_provider_descriptor, skill_provider_list_request, skill_provider_list_result, skill_provider_read_request, skill_provider_read_result, skills_config_set_disabled_skills_request, skills_config_set_skill_disabled_request, skills_disable_request, skills_discover_request, skills_enable_request, skill_set_enabled_request, skills_get_discovery_paths_request, skills_get_invoked_result, skills_invoked_skill, skills_load_diagnostics, skill_uninstall_plan, slash_command_add_timeline_entry_result, slash_command_agent_prompt_result, slash_command_completed_result, slash_command_info, slash_command_input, slash_command_input_choice, slash_command_input_completion, slash_command_invocation_result, slash_command_kind, slash_command_model_picker_dialog, slash_command_select_subcommand_option, slash_command_select_subcommand_result, slash_command_set_model_result, slash_command_set_plan_model_result, slash_command_show_dialog_result, slash_command_text_result, slash_command_timeline_entry, subagent_settings_entry, subagent_settings_entry_context_tier, system_message_block, task_agent_info, task_agent_progress, task_client_active_status, task_client_execution_mode, task_client_info, task_client_owner, task_client_owner_kind, task_client_owner_presence, task_client_progress, task_client_status, task_client_type, task_client_update, task_complete_data, task_completion_decision, task_execution_mode, task_info, task_kind, task_list, task_progress_line, tasks_cancel_request, tasks_cancel_result, tasks_get_current_promotable_result, tasks_get_progress_request, tasks_get_progress_result, task_shell_info, task_shell_info_attachment_mode, task_shell_progress, tasks_promote_current_to_background_result, tasks_promote_to_background_request, tasks_promote_to_background_result, tasks_refresh_result, tasks_register_request, tasks_register_result, tasks_remove_request, tasks_remove_result, tasks_send_message_request, tasks_send_message_result, tasks_start_agent_request, tasks_start_agent_result, task_status, tasks_update_request, tasks_update_result, tasks_wait_for_pending_result, telemetry_set_feature_overrides_request, token_auth_info, token_provider_auth_info, tool, tool_list, tool_result, tool_result_expanded, tool_result_new_message, tool_result_type, tools_execute_request, tools_get_builtin_descriptors_request, tools_get_builtin_descriptors_result, tools_get_current_metadata_result, tools_initialize_and_validate_result, tools_list_pending_requests_request, tools_list_request, tools_set_request, tools_set_result, tools_shell_descriptor_config, tools_task_complete_event_data_request, tools_update_subagent_settings_result, ui_auto_mode_switch_response, ui_elicitation_array_any_of_field, ui_elicitation_array_any_of_field_items, ui_elicitation_array_any_of_field_items_any_of, ui_elicitation_array_enum_field, ui_elicitation_array_enum_field_items, ui_elicitation_field_value, ui_elicitation_request, ui_elicitation_response, ui_elicitation_response_action, ui_elicitation_response_content, ui_elicitation_result, ui_elicitation_schema, ui_elicitation_schema_property, ui_elicitation_schema_property_boolean, ui_elicitation_schema_property_number, ui_elicitation_schema_property_number_type, ui_elicitation_schema_property_string, ui_elicitation_schema_property_string_format, ui_elicitation_string_enum_field, ui_elicitation_string_one_of_field, ui_elicitation_string_one_of_field_one_of, ui_ephemeral_query_request, ui_ephemeral_query_result, ui_exit_plan_mode_action, ui_exit_plan_mode_response, ui_handle_pending_auto_mode_switch_request, ui_handle_pending_elicitation_request, ui_handle_pending_exit_plan_mode_request, ui_handle_pending_result, ui_handle_pending_sampling_request, ui_handle_pending_sampling_response, ui_handle_pending_session_limits_exhausted_request, ui_handle_pending_user_input_request, ui_register_direct_auto_mode_switch_handler_result, ui_session_limits_exhausted_response, ui_session_limits_exhausted_response_action, ui_unregister_direct_auto_mode_switch_handler_request, ui_unregister_direct_auto_mode_switch_handler_result, ui_user_input_response, unsupported_enqueue_command_result, update_subagent_settings_request, usage_get_metrics_result, usage_set_code_changes_request, user_auth_info, user_requested_shell_command_result, user_setting_metadata, user_settings_get_result, user_settings_set_request, visibility_get_result, visibility_set_request, visibility_set_result, workflow_abort_request, workflow_ack_result, workflow_agent_options, workflow_agent_request, workflow_agent_result, workflow_agent_summary, workflow_cancel_request, workflow_current_phase, workflow_declared_limits, workflow_durable_operation, workflow_execute_request, workflow_execute_result, workflow_get_run_progress_request, workflow_get_run_request, workflow_journal_get_request, workflow_journal_get_result, workflow_journal_put_request, workflow_list_runs_request, workflow_list_runs_result, workflow_log_line, workflow_log_line_kind, workflow_log_request, workflow_pause_checkpoint_action, workflow_pause_checkpoint_request, workflow_pause_checkpoint_result, workflow_pause_info, workflow_pause_request, workflow_phase_observation, workflow_phase_status, workflow_progress_line, workflow_progress_page, workflow_resume_request, workflow_resume_result, workflow_run_consumed, workflow_run_detail, workflow_run_failure, workflow_run_failure_kind, workflow_run_limits, workflow_run_options, workflow_run_request, workflow_run_result, workflow_run_status, workflow_run_summary, workflow_run_terminal, workflow_tool_resume_request, workflow_tool_run_options, workflow_tool_run_request, workspace_diff_contents, workspace_diff_file_change, workspace_diff_file_change_type, workspace_diff_mode, workspace_diff_result, workspaces_add_summary_request, workspaces_add_summary_result, workspaces_autopilot_objective_exists_result, workspaces_checkpoints, workspaces_create_directory_request, workspaces_create_file_request, workspaces_delete_autopilot_objective_result, workspaces_diff_request, workspaces_ensure_request, workspaces_get_workspace_result, workspaces_list_checkpoints_result, workspaces_list_files_result, workspaces_read_autopilot_objective_result, workspaces_read_checkpoint_request, workspaces_read_checkpoint_result, workspaces_read_file_request, workspaces_read_file_result, workspaces_remove_path_request, workspaces_rename_path_request, workspaces_save_large_paste_request, workspaces_save_large_paste_result, workspaces_stat_file_request, workspaces_stat_file_result, workspaces_truncate_summaries_request, workspace_summary_host_type, workspaces_update_metadata_request, workspaces_workspace_details_host_type, workspaces_write_autopilot_objective_request, workspaces_write_autopilot_objective_result, connector_session_account_result, session_auth_info_result, session_context_attribution, session_context_info, subagent_settings, task_progress, workspace_summary) def to_dict(self) -> dict: result: dict = {} @@ -53356,6 +53448,8 @@ def to_dict(self) -> dict: result["LogResult"] = to_class(LogResult, self.log_result) result["LspInitializeRequest"] = to_class(LspInitializeRequest, self.lsp_initialize_request) result["ManagedMcpServerConfig"] = to_class(ManagedMCPServerConfig, self.managed_mcp_server_config) + result["ManagedPluginRetryEntry"] = to_class(ManagedPluginRetryEntry, self.managed_plugin_retry_entry) + result["ManagedPluginRetryStatus"] = to_enum(ManagedPluginRetryStatus, self.managed_plugin_retry_status) result["ManagedSettingMeta"] = to_class(ManagedSettingMeta, self.managed_setting_meta) result["ManagedSettingsChannel"] = to_enum(ManagedSettingsChannel, self.managed_settings_channel) result["ManagedSettingsComposeLayer"] = to_class(ManagedSettingsComposeLayer, self.managed_settings_compose_layer) @@ -54085,6 +54179,8 @@ def to_dict(self) -> dict: result["SessionPluginsInstallRequest"] = to_class(SessionPluginsInstallRequest, self.session_plugins_install_request) result["SessionPluginsMarketplacesRefreshRequest"] = to_class(SessionPluginsMarketplacesRefreshRequest, self.session_plugins_marketplaces_refresh_request) result["SessionPluginsReloadRequest"] = to_class(SessionPluginsReloadRequest, self.session_plugins_reload_request) + result["SessionPluginsRetryManagedRequest"] = to_class(SessionPluginsRetryManagedRequest, self.session_plugins_retry_managed_request) + result["SessionPluginsRetryManagedResult"] = to_class(SessionPluginsRetryManagedResult, self.session_plugins_retry_managed_result) result["SessionProviderGetEndpointRequest"] = to_class(SessionProviderGetEndpointRequest, self.session_provider_get_endpoint_request) result["SessionPruneResult"] = to_class(SessionPruneResult, self.session_prune_result) result["SessionQuotaDelegateWarning"] = to_class(SessionQuotaDelegateWarning, self.session_quota_delegate_warning) @@ -57140,6 +57236,12 @@ async def reload(self, params: SessionPluginsReloadRequest | None = None, *, tim params_dict["sessionId"] = self._session_id await self._client.request("session.plugins.reload", params_dict, **_timeout_kwargs(timeout)) + async def retry_managed(self, params: SessionPluginsRetryManagedRequest | None = None, *, timeout: float | None = None) -> SessionPluginsRetryManagedResult: + "Installs or updates the plugins the session's managed settings require now, without waiting for the next automatic attempt after a failure, then reloads plugins. Reports progress and failures with the same `session.info` and `session.warning` events as automatic preparation. Fails when the runtime does not prepare managed plugins for the session.\n\nArgs:\n params: Plugins required by the session's managed settings to install or update again.\n\nReturns:\n Per-plugin outcomes of retrying the plugins required by the session's managed settings." + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + params_dict["sessionId"] = self._session_id + return SessionPluginsRetryManagedResult.from_dict(await self._client.request("session.plugins.retryManaged", params_dict, **_timeout_kwargs(timeout))) + # Experimental: this API group is experimental and may change or be removed. class ProviderApi: @@ -59570,6 +59672,8 @@ async def handle_installations_confirm(params: dict) -> dict | None: "MCPUninstallPlan", "MCPUnregisterExternalClientRequest", "ManagedMCPServerConfig", + "ManagedPluginRetryEntry", + "ManagedPluginRetryStatus", "ManagedSettingMeta", "ManagedSettingsApi", "ManagedSettingsChannel", @@ -60249,6 +60353,8 @@ async def handle_installations_confirm(params: dict) -> dict | None: "SessionPluginsInstallRequest", "SessionPluginsMarketplacesRefreshRequest", "SessionPluginsReloadRequest", + "SessionPluginsRetryManagedRequest", + "SessionPluginsRetryManagedResult", "SessionProviderGetEndpointRequest", "SessionPruneResult", "SessionQuotaDelegateWarning", diff --git a/python/copilot/session.py b/python/copilot/session.py index 9c8e0cf55f..b61d753956 100644 --- a/python/copilot/session.py +++ b/python/copilot/session.py @@ -1448,6 +1448,20 @@ class LargeToolOutputConfig(TypedDict, total=False): output_directory: str +class ImageGenerationConfig(TypedDict, total=False): + """**Experimental.** Opt in to an authorized Copilot image model. + + This API may change or be removed in a future release. + + Omission disables on create/cold resume and preserves resident state on + resume. Not persisted: re-supply after runtime restart. Policy, permissions, + offline mode, and tool filters still apply. BYOK is not supported. + """ + + enabled: bool + """True opts in; False disables image generation.""" + + class ToolSearchConfig(TypedDict, total=False): """ Override for the runtime's built-in tool-search behavior. diff --git a/python/test_image_generation.py b/python/test_image_generation.py new file mode 100644 index 0000000000..7323d869da --- /dev/null +++ b/python/test_image_generation.py @@ -0,0 +1,47 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. + +"""Image generation request serialization without starting a runtime.""" + +import json +from unittest.mock import AsyncMock, Mock + +import pytest + +from copilot import CopilotClient, ImageGenerationConfig, PermissionHandler, RuntimeConnection + + +@pytest.mark.asyncio +@pytest.mark.parametrize("option", [None, {}, {"enabled": True}, {"enabled": False}]) +async def test_image_generation_create_and_resume_wire(option: ImageGenerationConfig | None): + client = CopilotClient(connection=RuntimeConnection.for_stdio(path="unused-cli")) + client._state = "connected" + transport = Mock() + captured = {} + + async def request(method, params, **kwargs): + captured[method] = json.loads(json.dumps(params)) + response = {"sessionId": params["sessionId"]} + if callback := kwargs.get("on_response_inline"): + callback(response) + return response + + transport.request = AsyncMock(side_effect=request) + transport.stop = AsyncMock() + client._client = transport + try: + session = await client.create_session( + on_permission_request=PermissionHandler.approve_all, + image_generation=option, + ) + await client.resume_session( + session.session_id, + on_permission_request=PermissionHandler.approve_all, + image_generation=option, + ) + for method in ("session.create", "session.resume"): + if option is None: + assert "imageGeneration" not in captured[method], captured[method] + else: + assert captured[method]["imageGeneration"] == option + finally: + await client.force_stop() diff --git a/rust/src/generated/api_types.rs b/rust/src/generated/api_types.rs index 31cc1b82d7..e6a4b6f6bc 100644 --- a/rust/src/generated/api_types.rs +++ b/rust/src/generated/api_types.rs @@ -724,6 +724,8 @@ pub mod rpc_methods { pub const SESSION_PLUGINS_MARKETPLACES_REFRESH: &str = "session.plugins.marketplaces.refresh"; /// `session.plugins.reload` pub const SESSION_PLUGINS_RELOAD: &str = "session.plugins.reload"; + /// `session.plugins.retryManaged` + pub const SESSION_PLUGINS_RETRYMANAGED: &str = "session.plugins.retryManaged"; /// `session.provider.getEndpoint` pub const SESSION_PROVIDER_GETENDPOINT: &str = "session.provider.getEndpoint"; /// `session.provider.add` @@ -11108,6 +11110,26 @@ pub struct ManagedMcpServerConfig { pub url: String, } +/// Retry outcome for one plugin required by managed settings. +/// +///

+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ManagedPluginRetryEntry { + /// Why the plugin was not prepared. Present when `status` is `failed` or `deferred`. + #[serde(skip_serializing_if = "Option::is_none")] + pub error: Option, + /// Plugin spec in "plugin@marketplace" form. + pub spec: String, + /// What the retry did for this plugin. + pub status: ManagedPluginRetryStatus, +} + /// Lock state and provenance of one managed setting. /// ///
@@ -23884,6 +23906,37 @@ pub struct SessionPluginsInstallRequest { pub source: String, } +/// Plugins required by the session's managed settings to install or update again. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SessionPluginsRetryManagedRequest { + /// "plugin@marketplace" specs to retry. Omit to retry every plugin the session's managed settings require. + #[serde(skip_serializing_if = "Option::is_none")] + pub plugins: Option>, +} + +/// Per-plugin outcomes of retrying the plugins required by the session's managed settings. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SessionPluginsRetryManagedResult { + /// One entry per requested plugin, in request order. When no plugins were requested, one entry per plugin the managed settings require. + pub plugins: Vec, +} + /// Outcome of the prune operation: deleted IDs, dry-run candidates, skipped IDs, total bytes freed, and the dry-run flag. /// ///
@@ -42544,6 +42597,40 @@ pub enum SessionLogLevel { Unknown, } +/// What retrying did for one plugin required by managed settings. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum ManagedPluginRetryStatus { + /// The plugin was missing and is now installed. + #[serde(rename = "installed")] + Installed, + /// An update was available and is now installed. + #[serde(rename = "updated")] + Updated, + /// The plugin was already installed and current, so nothing was done. + #[serde(rename = "already_present")] + AlreadyPresent, + /// Checking, installing, or updating the plugin failed. See `error`. + #[serde(rename = "failed")] + Failed, + /// The plugin was not prepared because another session was changing plugins or the managed settings changed during the retry. It is prepared again before a later message. + #[serde(rename = "deferred")] + Deferred, + /// The session's managed settings do not require this plugin, so nothing was done. + #[serde(rename = "not_required")] + NotRequired, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + /// A channel accepted by managedSettings.compose. /// ///
diff --git a/rust/src/generated/rpc.rs b/rust/src/generated/rpc.rs index 2eb9168bab..518b3d0208 100644 --- a/rust/src/generated/rpc.rs +++ b/rust/src/generated/rpc.rs @@ -12168,6 +12168,64 @@ impl<'a> SessionRpcPlugins<'a> { .await?; Ok(()) } + + /// Installs or updates the plugins the session's managed settings require now, without waiting for the next automatic attempt after a failure, then reloads plugins. Reports progress and failures with the same `session.info` and `session.warning` events as automatic preparation. Fails when the runtime does not prepare managed plugins for the session. + /// + /// Wire method: `session.plugins.retryManaged`. + /// + /// # Returns + /// + /// Per-plugin outcomes of retrying the plugins required by the session's managed settings. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn retry_managed(&self) -> Result { + let wire_params = serde_json::json!({ "sessionId": self.session.id() }); + let _value = self + .session + .client() + .call(rpc_methods::SESSION_PLUGINS_RETRYMANAGED, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Installs or updates the plugins the session's managed settings require now, without waiting for the next automatic attempt after a failure, then reloads plugins. Reports progress and failures with the same `session.info` and `session.warning` events as automatic preparation. Fails when the runtime does not prepare managed plugins for the session. + /// + /// Wire method: `session.plugins.retryManaged`. + /// + /// # Parameters + /// + /// * `params` - Plugins required by the session's managed settings to install or update again. + /// + /// # Returns + /// + /// Per-plugin outcomes of retrying the plugins required by the session's managed settings. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn retry_managed_with_params( + &self, + params: SessionPluginsRetryManagedRequest, + ) -> Result { + let mut wire_params = serde_json::to_value(params)?; + wire_params["sessionId"] = serde_json::Value::String(self.session.id().to_string()); + let _value = self + .session + .client() + .call(rpc_methods::SESSION_PLUGINS_RETRYMANAGED, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } } /// `session.plugins.marketplaces.*` RPCs. diff --git a/rust/src/types.rs b/rust/src/types.rs index ba9c8a7451..9917693110 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -838,6 +838,35 @@ impl LargeToolOutputConfig { } } +/// Opt in to image generation through an authorized Copilot image model. +/// +/// **Experimental.** This API may change or be removed in a future release. +/// +/// Omission disables on create/cold resume and preserves resident resume state. +/// Not persisted: re-supply after runtime restart. Policy, permissions, offline +/// mode, and tool filters still apply. BYOK image generation is not supported. +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[non_exhaustive] +pub struct ImageGenerationConfig { + /// True opts in; false disables image generation. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub enabled: Option, +} + +impl ImageGenerationConfig { + /// Construct an unset image generation configuration. + pub fn new() -> Self { + Self::default() + } + + /// Enable or disable image generation. + pub fn with_enabled(mut self, enabled: bool) -> Self { + self.enabled = Some(enabled); + self + } +} + /// Overrides the runtime's built-in tool-search behavior. /// /// Tool search defers tools to keep the model's active tool set small. @@ -2189,6 +2218,8 @@ pub struct SessionConfig { /// rarely used tools behind a searchable index. When unset, the runtime /// default applies. pub tool_search: Option, + /// **Experimental.** Non-persisted image generation opt-in. Re-supply after runtime restart. + pub image_generation: Option, /// Skill names to disable. Skills in this set will not be available /// even if found in skill directories. pub disabled_skills: Option>, @@ -2478,6 +2509,7 @@ impl std::fmt::Debug for SessionConfig { .field("plugin_directories", &self.plugin_directories) .field("large_output", &self.large_output) .field("tool_search", &self.tool_search) + .field("image_generation", &self.image_generation) .field("disabled_skills", &self.disabled_skills) .field("disabled_mcp_servers", &self.disabled_mcp_servers) .field("hooks", &self.hooks) @@ -2616,6 +2648,7 @@ impl Default for SessionConfig { plugin_directories: None, large_output: None, tool_search: None, + image_generation: None, disabled_skills: None, disabled_mcp_servers: None, hooks: None, @@ -2788,6 +2821,7 @@ impl SessionConfig { plugin_directories: self.plugin_directories, large_output: self.large_output, tool_search: self.tool_search, + image_generation: self.image_generation, disabled_skills: self.disabled_skills, disabled_mcp_servers: self.disabled_mcp_servers, custom_agents: self.custom_agents, @@ -3279,6 +3313,12 @@ impl SessionConfig { self } + /// **Experimental.** Set the non-persisted image generation opt-in on create. + pub fn with_image_generation(mut self, config: ImageGenerationConfig) -> Self { + self.image_generation = Some(config); + self + } + /// Set the names of skills to disable (overrides skill discovery). pub fn with_disabled_skills(mut self, names: I) -> Self where @@ -3690,6 +3730,8 @@ pub struct ResumeSessionConfig { /// Overrides the runtime's built-in tool-search behavior on resume. When /// unset, the runtime default applies. pub tool_search: Option, + /// **Experimental.** Non-persisted image generation opt-in. Re-supply after runtime restart. + pub image_generation: Option, /// Skill names to disable on resume. pub disabled_skills: Option>, /// Exact MCP server names to disable on resume. This prevents startup and @@ -3921,6 +3963,7 @@ impl std::fmt::Debug for ResumeSessionConfig { .field("plugin_directories", &self.plugin_directories) .field("large_output", &self.large_output) .field("tool_search", &self.tool_search) + .field("image_generation", &self.image_generation) .field("disabled_skills", &self.disabled_skills) .field("disabled_mcp_servers", &self.disabled_mcp_servers) .field("hooks", &self.hooks) @@ -4096,6 +4139,7 @@ impl ResumeSessionConfig { plugin_directories: self.plugin_directories, large_output: self.large_output, tool_search: self.tool_search, + image_generation: self.image_generation, disabled_skills: self.disabled_skills, disabled_mcp_servers: self.disabled_mcp_servers, custom_agents: self.custom_agents, @@ -4205,6 +4249,7 @@ impl ResumeSessionConfig { plugin_directories: None, large_output: None, tool_search: None, + image_generation: None, disabled_skills: None, disabled_mcp_servers: None, hooks: None, @@ -4669,6 +4714,12 @@ impl ResumeSessionConfig { self } + /// **Experimental.** Set the image generation opt-in on resume, including after runtime restart. + pub fn with_image_generation(mut self, config: ImageGenerationConfig) -> Self { + self.image_generation = Some(config); + self + } + /// Set the names of skills to disable on resume. pub fn with_disabled_skills(mut self, names: I) -> Self where diff --git a/rust/src/types/tests.rs b/rust/src/types/tests.rs index 774feeda9f..0749d946bd 100644 --- a/rust/src/types/tests.rs +++ b/rust/src/types/tests.rs @@ -13,11 +13,11 @@ use super::{ AgentMode, Attachment, AttachmentLineRange, AttachmentSelectionPosition, AttachmentSelectionRange, AutoTier, AzureProviderOptions, CapiSessionOptions, ConnectionState, CopilotExpAssignmentResponse, CustomAgentConfig, DeliveryMode, ExpConfigEntry, ExpFlagValue, - ExtensionInfo, GitHubMcpToolConfig, GitHubReferenceType, InfiniteSessionConfig, - LargeToolOutputConfig, McpServerConfig, McpStdioServerConfig, MemoryConfiguration, - NamedProviderConfig, PermissionResponseCapability, ProviderConfig, ProviderModelConfig, - ReasoningSummary, ResumeSessionConfig, SessionConfig, SessionEvent, SessionId, - SystemMessageConfig, Tool, ToolBinaryResult, ToolResult, ToolResultExpanded, + ExtensionInfo, GitHubMcpToolConfig, GitHubReferenceType, ImageGenerationConfig, + InfiniteSessionConfig, LargeToolOutputConfig, McpServerConfig, McpStdioServerConfig, + MemoryConfiguration, NamedProviderConfig, PermissionResponseCapability, ProviderConfig, + ProviderModelConfig, ReasoningSummary, ResumeSessionConfig, SessionConfig, SessionEvent, + SessionId, SystemMessageConfig, Tool, ToolBinaryResult, ToolResult, ToolResultExpanded, ToolResultResponse, ensure_attachment_display_names, }; use crate::generated::session_events::TypedSessionEvent; @@ -1947,3 +1947,40 @@ fn github_anchored_attachment_variants_round_trip() { ); } } +#[test] +fn image_generation_create_and_resume_wire_options() { + for enabled in [true, false] { + let config = ImageGenerationConfig::new().with_enabled(enabled); + let (create, _) = SessionConfig::default() + .with_image_generation(config.clone()) + .into_wire(Some(SessionId::from("image-test"))) + .unwrap(); + let (resume, _) = ResumeSessionConfig::new(SessionId::from("image-test")) + .with_image_generation(config) + .into_wire() + .unwrap(); + for wire in [ + serde_json::to_value(create).unwrap(), + serde_json::to_value(resume).unwrap(), + ] { + assert_eq!( + wire["imageGeneration"], + serde_json::json!({"enabled": enabled}) + ); + } + } + let (create, _) = SessionConfig::default().into_wire(None).unwrap(); + let (resume, _) = ResumeSessionConfig::new(SessionId::from("image-test")) + .into_wire() + .unwrap(); + for wire in [ + serde_json::to_value(create).unwrap(), + serde_json::to_value(resume).unwrap(), + ] { + assert!(wire.get("imageGeneration").is_none(), "{wire}"); + } + assert_eq!( + serde_json::to_value(ImageGenerationConfig::new()).unwrap(), + serde_json::json!({}) + ); +} diff --git a/rust/src/wire.rs b/rust/src/wire.rs index 2720d3bf2d..32c46bc85f 100644 --- a/rust/src/wire.rs +++ b/rust/src/wire.rs @@ -27,9 +27,9 @@ use crate::generated::session_events::ReasoningSummary; use crate::types::{ AskUserVariant, CanvasProviderIdentity, CapiSessionOptions, CloudSessionOptions, CustomAgentConfig, DefaultAgentConfig, ExtensionInfo, GitHubMcpToolConfig, - InfiniteSessionConfig, LargeToolOutputConfig, McpServerConfig, MemoryConfiguration, - NamedProviderConfig, ProviderConfig, ProviderModelConfig, SessionId, SessionLimitsConfig, - SystemMessageConfig, Tool, ToolSearchConfig, + ImageGenerationConfig, InfiniteSessionConfig, LargeToolOutputConfig, McpServerConfig, + MemoryConfiguration, NamedProviderConfig, ProviderConfig, ProviderModelConfig, SessionId, + SessionLimitsConfig, SystemMessageConfig, Tool, ToolSearchConfig, }; /// Wire representation of a slash command (name + description only). The @@ -145,6 +145,8 @@ pub(crate) struct SessionCreateWire { #[serde(skip_serializing_if = "Option::is_none")] pub tool_search: Option, #[serde(skip_serializing_if = "Option::is_none")] + pub image_generation: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub disabled_skills: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub disabled_mcp_servers: Option>, @@ -317,6 +319,8 @@ pub(crate) struct SessionResumeWire { #[serde(skip_serializing_if = "Option::is_none")] pub tool_search: Option, #[serde(skip_serializing_if = "Option::is_none")] + pub image_generation: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub disabled_skills: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub disabled_mcp_servers: Option>, From 24f386ae7b5ce63e601eed3f0f669aca4e05fb2f Mon Sep 17 00:00:00 2001 From: "copilot-cli-release-app[bot]" Date: Fri, 9 Oct 2026 10:53:31 +0000 Subject: [PATCH 3/9] Update SDK snapshot for Copilot CLI 1.0.95-3 --- dotnet/test/Harness/ReplayProxy.cs | 7 +- nodejs/package.json | 2 +- nodejs/src/cliVersion.ts | 2 +- nodejs/test/e2e/image_edits.e2e.test.ts | 508 ++++++++++++++++++++++++ rust/src/jsonrpc.rs | 78 ++-- rust/src/router.rs | 59 ++- rust/src/router/tests.rs | 493 +++++++++++++++++++++++ test/harness/server.ts | 10 + test/harness/startup.mjs | 12 + test/harness/startup.test.ts | 73 ++++ 10 files changed, 1195 insertions(+), 49 deletions(-) create mode 100644 nodejs/test/e2e/image_edits.e2e.test.ts create mode 100644 test/harness/startup.mjs create mode 100644 test/harness/startup.test.ts diff --git a/dotnet/test/Harness/ReplayProxy.cs b/dotnet/test/Harness/ReplayProxy.cs index 140642a2f7..6891aeae71 100644 --- a/dotnet/test/Harness/ReplayProxy.cs +++ b/dotnet/test/Harness/ReplayProxy.cs @@ -32,7 +32,7 @@ async Task StartCoreAsync() { FileName = "node", WorkingDirectory = Path.Join(FindRepoRoot(), "test", "harness"), - Arguments = "--import tsx server.ts", + Arguments = "startup.mjs", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, @@ -89,7 +89,10 @@ async Task StartCoreAsync() { if (e.Data == null) return; diagnostics.AppendError(e.Data); - Console.Error.WriteLine(e.Data); + if (!e.Data.StartsWith("[SDK proxy startup]", StringComparison.Ordinal)) + { + Console.Error.WriteLine(e.Data); + } }; try diff --git a/nodejs/package.json b/nodejs/package.json index 5af5d28093..a65ffe4181 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -5,7 +5,7 @@ "url": "https://github.com/github/copilot-sdk.git" }, "version": "0.0.0-dev", - "copilotCliVersion": "1.0.95-2", + "copilotCliVersion": "1.0.95-3", "description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC", "main": "./dist/cjs/index.js", "types": "./dist/index.d.ts", diff --git a/nodejs/src/cliVersion.ts b/nodejs/src/cliVersion.ts index 833739e796..92ccdd2f0b 100644 --- a/nodejs/src/cliVersion.ts +++ b/nodejs/src/cliVersion.ts @@ -1,3 +1,3 @@ -export const COPILOT_CLI_VERSION = "1.0.95-2"; +export const COPILOT_CLI_VERSION = "1.0.95-3"; export const COPILOT_CLI_USE_NPM_PACKAGE = false; diff --git a/nodejs/test/e2e/image_edits.e2e.test.ts b/nodejs/test/e2e/image_edits.e2e.test.ts new file mode 100644 index 0000000000..952a61fb0c --- /dev/null +++ b/nodejs/test/e2e/image_edits.e2e.test.ts @@ -0,0 +1,508 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import { createHash, randomUUID } from "node:crypto"; +import { readFile } from "node:fs/promises"; +import { join } from "node:path"; +import { deflateSync } from "node:zlib"; +import { describe, expect, it } from "vitest"; +import { + approveAll, + CopilotRequestHandler, + type CopilotClient, + type CopilotRequestContext, + type SessionEvent, + type UserPromptTransformedHookInput, +} from "../../src/index.js"; +import { createSdkTestContext } from "./harness/sdkTestContext.js"; + +const MODEL = "gpt-image-2.5-sunburst"; +const FINAL = "IMAGE_EDIT_SDK_FINISHED"; + +function png(red: number, width = 1): string { + function chunk(name: string, data: Buffer): Buffer { + const payload = Buffer.concat([Buffer.from(name), data]); + let crc = 0xffffffff; + for (const byte of payload) { + crc ^= byte; + for (let bit = 0; bit < 8; bit++) { + crc = (crc >>> 1) ^ (crc & 1 ? 0xedb88320 : 0); + } + } + const length = Buffer.alloc(4); + length.writeUInt32BE(data.length); + const checksum = Buffer.alloc(4); + checksum.writeUInt32BE((crc ^ 0xffffffff) >>> 0); + return Buffer.concat([length, payload, checksum]); + } + const header = Buffer.alloc(13); + header.writeUInt32BE(width, 0); + header.writeUInt32BE(1, 4); + header[8] = 8; + header[9] = 2; + const pixels = Buffer.alloc(1 + width * 3); + for (let column = 0; column < width; column++) { + pixels[1 + column * 3] = red; + } + return Buffer.concat([ + Buffer.from("89504e470d0a1a0a", "hex"), + chunk("IHDR", header), + chunk("IDAT", deflateSync(pixels)), + chunk("IEND", Buffer.alloc(0)), + ]).toString("base64"); +} + +function imageId(data: string): string { + return `sha256:${createHash("sha256").update(Buffer.from(data, "base64")).digest("hex")}`; +} + +const SOURCE = png(20); +const EDITED = png(200); + +class ImageHandler extends CopilotRequestHandler { + readonly edits: Array> = []; + readonly generations: Array> = []; + readonly chats: Array> = []; + outputImage = EDITED; + supportedEndpoints = ["/v1/images/generations", "/v1/images/edits"]; + nextArguments: Record | undefined; + private calls = 0; + + protected override async sendRequest( + request: Request, + _context: CopilotRequestContext + ): Promise { + const path = new URL(request.url).pathname; + const body: Record = request.body ? await request.json() : {}; + if (path.endsWith("/models")) { + return Response.json({ + data: [ + { + id: MODEL, + name: "Image test", + capabilities: { type: "image" }, + supported_endpoints: this.supportedEndpoints, + model_picker_enabled: false, + policy: { state: "enabled" }, + }, + ], + }); + } + if (path.endsWith("/models/session") || path.includes("/policy")) { + return Response.json({ state: "enabled" }); + } + if (path === "/v1/images/edits" || path === "/v1/images/generations") { + (path.endsWith("/edits") ? this.edits : this.generations).push(body); + return Response.json({ + created: 1, + data: [{ b64_json: this.outputImage }], + output_format: "png", + }); + } + if (path.endsWith("/chat/completions")) { + this.chats.push(body); + const args = this.nextArguments; + this.nextArguments = undefined; + const toolCalls = args + ? [ + { + id: `image-edit-${++this.calls}`, + type: "function", + function: { name: "image_generation", arguments: JSON.stringify(args) }, + }, + ] + : undefined; + const message = { + role: "assistant", + content: args ? null : FINAL, + tool_calls: toolCalls, + }; + const finish = args ? "tool_calls" : "stop"; + if (body.stream === true) { + const delta = { + ...message, + tool_calls: toolCalls?.map((call, index) => ({ index, ...call })), + }; + return new Response( + [ + `data: ${JSON.stringify({ id: "image-chat", object: "chat.completion.chunk", choices: [{ index: 0, delta, finish_reason: null }] })}\n\n`, + `data: ${JSON.stringify({ id: "image-chat", object: "chat.completion.chunk", choices: [{ index: 0, delta: {}, finish_reason: finish }], usage: { prompt_tokens: 1, completion_tokens: 1, total_tokens: 2 } })}\n\n`, + "data: [DONE]\n\n", + ].join(""), + { headers: { "content-type": "text/event-stream" } } + ); + } + return Response.json({ + id: "image-chat", + object: "chat.completion", + model: "image-edit-chat", + choices: [{ index: 0, message, finish_reason: finish }], + usage: { prompt_tokens: 1, completion_tokens: 1, total_tokens: 2 }, + }); + } + throw new Error(`Unexpected image test request: ${request.method} ${path}`); + } +} + +describe("Native image editing", async () => { + const { createClient, env, openAiEndpoint } = await createSdkTestContext({ + copilotClientOptions: { env: { IMAGE_GENERATION_TOOL: "true" } }, + }); + async function readPersistedAssets(client: CopilotClient, sessionId: string) { + // Binary assets are internal persistence records, not public SDK events. + await client.rpc.sessions.save({ sessionId }); + const log = await readFile( + join(env.COPILOT_HOME, "session-state", sessionId, "events.jsonl"), + "utf8" + ); + return log + .trim() + .split("\n") + .map((line): SessionEvent => JSON.parse(line)) + .filter((event) => event.type === "session.binary_asset"); + } + const options = { + model: "image-edit-chat", + imageGeneration: { enabled: true }, + provider: { + type: "openai" as const, + wireApi: "completions" as const, + baseUrl: "https://image-edit-test.invalid/v1", + apiKey: "synthetic-image-test", + }, + onPermissionRequest: approveAll, + }; + + it("edits an explicit attachment and can reuse the generated result after resume", async () => { + const handler = new ImageHandler(); + const client = createClient({ requestHandler: handler }); + try { + await client.start(); + const session = await client.createSession(options); + const events: SessionEvent[] = []; + session.on((event) => events.push(event)); + handler.nextArguments = { + prompt: "Use this reference", + input_images: [{ image_id: imageId(SOURCE) }], + }; + const reply = await session.sendAndWait({ + prompt: "Use the attached image as a reference for a new image.", + attachments: [{ type: "blob", mimeType: "image/png", data: SOURCE }], + }); + expect(reply?.data.content).toBe(FINAL); + const completion = events.find((event) => event.type === "tool.execution_complete"); + expect(completion?.data.error).toBeUndefined(); + expect(completion?.data.success).toBe(true); + expect(handler.generations).toHaveLength(0); + expect(handler.edits).toEqual([ + { + model: MODEL, + prompt: "Use this reference", + images: [{ image_url: `data:image/png;base64,${SOURCE}` }], + n: 1, + output_format: "png", + stream: false, + }, + ]); + const sessionId = session.sessionId; + await session.disconnect(); + await client.stop(); + await client.start(); + const resumed = await client.resumeSession(sessionId, options); + handler.nextArguments = { + prompt: "Make the result brighter", + input_images: [{ image_id: imageId(EDITED) }], + }; + expect( + (await resumed.sendAndWait({ prompt: "Make the generated image brighter." }))?.data + .content + ).toBe(FINAL); + expect(handler.edits).toHaveLength(2); + expect(handler.edits[1].images).toEqual([ + { image_url: `data:image/png;base64,${EDITED}` }, + ]); + expect(handler.generations).toHaveLength(0); + await resumed.disconnect(); + } finally { + await client.stop(); + } + }); + + it("does not upload an unrelated attachment when the tool selects text-only generation", async () => { + const handler = new ImageHandler(); + const client = createClient({ requestHandler: handler }); + try { + await client.start(); + const session = await client.createSession(options); + handler.nextArguments = { prompt: "A fresh landscape" }; + expect( + ( + await session.sendAndWait({ + prompt: "Ignore the attachment and generate a fresh landscape.", + attachments: [{ type: "blob", mimeType: "image/png", data: SOURCE }], + }) + )?.data.content + ).toBe(FINAL); + expect(handler.edits).toHaveLength(0); + expect(handler.generations).toHaveLength(1); + expect(handler.generations[0]).not.toHaveProperty("images"); + await session.disconnect(); + } finally { + await client.stop(); + } + }); + + it("rejects image references outside the session instead of generating a substitute", async () => { + const handler = new ImageHandler(); + const client = createClient({ requestHandler: handler }); + try { + await client.start(); + const session = await client.createSession(options); + const events: SessionEvent[] = []; + session.on((event) => events.push(event)); + handler.nextArguments = { + prompt: "Edit", + input_images: [{ image_id: imageId(SOURCE) }], + }; + expect( + (await session.sendAndWait({ prompt: "Edit the selected image." }))?.data.content + ).toBe(FINAL); + expect(handler.edits).toHaveLength(0); + expect(handler.generations).toHaveLength(0); + const completion = events.find((event) => event.type === "tool.execution_complete"); + expect(completion?.data.error?.message).toMatch(/^image_generation_input_unavailable:/); + expect(completion?.data.success).toBe(false); + await session.disconnect(); + } finally { + await client.stop(); + } + }); + + it("keeps the transformed hook final for batched image attachments", async () => { + const handler = new ImageHandler(); + const client = createClient({ requestHandler: handler }); + const preceding = "Inspect the first batch image."; + const replacement = "IMAGE_BATCH_HOOK_REPLACEMENT"; + const inputs: UserPromptTransformedHookInput[] = []; + try { + await client.start(); + const session = await client.createSession({ + ...options, + hooks: { + onUserPromptTransformed: async (input) => { + inputs.push(input); + return { modifiedTransformedPrompt: replacement }; + }, + }, + }); + const events: SessionEvent[] = []; + session.on((event) => events.push(event)); + await session.rpc.sendMessages({ + messages: [ + { + prompt: preceding, + attachments: [{ type: "blob", mimeType: "image/png", data: SOURCE }], + }, + { prompt: "Finish the batch." }, + ], + wait: true, + }); + expect(inputs.find((input) => input.prompt === preceding)?.transformedPrompt).toContain( + imageId(SOURCE) + ); + const messages = events.filter((event) => event.type === "user.message"); + expect(messages).toHaveLength(2); + for (const message of messages) { + expect(message.data.transformedContent).toBe(replacement); + } + expect(JSON.stringify(handler.chats.at(-1)?.messages)).not.toContain( + "Image input references" + ); + // Validate the final assistant response arrived (guards against truncated captures). + expect( + events.findLast((event) => event.type === "assistant.message")?.data.content + ).toBe(FINAL); + await session.disconnect(); + } finally { + await client.stop(); + } + }); + + it("emits the preceding image message when its transformed hook throws", async () => { + const handler = new ImageHandler(); + const client = createClient({ requestHandler: handler }); + const preceding = "Inspect the first batch image."; + const hooked: string[] = []; + try { + await client.start(); + const session = await client.createSession({ + ...options, + hooks: { + onUserPromptTransformed: async (input) => { + hooked.push(input.prompt); + if (input.prompt === preceding) { + throw new Error("IMAGE_TRANSFORM_EXPECTED_FAILURE"); + } + }, + }, + }); + const events: SessionEvent[] = []; + session.on((event) => events.push(event)); + await session.rpc.sendMessages({ + messages: [ + { + prompt: preceding, + attachments: [{ type: "blob", mimeType: "image/png", data: SOURCE }], + }, + { prompt: "Finish the batch." }, + ], + wait: true, + }); + expect(hooked).toEqual([preceding, "Finish the batch."]); + const messages = events.filter((event) => event.type === "user.message"); + expect(messages.map((message) => message.data.content)).toEqual(hooked); + expect(messages[0].data.attachments).toContainEqual( + expect.objectContaining({ type: "blob", mimeType: "image/png", data: SOURCE }) + ); + expect( + (await readPersistedAssets(client, session.sessionId)).map( + (asset) => asset.data.assetId + ) + ).toEqual([imageId(SOURCE)]); + // Validate the final assistant response arrived (guards against truncated captures). + expect( + events.findLast((event) => event.type === "assistant.message")?.data.content + ).toBe(FINAL); + await session.disconnect(); + } finally { + await client.stop(); + } + }); + + it("adds a persisted preview when reattaching a generated image", async () => { + const handler = new ImageHandler(); + handler.outputImage = png(200, 2200); + const client = createClient({ requestHandler: handler }); + try { + await client.start(); + const session = await client.createSession(options); + handler.nextArguments = { prompt: "Generate a wide image." }; + expect( + (await session.sendAndWait({ prompt: "Generate a wide image." }))?.data.content + ).toBe(FINAL); + expect(handler.generations).toHaveLength(1); + expect( + ( + await session.sendAndWait({ + prompt: "Inspect the reattached image.", + attachments: [ + { type: "blob", mimeType: "image/png", data: handler.outputImage }, + ], + }) + )?.data.content + ).toBe(FINAL); + const assets = await readPersistedAssets(client, session.sessionId); + const update = assets.findLast( + (event) => event.data.assetId === `image-edit:${imageId(handler.outputImage)}` + ); + expect(update?.data.metadata?.imageEditSource).toEqual({ + data: handler.outputImage, + mimeType: "image/png", + }); + const preview = update?.data.data; + if (typeof preview !== "string") { + throw new Error("The reattached image has no persisted chat preview"); + } + expect(preview).not.toBe(handler.outputImage); + expect(Buffer.from(preview, "base64").length).toBeLessThanOrEqual(3 * 1024 * 1024); + const imageMessage = expect.objectContaining({ + role: "user", + content: expect.arrayContaining([ + expect.objectContaining({ + type: "image_url", + image_url: expect.objectContaining({ + url: `data:image/png;base64,${preview}`, + }), + }), + ]), + }); + expect(handler.chats.at(-1)?.messages).toContainEqual(imageMessage); + + const sessionId = session.sessionId; + await session.disconnect(); + await client.stop(); + await client.start(); + const resumed = await client.resumeSession(sessionId, options); + expect((await resumed.sendAndWait({ prompt: "Inspect it again." }))?.data.content).toBe( + FINAL + ); + expect(handler.chats.at(-1)?.messages).toContainEqual(imageMessage); + handler.nextArguments = { + prompt: "Edit the original wide image.", + input_images: [{ image_id: imageId(handler.outputImage) }], + }; + // Validate the final assistant response arrived (guards against truncated captures). + expect( + (await resumed.sendAndWait({ prompt: "Edit the reattached image." }))?.data.content + ).toBe(FINAL); + expect(handler.edits.at(-1)?.images).toEqual([ + { image_url: `data:image/png;base64,${handler.outputImage}` }, + ]); + await resumed.disconnect(); + } finally { + await client.stop(); + } + }); + + it.each(["generations-only", "filtered-out"] as const)( + "does not retain originals or advertise image inputs when %s", + async (availability) => { + const handler = new ImageHandler(); + if (availability === "generations-only") { + handler.supportedEndpoints = ["/v1/images/generations"]; + } + // In-process clients share the model catalog cache, keyed by endpoint and auth. + const token = `image-input-${randomUUID()}`; + await openAiEndpoint.setCopilotUserByToken(token, { + login: "image-input-test", + copilot_plan: "individual_pro", + endpoints: { api: env.COPILOT_API_URL }, + analytics_tracking_id: token, + }); + const client = createClient({ requestHandler: handler, gitHubToken: token }); + const inputs: UserPromptTransformedHookInput[] = []; + try { + await client.start(); + const session = await client.createSession({ + ...options, + excludedTools: availability === "filtered-out" ? ["image_generation"] : [], + hooks: { + onUserPromptTransformed: async (input) => { + inputs.push(input); + }, + }, + }); + const original = png(20, 2200); + // Validate the final assistant response arrived (guards against truncated captures). + expect( + ( + await session.sendAndWait({ + prompt: "Inspect this attachment.", + attachments: [{ type: "blob", mimeType: "image/png", data: original }], + }) + )?.data.content + ).toBe(FINAL); + expect(inputs).toHaveLength(1); + expect(inputs[0].transformedPrompt).not.toContain("Image input references"); + const assets = await readPersistedAssets(client, session.sessionId); + expect(assets).toHaveLength(1); + expect(assets[0].data.data).not.toBe(original); + expect(assets[0].data.metadata?.imageEditSource).toBeUndefined(); + await session.disconnect(); + } finally { + await client.stop(); + } + } + ); +}); diff --git a/rust/src/jsonrpc.rs b/rust/src/jsonrpc.rs index 2f69da5ba9..c602ca9f4d 100644 --- a/rust/src/jsonrpc.rs +++ b/rust/src/jsonrpc.rs @@ -270,13 +270,13 @@ fn repair_lone_surrogates(body: &[u8]) -> Option> { /// /// `frame` is the fully serialized bytes (header + body); the caller pays /// the serde cost synchronously before enqueueing so the actor never sees a -/// `Result` from JSON encoding. `ack` resolves once the bytes have been +/// `Result` from JSON encoding. When present, `ack` resolves once the bytes have been /// fully written and flushed (or the underlying I/O reports an error). If /// the caller drops the `oneshot::Receiver`, the actor still completes the /// frame — caller cancellation cannot desync the wire. struct WriteCommand { frame: Vec, - ack: oneshot::Sender>, + ack: Option>>, } /// Inbound requests that honor `$/cancelRequest`. @@ -412,9 +412,12 @@ impl JsonRpcClient { host_notifications: Option>, ) -> Self { let (write_tx, write_rx) = mpsc::unbounded_channel::(); + let connection_closed = CancellationToken::new(); let writer_span = tracing::error_span!("jsonrpc_write_loop"); - let write_task = tokio::spawn(Self::write_loop(writer, write_rx).instrument(writer_span)); + let write_task = tokio::spawn( + Self::write_loop(writer, write_rx, connection_closed.clone()).instrument(writer_span), + ); let client = Self { request_id: AtomicU64::new(1), @@ -423,7 +426,7 @@ impl JsonRpcClient { notification_tx, request_tx, request_handlers: Arc::new(RwLock::new(HashMap::new())), - connection_closed: CancellationToken::new(), + connection_closed, cancellable_requests: Arc::new(CancellableRequests::default()), read_task: Mutex::new(None), write_task: Mutex::new(Some(write_task)), @@ -518,6 +521,7 @@ impl JsonRpcClient { async fn write_loop( mut writer: impl AsyncWrite + Unpin + Send + 'static, mut rx: mpsc::UnboundedReceiver, + connection_closed: CancellationToken, ) { while let Some(WriteCommand { frame, ack }) = rx.recv().await { let result = async { @@ -526,11 +530,21 @@ impl JsonRpcClient { Ok::<_, std::io::Error>(()) } .await; - // Caller may have dropped the ack receiver (e.g. their // `await` was cancelled); that's fine — we still completed // the write, which was the whole point. - let _ = ack.send(result); + match ack { + Some(ack) => { + let _ = ack.send(result); + } + None => { + if let Err(error) = result { + error!(%error, "router rejection write failed; closing connection"); + connection_closed.cancel(); + break; + } + } + } } } @@ -550,7 +564,12 @@ impl JsonRpcClient { let (connection_closed, cancellable_requests) = connection; loop { - match Self::read_message(&mut reader).await { + let message = tokio::select! { + biased; + _ = connection_closed.cancelled() => break, + message = Self::read_message(&mut reader) => message, + }; + match message { Ok(Some(message)) => match message { JsonRpcMessage::Response(mut response) => { let id = response.id; @@ -904,27 +923,18 @@ impl JsonRpcClient { Self::write_message(&self.write_tx, message).await } + /// Commit a router rejection to the existing writer actor without retaining + /// a delivery waiter. The actor reports write failure and closes the connection. + pub(crate) fn enqueue_response(&self, response: &JsonRpcResponse) -> Result<(), Error> { + Self::enqueue_message(&self.write_tx, response, None) + } + async fn write_message( write_tx: &mpsc::UnboundedSender, message: &T, ) -> Result<(), Error> { - let body = serde_json::to_vec(message)?; - let mut frame = Vec::with_capacity(CONTENT_LENGTH_HEADER.len() + 16 + body.len() + 4); - frame.extend_from_slice(CONTENT_LENGTH_HEADER.as_bytes()); - frame.extend_from_slice(body.len().to_string().as_bytes()); - frame.extend_from_slice(b"\r\n\r\n"); - frame.extend_from_slice(&body); - let (ack_tx, ack_rx) = oneshot::channel(); - write_tx - .send(WriteCommand { frame, ack: ack_tx }) - .map_err(|_| { - Error::from(std::io::Error::new( - std::io::ErrorKind::BrokenPipe, - "writer actor has shut down", - )) - })?; - + Self::enqueue_message(write_tx, message, Some(ack_tx))?; match ack_rx.await { Ok(Ok(())) => Ok(()), Ok(Err(e)) => Err(Error::from(e)), @@ -934,6 +944,28 @@ impl JsonRpcClient { ))), } } + + fn enqueue_message( + write_tx: &mpsc::UnboundedSender, + message: &T, + ack: Option>>, + ) -> Result<(), Error> { + let body = serde_json::to_vec(message)?; + let mut frame = Vec::with_capacity(CONTENT_LENGTH_HEADER.len() + 16 + body.len() + 4); + frame.extend_from_slice(CONTENT_LENGTH_HEADER.as_bytes()); + frame.extend_from_slice(body.len().to_string().as_bytes()); + frame.extend_from_slice(b"\r\n\r\n"); + frame.extend_from_slice(&body); + + write_tx.send(WriteCommand { frame, ack }).map_err(|_| { + Error::from(std::io::Error::new( + std::io::ErrorKind::BrokenPipe, + "writer actor has shut down", + )) + })?; + + Ok(()) + } } impl Drop for JsonRpcClient { diff --git a/rust/src/router.rs b/rust/src/router.rs index 9b0d68464b..dff61da6b1 100644 --- a/rust/src/router.rs +++ b/rust/src/router.rs @@ -302,8 +302,17 @@ impl SessionRouter { // Request routing task (if request_rx is available) if let Some(mut rx) = client.request_rx.lock().take() { let sessions = self.sessions.clone(); + let connection_closed = client.rpc.connection_closed_token(); tokio::spawn(async move { - while let Some(request) = rx.recv().await { + loop { + let request = tokio::select! { + biased; + _ = connection_closed.cancelled() => break, + request = rx.recv() => { + let Some(request) = request else { break }; + request + } + }; if request.method == crate::installation_confirmation::CONFIRM_METHOD { installation_confirmation.dispatch(request); continue; @@ -341,13 +350,14 @@ impl SessionRouter { .map(str::to_owned); let Some(session_id) = session_id else { warn!(method = %request.method, "request missing sessionId"); - send_error( + if !send_error( &weak_client, request.id, error_codes::INVALID_PARAMS, "missing required field: sessionId".to_string(), - ) - .await; + ) { + break; + } continue; }; @@ -368,43 +378,48 @@ impl SessionRouter { method = %request.method, "request for unregistered session" ); - send_error( + if !send_error( &weak_client, request.id, error_codes::INTERNAL_ERROR, format!("Session not found: {session_id}"), - ) - .await; + ) { + break; + } } } + sessions.lock().clear(); }); } } } -async fn send_error( +fn send_error( client: &Weak, request_id: u64, code: i32, message: String, -) { +) -> bool { let Some(inner) = client.upgrade() else { - return; + return false; }; // Retire any cancellation registered for a request that never reaches a handler. drop(inner.rpc.cancellable_requests.claim(request_id)); - let _ = crate::Client::from_inner(inner) - .send_response(&JsonRpcResponse { - jsonrpc: "2.0".to_string(), - id: request_id, - result: None, - error: Some(JsonRpcError { - code, - message, - data: None, - }), - }) - .await; + if let Err(error) = inner.rpc.enqueue_response(&JsonRpcResponse { + jsonrpc: "2.0".to_string(), + id: request_id, + result: None, + error: Some(JsonRpcError { + code, + message, + data: None, + }), + }) { + warn!(%error, "failed to enqueue router rejection; closing connection"); + crate::Client::from_inner(inner).force_stop(); + return false; + } + true } #[cfg(test)] diff --git a/rust/src/router/tests.rs b/rust/src/router/tests.rs index f63ca005f7..997829a50a 100644 --- a/rust/src/router/tests.rs +++ b/rust/src/router/tests.rs @@ -4,8 +4,501 @@ #![cfg(test)] +use std::pin::Pin; +use std::sync::atomic::AtomicBool; +use std::task::{Context, Poll}; +use std::time::Duration; + +use futures_util::task::AtomicWaker; +use serde_json::json; +use tokio::io::{ + AsyncBufReadExt, AsyncReadExt, AsyncWrite, AsyncWriteExt, BufReader, DuplexStream, +}; +use tokio::time::timeout; +use tokio_util::sync::CancellationToken; + use super::*; +const DEADLINE: Duration = Duration::from_secs(5); + +#[derive(Clone, Copy, Debug)] +enum BlockAt { + Write, + Flush, +} + +#[derive(Default)] +struct WriteGate { + released: AtomicBool, + waker: AtomicWaker, + entered: CancellationToken, + dropped: CancellationToken, +} + +impl WriteGate { + fn poll(&self, cx: &mut Context<'_>) -> Poll<()> { + self.waker.register(cx.waker()); + if self.released.load(Ordering::Acquire) { + Poll::Ready(()) + } else { + self.entered.cancel(); + Poll::Pending + } + } + + fn release(&self) { + self.released.store(true, Ordering::Release); + self.waker.wake(); + } +} + +struct GatedWriter { + writer: DuplexStream, + gate: Arc, + block_at: BlockAt, +} + +impl AsyncWrite for GatedWriter { + fn poll_write( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + bytes: &[u8], + ) -> Poll> { + if matches!(self.block_at, BlockAt::Write) && self.gate.poll(cx).is_pending() { + return Poll::Pending; + } + Pin::new(&mut self.writer).poll_write(cx, bytes) + } + + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + if matches!(self.block_at, BlockAt::Flush) && self.gate.poll(cx).is_pending() { + return Poll::Pending; + } + Pin::new(&mut self.writer).poll_flush(cx) + } + + fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Pin::new(&mut self.writer).poll_shutdown(cx) + } +} + +impl Drop for GatedWriter { + fn drop(&mut self) { + self.gate.dropped.cancel(); + } +} + +#[derive(Clone, Copy, Debug)] +enum Unroutable { + MissingSessionId, + UnknownSession, + ClosedReceiver, +} + +struct Peer { + client: crate::Client, + input: DuplexStream, + output: BufReader, + gate: Arc, +} + +impl Peer { + fn new(block_at: BlockAt) -> Self { + let (reader, input) = tokio::io::duplex(4096); + let (writer, output) = tokio::io::duplex(4096); + let gate = Arc::new(WriteGate::default()); + let client = crate::Client::from_streams( + reader, + GatedWriter { + writer, + gate: gate.clone(), + block_at, + }, + std::path::PathBuf::from("."), + ) + .unwrap(); + Self { + client, + input, + output: BufReader::new(output), + gate, + } + } + + async fn send(&mut self, message: &impl serde::Serialize) { + let body = serde_json::to_vec(message).unwrap(); + timeout(DEADLINE, async { + self.input + .write_all(format!("Content-Length: {}\r\n\r\n", body.len()).as_bytes()) + .await + .unwrap(); + self.input.write_all(&body).await.unwrap(); + }) + .await + .expect("peer could not inject a complete request"); + } + + async fn reject(&mut self, id: u64, kind: Unroutable) { + let params = match kind { + Unroutable::MissingSessionId => json!({}), + Unroutable::UnknownSession => json!({"sessionId": "gone"}), + Unroutable::ClosedReceiver => { + drop(self.client.register_session(&SessionId::new("closed"))); + json!({"sessionId": "closed"}) + } + }; + self.send(&JsonRpcRequest::new(id, "skillProvider.list", Some(params))) + .await; + } + + async fn read(&mut self) -> JsonRpcResponse { + timeout(DEADLINE, async { + let mut header = String::new(); + self.output.read_line(&mut header).await.unwrap(); + let length = header + .strip_prefix("Content-Length: ") + .expect("missing response header") + .trim() + .parse::() + .unwrap(); + header.clear(); + self.output.read_line(&mut header).await.unwrap(); + assert_eq!(header, "\r\n"); + let mut body = vec![0; length]; + self.output.read_exact(&mut body).await.unwrap(); + serde_json::from_slice(&body).unwrap() + }) + .await + .expect("error frame was not delivered") + } + + async fn stop(&self) { + self.client.force_stop(); + timeout(DEADLINE, self.gate.dropped.cancelled()) + .await + .expect("writer did not exit"); + } +} + +#[track_caller] +fn assert_error(response: JsonRpcResponse, id: u64, kind: Unroutable) { + assert_eq!(response.id, id); + assert!(response.result.is_none()); + let error = response.error.expect("unroutable request received success"); + let (code, message) = match kind { + Unroutable::MissingSessionId => ( + error_codes::INVALID_PARAMS, + "missing required field: sessionId", + ), + Unroutable::UnknownSession => (error_codes::INTERNAL_ERROR, "Session not found: gone"), + Unroutable::ClosedReceiver => (error_codes::INTERNAL_ERROR, "Session not found: closed"), + }; + assert_eq!(error.code, code); + assert_eq!(error.message, message); +} + +#[tokio::test] +async fn stalled_rejection_preserves_live_routing_and_eventual_error_delivery() { + for block_at in [BlockAt::Write, BlockAt::Flush] { + for kind in [ + Unroutable::MissingSessionId, + Unroutable::UnknownSession, + Unroutable::ClosedReceiver, + ] { + let mut peer = Peer::new(block_at); + let mut live = peer + .client + .register_session(&SessionId::new("live")) + .channels + .requests; + peer.reject(101, kind).await; + timeout(DEADLINE, peer.gate.entered.cancelled()) + .await + .unwrap(); + peer.send(&crate::JsonRpcNotification { + jsonrpc: "2.0".into(), + method: "$/cancelRequest".into(), + params: Some(json!({"id": 101})), + }) + .await; + peer.send(&JsonRpcRequest::new( + 102, + "skillProvider.list", + Some(json!({"sessionId": "live"})), + )) + .await; + let routed = timeout(DEADLINE, live.recv()) + .await + .unwrap_or_else(|_| panic!("live callback stalled behind {kind:?} at {block_at:?}")) + .expect("live channel closed"); + assert_eq!(routed.id, 102); + assert!( + peer.client + .inner + .rpc + .cancellable_requests + .claim(101) + .is_none() + ); + assert!( + !peer + .client + .inner + .rpc + .connection_closed_token() + .is_cancelled() + ); + peer.gate.release(); + assert_error(peer.read().await, 101, kind); + peer.stop().await; + } + } +} + +#[tokio::test] +async fn delayed_writer_preserves_a_large_healthy_burst_without_disconnect() { + const BURST: u64 = 512; + for block_at in [BlockAt::Write, BlockAt::Flush] { + let mut peer = Peer::new(block_at); + let mut live = peer + .client + .register_session(&SessionId::new("live")) + .channels + .requests; + peer.reject(100, Unroutable::UnknownSession).await; + timeout(DEADLINE, peer.gate.entered.cancelled()) + .await + .unwrap(); + for id in 101..100 + BURST { + peer.reject(id, Unroutable::UnknownSession).await; + } + peer.send(&JsonRpcRequest::new( + 100 + BURST, + "skillProvider.list", + Some(json!({"sessionId": "live"})), + )) + .await; + assert_eq!( + timeout(DEADLINE, live.recv()).await.unwrap().unwrap().id, + 100 + BURST + ); + assert!( + !peer + .client + .inner + .rpc + .connection_closed_token() + .is_cancelled() + ); + for id in 100..100 + BURST { + assert!( + peer.client + .inner + .rpc + .cancellable_requests + .claim(id) + .is_none() + ); + } + peer.gate.release(); + for id in 100..100 + BURST { + assert_error(peer.read().await, id, Unroutable::UnknownSession); + } + peer.stop().await; + } +} + +#[tokio::test] +async fn pending_rejection_does_not_retain_the_last_client() { + for block_at in [BlockAt::Write, BlockAt::Flush] { + let mut peer = Peer::new(block_at); + let mut live = peer + .client + .register_session(&SessionId::new("live")) + .channels + .requests; + peer.reject(101, Unroutable::UnknownSession).await; + timeout(DEADLINE, peer.gate.entered.cancelled()) + .await + .unwrap(); + let weak = Arc::downgrade(&peer.client.inner); + let gate = peer.gate.clone(); + drop(peer); + assert!( + weak.upgrade().is_none(), + "error delivery retained the client" + ); + timeout(DEADLINE, gate.dropped.cancelled()).await.unwrap(); + assert!(timeout(DEADLINE, live.recv()).await.unwrap().is_none()); + } +} + +#[tokio::test] +async fn force_stop_releases_pending_rejections() { + for kind in [ + Unroutable::MissingSessionId, + Unroutable::UnknownSession, + Unroutable::ClosedReceiver, + ] { + let mut peer = Peer::new(BlockAt::Write); + let mut live = peer + .client + .register_session(&SessionId::new("live")) + .channels + .requests; + peer.reject(101, kind).await; + timeout(DEADLINE, peer.gate.entered.cancelled()) + .await + .unwrap(); + peer.stop().await; + assert!(timeout(DEADLINE, live.recv()).await.unwrap().is_none()); + assert!( + peer.client + .inner + .rpc + .cancellable_requests + .claim(101) + .is_none() + ); + } +} + +#[tokio::test] +async fn client_stop_does_not_await_router_rejection_delivery() { + for block_at in [BlockAt::Write, BlockAt::Flush] { + let mut peer = Peer::new(block_at); + peer.client.inner.router.ensure_started(&peer.client.inner); + peer.reject(101, Unroutable::UnknownSession).await; + timeout(DEADLINE, peer.gate.entered.cancelled()) + .await + .unwrap(); + timeout(DEADLINE, peer.client.stop()) + .await + .expect("stop awaited rejection output") + .unwrap(); + timeout(DEADLINE, peer.gate.dropped.cancelled()) + .await + .unwrap(); + } +} + +#[tokio::test] +async fn late_rejection_delivery_does_not_retire_a_reused_request_id() { + let mut peer = Peer::new(BlockAt::Write); + let mut live = peer + .client + .register_session(&SessionId::new("live")) + .channels + .requests; + peer.reject(101, Unroutable::UnknownSession).await; + timeout(DEADLINE, peer.gate.entered.cancelled()) + .await + .unwrap(); + peer.send(&JsonRpcRequest::new( + 101, + "skillProvider.list", + Some(json!({"sessionId": "live"})), + )) + .await; + assert_eq!( + timeout(DEADLINE, live.recv()).await.unwrap().unwrap().id, + 101 + ); + let pending = peer + .client + .inner + .rpc + .cancellable_requests + .claim(101) + .expect("new request lost cancellation"); + peer.gate.release(); + assert_error(peer.read().await, 101, Unroutable::UnknownSession); + peer.send(&crate::JsonRpcNotification { + jsonrpc: "2.0".into(), + method: "$/cancelRequest".into(), + params: Some(json!({"id": 101})), + }) + .await; + timeout(DEADLINE, pending.cancellation().cancelled()) + .await + .expect("old completion retired new cancellation"); + peer.stop().await; +} + +#[tokio::test] +async fn failed_router_rejection_write_closes_connection_and_wakes_pending_work() { + let mut peer = Peer::new(BlockAt::Write); + let mut live = peer + .client + .register_session(&SessionId::new("live")) + .channels + .requests; + peer.reject(101, Unroutable::UnknownSession).await; + timeout(DEADLINE, peer.gate.entered.cancelled()) + .await + .unwrap(); + let pending = peer + .client + .inner + .rpc + .send_request_with_inline_callback("ping", None, None); + tokio::pin!(pending); + assert!(futures_util::poll!(&mut pending).is_pending()); + let Peer { + client, + input: _input, + output, + gate, + } = peer; + drop(output); + gate.release(); + timeout( + DEADLINE, + client.inner.rpc.connection_closed_token().cancelled(), + ) + .await + .expect("write failure left connection open"); + let error = timeout(DEADLINE, pending) + .await + .expect("pending request did not wake") + .expect_err("request succeeded on broken output"); + assert_eq!(error.kind(), &crate::ErrorKind::Io); + assert!(timeout(DEADLINE, live.recv()).await.unwrap().is_none()); + timeout(DEADLINE, gate.dropped.cancelled()).await.unwrap(); + client.force_stop(); +} + +#[tokio::test] +async fn peer_eof_retires_routing_with_a_committed_rejection_pending() { + let mut peer = Peer::new(BlockAt::Write); + let mut live = peer + .client + .register_session(&SessionId::new("live")) + .channels + .requests; + peer.reject(101, Unroutable::UnknownSession).await; + timeout(DEADLINE, peer.gate.entered.cancelled()) + .await + .unwrap(); + peer.input.shutdown().await.unwrap(); + timeout( + DEADLINE, + peer.client.inner.rpc.connection_closed_token().cancelled(), + ) + .await + .unwrap(); + assert!(timeout(DEADLINE, live.recv()).await.unwrap().is_none()); + assert!( + peer.client + .inner + .rpc + .cancellable_requests + .claim(101) + .is_none() + ); + peer.stop().await; +} + fn session_id() -> SessionId { SessionId::new("router-ownership") } diff --git a/test/harness/server.ts b/test/harness/server.ts index 887a57178b..f190b2d2f5 100644 --- a/test/harness/server.ts +++ b/test/harness/server.ts @@ -6,11 +6,18 @@ import { ReplayingCapiProxy } from "./replayingCapiProxy"; import { ConnectProxy } from "./connectProxy"; import { createE2eRequestHandler } from "./mockHandlers"; +console.error( + `[SDK proxy startup] Server dependencies loaded at ${Math.round(performance.now())}ms`, +); + // Starts up an instance of the ReplayingCapiProxy server // The intention is for this to be usable in E2E tests across all languages const proxy = new ReplayingCapiProxy("https://api.githubcopilot.com"); const proxyUrl = await proxy.start(); +console.error( + `[SDK proxy startup] Replay server listening at ${Math.round(performance.now())}ms`, +); const blockedHosts: string[] = []; const unhandledRequests: string[] = []; @@ -39,6 +46,9 @@ const connectProxy = new ConnectProxy( }, ); await connectProxy.start(); +console.error( + `[SDK proxy startup] CONNECT server listening at ${Math.round(performance.now())}ms`, +); proxy.onStopRequested = async () => { if (blockedHosts.length || unhandledRequests.length) { diff --git a/test/harness/startup.mjs b/test/harness/startup.mjs new file mode 100644 index 0000000000..38f2540b57 --- /dev/null +++ b/test/harness/startup.mjs @@ -0,0 +1,12 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +console.error( + `[SDK proxy startup] Node entered at ${Math.round(performance.now())}ms`, +); +await import("tsx"); +console.error( + `[SDK proxy startup] TypeScript loader ready at ${Math.round(performance.now())}ms`, +); +await import("./server.ts"); diff --git a/test/harness/startup.test.ts b/test/harness/startup.test.ts new file mode 100644 index 0000000000..d3ada9ee3b --- /dev/null +++ b/test/harness/startup.test.ts @@ -0,0 +1,73 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import { execFile } from "node:child_process"; +import { mkdtemp, rm, writeFile } from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; +import { fileURLToPath, pathToFileURL } from "node:url"; +import { promisify } from "node:util"; +import { test } from "vitest"; + +const execute = promisify(execFile); +const bootstrap = fileURLToPath(new URL("./startup.mjs", import.meta.url)); + +test.for(["tsx", "./server.ts"])( + "records the last startup phase before import %s fails", + async (failedImport, { expect, onTestFinished, signal }) => { + const creatingDirectory = mkdtemp( + path.join(os.tmpdir(), "sdk-proxy-startup-"), + ); + let executing: ReturnType | undefined; + onTestFinished(async () => { + const [created] = await Promise.allSettled([creatingDirectory]); + try { + if (executing) await Promise.allSettled([executing]); + } finally { + if (created.status === "fulfilled") { + await rm(created.value, { recursive: true, force: true }); + } + } + }); + const directory = await creatingDirectory; + signal.throwIfAborted(); + const loader = path.join(directory, "loader.mjs"); + const registration = path.join(directory, "register.mjs"); + await writeFile( + loader, + `export function resolve(specifier, context, nextResolve) { + if (specifier === ${JSON.stringify(failedImport)}) throw new Error("CONTROLLED_IMPORT_FAILURE"); + if (specifier === "tsx") return { url: "data:text/javascript,export%20%7B%7D", shortCircuit: true }; + return nextResolve(specifier, context); + }`, + ); + await writeFile( + registration, + `import { register } from "node:module"; + register(${JSON.stringify(pathToFileURL(loader).href)}, import.meta.url);`, + ); + + executing = execute( + process.execPath, + ["--import", pathToFileURL(registration).href, bootstrap], + { + signal, + env: { ...process.env, NODE_OPTIONS: "" }, + }, + ); + await expect(executing).rejects.toMatchObject({ + code: 1, + stdout: "", + stderr: expect.stringMatching( + /\[SDK proxy startup\] Node entered.*CONTROLLED_IMPORT_FAILURE/su, + ), + }); + await expect(executing).rejects.toMatchObject({ + stderr: + failedImport === "tsx" + ? expect.not.stringContaining("TypeScript loader ready") + : expect.stringContaining("TypeScript loader ready"), + }); + }, +); From 24e9638db1bf292beb02efd375ce51e535c3d066 Mon Sep 17 00:00:00 2001 From: "copilot-cli-release-app[bot]" Date: Fri, 9 Oct 2026 19:29:09 +0000 Subject: [PATCH 4/9] Update SDK snapshot for Copilot CLI 1.0.96-0 --- .github/workflows/java-publish-snapshot.yml | 2 +- .github/workflows/sdk-dotnet.yml | 4 +- .github/workflows/sdk-go.yml | 2 +- .github/workflows/sdk-java.yml | 4 +- .github/workflows/sdk-nodejs.yml | 8 +- .github/workflows/sdk-python.yml | 2 +- .github/workflows/sdk-rust.yml | 2 +- .github/workflows/sdk.yml | 2 +- dotnet/src/Client.cs | 58 +- dotnet/src/Generated/Rpc.cs | 189 ++++ dotnet/src/Generated/SessionEvents.cs | 511 ++++++++++- .../Unit/InProcessRuntimeArgumentsTests.cs | 27 + go/client.go | 8 +- go/client_test.go | 29 +- go/rpc/zrpc.go | 191 ++++ go/rpc/zsession_events.go | 78 +- go/zsession_events.go | 27 + java/scripts/codegen/java.test.ts | 58 ++ java/scripts/codegen/java.ts | 27 + .../generated/AssistantUsageEvent.java | 16 +- .../generated/ManagedPermissionsContext.java | 29 + .../generated/ModelCallFailureEvent.java | 16 +- .../ModelCallRequestBodyEncoding.java | 37 + .../ModelCallWebSocketFallbackErrorKind.java | 55 ++ .../generated/ProviderMonthlyUsage.java | 43 + .../generated/ProviderMonthlyUsageScope.java | 35 + .../generated/ProviderMonthlyUsageState.java | 39 + .../copilot/generated/ProviderQuotaState.java | 2 + .../SessionManagedSettingsResolvedEvent.java | 2 + .../SessionQuotaObservationEvent.java | 2 +- .../copilot/generated/rpc/AccountStatus.java | 2 + .../rpc/ManagedPermissionEvaluation.java | 24 + .../rpc/ManagedPermissionOperation.java | 42 + .../rpc/ManagedPermissionVerdict.java | 39 + ...agedSettingsPermissionsEvaluateParams.java | 34 + ...agedSettingsPermissionsEvaluateResult.java | 33 + .../rpc/ManagedSettingsResolveResult.java | 3 + .../rpc/ManagedSettingsResolvedData.java | 3 + .../generated/rpc/ProviderMonthlyUsage.java | 43 + .../rpc/ProviderMonthlyUsageScope.java | 35 + .../rpc/ProviderMonthlyUsageState.java | 39 + .../generated/rpc/ProviderQuotaState.java | 2 + .../rpc/ServerManagedSettingsApi.java | 4 + .../ServerManagedSettingsPermissionsApi.java | 40 + .../rpc/SessionManagedSettingsGetResult.java | 3 + .../com/github/copilot/CopilotClient.java | 6 +- .../github/copilot/ffi/FfiRuntimeHost.java | 24 +- .../copilot/ffi/FfiRuntimeHostTest.java | 13 +- .../rpc/GeneratedRpcRecordsCoverageTest.java | 22 + nodejs/README.md | 30 + nodejs/package.json | 2 +- nodejs/src/cliVersion.ts | 2 +- nodejs/src/client.ts | 8 +- nodejs/src/generated/rpc.ts | 115 ++- nodejs/src/generated/session-events.ts | 170 +++- .../test/computer-use-oauth-fixture.test.ts | 68 ++ nodejs/test/e2e/accounts_login.e2e.test.ts | 2 +- nodejs/test/e2e/accounts_platform.e2e.test.ts | 180 ++++ .../assisted_autopilot_permission.e2e.test.ts | 833 ++++++++++++++++-- .../test/e2e/computer_use_oauth.e2e.test.ts | 347 ++++++++ .../test/e2e/entra_identity_first.e2e.test.ts | 14 + nodejs/test/e2e/entra_renewal.e2e.test.ts | 10 + .../e2e/harness/webSocketResponsesServer.ts | 21 + .../managed_permissions_limit_to.e2e.test.ts | 117 +++ .../e2e/memory_tool_overrides.e2e.test.ts | 102 +++ nodejs/test/e2e/monthly_usage.e2e.test.ts | 229 +++++ nodejs/test/e2e/rpc_server.e2e.test.ts | 43 + .../test/e2e/rpc_server_plugins.e2e.test.ts | 122 ++- .../test/e2e/rpc_shell_and_fleet.e2e.test.ts | 107 +++ .../test/e2e/rpc_surface_coverage.e2e.test.ts | 13 +- .../e2e/rpc_tasks_and_handlers.e2e.test.ts | 92 +- .../e2e/subagent_prompt_resume.e2e.test.ts | 105 ++- .../e2e/websocket_http_fallback.e2e.test.ts | 143 +++ nodejs/test/e2e/workiq_discovery.e2e.test.ts | 39 +- nodejs/test/ffiRuntimeHost.test.ts | 12 + nodejs/test/python-codegen.test.ts | 13 + nodejs/test/rust-codegen.test.ts | 39 + nodejs/vitest.config.ts | 1 + python/copilot/client.py | 5 + python/copilot/generated/rpc.py | 336 +++++-- python/copilot/generated/session_events.py | 216 +++++ python/test_client.py | 24 + rust/src/ffi.rs | 18 +- rust/src/ffi/tests.rs | 17 +- rust/src/generated/api_types.rs | 146 ++- rust/src/generated/rpc.rs | 49 ++ rust/src/generated/session_events.rs | 233 ++++- rust/src/lib.rs | 5 + rust/tests/api_types_test.rs | 25 + scripts/codegen/python.ts | 25 +- scripts/codegen/rust.ts | 7 +- .../test-mcp-computer-use-oauth-server.mjs | 173 ++++ ...r_cancelling_a_running_attached_shell.yaml | 21 + ...r_cancelling_a_running_attached_shell.yaml | 25 + 94 files changed, 5865 insertions(+), 355 deletions(-) create mode 100644 dotnet/test/Unit/InProcessRuntimeArgumentsTests.cs create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/ManagedPermissionsContext.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/ModelCallRequestBodyEncoding.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/ModelCallWebSocketFallbackErrorKind.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/ProviderMonthlyUsage.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/ProviderMonthlyUsageScope.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/ProviderMonthlyUsageState.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPermissionEvaluation.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPermissionOperation.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPermissionVerdict.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPermissionsEvaluateParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPermissionsEvaluateResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderMonthlyUsage.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderMonthlyUsageScope.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderMonthlyUsageState.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerManagedSettingsPermissionsApi.java create mode 100644 nodejs/test/computer-use-oauth-fixture.test.ts create mode 100644 nodejs/test/e2e/accounts_platform.e2e.test.ts create mode 100644 nodejs/test/e2e/computer_use_oauth.e2e.test.ts create mode 100644 nodejs/test/e2e/memory_tool_overrides.e2e.test.ts create mode 100644 nodejs/test/e2e/monthly_usage.e2e.test.ts create mode 100644 nodejs/test/e2e/websocket_http_fallback.e2e.test.ts create mode 100644 test/harness/test-mcp-computer-use-oauth-server.mjs create mode 100644 test/snapshots/rpc_tasks_and_handlers/should_emit_session_idle_after_cancelling_a_running_attached_shell.yaml create mode 100644 test/snapshots/rpc_tasks_and_handlers/should_run_a_queued_message_after_cancelling_a_running_attached_shell.yaml diff --git a/.github/workflows/java-publish-snapshot.yml b/.github/workflows/java-publish-snapshot.yml index 77d5287964..219dd43bf2 100644 --- a/.github/workflows/java-publish-snapshot.yml +++ b/.github/workflows/java-publish-snapshot.yml @@ -370,7 +370,7 @@ jobs: build-darwin-classifier: name: Build Darwin snapshot classifier needs: resolve-source - runs-on: macos-26 + runs-on: macos-26-agent-runtime permissions: contents: read outputs: diff --git a/.github/workflows/sdk-dotnet.yml b/.github/workflows/sdk-dotnet.yml index 63b689f94e..14a4c3265b 100644 --- a/.github/workflows/sdk-dotnet.yml +++ b/.github/workflows/sdk-dotnet.yml @@ -99,9 +99,9 @@ jobs: retention-days: 7 dotnet-darwin-arm64: - name: ".NET (macos-26-xlarge, default, CAPI)" + name: ".NET (macos-26-xlarge-agent-runtime, default, CAPI)" if: inputs.platform == 'all' || inputs.platform == 'darwin-arm64' - runs-on: macos-26-xlarge + runs-on: macos-26-xlarge-agent-runtime timeout-minutes: 30 defaults: run: diff --git a/.github/workflows/sdk-go.yml b/.github/workflows/sdk-go.yml index e7235998f8..b5593f26b1 100644 --- a/.github/workflows/sdk-go.yml +++ b/.github/workflows/sdk-go.yml @@ -30,7 +30,7 @@ jobs: strategy: fail-fast: false matrix: - os: ${{ fromJSON(inputs.platform == 'linux-x64' && '["ubuntu-latest"]' || inputs.platform == 'darwin-arm64' && '["macos-26"]' || inputs.platform == 'win32-x64' && '["windows-latest"]' || '["ubuntu-latest","macos-26","windows-latest"]') }} + os: ${{ fromJSON(inputs.platform == 'linux-x64' && '["ubuntu-latest"]' || inputs.platform == 'darwin-arm64' && '["macos-26-agent-runtime"]' || inputs.platform == 'win32-x64' && '["windows-latest"]' || '["ubuntu-latest","macos-26-agent-runtime","windows-latest"]') }} runs-on: ${{ matrix.os }} defaults: run: diff --git a/.github/workflows/sdk-java.yml b/.github/workflows/sdk-java.yml index fbadf275ce..011fef0898 100644 --- a/.github/workflows/sdk-java.yml +++ b/.github/workflows/sdk-java.yml @@ -29,10 +29,10 @@ jobs: strategy: fail-fast: false matrix: - os: ${{ fromJSON(inputs.platform == 'linux-x64' && '["ubuntu-latest"]' || inputs.platform == 'darwin-arm64' && '["macos-26"]' || inputs.platform == 'win32-x64' && '["windows-latest"]' || '["ubuntu-latest","macos-26","windows-latest"]') }} + os: ${{ fromJSON(inputs.platform == 'linux-x64' && '["ubuntu-latest"]' || inputs.platform == 'darwin-arm64' && '["macos-26-agent-runtime"]' || inputs.platform == 'win32-x64' && '["windows-latest"]' || '["ubuntu-latest","macos-26-agent-runtime","windows-latest"]') }} test-jdk: ["25", "17"] exclude: - - os: macos-26 + - os: macos-26-agent-runtime test-jdk: "17" - os: windows-latest test-jdk: "17" diff --git a/.github/workflows/sdk-nodejs.yml b/.github/workflows/sdk-nodejs.yml index 9fbbf97e76..db14685c13 100644 --- a/.github/workflows/sdk-nodejs.yml +++ b/.github/workflows/sdk-nodejs.yml @@ -35,7 +35,7 @@ jobs: strategy: fail-fast: false matrix: - os: ${{ fromJSON(inputs.platform == 'linux-x64' && '["ubuntu-latest"]' || inputs.platform == 'darwin-arm64' && '["macos-26"]' || inputs.platform == 'win32-x64' && '["windows-latest"]' || '["ubuntu-latest","macos-26","windows-latest"]') }} + os: ${{ fromJSON(inputs.platform == 'linux-x64' && '["ubuntu-latest"]' || inputs.platform == 'darwin-arm64' && '["macos-26-agent-runtime"]' || inputs.platform == 'win32-x64' && '["windows-latest"]' || '["ubuntu-latest","macos-26-agent-runtime","windows-latest"]') }} runs-on: ${{ matrix.os }} defaults: run: @@ -94,17 +94,17 @@ jobs: env: COPILOT_HMAC_KEY: ${{ secrets.COPILOT_DEVELOPER_CLI_INTEGRATION_HMAC_KEY }} run: | - if [ "$GITHUB_EVENT_NAME" = "merge_group" ] || [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then + if [ "$GITHUB_EVENT_NAME" = "merge_group" ] || [ "$GITHUB_EVENT_NAME" = "pull_request" ] || [ "$GITHUB_EVENT_NAME" = "push" ]; then npm test -- --reporter=default --reporter=json --outputFile="$RUNNER_TEMP/sdk-nodejs-results.json" else npm test fi - name: Upload Flake Finder Node.js test results - if: always() && (github.event_name == 'merge_group' || github.event_name == 'pull_request') && runner.os == 'Linux' + if: always() && (github.event_name == 'merge_group' || github.event_name == 'pull_request' || github.event_name == 'push') continue-on-error: true uses: actions/upload-artifact@v7 with: - name: suspected-flakes-sdk-nodejs-${{ github.run_attempt }}-linux + name: suspected-flakes-sdk-nodejs-${{ github.run_attempt }}-${{ runner.os == 'macOS' && 'macos' || runner.os == 'Windows' && 'windows' || 'linux' }} path: ${{ runner.temp }}/sdk-nodejs-results.json if-no-files-found: warn retention-days: 7 diff --git a/.github/workflows/sdk-python.yml b/.github/workflows/sdk-python.yml index 2abeca3d8a..df9cbab1a9 100644 --- a/.github/workflows/sdk-python.yml +++ b/.github/workflows/sdk-python.yml @@ -30,7 +30,7 @@ jobs: strategy: fail-fast: false matrix: - os: ${{ fromJSON(inputs.platform == 'linux-x64' && '["ubuntu-latest"]' || inputs.platform == 'darwin-arm64' && '["macos-26"]' || inputs.platform == 'win32-x64' && '["windows-latest"]' || '["ubuntu-latest","macos-26","windows-latest"]') }} + os: ${{ fromJSON(inputs.platform == 'linux-x64' && '["ubuntu-latest"]' || inputs.platform == 'darwin-arm64' && '["macos-26-agent-runtime"]' || inputs.platform == 'win32-x64' && '["windows-latest"]' || '["ubuntu-latest","macos-26-agent-runtime","windows-latest"]') }} runs-on: ${{ matrix.os }} timeout-minutes: 20 defaults: diff --git a/.github/workflows/sdk-rust.yml b/.github/workflows/sdk-rust.yml index abe13e28bb..04500c3489 100644 --- a/.github/workflows/sdk-rust.yml +++ b/.github/workflows/sdk-rust.yml @@ -31,7 +31,7 @@ jobs: strategy: fail-fast: false matrix: - os: ${{ fromJSON(inputs.platform == 'linux-x64' && '["ubuntu-latest"]' || inputs.platform == 'darwin-arm64' && '["macos-26-xlarge"]' || inputs.platform == 'win32-x64' && '["windows-latest"]' || '["ubuntu-latest","macos-26-xlarge","windows-latest"]') }} + os: ${{ fromJSON(inputs.platform == 'linux-x64' && '["ubuntu-latest"]' || inputs.platform == 'darwin-arm64' && '["macos-26-xlarge-agent-runtime"]' || inputs.platform == 'win32-x64' && '["windows-latest"]' || '["ubuntu-latest","macos-26-xlarge-agent-runtime","windows-latest"]') }} runs-on: ${{ matrix.os }} defaults: run: diff --git a/.github/workflows/sdk.yml b/.github/workflows/sdk.yml index 56c165db89..602d02b027 100644 --- a/.github/workflows/sdk.yml +++ b/.github/workflows/sdk.yml @@ -408,7 +408,7 @@ jobs: with: runtime-source: ${{ needs.detect-layout.outputs.runtime-source }} sdk-home: ${{ needs.detect-layout.outputs.sdk-home }} - os: macos-26-xlarge + os: macos-26-xlarge-agent-runtime target: darwin-arm64 artifact: macOS-ARM64 bazel-config: e2e-no-lto diff --git a/dotnet/src/Client.cs b/dotnet/src/Client.cs index d22e329428..ad75548f77 100644 --- a/dotnet/src/Client.cs +++ b/dotnet/src/Client.cs @@ -403,29 +403,7 @@ async Task StartCoreAsync(CancellationToken ct) ffiEnvironment["COPILOT_DISABLE_KEYTAR"] = "1"; } - var ffiArgs = new List(); - if (_options.LogLevel is { } logLevel && !string.IsNullOrEmpty(logLevel.Value)) - { - ffiArgs.AddRange(["--log-level", logLevel.Value]); - } - if (!string.IsNullOrEmpty(_options.GitHubToken)) - { - ffiArgs.AddRange(["--auth-token-env", "COPILOT_SDK_AUTH_TOKEN"]); - } - var useLoggedInUser = _options.UseLoggedInUser ?? string.IsNullOrEmpty(_options.GitHubToken); - if (!useLoggedInUser) - { - ffiArgs.Add("--no-auto-login"); - } - if (_options.SessionIdleTimeoutSeconds is > 0) - { - ffiArgs.AddRange(["--session-idle-timeout", _options.SessionIdleTimeoutSeconds.Value.ToString(CultureInfo.InvariantCulture)]); - } - if (_options.EnableRemoteSessions) - { - ffiArgs.Add("--remote"); - } - + var ffiArgs = BuildInProcessRuntimeArguments(_options); var explicitCliPath = System.Environment.GetEnvironmentVariable("COPILOT_CLI_PATH"); if (string.IsNullOrEmpty(explicitCliPath)) { @@ -2581,6 +2559,40 @@ private static void ApplyTelemetryEnvironment(IDictionary envir return GetBundledNativePath(OperatingSystem.IsWindows() ? "copilot.exe" : "copilot", out searchedPath); } + private static List BuildInProcessRuntimeArguments(CopilotClientOptions options) + { + var args = new List(); + if (options.LogLevel is { } logLevel && !string.IsNullOrEmpty(logLevel.Value)) + { + args.AddRange(["--log-level", logLevel.Value]); + } + if (!string.IsNullOrEmpty(options.GitHubToken)) + { + args.AddRange(["--auth-token-env", "COPILOT_SDK_AUTH_TOKEN"]); + } + var useLoggedInUser = options.UseLoggedInUser ?? string.IsNullOrEmpty(options.GitHubToken); + if (!useLoggedInUser) + { + args.Add("--no-auto-login"); + } + if (options.SessionIdleTimeoutSeconds is > 0) + { + args.AddRange(["--session-idle-timeout", options.SessionIdleTimeoutSeconds.Value.ToString(CultureInfo.InvariantCulture)]); + } + if (options.EnableRemoteSessions) + { + args.Add("--remote"); + } + + var cliLoginSyncIntegrationId = + System.Environment.GetEnvironmentVariable("GITHUB_COPILOT_INTEGRATION_ID")?.Trim(); + if (!string.IsNullOrEmpty(cliLoginSyncIntegrationId)) + { + args.Add($"--cli-login-sync-integration-id={cliLoginSyncIntegrationId}"); + } + return args; + } + private static string? GetBundledNativePath(string binaryName, out string searchedPath) { // Always use portable RID (e.g., linux-x64) to match the build-time placement, diff --git a/dotnet/src/Generated/Rpc.cs b/dotnet/src/Generated/Rpc.cs index 6ab5009adc..6652e3755f 100644 --- a/dotnet/src/Generated/Rpc.cs +++ b/dotnet/src/Generated/Rpc.cs @@ -7673,6 +7673,10 @@ public sealed class ManagedSettingsResolvedData [JsonPropertyName("permissionsAllowIntersected")] public bool? PermissionsAllowIntersected { get; set; } + /// Reusable retained managed permission policy for managedSettings.permissions.evaluate, including source composition and session-local injection. Provided by live session snapshots; absent in older events. Refresh the context when managed policy changes. + [JsonPropertyName("permissionsContext")] + public ManagedPermissionsContext? PermissionsContext { get; set; } + /// Whether the policy-helper managed-settings layer was present. The policy helper is the weakest channel: it fills keys no enterprise source set and can never replace one. [JsonPropertyName("policyHelperManaged")] public bool? PolicyHelperManaged { get; set; } @@ -7735,6 +7739,10 @@ public sealed class ManagedSettingsResolveResult [JsonPropertyName("meta")] public ManagedSettingsMeta? Meta { get; set; } + /// Reusable source-composed permission policy for managedSettings.permissions.evaluate. Unlike resolved.settings.permissions, this retains every source's allowlist and default-prompt semantics. Refresh through resolve when account/device policy changes. Absent on runtimes that do not support permission evaluation. + [JsonPropertyName("permissionsContext")] + public ManagedPermissionsContext? PermissionsContext { get; set; } + /// Effective managed settings from the device and account (server) channels, in the same shape as `session.managedSettings.get`, excluding session-local injection. [JsonPropertyName("resolved")] public ManagedSettingsResolvedData Resolved { get => field ??= new(); set; } @@ -7855,6 +7863,72 @@ internal sealed class ManagedSettingsComposeRequest public IList Layers { get => field ??= []; set; } } +/// Polymorphic base type discriminated by kind. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(ManagedPermissionOperationUrl), "url")] +public partial class ManagedPermissionOperation +{ + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} + + +/// The url variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class ManagedPermissionOperationUrl : ManagedPermissionOperation +{ + /// + [JsonIgnore] + public override string Kind => "url"; + + /// Absolute HTTP(S) URL with a host. Invalid URLs reject the entire evaluation batch. + [JsonPropertyName("url")] + public required string Url { get; set; } +} + +/// RPC data type for ManagedPermissionEvaluation operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ManagedPermissionEvaluation +{ + /// Original input operation associated with this verdict. + [JsonPropertyName("operation")] + public ManagedPermissionOperation Operation { get => field ??= new(); set; } + + /// Managed-policy decision only; never bypasses user permissions or other security controls. + [JsonPropertyName("verdict")] + public ManagedPermissionVerdict Verdict { get; set; } +} + +/// Ordered managed permission verdicts and the supplied policy's fail-closed posture. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ManagedSettingsPermissionsEvaluateResult +{ + /// Managed permission policy could not be determined; every operation is denied. + [JsonPropertyName("failClosed")] + public bool FailClosed { get; set; } + + /// One verdict per input operation, in the same order, including duplicates. + [JsonPropertyName("results")] + public IList Results { get => field ??= []; set; } +} + +/// Managed policy context and ordered operations for pure, sessionless evaluation. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ManagedSettingsPermissionsEvaluateRequest +{ + /// Trusted, reusable managed permission policy snapshot; no policy is discovered during evaluation. + [JsonPropertyName("context")] + public ManagedPermissionsContext Context { get; set; } = null!; + + /// Operations to evaluate, preserving input order and duplicates. An empty batch is valid. + [JsonPropertyName("operations")] + public IList Operations { get => field ??= []; set; } +} + /// Indicates whether the calling client was registered as the session filesystem provider. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] public sealed class SessionFsSetProviderResult @@ -11478,6 +11552,10 @@ public sealed class AccountStatus [JsonPropertyName("active")] public bool Active { get; set; } + /// Human-readable credential source used to authenticate this account, such as `gh` or `GITHUB_TOKEN`. + [JsonPropertyName("authSource")] + public string? AuthSource { get; set; } + /// Opaque id of the account this one was derived from (e.g. an EMU account's base Entra identity); absent for a root account. Matches the base identity account's selectionId, forming the derivation edge. [JsonPropertyName("derivedFrom")] public string? DerivedFrom { get; set; } @@ -32806,6 +32884,75 @@ public override void Write(Utf8JsonWriter writer, ManagedSettingsChannel value, } +/// Managed-policy verdict only: deny blocks the URL, ask requires approval, allow approves under managed policy, and unmanaged leaves the normal consumer permission flow in effect. No verdict bypasses other security controls. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ManagedPermissionVerdict : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ManagedPermissionVerdict(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// Managed policy prohibits the operation; do not offer approval. + public static ManagedPermissionVerdict Deny { get; } = new("deny"); + + /// Managed policy requires the consumer to obtain approval. + public static ManagedPermissionVerdict Ask { get; } = new("ask"); + + /// Managed policy allows the operation, subject to other security controls. + public static ManagedPermissionVerdict Allow { get; } = new("allow"); + + /// Managed policy does not decide the operation; use the consumer's normal permission flow. + public static ManagedPermissionVerdict Unmanaged { get; } = new("unmanaged"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedPermissionVerdict left, ManagedPermissionVerdict right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedPermissionVerdict left, ManagedPermissionVerdict right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ManagedPermissionVerdict other && Equals(other); + + /// + public bool Equals(ManagedPermissionVerdict other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ManagedPermissionVerdict Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ManagedPermissionVerdict value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedPermissionVerdict)); + } + } +} + + /// Path conventions used by this filesystem. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] @@ -45315,6 +45462,38 @@ public async Task ComposeAsync(IList(_rpc, "managedSettings.compose", [request], cancellationToken); } + + /// Permissions APIs. + public ServerManagedSettingsPermissionsApi Permissions => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; +} + +/// Provides server-scoped ManagedSettingsPermissions APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerManagedSettingsPermissionsApi +{ + private readonly JsonRpc _rpc; + + internal ServerManagedSettingsPermissionsApi(JsonRpc rpc) + { + _rpc = rpc; + } + + /// Pure, sessionless evaluation of operations against a supplied permissionsContext. Performs no policy discovery, I/O, prompting, navigation, permission grants, or sandbox changes. Obtain the context from managedSettings.resolve or session.managedSettings.get, or reuse an in-memory context. Results preserve input order and duplicates. Consumers must block deny, obtain approval for ask, and use their normal permission flow for unmanaged. Unknown policy returns failClosed with every operation denied. This is not a substitute for user permissions or other security controls. + /// Trusted, reusable managed permission policy snapshot; no policy is discovered during evaluation. + /// Operations to evaluate, preserving input order and duplicates. An empty batch is valid. + /// The to monitor for cancellation requests. The default is . + /// Ordered managed permission verdicts and the supplied policy's fail-closed posture. + public async Task EvaluateAsync(ManagedPermissionsContext context, IList operations, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(context); + ArgumentNullException.ThrowIfNull(operations); + + var request = new ManagedSettingsPermissionsEvaluateRequest { Context = context, Operations = operations }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.permissions.evaluate", [request], cancellationToken); + } } /// Provides server-scoped Runtime APIs. @@ -52216,6 +52395,7 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(GitHub.Copilot.IndexedSearchIncrementalPhase), TypeInfoPropertyName = "SessionEventsIndexedSearchIncrementalPhase")] [JsonSerializable(typeof(GitHub.Copilot.IndexedSearchOutcome), TypeInfoPropertyName = "SessionEventsIndexedSearchOutcome")] [JsonSerializable(typeof(GitHub.Copilot.IndexedSearchState), TypeInfoPropertyName = "SessionEventsIndexedSearchState")] +[JsonSerializable(typeof(GitHub.Copilot.ManagedPermissionsContext), TypeInfoPropertyName = "SessionEventsManagedPermissionsContext")] [JsonSerializable(typeof(GitHub.Copilot.ManagedPluginProgressPhase), TypeInfoPropertyName = "SessionEventsManagedPluginProgressPhase")] [JsonSerializable(typeof(GitHub.Copilot.ManagedSettingsEnforcedAction), TypeInfoPropertyName = "SessionEventsManagedSettingsEnforcedAction")] [JsonSerializable(typeof(GitHub.Copilot.ManagedSettingsEnforcedEscalation), TypeInfoPropertyName = "SessionEventsManagedSettingsEnforcedEscalation")] @@ -52261,8 +52441,10 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(GitHub.Copilot.ModelCallFinishedData), TypeInfoPropertyName = "SessionEventsModelCallFinishedData")] [JsonSerializable(typeof(GitHub.Copilot.ModelCallFinishedEvent), TypeInfoPropertyName = "SessionEventsModelCallFinishedEvent")] [JsonSerializable(typeof(GitHub.Copilot.ModelCallFinishedOutcome), TypeInfoPropertyName = "SessionEventsModelCallFinishedOutcome")] +[JsonSerializable(typeof(GitHub.Copilot.ModelCallRequestBodyEncoding), TypeInfoPropertyName = "SessionEventsModelCallRequestBodyEncoding")] [JsonSerializable(typeof(GitHub.Copilot.ModelCallStartData), TypeInfoPropertyName = "SessionEventsModelCallStartData")] [JsonSerializable(typeof(GitHub.Copilot.ModelCallStartEvent), TypeInfoPropertyName = "SessionEventsModelCallStartEvent")] +[JsonSerializable(typeof(GitHub.Copilot.ModelCallWebSocketFallbackErrorKind), TypeInfoPropertyName = "SessionEventsModelCallWebSocketFallbackErrorKind")] [JsonSerializable(typeof(GitHub.Copilot.ModelCallWebSocketFallbackReason), TypeInfoPropertyName = "SessionEventsModelCallWebSocketFallbackReason")] [JsonSerializable(typeof(GitHub.Copilot.ModelChangeSource), TypeInfoPropertyName = "SessionEventsModelChangeSource")] [JsonSerializable(typeof(GitHub.Copilot.ModelDeselectedReason), TypeInfoPropertyName = "SessionEventsModelDeselectedReason")] @@ -52349,6 +52531,9 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(GitHub.Copilot.PlanChangedOperation), TypeInfoPropertyName = "SessionEventsPlanChangedOperation")] [JsonSerializable(typeof(GitHub.Copilot.PromptCacheBreakData), TypeInfoPropertyName = "SessionEventsPromptCacheBreakData")] [JsonSerializable(typeof(GitHub.Copilot.PromptCacheBreakEvent), TypeInfoPropertyName = "SessionEventsPromptCacheBreakEvent")] +[JsonSerializable(typeof(GitHub.Copilot.ProviderMonthlyUsage), TypeInfoPropertyName = "SessionEventsProviderMonthlyUsage")] +[JsonSerializable(typeof(GitHub.Copilot.ProviderMonthlyUsageScope), TypeInfoPropertyName = "SessionEventsProviderMonthlyUsageScope")] +[JsonSerializable(typeof(GitHub.Copilot.ProviderMonthlyUsageState), TypeInfoPropertyName = "SessionEventsProviderMonthlyUsageState")] [JsonSerializable(typeof(GitHub.Copilot.ProviderQuotaAccessState), TypeInfoPropertyName = "SessionEventsProviderQuotaAccessState")] [JsonSerializable(typeof(GitHub.Copilot.ProviderQuotaAcquisitionStatus), TypeInfoPropertyName = "SessionEventsProviderQuotaAcquisitionStatus")] [JsonSerializable(typeof(GitHub.Copilot.ProviderQuotaBudgetMetadata), TypeInfoPropertyName = "SessionEventsProviderQuotaBudgetMetadata")] @@ -52854,6 +53039,8 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(LogResult))] [JsonSerializable(typeof(LoggedInUser))] [JsonSerializable(typeof(LspInitializeRequest))] +[JsonSerializable(typeof(ManagedPermissionEvaluation))] +[JsonSerializable(typeof(ManagedPermissionOperation))] [JsonSerializable(typeof(ManagedPluginRetryEntry))] [JsonSerializable(typeof(ManagedSettingMeta))] [JsonSerializable(typeof(ManagedSettingsComposeLayer))] @@ -52862,6 +53049,8 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(ManagedSettingsDiagnostic))] [JsonSerializable(typeof(ManagedSettingsLayer))] [JsonSerializable(typeof(ManagedSettingsMeta))] +[JsonSerializable(typeof(ManagedSettingsPermissionsEvaluateRequest))] +[JsonSerializable(typeof(ManagedSettingsPermissionsEvaluateResult))] [JsonSerializable(typeof(ManagedSettingsReadResult))] [JsonSerializable(typeof(ManagedSettingsResolveRequest))] [JsonSerializable(typeof(ManagedSettingsResolveResult))] diff --git a/dotnet/src/Generated/SessionEvents.cs b/dotnet/src/Generated/SessionEvents.cs index fb23ccb58a..b114c14840 100644 --- a/dotnet/src/Generated/SessionEvents.cs +++ b/dotnet/src/Generated/SessionEvents.cs @@ -3678,7 +3678,7 @@ public sealed partial class SessionUsageCheckpointData [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] public sealed partial class SessionQuotaObservationData { - /// The admitted provider's state observation. Admission observations never contain quantities or reset/percentage semantics. + /// The admitted provider's state observation. Admission balances and percentages remain absent; separate monthly usage may report its own amount and cycle. [JsonPropertyName("observation")] public required ProviderQuotaState Observation { get; set; } } @@ -5218,11 +5218,21 @@ public sealed partial class AssistantUsageData [JsonPropertyName("rejectedPredictionTokens")] public long? RejectedPredictionTokens { get; set; } - /// Serialized (uncompressed) byte length of the request body. A content-free size signal. + /// Serialized (uncompressed) byte length of the request body, before any Content-Encoding. A content-free size signal. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("requestBodyBytes")] public long? RequestBodyBytes { get; set; } + /// Content-Encoding applied to the request body of the attempt that produced this outcome; identity when uncompressed. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("requestBodyEncoding")] + public ModelCallRequestBodyEncoding? RequestBodyEncoding { get; set; } + + /// Byte length of the request body actually sent on the wire for the attempt that produced this outcome, after any Content-Encoding. Equals requestBodyBytes when the body was not compressed. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("requestBodyWireBytes")] + public long? RequestBodyWireBytes { get; set; } + /// Per-request treatment/eligibility signal returned by the Copilot API in the `X-GitHub-Copilot-Request-TE` response header for the associated model call; `false` when the header was absent or unparseable. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("rte")] @@ -5274,10 +5284,35 @@ public sealed partial class AssistantUsageData [JsonPropertyName("websocketFallbackAfterMs")] public TimeSpan? WebsocketFallbackAfter { get; set; } + /// WebSocket close code received before the HTTP fallback. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackCloseCode")] + public int? WebsocketFallbackCloseCode { get; set; } + + /// Normalized cause of the WebSocket failure that triggered the HTTP fallback; absent when no fallback occurred or the cause is unknown. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackErrorKind")] + public ModelCallWebSocketFallbackErrorKind? WebsocketFallbackErrorKind { get; set; } + /// Why the call was carried by the HTTP fallback of a WebSocket-capable dispatcher; absent when no fallback occurred. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("websocketFallbackReason")] public ModelCallWebSocketFallbackReason? WebsocketFallbackReason { get; set; } + + /// Whether a WebSocket reconnect was attempted before falling back to HTTP. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackReconnectAttempted")] + public bool? WebsocketFallbackReconnectAttempted { get; set; } + + /// Whether the HTTP fallback started during this model call, rather than being inherited from an earlier call. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackStartedThisCall")] + public bool? WebsocketFallbackStartedThisCall { get; set; } + + /// HTTP status of the WebSocket upgrade rejection or WebSocket API error that triggered the HTTP fallback. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackStatusCode")] + public int? WebsocketFallbackStatusCode { get; set; } } /// A detected loss of a previously cached prompt prefix. @@ -5532,11 +5567,21 @@ public sealed partial class ModelCallFailureData [JsonPropertyName("reasoningEffort")] public string? ReasoningEffort { get; set; } - /// Serialized (uncompressed) byte length of the failed request body. A content-free size signal. + /// Serialized (uncompressed) byte length of the failed request body, before any Content-Encoding. A content-free size signal. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("requestBodyBytes")] public long? RequestBodyBytes { get; set; } + /// Content-Encoding applied to the failed request body; identity when uncompressed. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("requestBodyEncoding")] + public ModelCallRequestBodyEncoding? RequestBodyEncoding { get; set; } + + /// Byte length of the failed request body actually sent on the wire, after any Content-Encoding. Equals requestBodyBytes when the body was not compressed. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("requestBodyWireBytes")] + public long? RequestBodyWireBytes { get; set; } + /// Content-free structural summary of the failing request. Contains only counts and shape flags (no prompt content), so it is safe for unrestricted telemetry. Populated only for client-error (4xx) failures. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("requestFingerprint")] @@ -5577,10 +5622,35 @@ public sealed partial class ModelCallFailureData [JsonPropertyName("websocketFallbackAfterMs")] public TimeSpan? WebsocketFallbackAfter { get; set; } + /// WebSocket close code received before the HTTP fallback. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackCloseCode")] + public int? WebsocketFallbackCloseCode { get; set; } + + /// Normalized cause of the WebSocket failure that triggered the HTTP fallback; absent when no fallback occurred or the cause is unknown. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackErrorKind")] + public ModelCallWebSocketFallbackErrorKind? WebsocketFallbackErrorKind { get; set; } + /// Why the failed call was carried by the HTTP fallback of a WebSocket-capable dispatcher; absent when no fallback occurred. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("websocketFallbackReason")] public ModelCallWebSocketFallbackReason? WebsocketFallbackReason { get; set; } + + /// Whether a WebSocket reconnect was attempted before falling back to HTTP. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackReconnectAttempted")] + public bool? WebsocketFallbackReconnectAttempted { get; set; } + + /// Whether the HTTP fallback started during this model call, rather than being inherited from an earlier call. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackStartedThisCall")] + public bool? WebsocketFallbackStartedThisCall { get; set; } + + /// HTTP status of the WebSocket upgrade rejection or WebSocket API error that triggered the HTTP fallback. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("websocketFallbackStatusCode")] + public int? WebsocketFallbackStatusCode { get; set; } } /// Internal telemetry result for one logical model operation after all orchestrator-owned retries settle. @@ -7321,6 +7391,11 @@ public sealed partial class SessionManagedSettingsResolvedData [JsonPropertyName("permissionsAllowIntersected")] public bool? PermissionsAllowIntersected { get; set; } + /// Reusable retained managed permission policy for managedSettings.permissions.evaluate, including source composition and session-local injection. Provided by live session snapshots; absent in older events. Refresh the context when managed policy changes. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("permissionsContext")] + public ManagedPermissionsContext? PermissionsContext { get; set; } + /// Whether the policy-helper managed-settings layer was present. The policy helper is the weakest channel: it fills keys no enterprise source set and can never replace one. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("policyHelperManaged")] @@ -8489,6 +8564,44 @@ public sealed partial class ProviderQuotaBudgetMetadata public required bool UsageAllowedWhenExhausted { get; set; } } +/// An authoritative monthly usage reading for the observation's provider, account, and service. +/// Nested data type for ProviderMonthlyUsage. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed partial class ProviderMonthlyUsage +{ + /// Nonnegative finite consumption reported by the service, preserving zero and fractions. Present only when state is available; never computed from tokens or balance differences. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("consumedQuantity")] + public double? ConsumedQuantity { get; set; } + + /// Start of the service-reported monthly billing cycle, in UTC RFC 3339. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("cycleStart")] + public string? CycleStart { get; set; } + + /// Service read time in UTC RFC 3339, not a ledger reconciliation watermark or confirmation of the latest inference charge. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("queriedAt")] + public string? QueriedAt { get; set; } + + /// End of the service-reported monthly billing cycle, in UTC RFC 3339. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("resetOn")] + public string? ResetOn { get; set; } + + /// Identity scope of the reading within its provider and service. + [JsonPropertyName("scope")] + public required ProviderMonthlyUsageScope Scope { get; set; } + + /// Availability of monthly consumption. Missing or unavailable usage must never be interpreted as zero. + [JsonPropertyName("state")] + public required ProviderMonthlyUsageState State { get; set; } + + /// Unit of consumedQuantity; independent of the parent observation's balance unit. + [JsonPropertyName("unit")] + public required ProviderQuotaUnit Unit { get; set; } +} + /// An account quota reading. Absence of a quantity is unknown, never zero. /// Nested data type for ProviderQuotaState. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] @@ -8542,6 +8655,11 @@ public sealed partial class ProviderQuotaState [JsonPropertyName("httpStatus")] public long? HttpStatus { get; set; } + /// Service-reported monthly consumption, independent of quota balances and per-call or session cost. Omitted when the service does not report monthly usage. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("monthlyUsage")] + public ProviderMonthlyUsage? MonthlyUsage { get; set; } + /// Whether this is a GET account reading or a pre-response admission observation. Observations are never merged across kinds. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("observationKind")] @@ -13548,6 +13666,20 @@ public sealed partial class SessionLimitsExhaustedResponse public double? MaxAiCredits { get; set; } } +/// Reusable managed permission evaluation context. Treat permissions as runtime-owned policy data and retain it verbatim; it includes source-aware composition metadata. This is a snapshot, not a capability or approval token; only use contexts obtained from trusted policy sources. +/// Nested data type for ManagedPermissionsContext. +public sealed partial class ManagedPermissionsContext +{ + /// Policy could not be determined; evaluation must deny every operation. + [JsonPropertyName("failClosed")] + public required bool FailClosed { get; set; } + + /// Runtime-owned composed permissions object. Absent when no permission policy is configured. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("permissions")] + public JsonElement? Permissions { get; set; } +} + /// A single slash command available in the session, as listed by the `commands.changed` event. /// Nested data type for CommandsChangedCommand. public sealed partial class CommandsChangedCommand @@ -15884,42 +16016,42 @@ public override void Write(Utf8JsonWriter writer, ProviderQuotaCapacityState val } } -/// Timing and purpose of a provider quota observation. +/// Identity scope of a monthly usage reading. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct ProviderQuotaObservationKind : IEquatable +public readonly struct ProviderMonthlyUsageScope : IEquatable { private readonly string? _value; - /// Initializes a new instance of the struct. - /// The value to associate with this . + /// Initializes a new instance of the struct. + /// The value to associate with this . [JsonConstructor] - public ProviderQuotaObservationKind(string value) + public ProviderMonthlyUsageScope(string value) { ArgumentException.ThrowIfNullOrWhiteSpace(value); _value = value; } - /// Gets the value associated with this . + /// Gets the value associated with this . public string Value => _value ?? string.Empty; - /// An explicit account read; consumption may still be subject to service aggregation delay. - public static ProviderQuotaObservationKind AccountSnapshot { get; } = new("account_snapshot"); + /// Consumption of the authenticated user within the parent observation's service and returned cycle. + public static ProviderMonthlyUsageScope User { get; } = new("user"); - /// A verdict attached before an inference response. May be cached; never a post-charge balance. - public static ProviderQuotaObservationKind AdmissionState { get; } = new("admission_state"); + /// The service did not establish a recognized usage scope. + public static ProviderMonthlyUsageScope Unknown { get; } = new("unknown"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ProviderQuotaObservationKind left, ProviderQuotaObservationKind right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ProviderMonthlyUsageScope left, ProviderMonthlyUsageScope right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ProviderQuotaObservationKind left, ProviderQuotaObservationKind right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ProviderMonthlyUsageScope left, ProviderMonthlyUsageScope right) => !(left == right); /// - public override bool Equals(object? obj) => obj is ProviderQuotaObservationKind other && Equals(other); + public override bool Equals(object? obj) => obj is ProviderMonthlyUsageScope other && Equals(other); /// - public bool Equals(ProviderQuotaObservationKind other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ProviderMonthlyUsageScope other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -15927,63 +16059,66 @@ public ProviderQuotaObservationKind(string value) /// public override string ToString() => Value; - /// Provides a for serializing instances. + /// Provides a for serializing instances. [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + public sealed class Converter : JsonConverter { /// - public override ProviderQuotaObservationKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ProviderMonthlyUsageScope Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, ProviderQuotaObservationKind value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ProviderMonthlyUsageScope value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ProviderQuotaObservationKind)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ProviderMonthlyUsageScope)); } } } -/// Interpretation permitted for independently reported quantities. +/// Availability of a service's monthly consumption reading. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct ProviderQuotaQuantityKind : IEquatable +public readonly struct ProviderMonthlyUsageState : IEquatable { private readonly string? _value; - /// Initializes a new instance of the struct. - /// The value to associate with this . + /// Initializes a new instance of the struct. + /// The value to associate with this . [JsonConstructor] - public ProviderQuotaQuantityKind(string value) + public ProviderMonthlyUsageState(string value) { ArgumentException.ThrowIfNullOrWhiteSpace(value); _value = value; } - /// Gets the value associated with this . + /// Gets the value associated with this . public string Value => _value ?? string.Empty; - /// Quantities form an authoritative available-of-entitled budget suitable for percentage presentation. - public static ProviderQuotaQuantityKind AuthoritativeBudget { get; } = new("authoritative_budget"); + /// The service reported a usable consumption reading, including an explicit zero. + public static ProviderMonthlyUsageState Available { get; } = new("available"); - /// Raw advisory quantities; do not infer permission, usage percentage, reset cadence, or post-charge balance. - public static ProviderQuotaQuantityKind AdvisoryBalance { get; } = new("advisory_balance"); + /// The service found no usage policy; no consumption amount is known. + public static ProviderMonthlyUsageState NoPolicy { get; } = new("no_policy"); - /// No quantity measurement, as with admission-only response headers. - public static ProviderQuotaQuantityKind None { get; } = new("none"); + /// The read failed or its data could not be used; consumption is unknown. + public static ProviderMonthlyUsageState Unavailable { get; } = new("unavailable"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ProviderQuotaQuantityKind left, ProviderQuotaQuantityKind right) => left.Equals(right); + /// The service reported an unrecognized usage state. + public static ProviderMonthlyUsageState Unknown { get; } = new("unknown"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ProviderQuotaQuantityKind left, ProviderQuotaQuantityKind right) => !(left == right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ProviderMonthlyUsageState left, ProviderMonthlyUsageState right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ProviderMonthlyUsageState left, ProviderMonthlyUsageState right) => !(left == right); /// - public override bool Equals(object? obj) => obj is ProviderQuotaQuantityKind other && Equals(other); + public override bool Equals(object? obj) => obj is ProviderMonthlyUsageState other && Equals(other); /// - public bool Equals(ProviderQuotaQuantityKind other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ProviderMonthlyUsageState other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -15991,20 +16126,20 @@ public ProviderQuotaQuantityKind(string value) /// public override string ToString() => Value; - /// Provides a for serializing instances. + /// Provides a for serializing instances. [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + public sealed class Converter : JsonConverter { /// - public override ProviderQuotaQuantityKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ProviderMonthlyUsageState Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, ProviderQuotaQuantityKind value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ProviderMonthlyUsageState value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ProviderQuotaQuantityKind)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ProviderMonthlyUsageState)); } } } @@ -16076,6 +16211,131 @@ public override void Write(Utf8JsonWriter writer, ProviderQuotaUnit value, JsonS } } +/// Timing and purpose of a provider quota observation. +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ProviderQuotaObservationKind : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ProviderQuotaObservationKind(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// An explicit account read; consumption may still be subject to service aggregation delay. + public static ProviderQuotaObservationKind AccountSnapshot { get; } = new("account_snapshot"); + + /// A verdict attached before an inference response. May be cached; never a post-charge balance. + public static ProviderQuotaObservationKind AdmissionState { get; } = new("admission_state"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ProviderQuotaObservationKind left, ProviderQuotaObservationKind right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ProviderQuotaObservationKind left, ProviderQuotaObservationKind right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ProviderQuotaObservationKind other && Equals(other); + + /// + public bool Equals(ProviderQuotaObservationKind other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ProviderQuotaObservationKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ProviderQuotaObservationKind value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ProviderQuotaObservationKind)); + } + } +} + +/// Interpretation permitted for independently reported quantities. +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ProviderQuotaQuantityKind : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ProviderQuotaQuantityKind(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// Quantities form an authoritative available-of-entitled budget suitable for percentage presentation. + public static ProviderQuotaQuantityKind AuthoritativeBudget { get; } = new("authoritative_budget"); + + /// Raw advisory quantities; do not infer permission, usage percentage, reset cadence, or post-charge balance. + public static ProviderQuotaQuantityKind AdvisoryBalance { get; } = new("advisory_balance"); + + /// No quantity measurement, as with admission-only response headers. + public static ProviderQuotaQuantityKind None { get; } = new("none"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ProviderQuotaQuantityKind left, ProviderQuotaQuantityKind right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ProviderQuotaQuantityKind left, ProviderQuotaQuantityKind right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ProviderQuotaQuantityKind other && Equals(other); + + /// + public bool Equals(ProviderQuotaQuantityKind other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ProviderQuotaQuantityKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ProviderQuotaQuantityKind value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ProviderQuotaQuantityKind)); + } + } +} + /// What initiated a conversation compaction. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] @@ -18038,6 +18298,70 @@ public override void Write(Utf8JsonWriter writer, AssistantUsageApiEndpoint valu } } +/// Content-Encoding applied to the request body sent on the wire. +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ModelCallRequestBodyEncoding : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ModelCallRequestBodyEncoding(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// The request body was sent uncompressed (including every WebSocket request). + public static ModelCallRequestBodyEncoding Identity { get; } = new("identity"); + + /// The request body was sent gzip-compressed. + public static ModelCallRequestBodyEncoding Gzip { get; } = new("gzip"); + + /// The request body was sent zstd-compressed. + public static ModelCallRequestBodyEncoding Zstd { get; } = new("zstd"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ModelCallRequestBodyEncoding left, ModelCallRequestBodyEncoding right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ModelCallRequestBodyEncoding left, ModelCallRequestBodyEncoding right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ModelCallRequestBodyEncoding other && Equals(other); + + /// + public bool Equals(ModelCallRequestBodyEncoding other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ModelCallRequestBodyEncoding Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ModelCallRequestBodyEncoding value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ModelCallRequestBodyEncoding)); + } + } +} + /// Transport used for a successful model call. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] @@ -18099,6 +18423,97 @@ public override void Write(Utf8JsonWriter writer, AssistantUsageTransport value, } } +/// Normalized cause of the WebSocket failure that triggered the HTTP fallback. +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ModelCallWebSocketFallbackErrorKind : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ModelCallWebSocketFallbackErrorKind(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// DNS resolution of the WebSocket host failed. + public static ModelCallWebSocketFallbackErrorKind Dns { get; } = new("dns"); + + /// The TLS handshake or a TLS record failed. + public static ModelCallWebSocketFallbackErrorKind Tls { get; } = new("tls"); + + /// A WebSocket connect or read timed out. + public static ModelCallWebSocketFallbackErrorKind Timeout { get; } = new("timeout"); + + /// The peer refused the TCP connection. + public static ModelCallWebSocketFallbackErrorKind ConnectionRefused { get; } = new("connection_refused"); + + /// The connection was reset, aborted, or ended mid-stream without a close. + public static ModelCallWebSocketFallbackErrorKind ConnectionReset { get; } = new("connection_reset"); + + /// The peer closed the WebSocket. + public static ModelCallWebSocketFallbackErrorKind ClosedByPeer { get; } = new("closed_by_peer"); + + /// The runtime closed the WebSocket itself. + public static ModelCallWebSocketFallbackErrorKind ClosedLocally { get; } = new("closed_locally"); + + /// The socket was already closed before it was used. + public static ModelCallWebSocketFallbackErrorKind NotConnected { get; } = new("not_connected"); + + /// The upgrade or request was rejected with an HTTP status. + public static ModelCallWebSocketFallbackErrorKind HttpStatus { get; } = new("http_status"); + + /// A WebSocket protocol violation or an undecodable frame. + public static ModelCallWebSocketFallbackErrorKind Protocol { get; } = new("protocol"); + + /// The WebSocket request could not be built. + public static ModelCallWebSocketFallbackErrorKind Configuration { get; } = new("configuration"); + + /// A failure that maps onto none of the other kinds. + public static ModelCallWebSocketFallbackErrorKind Other { get; } = new("other"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ModelCallWebSocketFallbackErrorKind left, ModelCallWebSocketFallbackErrorKind right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ModelCallWebSocketFallbackErrorKind left, ModelCallWebSocketFallbackErrorKind right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ModelCallWebSocketFallbackErrorKind other && Equals(other); + + /// + public bool Equals(ModelCallWebSocketFallbackErrorKind other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ModelCallWebSocketFallbackErrorKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ModelCallWebSocketFallbackErrorKind value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ModelCallWebSocketFallbackErrorKind)); + } + } +} + /// Why a WebSocket-capable model call was carried by the HTTP fallback. [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] @@ -23184,6 +23599,7 @@ public override void Write(Utf8JsonWriter writer, ExtensionsLoadedExtensionStatu [JsonSerializable(typeof(HumanResponseRecordedResponseAskUser))] [JsonSerializable(typeof(HumanResponseRecordedResponseExitPlanMode))] [JsonSerializable(typeof(HumanResponseRecordedResponseUserInput))] +[JsonSerializable(typeof(ManagedPermissionsContext))] [JsonSerializable(typeof(McpAppToolCallCompleteData))] [JsonSerializable(typeof(McpAppToolCallCompleteError))] [JsonSerializable(typeof(McpAppToolCallCompleteEvent))] @@ -23290,6 +23706,7 @@ public override void Write(Utf8JsonWriter writer, ExtensionsLoadedExtensionStatu [JsonSerializable(typeof(PersistedBinaryResult))] [JsonSerializable(typeof(PromptCacheBreakData))] [JsonSerializable(typeof(PromptCacheBreakEvent))] +[JsonSerializable(typeof(ProviderMonthlyUsage))] [JsonSerializable(typeof(ProviderQuotaBudgetMetadata))] [JsonSerializable(typeof(ProviderQuotaState))] [JsonSerializable(typeof(ResponsesReasoning))] diff --git a/dotnet/test/Unit/InProcessRuntimeArgumentsTests.cs b/dotnet/test/Unit/InProcessRuntimeArgumentsTests.cs new file mode 100644 index 0000000000..1dc5e4d93e --- /dev/null +++ b/dotnet/test/Unit/InProcessRuntimeArgumentsTests.cs @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +using System.Reflection; +using GitHub.Copilot.Test.Harness; +using Xunit; + +namespace GitHub.Copilot.Test.Unit; + +public sealed class InProcessRuntimeArgumentsTests +{ + [Fact] + public void Integration_Id_Is_Forwarded_To_The_Native_Host() + { + InProcessEnvIsolation.Apply("GITHUB_COPILOT_INTEGRATION_ID", " microsoft/vscode "); + var method = typeof(CopilotClient).GetMethod( + "BuildInProcessRuntimeArguments", + BindingFlags.Static | BindingFlags.NonPublic); + Assert.NotNull(method); + + var args = Assert.IsType>( + method!.Invoke(null, [new CopilotClientOptions()])); + + Assert.Contains("--cli-login-sync-integration-id=microsoft/vscode", args); + } +} diff --git a/go/client.go b/go/client.go index aa8659fd4b..bc41bc4c44 100644 --- a/go/client.go +++ b/go/client.go @@ -2426,7 +2426,8 @@ func (c *Client) startInProcess(ctx context.Context) error { return errors.New("in-process runtime unavailable: build with the bundled embedded runtime or set COPILOT_CLI_PATH to a compatible runtime package") } - config := c.inProcessHostConfig() + integrationID := strings.TrimSpace(getEnvValue(c.options.Env, "GITHUB_COPILOT_INTEGRATION_ID")) + config := c.inProcessHostConfig(integrationID) host, err := createInProcessHost(runtimePath, cliEntrypoint, config) if err != nil { @@ -2464,7 +2465,7 @@ func (c *Client) startInProcess(ctx context.Context) error { return nil } -func (c *Client) inProcessHostConfig() inProcessHostConfig { +func (c *Client) inProcessHostConfig(cliLoginSyncIntegrationID string) inProcessHostConfig { args := make([]string, 0, 8) if c.options.LogLevel != "" { args = append(args, "--log-level", c.options.LogLevel) @@ -2487,6 +2488,9 @@ func (c *Client) inProcessHostConfig() inProcessHostConfig { if c.options.EnableRemoteSessions { args = append(args, "--remote") } + if cliLoginSyncIntegrationID != "" { + args = append(args, "--cli-login-sync-integration-id="+cliLoginSyncIntegrationID) + } environment := make(map[string]string) if c.options.GitHubToken != "" { diff --git a/go/client_test.go b/go/client_test.go index c9a6225cde..2283385b33 100644 --- a/go/client_test.go +++ b/go/client_test.go @@ -2099,7 +2099,7 @@ func TestClient_InProcessConnection(t *testing.T) { Mode: ModeEmpty, }) - config := client.inProcessHostConfig() + config := client.inProcessHostConfig("") expectedArgs := []string{ "--log-level", "debug", "--auth-token-env", "COPILOT_SDK_AUTH_TOKEN", @@ -2119,6 +2119,33 @@ func TestClient_InProcessConnection(t *testing.T) { t.Fatalf("Expected managed environment %v, got %v", expectedEnvironment, config.Environment) } }) + + t.Run("forwards supported CLI login sync integrations", func(t *testing.T) { + t.Setenv("GITHUB_COPILOT_INTEGRATION_ID", "github/github-app") + client := NewClient(&ClientOptions{Connection: InProcessConnection{}}) + t.Setenv("GITHUB_COPILOT_INTEGRATION_ID", "changed/after-construction") + + integrationID := getEnvValue(client.options.Env, "GITHUB_COPILOT_INTEGRATION_ID") + config := client.inProcessHostConfig(integrationID) + + expectedArgs := []string{"--cli-login-sync-integration-id=github/github-app"} + if !reflect.DeepEqual(config.Args, expectedArgs) { + t.Fatalf("Expected CLI login sync arguments %v, got %v", expectedArgs, config.Args) + } + }) + + t.Run("forwards integration validation to the runtime", func(t *testing.T) { + t.Setenv("GITHUB_COPILOT_INTEGRATION_ID", "third-party/integration") + client := NewClient(&ClientOptions{Connection: InProcessConnection{}}) + + integrationID := getEnvValue(client.options.Env, "GITHUB_COPILOT_INTEGRATION_ID") + config := client.inProcessHostConfig(integrationID) + + expectedArgs := []string{"--cli-login-sync-integration-id=third-party/integration"} + if !reflect.DeepEqual(config.Args, expectedArgs) { + t.Fatalf("Expected CLI login sync arguments %v, got %v", expectedArgs, config.Args) + } + }) } func TestClient_DefaultConnection(t *testing.T) { diff --git a/go/rpc/zrpc.go b/go/rpc/zrpc.go index 7f341d8b5f..810998664e 100644 --- a/go/rpc/zrpc.go +++ b/go/rpc/zrpc.go @@ -167,6 +167,9 @@ type AccountsSetRequest struct { type AccountStatus struct { // Whether this is the active account. Active bool `json:"active"` + // Human-readable credential source used to authenticate this account, such as `gh` or + // `GITHUB_TOKEN`. + AuthSource *string `json:"authSource,omitempty"` // Opaque id of the account this one was derived from (e.g. an EMU account's base Entra // identity); absent for a root account. Matches the base identity account's selectionId, // forming the derivation edge. @@ -6787,6 +6790,58 @@ type ManagedMCPServerConfig struct { URL string `json:"url"` } +// Experimental: ManagedPermissionEvaluation is part of an experimental API and may change +// or be removed. +type ManagedPermissionEvaluation struct { + // Original input operation associated with this verdict. + Operation ManagedPermissionOperation `json:"operation"` + // Managed-policy decision only; never bypasses user permissions or other security controls. + Verdict ManagedPermissionVerdict `json:"verdict"` +} + +// Experimental: ManagedPermissionOperation is part of an experimental API and may change or +// be removed. +type ManagedPermissionOperation struct { + // Operation to evaluate. Currently only url is supported. + Kind ManagedPermissionOperationKind `json:"kind"` + // Absolute HTTP(S) URL with a host. Invalid URLs reject the entire evaluation batch. + URL string `json:"url"` +} + +// Reusable managed permission evaluation context. Treat permissions as runtime-owned policy +// data and retain it verbatim; it includes source-aware composition metadata. This is a +// snapshot, not a capability or approval token; only use contexts obtained from trusted +// policy sources. +// Experimental: ManagedPermissionsContext is part of an experimental API and may change or +// be removed. +type ManagedPermissionsContext struct { + // Policy could not be determined; evaluation must deny every operation. + FailClosed bool `json:"failClosed"` + // Runtime-owned composed permissions object. Absent when no permission policy is configured. + Permissions any `json:"permissions,omitempty"` +} + +// Managed policy context and ordered operations for pure, sessionless evaluation. +// Experimental: ManagedPermissionsEvaluateRequest is part of an experimental API and may +// change or be removed. +type ManagedPermissionsEvaluateRequest struct { + // Trusted, reusable managed permission policy snapshot; no policy is discovered during + // evaluation. + Context ManagedPermissionsContext `json:"context"` + // Operations to evaluate, preserving input order and duplicates. An empty batch is valid. + Operations []ManagedPermissionOperation `json:"operations"` +} + +// Ordered managed permission verdicts and the supplied policy's fail-closed posture. +// Experimental: ManagedPermissionsEvaluateResult is part of an experimental API and may +// change or be removed. +type ManagedPermissionsEvaluateResult struct { + // Managed permission policy could not be determined; every operation is denied. + FailClosed bool `json:"failClosed"` + // One verdict per input operation, in the same order, including duplicates. + Results []ManagedPermissionEvaluation `json:"results"` +} + // Retry outcome for one plugin required by managed settings. // Experimental: ManagedPluginRetryEntry is part of an experimental API and may change or be // removed. @@ -6906,6 +6961,16 @@ type ManagedSettingsMeta struct { Model *ManagedSettingMeta `json:"model,omitempty"` } +// Ordered managed permission verdicts and the supplied policy's fail-closed posture. +// Experimental: ManagedSettingsPermissionsEvaluateResult is part of an experimental API and +// may change or be removed. +type ManagedSettingsPermissionsEvaluateResult struct { + // Managed permission policy could not be determined; every operation is denied. + FailClosed bool `json:"failClosed"` + // One verdict per input operation, in the same order, including duplicates. + Results []ManagedPermissionEvaluation `json:"results"` +} + // Validated device-managed settings discovered before a session exists. // Experimental: ManagedSettingsReadResult is part of an experimental API and may change or // be removed. @@ -6943,6 +7008,10 @@ type ManagedSettingsResolvedData struct { // Whether at least two managed sources supplied permission allowlists, so enforcement // intersects them and the flattened settings payload omits `permissions.allow`. PermissionsAllowIntersected *bool `json:"permissionsAllowIntersected,omitempty"` + // Reusable retained managed permission policy for managedSettings.permissions.evaluate, + // including source composition and session-local injection. Provided by live session + // snapshots; absent in older events. Refresh the context when managed policy changes. + PermissionsContext *ManagedPermissionsContext `json:"permissionsContext,omitempty"` // Whether the policy-helper managed-settings layer was present. The policy helper is the // weakest channel: it fills keys no enterprise source set and can never replace one. PolicyHelperManaged *bool `json:"policyHelperManaged,omitempty"` @@ -6997,6 +7066,11 @@ type ManagedSettingsResolveResult struct { Layers []ManagedSettingsLayer `json:"layers"` // Per-key lock state and provenance for the entries in `values`, using the same key names. Meta *ManagedSettingsMeta `json:"meta,omitempty"` + // Reusable source-composed permission policy for managedSettings.permissions.evaluate. + // Unlike resolved.settings.permissions, this retains every source's allowlist and + // default-prompt semantics. Refresh through resolve when account/device policy changes. + // Absent on runtimes that do not support permission evaluation. + PermissionsContext *ManagedPermissionsContext `json:"permissionsContext,omitempty"` // Effective managed settings from the device and account (server) channels, in the same // shape as `session.managedSettings.get`, excluding session-local injection. Resolved ManagedSettingsResolvedData `json:"resolved"` @@ -13273,6 +13347,30 @@ type ProviderModelConfig struct { WireModel *string `json:"wireModel,omitempty"` } +// An authoritative monthly usage reading for the observation's provider, account, and +// service. +// Experimental: ProviderMonthlyUsage is part of an experimental API and may change or be +// removed. +type ProviderMonthlyUsage struct { + // Nonnegative finite consumption reported by the service, preserving zero and fractions. + // Present only when state is available; never computed from tokens or balance differences. + ConsumedQuantity *float64 `json:"consumedQuantity,omitempty"` + // Start of the service-reported monthly billing cycle, in UTC RFC 3339. + CycleStart *string `json:"cycleStart,omitempty"` + // Service read time in UTC RFC 3339, not a ledger reconciliation watermark or confirmation + // of the latest inference charge. + QueriedAt *string `json:"queriedAt,omitempty"` + // End of the service-reported monthly billing cycle, in UTC RFC 3339. + ResetOn *string `json:"resetOn,omitempty"` + // Identity scope of the reading within its provider and service. + Scope ProviderMonthlyUsageScope `json:"scope"` + // Availability of monthly consumption. Missing or unavailable usage must never be + // interpreted as zero. + State ProviderMonthlyUsageState `json:"state"` + // Unit of consumedQuantity; independent of the parent observation's balance unit. + Unit ProviderQuotaUnit `json:"unit"` +} + // Authoritative budget measurements and policy metadata, independent of provider. // Experimental: ProviderQuotaBudgetMetadata is part of an experimental API and may change // or be removed. @@ -13331,6 +13429,9 @@ type ProviderQuotaState struct { HasQuota *bool `json:"hasQuota,omitempty"` // HTTP status from acquisition, when available. HTTPStatus *int64 `json:"httpStatus,omitempty"` + // Service-reported monthly consumption, independent of quota balances and per-call or + // session cost. Omitted when the service does not report monthly usage. + MonthlyUsage *ProviderMonthlyUsage `json:"monthlyUsage,omitempty"` // Whether this is a GET account reading or a pre-response admission observation. // Observations are never merged across kinds. ObservationKind *ProviderQuotaObservationKind `json:"observationKind,omitempty"` @@ -24580,6 +24681,31 @@ const ( LoginProviderKindProxima LoginProviderKind = "proxima" ) +// Operation to evaluate. Currently only url is supported. +type ManagedPermissionOperationKind string + +const ( + ManagedPermissionOperationKindURL ManagedPermissionOperationKind = "url" +) + +// Managed-policy verdict only: deny blocks the URL, ask requires approval, allow approves +// under managed policy, and unmanaged leaves the normal consumer permission flow in effect. +// No verdict bypasses other security controls. +// Experimental: ManagedPermissionVerdict is part of an experimental API and may change or +// be removed. +type ManagedPermissionVerdict string + +const ( + // Managed policy allows the operation, subject to other security controls. + ManagedPermissionVerdictAllow ManagedPermissionVerdict = "allow" + // Managed policy requires the consumer to obtain approval. + ManagedPermissionVerdictAsk ManagedPermissionVerdict = "ask" + // Managed policy prohibits the operation; do not offer approval. + ManagedPermissionVerdictDeny ManagedPermissionVerdict = "deny" + // Managed policy does not decide the operation; use the consumer's normal permission flow. + ManagedPermissionVerdictUnmanaged ManagedPermissionVerdict = "unmanaged" +) + // What retrying did for one plugin required by managed settings. // Experimental: ManagedPluginRetryStatus is part of an experimental API and may change or // be removed. @@ -26253,6 +26379,35 @@ const ( ProviderEndpointWireAPIResponses ProviderEndpointWireAPI = "responses" ) +// Identity scope of a monthly usage reading. +// Experimental: ProviderMonthlyUsageScope is part of an experimental API and may change or +// be removed. +type ProviderMonthlyUsageScope string + +const ( + // The service did not establish a recognized usage scope. + ProviderMonthlyUsageScopeUnknown ProviderMonthlyUsageScope = "unknown" + // Consumption of the authenticated user within the parent observation's service and + // returned cycle. + ProviderMonthlyUsageScopeUser ProviderMonthlyUsageScope = "user" +) + +// Availability of a service's monthly consumption reading. +// Experimental: ProviderMonthlyUsageState is part of an experimental API and may change or +// be removed. +type ProviderMonthlyUsageState string + +const ( + // The service reported a usable consumption reading, including an explicit zero. + ProviderMonthlyUsageStateAvailable ProviderMonthlyUsageState = "available" + // The service found no usage policy; no consumption amount is known. + ProviderMonthlyUsageStateNoPolicy ProviderMonthlyUsageState = "no_policy" + // The read failed or its data could not be used; consumption is unknown. + ProviderMonthlyUsageStateUnavailable ProviderMonthlyUsageState = "unavailable" + // The service reported an unrecognized usage state. + ProviderMonthlyUsageStateUnknown ProviderMonthlyUsageState = "unknown" +) + // Access policy reported by the quota service. // Experimental: ProviderQuotaAccessState is part of an experimental API and may change or // be removed. @@ -28745,6 +28900,42 @@ func (a *ServerManagedSettingsAPI) Validate(ctx context.Context, params *Managed return &result, nil } +// Experimental: ServerManagedSettingsPermissionsAPI contains experimental APIs that may +// change or be removed. +type ServerManagedSettingsPermissionsAPI serverAPI + +// Evaluate pure, sessionless evaluation of operations against a supplied +// permissionsContext. Performs no policy discovery, I/O, prompting, navigation, permission +// grants, or sandbox changes. Obtain the context from managedSettings.resolve or +// session.managedSettings.get, or reuse an in-memory context. Results preserve input order +// and duplicates. Consumers must block deny, obtain approval for ask, and use their normal +// permission flow for unmanaged. Unknown policy returns failClosed with every operation +// denied. This is not a substitute for user permissions or other security controls. +// +// RPC method: managedSettings.permissions.evaluate. +// +// Parameters: Managed policy context and ordered operations for pure, sessionless +// evaluation. +// +// Returns: Ordered managed permission verdicts and the supplied policy's fail-closed +// posture. +func (a *ServerManagedSettingsPermissionsAPI) Evaluate(ctx context.Context, params *ManagedPermissionsEvaluateRequest) (*ManagedSettingsPermissionsEvaluateResult, error) { + raw, err := a.client.Request(ctx, "managedSettings.permissions.evaluate", params) + if err != nil { + return nil, err + } + var result ManagedSettingsPermissionsEvaluateResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: Permissions returns experimental APIs that may change or be removed. +func (s *ServerManagedSettingsAPI) Permissions() *ServerManagedSettingsPermissionsAPI { + return (*ServerManagedSettingsPermissionsAPI)(s) +} + // Experimental: ServerMCPAPI contains experimental APIs that may change or be removed. type ServerMCPAPI serverAPI diff --git a/go/rpc/zsession_events.go b/go/rpc/zsession_events.go index a9bc3e7a63..8ee7565f13 100644 --- a/go/rpc/zsession_events.go +++ b/go/rpc/zsession_events.go @@ -358,7 +358,7 @@ func (*PromptCacheBreakData) Type() SessionEventType { return SessionEventTypePr // A provider-owned quota observation, distinct from per-call usage and charge accounting. // Experimental: SessionQuotaObservationData is part of an experimental API and may change or be removed. type SessionQuotaObservationData struct { - // The admitted provider's state observation. Admission observations never contain quantities or reset/percentage semantics. + // The admitted provider's state observation. Admission balances and percentages remain absent; separate monthly usage may report its own amount and cycle. Observation ProviderQuotaState `json:"observation"` } @@ -907,6 +907,8 @@ type SessionManagedSettingsResolvedData struct { ManagedKeys []string `json:"managedKeys"` // Whether at least two managed sources supplied permission allowlists, so enforcement intersects them and the flattened settings payload omits `permissions.allow`. PermissionsAllowIntersected *bool `json:"permissionsAllowIntersected,omitempty"` + // Reusable retained managed permission policy for managedSettings.permissions.evaluate, including source composition and session-local injection. Provided by live session snapshots; absent in older events. Refresh the context when managed policy changes. + PermissionsContext *ManagedPermissionsContext `json:"permissionsContext,omitempty"` // Whether the policy-helper managed-settings layer was present. The policy helper is the weakest channel: it fills keys no enterprise source set and can never replace one. PolicyHelperManaged *bool `json:"policyHelperManaged,omitempty"` // Whether the effective sandbox policy forces the sandbox on *only* because managed policy could not be determined, rather than because the policy requires it. Lets clients tell a user whose `--no-sandbox` was overridden that the sandbox stayed on as a fail-closed fallback, instead of attributing it to an administrator who set no such policy. @@ -1471,8 +1473,12 @@ type ModelCallFailureData struct { QuotaSnapshots map[string]AssistantUsageQuotaSnapshot `json:"quotaSnapshots,omitzero"` // Reasoning effort level used for the failed model call, if applicable ReasoningEffort *string `json:"reasoningEffort,omitempty"` - // Serialized (uncompressed) byte length of the failed request body. A content-free size signal. + // Serialized (uncompressed) byte length of the failed request body, before any Content-Encoding. A content-free size signal. RequestBodyBytes *int64 `json:"requestBodyBytes,omitempty"` + // Content-Encoding applied to the failed request body; identity when uncompressed + RequestBodyEncoding *ModelCallRequestBodyEncoding `json:"requestBodyEncoding,omitempty"` + // Byte length of the failed request body actually sent on the wire, after any Content-Encoding. Equals requestBodyBytes when the body was not compressed. + RequestBodyWireBytes *int64 `json:"requestBodyWireBytes,omitempty"` // Content-free structural summary of the failing request. Contains only counts and shape flags (no prompt content), so it is safe for unrestricted telemetry. Populated only for client-error (4xx) failures. RequestFingerprint *ModelCallFailureRequestFingerprint `json:"requestFingerprint,omitempty"` // Zero-based orchestrator retry index of the failed attempt @@ -1489,8 +1495,18 @@ type ModelCallFailureData struct { Transport *ModelCallFailureTransport `json:"transport,omitempty"` // Milliseconds spent on the WebSocket attempt before falling back to HTTP WebsocketFallbackAfterMs *int64 `json:"websocketFallbackAfterMs,omitempty"` + // WebSocket close code received before the HTTP fallback + WebsocketFallbackCloseCode *int32 `json:"websocketFallbackCloseCode,omitempty"` + // Normalized cause of the WebSocket failure that triggered the HTTP fallback; absent when no fallback occurred or the cause is unknown + WebsocketFallbackErrorKind *ModelCallWebSocketFallbackErrorKind `json:"websocketFallbackErrorKind,omitempty"` // Why the failed call was carried by the HTTP fallback of a WebSocket-capable dispatcher; absent when no fallback occurred WebsocketFallbackReason *ModelCallWebSocketFallbackReason `json:"websocketFallbackReason,omitempty"` + // Whether a WebSocket reconnect was attempted before falling back to HTTP + WebsocketFallbackReconnectAttempted *bool `json:"websocketFallbackReconnectAttempted,omitempty"` + // Whether the HTTP fallback started during this model call, rather than being inherited from an earlier call + WebsocketFallbackStartedThisCall *bool `json:"websocketFallbackStartedThisCall,omitempty"` + // HTTP status of the WebSocket upgrade rejection or WebSocket API error that triggered the HTTP fallback + WebsocketFallbackStatusCode *int32 `json:"websocketFallbackStatusCode,omitempty"` } func (*ModelCallFailureData) sessionEventData() {} @@ -1854,8 +1870,12 @@ type AssistantUsageData struct { ReasoningTokens *int64 `json:"reasoningTokens,omitempty"` // Number of rejected speculative prediction tokens RejectedPredictionTokens *int64 `json:"rejectedPredictionTokens,omitempty"` - // Serialized (uncompressed) byte length of the request body. A content-free size signal. + // Serialized (uncompressed) byte length of the request body, before any Content-Encoding. A content-free size signal. RequestBodyBytes *int64 `json:"requestBodyBytes,omitempty"` + // Content-Encoding applied to the request body of the attempt that produced this outcome; identity when uncompressed + RequestBodyEncoding *ModelCallRequestBodyEncoding `json:"requestBodyEncoding,omitempty"` + // Byte length of the request body actually sent on the wire for the attempt that produced this outcome, after any Content-Encoding. Equals requestBodyBytes when the body was not compressed. + RequestBodyWireBytes *int64 `json:"requestBodyWireBytes,omitempty"` // Per-request treatment/eligibility signal returned by the Copilot API in the `X-GitHub-Copilot-Request-TE` response header for the associated model call; `false` when the header was absent or unparseable. Rte *bool `json:"rte,omitempty"` // Copilot service request ID (x-copilot-service-request-id header) for CAPI log correlation @@ -1878,8 +1898,18 @@ type AssistantUsageData struct { Transport *AssistantUsageTransport `json:"transport,omitempty"` // Milliseconds spent on the WebSocket attempt before falling back to HTTP WebsocketFallbackAfterMs *int64 `json:"websocketFallbackAfterMs,omitempty"` + // WebSocket close code received before the HTTP fallback + WebsocketFallbackCloseCode *int32 `json:"websocketFallbackCloseCode,omitempty"` + // Normalized cause of the WebSocket failure that triggered the HTTP fallback; absent when no fallback occurred or the cause is unknown + WebsocketFallbackErrorKind *ModelCallWebSocketFallbackErrorKind `json:"websocketFallbackErrorKind,omitempty"` // Why the call was carried by the HTTP fallback of a WebSocket-capable dispatcher; absent when no fallback occurred WebsocketFallbackReason *ModelCallWebSocketFallbackReason `json:"websocketFallbackReason,omitempty"` + // Whether a WebSocket reconnect was attempted before falling back to HTTP + WebsocketFallbackReconnectAttempted *bool `json:"websocketFallbackReconnectAttempted,omitempty"` + // Whether the HTTP fallback started during this model call, rather than being inherited from an earlier call + WebsocketFallbackStartedThisCall *bool `json:"websocketFallbackStartedThisCall,omitempty"` + // HTTP status of the WebSocket upgrade rejection or WebSocket API error that triggered the HTTP fallback + WebsocketFallbackStatusCode *int32 `json:"websocketFallbackStatusCode,omitempty"` } func (*AssistantUsageData) sessionEventData() {} @@ -6531,6 +6561,48 @@ const ( ModelCallFinishedOutcomeSuccess ModelCallFinishedOutcome = "success" ) +// Content-Encoding applied to the request body sent on the wire +type ModelCallRequestBodyEncoding string + +const ( + // The request body was sent gzip-compressed. + ModelCallRequestBodyEncodingGzip ModelCallRequestBodyEncoding = "gzip" + // The request body was sent uncompressed (including every WebSocket request). + ModelCallRequestBodyEncodingIdentity ModelCallRequestBodyEncoding = "identity" + // The request body was sent zstd-compressed. + ModelCallRequestBodyEncodingZstd ModelCallRequestBodyEncoding = "zstd" +) + +// Normalized cause of the WebSocket failure that triggered the HTTP fallback +type ModelCallWebSocketFallbackErrorKind string + +const ( + // The peer closed the WebSocket. + ModelCallWebSocketFallbackErrorKindClosedByPeer ModelCallWebSocketFallbackErrorKind = "closed_by_peer" + // The runtime closed the WebSocket itself. + ModelCallWebSocketFallbackErrorKindClosedLocally ModelCallWebSocketFallbackErrorKind = "closed_locally" + // The WebSocket request could not be built. + ModelCallWebSocketFallbackErrorKindConfiguration ModelCallWebSocketFallbackErrorKind = "configuration" + // The peer refused the TCP connection. + ModelCallWebSocketFallbackErrorKindConnectionRefused ModelCallWebSocketFallbackErrorKind = "connection_refused" + // The connection was reset, aborted, or ended mid-stream without a close. + ModelCallWebSocketFallbackErrorKindConnectionReset ModelCallWebSocketFallbackErrorKind = "connection_reset" + // DNS resolution of the WebSocket host failed. + ModelCallWebSocketFallbackErrorKindDns ModelCallWebSocketFallbackErrorKind = "dns" + // The upgrade or request was rejected with an HTTP status. + ModelCallWebSocketFallbackErrorKindHTTPStatus ModelCallWebSocketFallbackErrorKind = "http_status" + // The socket was already closed before it was used. + ModelCallWebSocketFallbackErrorKindNotConnected ModelCallWebSocketFallbackErrorKind = "not_connected" + // A failure that maps onto none of the other kinds. + ModelCallWebSocketFallbackErrorKindOther ModelCallWebSocketFallbackErrorKind = "other" + // A WebSocket protocol violation or an undecodable frame. + ModelCallWebSocketFallbackErrorKindProtocol ModelCallWebSocketFallbackErrorKind = "protocol" + // A WebSocket connect or read timed out. + ModelCallWebSocketFallbackErrorKindTimeout ModelCallWebSocketFallbackErrorKind = "timeout" + // The TLS handshake or a TLS record failed. + ModelCallWebSocketFallbackErrorKindTls ModelCallWebSocketFallbackErrorKind = "tls" +) + // Why a WebSocket-capable model call was carried by the HTTP fallback type ModelCallWebSocketFallbackReason string diff --git a/go/zsession_events.go b/go/zsession_events.go index 0c4775d386..3755ff6e4d 100644 --- a/go/zsession_events.go +++ b/go/zsession_events.go @@ -152,6 +152,7 @@ type ( HumanResponseRecordedResponseResponseKind = rpc.HumanResponseRecordedResponseResponseKind HumanResponseRecordedResponseUserInput = rpc.HumanResponseRecordedResponseUserInput IndexedSearchState = rpc.IndexedSearchState + ManagedPermissionsContext = rpc.ManagedPermissionsContext ManagedPluginProgressPhase = rpc.ManagedPluginProgressPhase ManagedSettingsEnforcedAction = rpc.ManagedSettingsEnforcedAction ManagedSettingsEnforcedEscalation = rpc.ManagedSettingsEnforcedEscalation @@ -191,7 +192,9 @@ type ( ModelCallFinalResultData = rpc.ModelCallFinalResultData ModelCallFinishedData = rpc.ModelCallFinishedData ModelCallFinishedOutcome = rpc.ModelCallFinishedOutcome + ModelCallRequestBodyEncoding = rpc.ModelCallRequestBodyEncoding ModelCallStartData = rpc.ModelCallStartData + ModelCallWebSocketFallbackErrorKind = rpc.ModelCallWebSocketFallbackErrorKind ModelCallWebSocketFallbackReason = rpc.ModelCallWebSocketFallbackReason ModelChangeSource = rpc.ModelChangeSource ModelDeselectedReason = rpc.ModelDeselectedReason @@ -286,6 +289,9 @@ type ( PlanChangedOperation = rpc.PlanChangedOperation PossibleURL = rpc.PossibleURL PromptCacheBreakData = rpc.PromptCacheBreakData + ProviderMonthlyUsage = rpc.ProviderMonthlyUsage + ProviderMonthlyUsageScope = rpc.ProviderMonthlyUsageScope + ProviderMonthlyUsageState = rpc.ProviderMonthlyUsageState ProviderQuotaAccessState = rpc.ProviderQuotaAccessState ProviderQuotaAcquisitionStatus = rpc.ProviderQuotaAcquisitionStatus ProviderQuotaBudgetMetadata = rpc.ProviderQuotaBudgetMetadata @@ -738,6 +744,21 @@ const ( ModelCallFinishedOutcomeError = rpc.ModelCallFinishedOutcomeError ModelCallFinishedOutcomeRejected = rpc.ModelCallFinishedOutcomeRejected ModelCallFinishedOutcomeSuccess = rpc.ModelCallFinishedOutcomeSuccess + ModelCallRequestBodyEncodingGzip = rpc.ModelCallRequestBodyEncodingGzip + ModelCallRequestBodyEncodingIdentity = rpc.ModelCallRequestBodyEncodingIdentity + ModelCallRequestBodyEncodingZstd = rpc.ModelCallRequestBodyEncodingZstd + ModelCallWebSocketFallbackErrorKindClosedByPeer = rpc.ModelCallWebSocketFallbackErrorKindClosedByPeer + ModelCallWebSocketFallbackErrorKindClosedLocally = rpc.ModelCallWebSocketFallbackErrorKindClosedLocally + ModelCallWebSocketFallbackErrorKindConfiguration = rpc.ModelCallWebSocketFallbackErrorKindConfiguration + ModelCallWebSocketFallbackErrorKindConnectionRefused = rpc.ModelCallWebSocketFallbackErrorKindConnectionRefused + ModelCallWebSocketFallbackErrorKindConnectionReset = rpc.ModelCallWebSocketFallbackErrorKindConnectionReset + ModelCallWebSocketFallbackErrorKindDns = rpc.ModelCallWebSocketFallbackErrorKindDns + ModelCallWebSocketFallbackErrorKindHTTPStatus = rpc.ModelCallWebSocketFallbackErrorKindHTTPStatus + ModelCallWebSocketFallbackErrorKindNotConnected = rpc.ModelCallWebSocketFallbackErrorKindNotConnected + ModelCallWebSocketFallbackErrorKindOther = rpc.ModelCallWebSocketFallbackErrorKindOther + ModelCallWebSocketFallbackErrorKindProtocol = rpc.ModelCallWebSocketFallbackErrorKindProtocol + ModelCallWebSocketFallbackErrorKindTimeout = rpc.ModelCallWebSocketFallbackErrorKindTimeout + ModelCallWebSocketFallbackErrorKindTls = rpc.ModelCallWebSocketFallbackErrorKindTls ModelCallWebSocketFallbackReasonAPIError = rpc.ModelCallWebSocketFallbackReasonAPIError ModelCallWebSocketFallbackReasonConnectFailed = rpc.ModelCallWebSocketFallbackReasonConnectFailed ModelCallWebSocketFallbackReasonConnectionUnavailable = rpc.ModelCallWebSocketFallbackReasonConnectionUnavailable @@ -896,6 +917,12 @@ const ( PlanChangedOperationCreate = rpc.PlanChangedOperationCreate PlanChangedOperationDelete = rpc.PlanChangedOperationDelete PlanChangedOperationUpdate = rpc.PlanChangedOperationUpdate + ProviderMonthlyUsageScopeUnknown = rpc.ProviderMonthlyUsageScopeUnknown + ProviderMonthlyUsageScopeUser = rpc.ProviderMonthlyUsageScopeUser + ProviderMonthlyUsageStateAvailable = rpc.ProviderMonthlyUsageStateAvailable + ProviderMonthlyUsageStateNoPolicy = rpc.ProviderMonthlyUsageStateNoPolicy + ProviderMonthlyUsageStateUnavailable = rpc.ProviderMonthlyUsageStateUnavailable + ProviderMonthlyUsageStateUnknown = rpc.ProviderMonthlyUsageStateUnknown ProviderQuotaAccessStateAllowed = rpc.ProviderQuotaAccessStateAllowed ProviderQuotaAccessStateDenied = rpc.ProviderQuotaAccessStateDenied ProviderQuotaAccessStateNotRequired = rpc.ProviderQuotaAccessStateNotRequired diff --git a/java/scripts/codegen/java.test.ts b/java/scripts/codegen/java.test.ts index ba931e7132..1a795e94d6 100644 --- a/java/scripts/codegen/java.test.ts +++ b/java/scripts/codegen/java.test.ts @@ -24,6 +24,64 @@ import { } from "./java.js"; import { RPC_VARIANT_OWNERS } from "./rpc-variant-owners.js"; +test("managed permission contexts share the session-event model in RPC inputs and outputs", () => { + const generated = "../../sdk/src/generated/java/com/github/copilot/generated/"; + for (const name of ["ManagedSettingsResolveResult", "ManagedSettingsPermissionsEvaluateParams"]) { + const source = fs.readFileSync(new URL(`${generated}rpc/${name}.java`, import.meta.url), "utf8"); + assert.match(source, /import com\.github\.copilot\.generated\.ManagedPermissionsContext;/); + assert.match(source, /ManagedPermissionsContext (?:context|permissionsContext)/); + } + assert.equal(fs.existsSync(new URL(`${generated}rpc/ManagedPermissionsContext.java`, import.meta.url)), false); + const event = fs.readFileSync(new URL(`${generated}SessionManagedSettingsResolvedEvent.java`, import.meta.url), "utf8"); + assert.match(event, /ManagedPermissionsContext permissionsContext/); +}); + +test("managed permission requests and results reuse one named operation and kind", async () => { + const files = await renderRpcTypes({ + definitions: { + ManagedPermissionOperation: { + anyOf: [{ + type: "object", + properties: { kind: { type: "string", const: "url" }, url: { type: "string" } }, + required: ["kind", "url"], + }], + }, + ManagedPermissionEvaluation: { + type: "object", + properties: { operation: { $ref: "#/definitions/ManagedPermissionOperation" } }, + required: ["operation"], + }, + }, + server: { + managedSettings: { + permissions: { + evaluate: { + rpcMethod: "managedSettings.permissions.evaluate", + params: { + type: "object", + properties: { operations: { type: "array", items: { $ref: "#/definitions/ManagedPermissionOperation" } } }, + required: ["operations"], + }, + result: { + type: "object", + properties: { results: { type: "array", items: { $ref: "#/definitions/ManagedPermissionEvaluation" } } }, + required: ["results"], + }, + }, + }, + }, + }, + }, {}); + const operation = generatedFile(files, "ManagedPermissionOperation"); + assert.ok(operation); + assert.match(operation, /record ManagedPermissionOperation\(/); + assert.match(operation, /ManagedPermissionOperationKind kind/); + assert.match(operation, /enum ManagedPermissionOperationKind/); + assert.match(operation, /URL\("url"\)/); + assert.match(generatedFile(files, "ManagedSettingsPermissionsEvaluateParams")!, /List operations/); + assert.match(generatedFile(files, "ManagedPermissionEvaluation")!, /ManagedPermissionOperation operation/); +}); + test("wrapper Javadoc preserves the operation contract ahead of parameter documentation", () => { const tree = buildNamespaceTree({ reconcile: { diff --git a/java/scripts/codegen/java.ts b/java/scripts/codegen/java.ts index d327ec4409..36ebc4a674 100644 --- a/java/scripts/codegen/java.ts +++ b/java/scripts/codegen/java.ts @@ -1343,7 +1343,34 @@ export function schemaTypeToJava( const name = schema.$ref.replace(/^#\/definitions\//, ""); const resolved = resolution.definitions[name]; if (resolved) { + if ( + name === "ManagedPermissionsContext" + && generatedSessionEventTypeNames.has(name) + && crossSchemaDefinitions.get("session-events.schema.json")?.[name] + ) { + imports.add(`com.github.copilot.generated.${name}`); + return { javaType: name, imports }; + } const directUnion = unionVariants(resolved); + if (name === "ManagedPermissionOperation" && directUnion) { + const variants = resolveAnyOfVariants(directUnion, resolution.definitions); + const [variant] = variants; + if (variants.length === 1 && variant?.properties) { + const kind = variant.properties.kind; + if (!kind || typeof kind !== "object" || typeof kind.const !== "string") { + throw new Error("Expected a string discriminator for ManagedPermissionOperation.kind"); + } + resolution.standaloneTypes.set(name, { + ...resolved, + ...variant, + properties: { + ...variant.properties, + kind: { ...kind, enum: [kind.const] }, + }, + }); + return { javaType: name, imports }; + } + } if (directUnion && ["InstallationReview", "McpInstallationReview", "SkillInstallationReview"].includes(name)) { const variants = resolveAnyOfVariants(directUnion, resolution.definitions); if (variants.length > 1 && findDiscriminator(variants)) { diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/AssistantUsageEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/AssistantUsageEvent.java index 75eb6f53f0..a392f290be 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/AssistantUsageEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/AssistantUsageEvent.java @@ -97,12 +97,26 @@ public record AssistantUsageEventData( @JsonProperty("rejectedPredictionTokens") Long rejectedPredictionTokens, /** Transport used for this model call (http or websocket) */ @JsonProperty("transport") AssistantUsageTransport transport, - /** Serialized (uncompressed) byte length of the request body. A content-free size signal. */ + /** Serialized (uncompressed) byte length of the request body, before any Content-Encoding. A content-free size signal. */ @JsonProperty("requestBodyBytes") Long requestBodyBytes, + /** Byte length of the request body actually sent on the wire for the attempt that produced this outcome, after any Content-Encoding. Equals requestBodyBytes when the body was not compressed. */ + @JsonProperty("requestBodyWireBytes") Long requestBodyWireBytes, + /** Content-Encoding applied to the request body of the attempt that produced this outcome; identity when uncompressed */ + @JsonProperty("requestBodyEncoding") ModelCallRequestBodyEncoding requestBodyEncoding, /** Why the call was carried by the HTTP fallback of a WebSocket-capable dispatcher; absent when no fallback occurred */ @JsonProperty("websocketFallbackReason") ModelCallWebSocketFallbackReason websocketFallbackReason, /** Milliseconds spent on the WebSocket attempt before falling back to HTTP */ @JsonProperty("websocketFallbackAfterMs") Long websocketFallbackAfterMs, + /** Normalized cause of the WebSocket failure that triggered the HTTP fallback; absent when no fallback occurred or the cause is unknown */ + @JsonProperty("websocketFallbackErrorKind") ModelCallWebSocketFallbackErrorKind websocketFallbackErrorKind, + /** HTTP status of the WebSocket upgrade rejection or WebSocket API error that triggered the HTTP fallback */ + @JsonProperty("websocketFallbackStatusCode") Long websocketFallbackStatusCode, + /** WebSocket close code received before the HTTP fallback */ + @JsonProperty("websocketFallbackCloseCode") Long websocketFallbackCloseCode, + /** Whether a WebSocket reconnect was attempted before falling back to HTTP */ + @JsonProperty("websocketFallbackReconnectAttempted") Boolean websocketFallbackReconnectAttempted, + /** Whether the HTTP fallback started during this model call, rather than being inherited from an earlier call */ + @JsonProperty("websocketFallbackStartedThisCall") Boolean websocketFallbackStartedThisCall, /** Completion ID from the model provider (e.g., chatcmpl-abc123) */ @JsonProperty("apiCallId") String apiCallId, /** GitHub request tracing ID (x-github-request-id header) for server-side log correlation */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ManagedPermissionsContext.java b/java/sdk/src/generated/java/com/github/copilot/generated/ManagedPermissionsContext.java new file mode 100644 index 0000000000..990ae9ace0 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ManagedPermissionsContext.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Reusable managed permission evaluation context. Treat permissions as runtime-owned policy data and retain it verbatim; it includes source-aware composition metadata. This is a snapshot, not a capability or approval token; only use contexts obtained from trusted policy sources. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ManagedPermissionsContext( + /** Runtime-owned composed permissions object. Absent when no permission policy is configured. */ + @JsonProperty("permissions") Object permissions, + /** Policy could not be determined; evaluation must deny every operation. */ + @JsonProperty("failClosed") Boolean failClosed +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallFailureEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallFailureEvent.java index 717523a2ee..9bfa1cc686 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallFailureEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallFailureEvent.java @@ -60,14 +60,28 @@ public record ModelCallFailureEventData( @JsonProperty("transport") ModelCallFailureTransport transport, /** Whether the failure originated from an API response or the request transport */ @JsonProperty("failureKind") ModelCallFailureKind failureKind, - /** Serialized (uncompressed) byte length of the failed request body. A content-free size signal. */ + /** Serialized (uncompressed) byte length of the failed request body, before any Content-Encoding. A content-free size signal. */ @JsonProperty("requestBodyBytes") Long requestBodyBytes, + /** Byte length of the failed request body actually sent on the wire, after any Content-Encoding. Equals requestBodyBytes when the body was not compressed. */ + @JsonProperty("requestBodyWireBytes") Long requestBodyWireBytes, + /** Content-Encoding applied to the failed request body; identity when uncompressed */ + @JsonProperty("requestBodyEncoding") ModelCallRequestBodyEncoding requestBodyEncoding, /** Zero-based orchestrator retry index of the failed attempt */ @JsonProperty("retryAttempt") Long retryAttempt, /** Why the failed call was carried by the HTTP fallback of a WebSocket-capable dispatcher; absent when no fallback occurred */ @JsonProperty("websocketFallbackReason") ModelCallWebSocketFallbackReason websocketFallbackReason, /** Milliseconds spent on the WebSocket attempt before falling back to HTTP */ @JsonProperty("websocketFallbackAfterMs") Long websocketFallbackAfterMs, + /** Normalized cause of the WebSocket failure that triggered the HTTP fallback; absent when no fallback occurred or the cause is unknown */ + @JsonProperty("websocketFallbackErrorKind") ModelCallWebSocketFallbackErrorKind websocketFallbackErrorKind, + /** HTTP status of the WebSocket upgrade rejection or WebSocket API error that triggered the HTTP fallback */ + @JsonProperty("websocketFallbackStatusCode") Long websocketFallbackStatusCode, + /** WebSocket close code received before the HTTP fallback */ + @JsonProperty("websocketFallbackCloseCode") Long websocketFallbackCloseCode, + /** Whether a WebSocket reconnect was attempted before falling back to HTTP */ + @JsonProperty("websocketFallbackReconnectAttempted") Boolean websocketFallbackReconnectAttempted, + /** Whether the HTTP fallback started during this model call, rather than being inherited from an earlier call */ + @JsonProperty("websocketFallbackStartedThisCall") Boolean websocketFallbackStartedThisCall, /** Effective maximum prompt-token limit for the failed call */ @JsonProperty("maxPromptTokens") Long maxPromptTokens, /** Effective maximum output-token limit for the failed call */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallRequestBodyEncoding.java b/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallRequestBodyEncoding.java new file mode 100644 index 0000000000..ad1b96ad9d --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallRequestBodyEncoding.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import javax.annotation.processing.Generated; + +/** + * Content-Encoding applied to the request body sent on the wire + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ModelCallRequestBodyEncoding { + /** The {@code identity} variant. */ + IDENTITY("identity"), + /** The {@code gzip} variant. */ + GZIP("gzip"), + /** The {@code zstd} variant. */ + ZSTD("zstd"); + + private final String value; + ModelCallRequestBodyEncoding(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ModelCallRequestBodyEncoding fromValue(String value) { + for (ModelCallRequestBodyEncoding v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ModelCallRequestBodyEncoding value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallWebSocketFallbackErrorKind.java b/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallWebSocketFallbackErrorKind.java new file mode 100644 index 0000000000..cb429a7d6d --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ModelCallWebSocketFallbackErrorKind.java @@ -0,0 +1,55 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import javax.annotation.processing.Generated; + +/** + * Normalized cause of the WebSocket failure that triggered the HTTP fallback + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ModelCallWebSocketFallbackErrorKind { + /** The {@code dns} variant. */ + DNS("dns"), + /** The {@code tls} variant. */ + TLS("tls"), + /** The {@code timeout} variant. */ + TIMEOUT("timeout"), + /** The {@code connection_refused} variant. */ + CONNECTION_REFUSED("connection_refused"), + /** The {@code connection_reset} variant. */ + CONNECTION_RESET("connection_reset"), + /** The {@code closed_by_peer} variant. */ + CLOSED_BY_PEER("closed_by_peer"), + /** The {@code closed_locally} variant. */ + CLOSED_LOCALLY("closed_locally"), + /** The {@code not_connected} variant. */ + NOT_CONNECTED("not_connected"), + /** The {@code http_status} variant. */ + HTTP_STATUS("http_status"), + /** The {@code protocol} variant. */ + PROTOCOL("protocol"), + /** The {@code configuration} variant. */ + CONFIGURATION("configuration"), + /** The {@code other} variant. */ + OTHER("other"); + + private final String value; + ModelCallWebSocketFallbackErrorKind(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ModelCallWebSocketFallbackErrorKind fromValue(String value) { + for (ModelCallWebSocketFallbackErrorKind v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ModelCallWebSocketFallbackErrorKind value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ProviderMonthlyUsage.java b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderMonthlyUsage.java new file mode 100644 index 0000000000..b0c3fdf5b6 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderMonthlyUsage.java @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * An authoritative monthly usage reading for the observation's provider, account, and service. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ProviderMonthlyUsage( + /** Availability of monthly consumption. Missing or unavailable usage must never be interpreted as zero. */ + @JsonProperty("state") ProviderMonthlyUsageState state, + /** Unit of consumedQuantity; independent of the parent observation's balance unit. */ + @JsonProperty("unit") ProviderQuotaUnit unit, + /** Identity scope of the reading within its provider and service. */ + @JsonProperty("scope") ProviderMonthlyUsageScope scope, + /** Nonnegative finite consumption reported by the service, preserving zero and fractions. Present only when state is available; never computed from tokens or balance differences. */ + @JsonProperty("consumedQuantity") Double consumedQuantity, + /** Service read time in UTC RFC 3339, not a ledger reconciliation watermark or confirmation of the latest inference charge. */ + @JsonProperty("queriedAt") String queriedAt, + /** Start of the service-reported monthly billing cycle, in UTC RFC 3339. */ + @JsonProperty("cycleStart") String cycleStart, + /** End of the service-reported monthly billing cycle, in UTC RFC 3339. */ + @JsonProperty("resetOn") String resetOn +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ProviderMonthlyUsageScope.java b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderMonthlyUsageScope.java new file mode 100644 index 0000000000..fb61e9283e --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderMonthlyUsageScope.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import javax.annotation.processing.Generated; + +/** + * Identity scope of a monthly usage reading. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ProviderMonthlyUsageScope { + /** The {@code user} variant. */ + USER("user"), + /** The {@code unknown} variant. */ + UNKNOWN("unknown"); + + private final String value; + ProviderMonthlyUsageScope(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ProviderMonthlyUsageScope fromValue(String value) { + for (ProviderMonthlyUsageScope v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ProviderMonthlyUsageScope value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ProviderMonthlyUsageState.java b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderMonthlyUsageState.java new file mode 100644 index 0000000000..27df08fdb1 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderMonthlyUsageState.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: session-events.schema.json + +package com.github.copilot.generated; + +import javax.annotation.processing.Generated; + +/** + * Availability of a service's monthly consumption reading. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ProviderMonthlyUsageState { + /** The {@code available} variant. */ + AVAILABLE("available"), + /** The {@code no_policy} variant. */ + NO_POLICY("no_policy"), + /** The {@code unavailable} variant. */ + UNAVAILABLE("unavailable"), + /** The {@code unknown} variant. */ + UNKNOWN("unknown"); + + private final String value; + ProviderMonthlyUsageState(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ProviderMonthlyUsageState fromValue(String value) { + for (ProviderMonthlyUsageState v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ProviderMonthlyUsageState value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaState.java b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaState.java index ddb7fe9aa9..6beeefee69 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaState.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/ProviderQuotaState.java @@ -49,6 +49,8 @@ public record ProviderQuotaState( @JsonProperty("acquisitionError") String acquisitionError, /** Optional metadata for an authoritative budget. Advisory balances and admission-only observations do not populate this. */ @JsonProperty("budgetMetadata") ProviderQuotaBudgetMetadata budgetMetadata, + /** Service-reported monthly consumption, independent of quota balances and per-call or session cost. Omitted when the service does not report monthly usage. */ + @JsonProperty("monthlyUsage") ProviderMonthlyUsage monthlyUsage, /** Key for the backwards-compatible snapshots projection, when the authoritative budget supports that contract. */ @JsonProperty("compatibilityKey") String compatibilityKey, /** Explicit service admission flag, when reported. */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionManagedSettingsResolvedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionManagedSettingsResolvedEvent.java index 27f062596c..b80820d47a 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionManagedSettingsResolvedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionManagedSettingsResolvedEvent.java @@ -40,6 +40,8 @@ public final class SessionManagedSettingsResolvedEvent extends SessionEvent { @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SessionManagedSettingsResolvedEventData( + /** Reusable retained managed permission policy for managedSettings.permissions.evaluate, including source composition and session-local injection. Provided by live session snapshots; absent in older events. Refresh the context when managed policy changes. */ + @JsonProperty("permissionsContext") ManagedPermissionsContext permissionsContext, /** Channel summary: `server`, `device`, `client`, or `policyHelper` when exactly one channel contributed; `mixed` when multiple channels contributed; otherwise `none`. Consult the per-channel booleans for exact provenance. */ @JsonProperty("source") ManagedSettingsResolvedSource source, /** Whether the server (account/org) managed-settings layer was present */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionQuotaObservationEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionQuotaObservationEvent.java index c7b26660ca..00f710af94 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionQuotaObservationEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionQuotaObservationEvent.java @@ -39,7 +39,7 @@ public final class SessionQuotaObservationEvent extends SessionEvent { @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SessionQuotaObservationEventData( - /** The admitted provider's state observation. Admission observations never contain quantities or reset/percentage semantics. */ + /** The admitted provider's state observation. Admission balances and percentages remain absent; separate monthly usage may report its own amount and cycle. */ @JsonProperty("observation") ProviderQuotaState observation ) { } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountStatus.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountStatus.java index cb0868ce74..7cdebb3d29 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountStatus.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountStatus.java @@ -31,6 +31,8 @@ public record AccountStatus( @JsonProperty("login") String login, /** The provider kind of this account. */ @JsonProperty("kind") AccountKind kind, + /** Human-readable credential source used to authenticate this account, such as `gh` or `GITHUB_TOKEN`. */ + @JsonProperty("authSource") String authSource, /** Opaque id of the account this one was derived from (e.g. an EMU account's base Entra identity); absent for a root account. Matches the base identity account's selectionId, forming the derivation edge. */ @JsonProperty("derivedFrom") String derivedFrom, /** Whether this is the active account. */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPermissionEvaluation.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPermissionEvaluation.java new file mode 100644 index 0000000000..40f74da843 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPermissionEvaluation.java @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ManagedPermissionEvaluation( + /** Original input operation associated with this verdict. */ + @JsonProperty("operation") ManagedPermissionOperation operation, + /** Managed-policy decision only; never bypasses user permissions or other security controls. */ + @JsonProperty("verdict") ManagedPermissionVerdict verdict +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPermissionOperation.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPermissionOperation.java new file mode 100644 index 0000000000..ba60365d3c --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPermissionOperation.java @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ManagedPermissionOperation( + /** Absolute HTTP(S) URL with a host. Invalid URLs reject the entire evaluation batch. */ + @JsonProperty("url") String url, + /** Operation to evaluate. Currently only url is supported. */ + @JsonProperty("kind") ManagedPermissionOperationKind kind +) { + + /** Operation to evaluate. Currently only url is supported. */ + public enum ManagedPermissionOperationKind { + /** The {@code url} variant. */ + URL("url"); + + private final String value; + ManagedPermissionOperationKind(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ManagedPermissionOperationKind fromValue(String value) { + for (ManagedPermissionOperationKind v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ManagedPermissionOperationKind value: " + value); + } + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPermissionVerdict.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPermissionVerdict.java new file mode 100644 index 0000000000..1254c36718 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedPermissionVerdict.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * Managed-policy verdict only: deny blocks the URL, ask requires approval, allow approves under managed policy, and unmanaged leaves the normal consumer permission flow in effect. No verdict bypasses other security controls. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ManagedPermissionVerdict { + /** The {@code deny} variant. */ + DENY("deny"), + /** The {@code ask} variant. */ + ASK("ask"), + /** The {@code allow} variant. */ + ALLOW("allow"), + /** The {@code unmanaged} variant. */ + UNMANAGED("unmanaged"); + + private final String value; + ManagedPermissionVerdict(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ManagedPermissionVerdict fromValue(String value) { + for (ManagedPermissionVerdict v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ManagedPermissionVerdict value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPermissionsEvaluateParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPermissionsEvaluateParams.java new file mode 100644 index 0000000000..0a5d0c53ab --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPermissionsEvaluateParams.java @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import com.github.copilot.generated.ManagedPermissionsContext; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Managed policy context and ordered operations for pure, sessionless evaluation. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ManagedSettingsPermissionsEvaluateParams( + /** Trusted, reusable managed permission policy snapshot; no policy is discovered during evaluation. */ + @JsonProperty("context") ManagedPermissionsContext context, + /** Operations to evaluate, preserving input order and duplicates. An empty batch is valid. */ + @JsonProperty("operations") List operations +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPermissionsEvaluateResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPermissionsEvaluateResult.java new file mode 100644 index 0000000000..099a216b48 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPermissionsEvaluateResult.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Ordered managed permission verdicts and the supplied policy's fail-closed posture. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ManagedSettingsPermissionsEvaluateResult( + /** One verdict per input operation, in the same order, including duplicates. */ + @JsonProperty("results") List results, + /** Managed permission policy could not be determined; every operation is denied. */ + @JsonProperty("failClosed") Boolean failClosed +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveResult.java index 6d9941f4a9..d13b9a555b 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveResult.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveResult.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.github.copilot.CopilotExperimental; +import com.github.copilot.generated.ManagedPermissionsContext; import java.util.List; import javax.annotation.processing.Generated; @@ -25,6 +26,8 @@ @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public record ManagedSettingsResolveResult( + /** Reusable source-composed permission policy for managedSettings.permissions.evaluate. Unlike resolved.settings.permissions, this retains every source's allowlist and default-prompt semantics. Refresh through resolve when account/device policy changes. Absent on runtimes that do not support permission evaluation. */ + @JsonProperty("permissionsContext") ManagedPermissionsContext permissionsContext, /** Printable opaque identity of the account the settings were resolved for, suitable for comparison and storage, not an account selectionId. Absent when no account was available, in which case only device policy is reported. */ @JsonProperty("account") String account, /** Effective managed settings from the device and account (server) channels, in the same shape as `session.managedSettings.get`, excluding session-local injection. */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolvedData.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolvedData.java index 2020e9d434..35e11c4ad9 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolvedData.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolvedData.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.github.copilot.CopilotExperimental; +import com.github.copilot.generated.ManagedPermissionsContext; import java.util.List; import javax.annotation.processing.Generated; @@ -26,6 +27,8 @@ @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public record ManagedSettingsResolvedData( + /** Reusable retained managed permission policy for managedSettings.permissions.evaluate, including source composition and session-local injection. Provided by live session snapshots; absent in older events. Refresh the context when managed policy changes. */ + @JsonProperty("permissionsContext") ManagedPermissionsContext permissionsContext, /** Channel summary: `server`, `device`, `client`, or `policyHelper` when exactly one channel contributed; `mixed` when multiple channels contributed; otherwise `none`. Consult the per-channel booleans for exact provenance. */ @JsonProperty("source") ManagedSettingsResolvedSource source, /** Whether the server (account/org) managed-settings layer was present */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderMonthlyUsage.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderMonthlyUsage.java new file mode 100644 index 0000000000..355f7e38f0 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderMonthlyUsage.java @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * An authoritative monthly usage reading for the observation's provider, account, and service. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ProviderMonthlyUsage( + /** Availability of monthly consumption. Missing or unavailable usage must never be interpreted as zero. */ + @JsonProperty("state") ProviderMonthlyUsageState state, + /** Unit of consumedQuantity; independent of the parent observation's balance unit. */ + @JsonProperty("unit") ProviderQuotaUnit unit, + /** Identity scope of the reading within its provider and service. */ + @JsonProperty("scope") ProviderMonthlyUsageScope scope, + /** Nonnegative finite consumption reported by the service, preserving zero and fractions. Present only when state is available; never computed from tokens or balance differences. */ + @JsonProperty("consumedQuantity") Double consumedQuantity, + /** Service read time in UTC RFC 3339, not a ledger reconciliation watermark or confirmation of the latest inference charge. */ + @JsonProperty("queriedAt") String queriedAt, + /** Start of the service-reported monthly billing cycle, in UTC RFC 3339. */ + @JsonProperty("cycleStart") String cycleStart, + /** End of the service-reported monthly billing cycle, in UTC RFC 3339. */ + @JsonProperty("resetOn") String resetOn +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderMonthlyUsageScope.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderMonthlyUsageScope.java new file mode 100644 index 0000000000..56d9b4dd38 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderMonthlyUsageScope.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * Identity scope of a monthly usage reading. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ProviderMonthlyUsageScope { + /** The {@code user} variant. */ + USER("user"), + /** The {@code unknown} variant. */ + UNKNOWN("unknown"); + + private final String value; + ProviderMonthlyUsageScope(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ProviderMonthlyUsageScope fromValue(String value) { + for (ProviderMonthlyUsageScope v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ProviderMonthlyUsageScope value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderMonthlyUsageState.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderMonthlyUsageState.java new file mode 100644 index 0000000000..7788fbc219 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderMonthlyUsageState.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * Availability of a service's monthly consumption reading. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ProviderMonthlyUsageState { + /** The {@code available} variant. */ + AVAILABLE("available"), + /** The {@code no_policy} variant. */ + NO_POLICY("no_policy"), + /** The {@code unavailable} variant. */ + UNAVAILABLE("unavailable"), + /** The {@code unknown} variant. */ + UNKNOWN("unknown"); + + private final String value; + ProviderMonthlyUsageState(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ProviderMonthlyUsageState fromValue(String value) { + for (ProviderMonthlyUsageState v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ProviderMonthlyUsageState value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaState.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaState.java index 253d64bbe8..5473712f9c 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaState.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ProviderQuotaState.java @@ -49,6 +49,8 @@ public record ProviderQuotaState( @JsonProperty("acquisitionError") String acquisitionError, /** Optional metadata for an authoritative budget. Advisory balances and admission-only observations do not populate this. */ @JsonProperty("budgetMetadata") ProviderQuotaBudgetMetadata budgetMetadata, + /** Service-reported monthly consumption, independent of quota balances and per-call or session cost. Omitted when the service does not report monthly usage. */ + @JsonProperty("monthlyUsage") ProviderMonthlyUsage monthlyUsage, /** Key for the backwards-compatible snapshots projection, when the authoritative budget supports that contract. */ @JsonProperty("compatibilityKey") String compatibilityKey, /** Explicit service admission flag, when reported. */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerManagedSettingsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerManagedSettingsApi.java index a686df708c..579ef69f90 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerManagedSettingsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerManagedSettingsApi.java @@ -21,9 +21,13 @@ public final class ServerManagedSettingsApi { private final RpcCaller caller; + /** API methods for the {@code managedSettings.permissions} sub-namespace. */ + public final ServerManagedSettingsPermissionsApi permissions; + /** @param caller the RPC transport function */ ServerManagedSettingsApi(RpcCaller caller) { this.caller = caller; + this.permissions = new ServerManagedSettingsPermissionsApi(caller); } /** diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerManagedSettingsPermissionsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerManagedSettingsPermissionsApi.java new file mode 100644 index 0000000000..11526bde65 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerManagedSettingsPermissionsApi.java @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code managedSettings.permissions} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public final class ServerManagedSettingsPermissionsApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerManagedSettingsPermissionsApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Pure, sessionless evaluation of operations against a supplied permissionsContext. Performs no policy discovery, I/O, prompting, navigation, permission grants, or sandbox changes. Obtain the context from managedSettings.resolve or session.managedSettings.get, or reuse an in-memory context. Results preserve input order and duplicates. Consumers must block deny, obtain approval for ask, and use their normal permission flow for unmanaged. Unknown policy returns failClosed with every operation denied. This is not a substitute for user permissions or other security controls. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture evaluate(ManagedSettingsPermissionsEvaluateParams params) { + return caller.invoke("managedSettings.permissions.evaluate", params, ManagedSettingsPermissionsEvaluateResult.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionManagedSettingsGetResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionManagedSettingsGetResult.java index faf08c57d6..a20c0c6200 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionManagedSettingsGetResult.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionManagedSettingsGetResult.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.github.copilot.CopilotExperimental; +import com.github.copilot.generated.ManagedPermissionsContext; import java.util.List; import javax.annotation.processing.Generated; @@ -25,6 +26,8 @@ @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public record SessionManagedSettingsGetResult( + /** Reusable retained managed permission policy for managedSettings.permissions.evaluate, including source composition and session-local injection. Provided by live session snapshots; absent in older events. Refresh the context when managed policy changes. */ + @JsonProperty("permissionsContext") ManagedPermissionsContext permissionsContext, /** Channel summary: `server`, `device`, `client`, or `policyHelper` when exactly one channel contributed; `mixed` when multiple channels contributed; otherwise `none`. Consult the per-channel booleans for exact provenance. */ @JsonProperty("source") ManagedSettingsResolvedSource source, /** Whether the server (account/org) managed-settings layer was present */ diff --git a/java/sdk/src/main/java/com/github/copilot/CopilotClient.java b/java/sdk/src/main/java/com/github/copilot/CopilotClient.java index baccd4ad19..b277c09fa8 100644 --- a/java/sdk/src/main/java/com/github/copilot/CopilotClient.java +++ b/java/sdk/src/main/java/com/github/copilot/CopilotClient.java @@ -488,8 +488,10 @@ void setInProcessTransportFactory(InProcessTransportFactory factory) { private static InProcessTransport openInProcessTransport(CopilotClientOptions options) throws IOException { FfiRuntimeHost host = new FfiRuntimeHost(); try { - Path explicitEntrypoint = NativeRuntimeLoader.resolveConfiguredEntrypoint(); - host.start(explicitEntrypoint == null ? null : explicitEntrypoint.toString(), options); + String integrationId = System.getenv("GITHUB_COPILOT_INTEGRATION_ID"); + integrationId = integrationId == null || integrationId.isBlank() ? null : integrationId.trim(); + Path cliEntrypoint = NativeRuntimeLoader.resolveConfiguredEntrypoint(); + host.start(cliEntrypoint == null ? null : cliEntrypoint.toString(), integrationId, options); } catch (RuntimeException | Error e) { host.close(); throw e; diff --git a/java/sdk/src/main/java/com/github/copilot/ffi/FfiRuntimeHost.java b/java/sdk/src/main/java/com/github/copilot/ffi/FfiRuntimeHost.java index e28a573bc8..825a44497a 100644 --- a/java/sdk/src/main/java/com/github/copilot/ffi/FfiRuntimeHost.java +++ b/java/sdk/src/main/java/com/github/copilot/ffi/FfiRuntimeHost.java @@ -98,6 +98,23 @@ private static Path resolveLibraryPath() throws IOException { * {@code env_json} */ public void start(String entrypointPath, CopilotClientOptions options) { + start(entrypointPath, null, options); + } + + /** + * Starts the in-process runtime and opens a connection. + * + * @param entrypointPath + * optional explicit legacy CLI entrypoint passed in + * {@code argv_json} + * @param cliLoginSyncIntegrationId + * optional integration identifier used to synchronize login state + * with the Copilot CLI credential store + * @param options + * client options used to construct {@code argv_json} and + * {@code env_json} + */ + public void start(String entrypointPath, String cliLoginSyncIntegrationId, CopilotClientOptions options) { Objects.requireNonNull(options, "options must not be null"); if (disposed.get()) { throw new IllegalStateException("FfiRuntimeHost is already closed."); @@ -106,7 +123,7 @@ public void start(String entrypointPath, CopilotClientOptions options) { throw new IllegalStateException("FfiRuntimeHost has already been started."); } - byte[] argvJson = buildArgvJson(entrypointPath, options); + byte[] argvJson = buildArgvJson(entrypointPath, cliLoginSyncIntegrationId, options); byte[] envJson = buildEnvJson(options); int hostHandle = runHostStartOnBlockingThread(argvJson, envJson); if (hostHandle == 0) { @@ -275,7 +292,7 @@ private int runHostStartOnBlockingThread(byte[] argvJson, byte[] envJson) { } } - private static byte[] buildArgvJson(String entrypointPath, CopilotClientOptions options) { + static byte[] buildArgvJson(String entrypointPath, String cliLoginSyncIntegrationId, CopilotClientOptions options) { List argv = new ArrayList<>(); if (entrypointPath != null) { if (entrypointPath.toLowerCase().endsWith(".js")) { @@ -312,6 +329,9 @@ private static byte[] buildArgvJson(String entrypointPath, CopilotClientOptions if (options.isRemote()) { argv.add("--remote"); } + if (cliLoginSyncIntegrationId != null) { + argv.add("--cli-login-sync-integration-id=" + cliLoginSyncIntegrationId); + } String[] cliArgs = options.getCliArgs(); if (cliArgs != null && cliArgs.length > 0) { diff --git a/java/sdk/src/test/java/com/github/copilot/ffi/FfiRuntimeHostTest.java b/java/sdk/src/test/java/com/github/copilot/ffi/FfiRuntimeHostTest.java index 19d9694ce2..3891a9d483 100644 --- a/java/sdk/src/test/java/com/github/copilot/ffi/FfiRuntimeHostTest.java +++ b/java/sdk/src/test/java/com/github/copilot/ffi/FfiRuntimeHostTest.java @@ -77,7 +77,7 @@ public boolean connectionClose(int connectionId) { .setRemote(true).setMode(CopilotClientMode.EMPTY).setCliArgs(new String[]{"--extra-flag"}); FfiRuntimeHost host = new FfiRuntimeHost(binding, "/tmp/runtime.node"); - host.start("/tmp/entrypoint.js", options); + host.start("/tmp/entrypoint.js", "github/github-app", options); List argv = MAPPER.readValue(binding.argv, new TypeReference>() { }); @@ -92,6 +92,7 @@ public boolean connectionClose(int connectionId) { assertTrue(argv.contains("42")); assertTrue(argv.contains("--remote")); assertTrue(argv.contains("--extra-flag")); + assertTrue(argv.contains("--cli-login-sync-integration-id=github/github-app")); Map env = MAPPER.readValue(binding.env, new TypeReference>() { }); @@ -133,7 +134,7 @@ public boolean connectionClose(int connectionId) { }; try (FfiRuntimeHost host = new FfiRuntimeHost(binding, "/tmp/runtime.node")) { - host.start(null, new CopilotClientOptions().setLogLevel("debug")); + host.start(null, null, new CopilotClientOptions().setLogLevel("debug")); } List argv = MAPPER.readValue(argvJson.get(), new TypeReference>() { @@ -184,7 +185,7 @@ void enqueue(byte[] bytes) { }; FfiRuntimeHost host = new FfiRuntimeHost(binding, "test-lib", throwingStream); - assertDoesNotThrow(() -> host.start("/tmp/entrypoint", new CopilotClientOptions())); + assertDoesNotThrow(() -> host.start("/tmp/entrypoint", null, new CopilotClientOptions())); assertTrue(callbackReturned.get(), "callback should return normally even when enqueue throws"); } @@ -219,7 +220,7 @@ public boolean connectionClose(int connectionId) { }; FfiRuntimeHost host = new FfiRuntimeHost(binding, "test-lib"); - host.start("/tmp/entrypoint", new CopilotClientOptions()); + host.start("/tmp/entrypoint", null, new CopilotClientOptions()); assertDoesNotThrow(host::close); } @@ -310,7 +311,7 @@ public boolean connectionClose(int connectionId) { }; FfiRuntimeHost host = new FfiRuntimeHost(binding, "test-lib"); - host.start("/tmp/entrypoint", new CopilotClientOptions()); + host.start("/tmp/entrypoint", null, new CopilotClientOptions()); CompletableFuture writer = CompletableFuture.runAsync(() -> { try { @@ -389,7 +390,7 @@ void enqueue(byte[] bytes) { }; FfiRuntimeHost host = new FfiRuntimeHost(binding, "test-lib", blockingStream); - host.start("/tmp/entrypoint", new CopilotClientOptions()); + host.start("/tmp/entrypoint", null, new CopilotClientOptions()); assertNotNull(callbackRef.get()); ExecutorService executor = Executors.newFixedThreadPool(2); diff --git a/java/sdk/src/test/java/com/github/copilot/generated/rpc/GeneratedRpcRecordsCoverageTest.java b/java/sdk/src/test/java/com/github/copilot/generated/rpc/GeneratedRpcRecordsCoverageTest.java index 348a2d9f1a..73e0843c57 100644 --- a/java/sdk/src/test/java/com/github/copilot/generated/rpc/GeneratedRpcRecordsCoverageTest.java +++ b/java/sdk/src/test/java/com/github/copilot/generated/rpc/GeneratedRpcRecordsCoverageTest.java @@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.github.copilot.AllowCopilotExperimental; import com.github.copilot.TestUtil; +import com.github.copilot.generated.SessionManagedSettingsResolvedEvent.SessionManagedSettingsResolvedEventData; /** * Tests for generated RPC param and result record types. Exercises @@ -29,6 +30,27 @@ */ class GeneratedRpcRecordsCoverageTest { + @Test + @AllowCopilotExperimental + void managedPermissions_reuses_event_context_and_evaluated_operations() throws Exception { + var mapper = new ObjectMapper(); + var eventJson = mapper.readTree(""" + {"permissionsContext":{"permissions":{"_limitToLists":[["https://example.com"]]},"failClosed":false}} + """); + var eventData = mapper.treeToValue(eventJson, SessionManagedSettingsResolvedEventData.class); + var evaluation = mapper.readValue(""" + {"operation":{"kind":"url","url":"https://example.com/a"},"verdict":"allow"} + """, ManagedPermissionEvaluation.class); + var params = new ManagedSettingsPermissionsEvaluateParams(eventData.permissionsContext(), + List.of(evaluation.operation())); + var paramsJson = mapper.valueToTree(params); + assertEquals(eventJson.get("permissionsContext"), paramsJson.get("context")); + assertEquals("url", paramsJson.get("operations").get(0).get("kind").asText()); + assertEquals("https://example.com/a", paramsJson.get("operations").get(0).get("url").asText()); + assertEquals(ManagedPermissionOperation.ManagedPermissionOperationKind.URL, evaluation.operation().kind()); + assertEquals(params, mapper.treeToValue(paramsJson, ManagedSettingsPermissionsEvaluateParams.class)); + } + // ── Params records ───────────────────────────────────────────────────── @Test diff --git a/nodejs/README.md b/nodejs/README.md index 1566ea9cad..cf64fac0f7 100644 --- a/nodejs/README.md +++ b/nodejs/README.md @@ -1377,6 +1377,36 @@ const session = await client.createSession({ }); ``` +### Managed network policy for client-owned browsers + +Obtain a reusable `permissionsContext` from +`client.rpc.managedSettings.resolve({ selectionId })` for account and device +policy, or `session.rpc.managedSettings.get()` for the session's retained policy, +including SDK injection and policy-helper rules. Omit `selectionId` for the current +account, or device policy only when signed out. Resolution uses the managed-policy +cache and can fetch server policy; keep it off latency-critical startup paths. +Older runtimes may omit `permissionsContext`. Treat an absent context as unsupported +evaluation, not unmanaged policy; do not navigate without a policy decision. + +Call `client.rpc.managedSettings.permissions.evaluate({ context: permissionsContext, operations: [{ kind: "url", url: "https://docs.example.com/guide" }] })`. +This is pure, sessionless evaluation: it performs no policy discovery, I/O, +prompting, or sandbox changes. Reuse an in-memory context for repeated checks and +refresh it when managed policy changes. Retain the runtime-owned `permissions` +object verbatim rather than rebuilding it from the flattened settings display. + +The result is `{ results: [{ operation, verdict }], failClosed }`, with one entry per +input operation in the same order. `deny` blocks navigation, `ask` requires approval, +`allow` approves under managed policy, and `unmanaged` leaves the consumer's normal +permission flow in effect. A check never prompts or grants a saved approval. +Invalid URLs reject the batch. Unknown policy rejects or returns `failClosed: true` +with all URLs denied; do not navigate on an error. + +Check every navigation, redirect, and new-window destination before opening it. +These APIs evaluate managed permission rules only: they do not replace browser +security checks, user permissions, or sandbox policy. `permissions.limitTo` neither +enables the sandbox nor changes `sandbox.userPolicy.network`; configure sandbox +network restrictions explicitly. + ### Permission Result Kinds The handler must return one of the `PermissionDecision` shapes (or `{ kind: "no-result" }`). Approval scopes are present-tense — they describe the decision to apply, not the outcome reported back on session events: diff --git a/nodejs/package.json b/nodejs/package.json index a65ffe4181..e869d2b304 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -5,7 +5,7 @@ "url": "https://github.com/github/copilot-sdk.git" }, "version": "0.0.0-dev", - "copilotCliVersion": "1.0.95-3", + "copilotCliVersion": "1.0.96-0", "description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC", "main": "./dist/cjs/index.js", "types": "./dist/index.d.ts", diff --git a/nodejs/src/cliVersion.ts b/nodejs/src/cliVersion.ts index 92ccdd2f0b..3c1f791005 100644 --- a/nodejs/src/cliVersion.ts +++ b/nodejs/src/cliVersion.ts @@ -1,3 +1,3 @@ -export const COPILOT_CLI_VERSION = "1.0.95-3"; +export const COPILOT_CLI_VERSION = "1.0.96-0"; export const COPILOT_CLI_USE_NPM_PACKAGE = false; diff --git a/nodejs/src/client.ts b/nodejs/src/client.ts index fd82d52ada..ed10b482b2 100644 --- a/nodejs/src/client.ts +++ b/nodejs/src/client.ts @@ -3255,6 +3255,8 @@ export class CopilotClient { /** Starts the in-process FFI runtime with SDK-managed typed options. */ private async startInProcessFfi(): Promise { const explicitEntrypoint = this.resolvedEnv.COPILOT_CLI_PATH; + const cliLoginSyncIntegrationId = + this.resolvedEnv.GITHUB_COPILOT_INTEGRATION_ID?.trim() || undefined; let runtimeLibrary: string; if (explicitEntrypoint) { const entrypointDirectory = dirname(resolve(explicitEntrypoint)); @@ -3268,7 +3270,8 @@ export class CopilotClient { "runtime.node" ); } else { - runtimeLibrary = join(dirname(await getBundledRuntimePath()), "runtime.node"); + const bundledRuntimePath = await getBundledRuntimePath(); + runtimeLibrary = join(dirname(bundledRuntimePath), "runtime.node"); } // Load the FFI host lazily so the native `koffi` addon (and its // platform-specific `koffi.node`) is only loaded on the in-process path; @@ -3303,6 +3306,9 @@ export class CopilotClient { if (this.options.enableRemoteSessions) { args.push("--remote"); } + if (cliLoginSyncIntegrationId) { + args.push(`--cli-login-sync-integration-id=${cliLoginSyncIntegrationId}`); + } const host = FfiRuntimeHost.create(runtimeLibrary, explicitEntrypoint, environment, args); this.ffiHost = host; diff --git a/nodejs/src/generated/rpc.ts b/nodejs/src/generated/rpc.ts index bccd27643b..f4fbe69cfd 100644 --- a/nodejs/src/generated/rpc.ts +++ b/nodejs/src/generated/rpc.ts @@ -5,7 +5,7 @@ import type { MessageConnection } from "vscode-jsonrpc/node.js"; -import type { AbortReason, AgentModelPolicy, Attachment, AutoTier, ContextTier, EmbeddedBlobResourceContents, EmbeddedTextResourceContents, IndexedSearchState, ManagedSettingsResolvedData, McpOauthHttpResponse, McpOauthWWWAuthenticateParams, McpServerMetadata, McpServerSource, McpServerStatus, ModelChangeSource, ModelProviderKind, ModelProviderRef, PermissionDecisionSource, PermissionMode, PermissionPromptRequest, PermissionRule, ProviderQuotaState, ReasoningSummary, RemediationAction, SessionEvent, SessionLimitsConfig, SessionMode, ShutdownType, SkillSource, TaskCompleteData, TaskCompletionOutcome, UsageGetMetricsResult, UserToolSessionApproval, Verbosity } from "./session-events.js"; +import type { AbortReason, AgentModelPolicy, Attachment, AutoTier, ContextTier, EmbeddedBlobResourceContents, EmbeddedTextResourceContents, IndexedSearchState, ManagedPermissionsContext, ManagedSettingsResolvedData, McpOauthHttpResponse, McpOauthWWWAuthenticateParams, McpServerMetadata, McpServerSource, McpServerStatus, ModelChangeSource, ModelProviderKind, ModelProviderRef, PermissionDecisionSource, PermissionMode, PermissionPromptRequest, PermissionRule, ProviderQuotaState, ReasoningSummary, RemediationAction, SessionEvent, SessionLimitsConfig, SessionMode, ShutdownType, SkillSource, TaskCompleteData, TaskCompletionOutcome, UsageGetMetricsResult, UserToolSessionApproval, Verbosity } from "./session-events.js"; /** A value that can be represented losslessly on the SDK JSON wire. */ export type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue }; @@ -2680,6 +2680,34 @@ export type SessionLogLevel = | "warning" /** Error message describing a failure. */ | "error"; + +/** @experimental */ +export type ManagedPermissionOperation = { + /** + * Absolute HTTP(S) URL with a host. Invalid URLs reject the entire evaluation batch. + */ + url: string; + /** + * Operation to evaluate. Currently only url is supported. + */ + kind: "url"; +}; +/** + * Managed-policy verdict only: deny blocks the URL, ask requires approval, allow approves under managed policy, and unmanaged leaves the normal consumer permission flow in effect. No verdict bypasses other security controls. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ManagedPermissionVerdict". + */ +/** @experimental */ +export type ManagedPermissionVerdict = + /** Managed policy prohibits the operation; do not offer approval. */ + | "deny" + /** Managed policy requires the consumer to obtain approval. */ + | "ask" + /** Managed policy allows the operation, subject to other security controls. */ + | "allow" + /** Managed policy does not decide the operation; use the consumer's normal permission flow. */ + | "unmanaged"; /** * What retrying did for one plugin required by managed settings. * @@ -7092,6 +7120,10 @@ export interface AccountStatus { */ login: string; kind: AccountKind; + /** + * Human-readable credential source used to authenticate this account, such as `gh` or `GITHUB_TOKEN`. + */ + authSource?: string; /** * Opaque id of the account this one was derived from (e.g. an EMU account's base Entra identity); absent for a root account. Matches the base identity account's selectionId, forming the derivation edge. */ @@ -14713,6 +14745,43 @@ export interface ManagedMcpServerConfig { */ headersRefreshTtlMs?: number; } + +/** @experimental */ +export interface ManagedPermissionEvaluation { + operation: ManagedPermissionOperation; + verdict: ManagedPermissionVerdict; +} +/** + * Managed policy context and ordered operations for pure, sessionless evaluation. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ManagedPermissionsEvaluateRequest". + */ +/** @experimental */ +export interface ManagedPermissionsEvaluateRequest { + context: ManagedPermissionsContext; + /** + * Operations to evaluate, preserving input order and duplicates. An empty batch is valid. + */ + operations: ManagedPermissionOperation[]; +} +/** + * Ordered managed permission verdicts and the supplied policy's fail-closed posture. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ManagedPermissionsEvaluateResult". + */ +/** @experimental */ +export interface ManagedPermissionsEvaluateResult { + /** + * One verdict per input operation, in the same order, including duplicates. + */ + results: ManagedPermissionEvaluation[]; + /** + * Managed permission policy could not be determined; every operation is denied. + */ + failClosed: boolean; +} /** * Retry outcome for one plugin required by managed settings. * @@ -14911,6 +14980,7 @@ export interface ManagedSettingsResolveRequest { */ /** @experimental */ export interface ManagedSettingsResolveResult { + permissionsContext?: ManagedPermissionsContext; /** * Printable opaque identity of the account the settings were resolved for, suitable for comparison and storage, not an account selectionId. Absent when no account was available, in which case only device policy is reported. */ @@ -31462,6 +31532,37 @@ export interface HostGetConfigurationResult { */ /** @experimental */ export interface HostReadyResult {} +/** + * Ordered managed permission verdicts and the supplied policy's fail-closed posture. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ManagedSettingsPermissionsEvaluateResult". + */ +/** @experimental */ +export interface ManagedSettingsPermissionsEvaluateResult { + /** + * One verdict per input operation, in the same order, including duplicates. + */ + results: ManagedPermissionEvaluation[]; + /** + * Managed permission policy could not be determined; every operation is denied. + */ + failClosed: boolean; +} +/** + * Managed policy context and ordered operations for pure, sessionless evaluation. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ManagedSettingsPermissionsEvaluateRequest". + */ +/** @experimental */ +export interface ManagedSettingsPermissionsEvaluateRequest { + context: ManagedPermissionsContext; + /** + * Operations to evaluate, preserving input order and duplicates. An empty batch is valid. + */ + operations: ManagedPermissionOperation[]; +} /** @experimental */ export interface SessionWorkflowPauseAtCheckpointResult { @@ -32751,6 +32852,18 @@ export function createServerRpc(connection: MessageConnection) { */ resolve: async (params: ManagedSettingsResolveRequest): Promise => connection.sendRequest("managedSettings.resolve", params), + /** @experimental */ + permissions: { + /** + * Pure, sessionless evaluation of operations against a supplied permissionsContext. Performs no policy discovery, I/O, prompting, navigation, permission grants, or sandbox changes. Obtain the context from managedSettings.resolve or session.managedSettings.get, or reuse an in-memory context. Results preserve input order and duplicates. Consumers must block deny, obtain approval for ask, and use their normal permission flow for unmanaged. Unknown policy returns failClosed with every operation denied. This is not a substitute for user permissions or other security controls. + * + * @param params Managed policy context and ordered operations for pure, sessionless evaluation. + * + * @returns Ordered managed permission verdicts and the supplied policy's fail-closed posture. + */ + evaluate: async (params: ManagedSettingsPermissionsEvaluateRequest): Promise => + connection.sendRequest("managedSettings.permissions.evaluate", params), + }, /** * Returns the managed-settings authoring JSON schema with descriptive `x-composition` annotations aligned with the shared settings-engine vocabulary. These annotations are not a complete runtime composition contract: model, effortLevel, and contextTier remain coupled. Use `managedSettings.compose` for the runtime's effective result. Performs no I/O. * diff --git a/nodejs/src/generated/session-events.ts b/nodejs/src/generated/session-events.ts index 0938ae9744..77f15629ee 100644 --- a/nodejs/src/generated/session-events.ts +++ b/nodejs/src/generated/session-events.ts @@ -586,6 +586,38 @@ export type ProviderQuotaCapacityState = | "unknown" /** Client-only compatibility placeholder when acquisitionStatus is unavailable or failed; not an observed service verdict. */ | "unavailable"; +/** + * Identity scope of a monthly usage reading. + */ +export type ProviderMonthlyUsageScope = + /** Consumption of the authenticated user within the parent observation's service and returned cycle. */ + | "user" + /** The service did not establish a recognized usage scope. */ + | "unknown"; +/** + * Availability of a service's monthly consumption reading. + */ +export type ProviderMonthlyUsageState = + /** The service reported a usable consumption reading, including an explicit zero. */ + | "available" + /** The service found no usage policy; no consumption amount is known. */ + | "no_policy" + /** The read failed or its data could not be used; consumption is unknown. */ + | "unavailable" + /** The service reported an unrecognized usage state. */ + | "unknown"; +/** + * Units explicitly reported by a quota provider. + */ +export type ProviderQuotaUnit = + /** AI credits, not tokens or currency. */ + | "ai_credits" + /** Requests charged against an entitlement. */ + | "requests" + /** Model tokens. */ + | "tokens" + /** The observation does not establish a quantity unit. */ + | "unknown"; /** * Timing and purpose of a provider quota observation. */ @@ -604,18 +636,6 @@ export type ProviderQuotaQuantityKind = | "advisory_balance" /** No quantity measurement, as with admission-only response headers. */ | "none"; -/** - * Units explicitly reported by a quota provider. - */ -export type ProviderQuotaUnit = - /** AI credits, not tokens or currency. */ - | "ai_credits" - /** Requests charged against an entitlement. */ - | "requests" - /** Model tokens. */ - | "tokens" - /** The observation does not establish a quantity unit. */ - | "unknown"; /** * What initiated a conversation compaction */ @@ -942,6 +962,16 @@ export type AssistantUsageApiEndpoint = | "/responses" /** WebSocket Responses API endpoint. */ | "ws:/responses"; +/** + * Content-Encoding applied to the request body sent on the wire + */ +export type ModelCallRequestBodyEncoding = + /** The request body was sent uncompressed (including every WebSocket request). */ + | "identity" + /** The request body was sent gzip-compressed. */ + | "gzip" + /** The request body was sent zstd-compressed. */ + | "zstd"; /** * Transport used for a successful model call */ @@ -950,6 +980,34 @@ export type AssistantUsageTransport = | "http" /** WebSocket transport. */ | "websocket"; +/** + * Normalized cause of the WebSocket failure that triggered the HTTP fallback + */ +export type ModelCallWebSocketFallbackErrorKind = + /** DNS resolution of the WebSocket host failed. */ + | "dns" + /** The TLS handshake or a TLS record failed. */ + | "tls" + /** A WebSocket connect or read timed out. */ + | "timeout" + /** The peer refused the TCP connection. */ + | "connection_refused" + /** The connection was reset, aborted, or ended mid-stream without a close. */ + | "connection_reset" + /** The peer closed the WebSocket. */ + | "closed_by_peer" + /** The runtime closed the WebSocket itself. */ + | "closed_locally" + /** The socket was already closed before it was used. */ + | "not_connected" + /** The upgrade or request was rejected with an HTTP status. */ + | "http_status" + /** A WebSocket protocol violation or an undecodable frame. */ + | "protocol" + /** The WebSocket request could not be built. */ + | "configuration" + /** A failure that maps onto none of the other kinds. */ + | "other"; /** * Why a WebSocket-capable model call was carried by the HTTP fallback */ @@ -3869,6 +3927,7 @@ export interface ProviderQuotaState { * HTTP status from acquisition, when available. */ httpStatus?: number; + monthlyUsage?: ProviderMonthlyUsage; observationKind?: ProviderQuotaObservationKind; /** * When the runtime observed this reading, not a charge timestamp or guarantee that consumption has settled. @@ -3943,6 +4002,31 @@ export interface ProviderQuotaBudgetMetadata { */ usageAllowedWhenExhausted: boolean; } +/** + * An authoritative monthly usage reading for the observation's provider, account, and service. + */ +/** @experimental */ +export interface ProviderMonthlyUsage { + /** + * Nonnegative finite consumption reported by the service, preserving zero and fractions. Present only when state is available; never computed from tokens or balance differences. + */ + consumedQuantity?: number; + /** + * Start of the service-reported monthly billing cycle, in UTC RFC 3339. + */ + cycleStart?: string; + /** + * Service read time in UTC RFC 3339, not a ledger reconciliation watermark or confirmation of the latest inference charge. + */ + queriedAt?: string; + /** + * End of the service-reported monthly billing cycle, in UTC RFC 3339. + */ + resetOn?: string; + scope: ProviderMonthlyUsageScope; + state: ProviderMonthlyUsageState; + unit: ProviderQuotaUnit; +} /** * Session event "session.context_changed". Updated working directory and git context after the change */ @@ -7021,9 +7105,14 @@ export interface AssistantUsageData { */ rejectedPredictionTokens?: number; /** - * Serialized (uncompressed) byte length of the request body. A content-free size signal. + * Serialized (uncompressed) byte length of the request body, before any Content-Encoding. A content-free size signal. */ requestBodyBytes?: number; + requestBodyEncoding?: ModelCallRequestBodyEncoding; + /** + * Byte length of the request body actually sent on the wire for the attempt that produced this outcome, after any Content-Encoding. Equals requestBodyBytes when the body was not compressed. + */ + requestBodyWireBytes?: number; /** * Per-request treatment/eligibility signal returned by the Copilot API in the `X-GitHub-Copilot-Request-TE` response header for the associated model call; `false` when the header was absent or unparseable. */ @@ -7067,7 +7156,24 @@ export interface AssistantUsageData { * Milliseconds spent on the WebSocket attempt before falling back to HTTP */ websocketFallbackAfterMs?: number; + /** + * WebSocket close code received before the HTTP fallback + */ + websocketFallbackCloseCode?: number; + websocketFallbackErrorKind?: ModelCallWebSocketFallbackErrorKind; websocketFallbackReason?: ModelCallWebSocketFallbackReason; + /** + * Whether a WebSocket reconnect was attempted before falling back to HTTP + */ + websocketFallbackReconnectAttempted?: boolean; + /** + * Whether the HTTP fallback started during this model call, rather than being inherited from an earlier call + */ + websocketFallbackStartedThisCall?: boolean; + /** + * HTTP status of the WebSocket upgrade rejection or WebSocket API error that triggered the HTTP fallback + */ + websocketFallbackStatusCode?: number; } /** * Ordered accounting identity assigned under the source session's emission lock. @@ -7322,9 +7428,14 @@ export interface ModelCallFailureData { */ reasoningEffort?: string; /** - * Serialized (uncompressed) byte length of the failed request body. A content-free size signal. + * Serialized (uncompressed) byte length of the failed request body, before any Content-Encoding. A content-free size signal. */ requestBodyBytes?: number; + requestBodyEncoding?: ModelCallRequestBodyEncoding; + /** + * Byte length of the failed request body actually sent on the wire, after any Content-Encoding. Equals requestBodyBytes when the body was not compressed. + */ + requestBodyWireBytes?: number; requestFingerprint?: ModelCallFailureRequestFingerprint; /** * Zero-based orchestrator retry index of the failed attempt @@ -7348,7 +7459,24 @@ export interface ModelCallFailureData { * Milliseconds spent on the WebSocket attempt before falling back to HTTP */ websocketFallbackAfterMs?: number; + /** + * WebSocket close code received before the HTTP fallback + */ + websocketFallbackCloseCode?: number; + websocketFallbackErrorKind?: ModelCallWebSocketFallbackErrorKind; websocketFallbackReason?: ModelCallWebSocketFallbackReason; + /** + * Whether a WebSocket reconnect was attempted before falling back to HTTP + */ + websocketFallbackReconnectAttempted?: boolean; + /** + * Whether the HTTP fallback started during this model call, rather than being inherited from an earlier call + */ + websocketFallbackStartedThisCall?: boolean; + /** + * HTTP status of the WebSocket upgrade rejection or WebSocket API error that triggered the HTTP fallback + */ + websocketFallbackStatusCode?: number; } /** * Content-free structural summary of the failing request for diagnosing malformed 4xx calls @@ -12818,6 +12946,7 @@ export interface ManagedSettingsResolvedData { * Whether at least two managed sources supplied permission allowlists, so enforcement intersects them and the flattened settings payload omits `permissions.allow`. */ permissionsAllowIntersected?: boolean; + permissionsContext?: ManagedPermissionsContext; /** * Whether the policy-helper managed-settings layer was present. The policy helper is the weakest channel: it fills keys no enterprise source set and can never replace one. */ @@ -12836,6 +12965,19 @@ export interface ManagedSettingsResolvedData { settings?: JsonValue; source: ManagedSettingsResolvedSource; } +/** + * Reusable managed permission evaluation context. Treat permissions as runtime-owned policy data and retain it verbatim; it includes source-aware composition metadata. This is a snapshot, not a capability or approval token; only use contexts obtained from trusted policy sources. + */ +export interface ManagedPermissionsContext { + /** + * Policy could not be determined; evaluation must deny every operation. + */ + failClosed: boolean; + /** + * Runtime-owned composed permissions object. Absent when no permission policy is configured. + */ + permissions?: JsonValue; +} /** * Session event "session.managed_settings_enforced". Runtime enforcement of enterprise managed settings: fires when the session blocks or caps a runtime action because enterprise policy governs it, so SDK clients can explain *why* an action was governed. Unlike `session.managed_settings_resolved` (which reports *what* is managed), this reports a concrete governed action — e.g. a user or host tried to turn on bypass permissions or Assisted Permissions while the corresponding policy disables it. Emitted live (not persisted to the session event log) on user/host-initiated attempts only, never for silent policy application. Marked experimental while the managed-settings surface stabilizes. */ diff --git a/nodejs/test/computer-use-oauth-fixture.test.ts b/nodejs/test/computer-use-oauth-fixture.test.ts new file mode 100644 index 0000000000..419563d9dd --- /dev/null +++ b/nodejs/test/computer-use-oauth-fixture.test.ts @@ -0,0 +1,68 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import { test } from "vitest"; +import { startComputerUseOAuthServer } from "../../test/harness/test-mcp-computer-use-oauth-server.mjs"; + +test("rejects token exchanges without a registered client", async (context) => { + const { expect } = context; + const starting = startComputerUseOAuthServer(); + context.onTestFinished(async () => { + const [result] = await Promise.allSettled([starting]); + if (result.status === "fulfilled") await result.value.close(); + }); + const server = await starting; + context.signal.throwIfAborted(); + const exchange = (clientId: string) => + fetch(`${server.url}/token`, { + method: "POST", + body: new URLSearchParams({ + grant_type: "authorization_code", + code: "accepted-code", + code_verifier: "test-verifier", + ...(clientId ? { client_id: clientId } : {}), + }), + }); + for (const clientId of ["", "wrong-client", "registered-client"]) { + const response = await exchange(clientId); + expect(response.status).toBe(400); + expect(await response.json()).toEqual({ error: "invalid_client" }); + } + const registration = await fetch(`${server.url}/register`, { method: "POST" }); + expect(registration.status).toBe(201); + const { client_id: clientId } = await registration.json(); + for (const invalidClient of ["", "wrong-client"]) { + const response = await exchange(invalidClient); + expect(response.status).toBe(400); + expect(await response.json()).toEqual({ error: "invalid_client" }); + } + expect((await exchange(clientId)).status).toBe(200); +}); + +test("binds preconfigured-client token exchanges without dynamic registration", async (context) => { + const { expect } = context; + const starting = startComputerUseOAuthServer({ preconfiguredClientId: "app-client" }); + context.onTestFinished(async () => { + const [result] = await Promise.allSettled([starting]); + if (result.status === "fulfilled") await result.value.close(); + }); + const server = await starting; + context.signal.throwIfAborted(); + for (const clientId of ["", "wrong-client", "app-client"]) { + const response = await fetch(`${server.url}/token`, { + method: "POST", + body: new URLSearchParams({ + grant_type: "authorization_code", + code: "accepted-code", + code_verifier: "test-verifier", + ...(clientId ? { client_id: clientId } : {}), + }), + }); + expect(response.status).toBe(clientId === "app-client" ? 200 : 400); + if (clientId !== "app-client") { + expect(await response.json()).toEqual({ error: "invalid_client" }); + } + } + expect(server.requests.map((request) => request.path)).not.toContain("/register"); +}); diff --git a/nodejs/test/e2e/accounts_login.e2e.test.ts b/nodejs/test/e2e/accounts_login.e2e.test.ts index f0b08e7759..2440111bca 100644 --- a/nodejs/test/e2e/accounts_login.e2e.test.ts +++ b/nodejs/test/e2e/accounts_login.e2e.test.ts @@ -43,7 +43,7 @@ function clientForTest(): CopilotClient { return client; } -describe("Shared Entra login", () => { +describe.skipIf(process.platform === "linux")("Shared Entra login", () => { it("returns a cancellable flow before discovery and preserves session ownership", async () => { const client = clientForTest(); await using session = await client.createSession({ onPermissionRequest: approveAll }); diff --git a/nodejs/test/e2e/accounts_platform.e2e.test.ts b/nodejs/test/e2e/accounts_platform.e2e.test.ts new file mode 100644 index 0000000000..ae9bf93726 --- /dev/null +++ b/nodejs/test/e2e/accounts_platform.e2e.test.ts @@ -0,0 +1,180 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import { readFile, writeFile } from "node:fs/promises"; +import { join } from "node:path"; +import { describe, expect, it } from "vitest"; +import { approveAll } from "../../src/index.js"; +import { createSdkTestContext } from "./harness/sdkTestContext.js"; + +describe("Account provider platform support", async () => { + const { copilotClient: client } = await createSdkTestContext({ + useStdio: true, + copilotClientOptions: { + env: { + COPILOT_ENTRA_AUTH_AUD: "api://platform-gate-override", + COPILOT_DEBUG_ENTRA_BROKER_URL: "http://127.0.0.1:1/unused-broker", + }, + }, + }); + + it("keeps ordinary providers available and rejects unsupported Entra login", async () => { + const session = await client.createSession({ onPermissionRequest: approveAll }); + expect( + await session.rpc.accounts.enumerate({ query: { kind: "providers" } }) + ).toMatchObject({ + kind: "providers", + items: expect.arrayContaining([ + { kind: "githubDotCom", label: "GitHub.com", available: true }, + { kind: "proxima", label: "GitHub Enterprise Cloud (*.ghe.com)", available: true }, + ]), + }); + const flow = await session.rpc.accounts.login.begin({ kind: "proxima" }); + try { + expect(flow.step.kind).toBe("input-required"); + } finally { + await session.rpc.accounts.login.cancel({ flowId: flow.flowId }); + } + if (process.platform === "linux") { + expect( + await session.rpc.accounts.enumerate({ + query: { kind: "providers", brokerAvailable: true }, + }) + ).toMatchObject({ + kind: "providers", + items: expect.arrayContaining([ + expect.objectContaining({ kind: "entra", available: false }), + ]), + }); + await expect(session.rpc.accounts.login.begin({ kind: "entra" })).rejects.toThrow( + "only on Windows and macOS" + ); + } + }); +}); + +describe("Saved account platform support", async () => { + const { createClient, env, openAiEndpoint } = await createSdkTestContext({ + useStdio: true, + copilotClientOptions: { + gitHubToken: undefined, + useLoggedInUser: true, + env: { + COPILOT_GITHUB_TOKEN: "", + GH_TOKEN: "", + GITHUB_TOKEN: "", + GITHUB_ASKPASS: "", + COPILOT_GH_HOST: "github.com", + GH_HOST: "github.com", + COPILOT_HMAC_KEY: "", + CAPI_HMAC_KEY: "", + GITHUB_COPILOT_API_TOKEN: "", + COPILOT_ENABLE_ALT_PROVIDERS: "false", + COPILOT_DISABLE_KEYTAR: "1", + }, + }, + }); + it.each(["entraEmu", "githubDotCom"] as const)( + "restores %s only where supported", + async (kind) => { + const path = join(env.COPILOT_HOME, "config.json"); + const authTokens = { + "https://github.com:emu:entra": { + token: "ghu_platform_emu", + expiresAt: "2099-01-01T00:00:00Z", + accountType: "entra", + }, + "https://github.com:entra:github": { token: "ghu_platform_github" }, + }; + const login = kind === "entraEmu" ? "emu" : "entra"; + const profile = { + storeTokenPlaintext: true, + loggedInUsers: [ + { + host: "https://github.com", + login: "emu", + kind: "entraEmu", + derivedFrom: "base@tenant", + }, + { host: "https://github.com", login: "entra", kind: "githubDotCom" }, + ], + lastLoggedInUser: { host: "https://github.com", login }, + authTokens, + }; + await writeFile(path, JSON.stringify(profile)); + await openAiEndpoint.setCopilotUserByToken("ghu_platform_emu", { + login: "emu", + copilot_plan: "individual", + }); + await openAiEndpoint.setCopilotUserByToken("ghu_platform_github", { + login: "entra", + copilot_plan: "individual", + }); + const client = createClient({ gitHubToken: undefined, useLoggedInUser: true }); + try { + await client.start(); + expect(await client.getAuthStatus()).toMatchObject({ + isAuthenticated: kind === "githubDotCom" || process.platform !== "linux", + }); + } finally { + await client.stop(); + } + // The runtime adds a comment header to this JSON fixture. + const saved = (await readFile(path, "utf8")).replace(/^\/\/.*$/gm, ""); + expect(JSON.parse(saved).authTokens).toEqual(authTokens); + } + ); + + it("checks platform support before setCredentials replaces the selected account", async () => { + const path = join(env.COPILOT_HOME, "config.json"); + const authTokens = { + "https://github.com:emu:entra": { token: "ghu_platform_emu" }, + "https://github.com:ordinary:github": { token: "ghu_platform_github" }, + }; + await writeFile( + path, + JSON.stringify({ + storeTokenPlaintext: true, + loggedInUsers: [ + { host: "https://github.com", login: "emu" }, + { host: "https://github.com", login: "ordinary", kind: "githubDotCom" }, + ], + lastLoggedInUser: { host: "https://github.com", login: "ordinary" }, + authTokens, + }) + ); + await openAiEndpoint.setCopilotUserByToken("ghu_platform_github", { + login: "ordinary", + copilot_plan: "individual", + }); + const client = createClient({ gitHubToken: undefined, useLoggedInUser: true }); + try { + const session = await client.createSession({ onPermissionRequest: approveAll }); + const original = await session.rpc.gitHubAuth.getStatus(); + expect(original).toMatchObject({ isAuthenticated: true, login: "ordinary" }); + const update = session.rpc.gitHubAuth.setCredentials({ + credentials: { + type: "user", + host: "https://github.com", + login: "emu", + copilotUser: { login: "emu" }, + }, + }); + if (process.platform === "linux") { + await expect(update).rejects.toThrow("only on Windows and macOS"); + expect(await session.rpc.gitHubAuth.getStatus()).toEqual(original); + } else { + expect(await update).toMatchObject({ success: true }); + expect(await session.rpc.gitHubAuth.getStatus()).toMatchObject({ + isAuthenticated: true, + login: "emu", + }); + } + } finally { + await client.stop(); + } + const saved = (await readFile(path, "utf8")).replace(/^\/\/.*$/gm, ""); + expect(JSON.parse(saved).authTokens).toEqual(authTokens); + }); +}); diff --git a/nodejs/test/e2e/assisted_autopilot_permission.e2e.test.ts b/nodejs/test/e2e/assisted_autopilot_permission.e2e.test.ts index 9349d0091d..5577d03761 100644 --- a/nodejs/test/e2e/assisted_autopilot_permission.e2e.test.ts +++ b/nodejs/test/e2e/assisted_autopilot_permission.e2e.test.ts @@ -4,7 +4,7 @@ import { execFileSync } from "node:child_process"; import { existsSync } from "node:fs"; -import { mkdir, rm, writeFile } from "node:fs/promises"; +import { mkdir, realpath, rm, writeFile } from "node:fs/promises"; import { createServer } from "node:http"; import { join } from "node:path"; import { text } from "node:stream/consumers"; @@ -13,6 +13,7 @@ import { createAttributedPermissionResult, type CopilotSession, type NamedProviderConfig, + type PermissionRequest, type ProviderModelConfig, } from "../../src/index.js"; import { createSdkTestContext } from "./harness/sdkTestContext.js"; @@ -21,13 +22,33 @@ import { getNextEventOfType } from "./harness/sdkTestHelper.js"; const JUDGE_OUTPUT = "ALLOW: Explicitly authorized bounded filename search."; const HUMAN_REVIEW_OUTPUT = "DENY: Ask the registered human permission handler."; const SHELL_TOOL = process.platform === "win32" ? "powershell" : "bash"; +const EARLIER_RESTRICTION_MARKER = "ASSISTED_AUTHORIZATION_RESTRICT"; +const LATER_AUTHORIZATION_MARKER = "ASSISTED_AUTHORIZATION_ALLOW"; +const AUTHORIZATION_FIXTURE = "assisted-authorization-updated"; + +type ContractRecommendation = "approve" | "requireApproval" | "excluded"; +type ContractScope = "root" | "subagent"; + +function contractMarker(recommendation: ContractRecommendation): string { + return recommendation === "requireApproval" ? "REQUIRE" : recommendation.toUpperCase(); +} + +function contractShellCallId(scope: ContractScope, recommendation: ContractRecommendation): string { + const owner = scope === "subagent" ? "child" : "root"; + return `assisted-contract-${owner}-${recommendation}`; +} + +function contractFixtureName(scope: ContractScope, recommendation: ContractRecommendation): string { + return `assisted-contract-${recommendation}-${scope}`; +} describe("Assisted permission handling in Autopilot", async () => { const { copilotClient: client, workDir } = await createSdkTestContext({ useStdio: true }); - it("executes eligible shell and path ALLOWs without calling created or resumed SDK hosts", async () => { + it("resolves Assisted recommendations before Autopilot permission recovery", async () => { let agentCalls = 0; const judgeOutputs: string[] = []; + const authorizationJudgeRequests: string[] = []; const providerFailures: Error[] = []; const outsideDir = `${workDir}-outside`; await mkdir(outsideDir, { recursive: true }); @@ -42,6 +63,10 @@ describe("Assisted permission handling in Autopilot", async () => { }; const isJudge = body.model === "gpt-6-luna"; const messages = JSON.stringify(body.messages); + const latestUserMessage = [...body.messages] + .reverse() + .find((entry) => entry.role === "user"); + const latestUserText = JSON.stringify(latestUserMessage?.content); let message: | { role: "assistant"; content: string } | { @@ -54,9 +79,27 @@ describe("Assisted permission handling in Autopilot", async () => { }>; }; if (isJudge) { - const output = messages.includes("assisted-human-ask") - ? HUMAN_REVIEW_OUTPUT - : JUDGE_OUTPUT; + const earlierRestrictionIndex = messages.lastIndexOf( + EARLIER_RESTRICTION_MARKER + ); + const laterAuthorizationIndex = messages.lastIndexOf( + LATER_AUTHORIZATION_MARKER + ); + const authorizationRoute = laterAuthorizationIndex !== -1; + if (authorizationRoute) { + authorizationJudgeRequests.push(messages); + } + const contractRequiresApproval = + messages.includes(contractFixtureName("root", "requireApproval")) || + messages.includes(contractFixtureName("subagent", "requireApproval")); + const output = authorizationRoute + ? earlierRestrictionIndex !== -1 && + earlierRestrictionIndex < laterAuthorizationIndex + ? JUDGE_OUTPUT + : HUMAN_REVIEW_OUTPUT + : messages.includes("assisted-human-ask") || contractRequiresApproval + ? HUMAN_REVIEW_OUTPUT + : JUDGE_OUTPUT; judgeOutputs.push(output); message = { role: "assistant", content: output }; } else { @@ -64,90 +107,259 @@ describe("Assisted permission handling in Autopilot", async () => { const toolResultCount = body.messages.filter( (entry) => entry.role === "tool" ).length; - const primeIndex = messages.lastIndexOf("ASSISTED_SESSION_PRIME"); - const shellIndex = messages.lastIndexOf("ASSISTED_SHELL_"); - const pathIndex = messages.lastIndexOf("ASSISTED_PATH_ROUTE"); - const humanIndex = messages.lastIndexOf("ASSISTED_HUMAN_"); - const primeRoute = primeIndex > Math.max(shellIndex, pathIndex, humanIndex); - const humanRoute = humanIndex > Math.max(primeIndex, shellIndex, pathIndex); - const shellRoute = shellIndex > Math.max(primeIndex, pathIndex, humanIndex); - const resumedShellRoute = - messages.lastIndexOf("ASSISTED_SHELL_RESUME_ROUTE") === shellIndex; - const humanApproved = messages.includes("ASSISTED_HUMAN_APPROVE_"); - const humanLifecycle = - messages.includes("ASSISTED_HUMAN_APPROVE_RESUME_ROUTE") || - messages.includes("ASSISTED_HUMAN_DENY_RESUME_ROUTE") - ? "resume" - : "create"; - const finalText = humanRoute - ? humanApproved - ? "human-approved" - : "human-denied" - : shellRoute - ? "shell-approved" - : "approval-probe.txt"; - message = primeRoute - ? { role: "assistant", content: "prime-ready" } - : toolResultCount >= 2 - ? { + const contractChildRoute = latestUserText.includes("ASSISTED_CONTRACT_CHILD_"); + const contractSubagentRoute = latestUserText.includes( + "ASSISTED_CONTRACT_SUBAGENT_" + ); + const contractRootRoute = latestUserText.includes("ASSISTED_CONTRACT_ROOT_"); + const authorizationRestrictionRoute = latestUserText.includes( + EARLIER_RESTRICTION_MARKER + ); + const authorizationAllowRoute = latestUserText.includes( + LATER_AUTHORIZATION_MARKER + ); + if (authorizationRestrictionRoute) { + message = { role: "assistant", content: "restriction-recorded" }; + } else if (authorizationAllowRoute) { + message = + toolResultCount >= 2 + ? { role: "assistant", content: "authorization-updated" } + : toolResultCount === 1 + ? { + role: "assistant", + content: "", + tool_calls: [ + { + id: "assisted-authorization-task-complete", + type: "function", + function: { + name: "task_complete", + arguments: JSON.stringify({ + summary: "authorization-updated", + }), + }, + }, + ], + } + : { + role: "assistant", + content: "", + tool_calls: [ + { + id: "assisted-authorization-shell", + type: "function", + function: { + name: SHELL_TOOL, + arguments: JSON.stringify({ + command: + process.platform === "win32" + ? `New-Item -ItemType Directory -Path ${AUTHORIZATION_FIXTURE}` + : `mkdir ${AUTHORIZATION_FIXTURE}`, + description: + "Create the fixture authorized by the latest instruction", + }), + }, + }, + ], + }; + } else if (contractChildRoute || contractSubagentRoute || contractRootRoute) { + const recommendation: ContractRecommendation = latestUserText.includes( + "_REQUIRE" + ) + ? "requireApproval" + : latestUserText.includes("_EXCLUDED") + ? "excluded" + : "approve"; + const scope: ContractScope = + contractChildRoute || contractSubagentRoute ? "subagent" : "root"; + const finalText = `contract-${scope}-${ + recommendation === "approve" ? "approved" : "blocked" + }`; + if (contractSubagentRoute) { + message = + toolResultCount === 0 + ? { + role: "assistant", + content: "", + tool_calls: [ + { + id: `assisted-contract-task-${recommendation}`, + type: "function", + function: { + name: "task", + arguments: JSON.stringify({ + name: "assisted-contract", + description: + "Exercise an Assisted permission request", + prompt: `ASSISTED_CONTRACT_CHILD_${contractMarker( + recommendation + )}: Run the requested shell command once and report whether it completed.`, + agent_type: "task", + mode: "sync", + }), + }, + }, + ], + } + : { + role: "assistant", + content: "", + tool_calls: [ + { + id: `assisted-contract-task-complete-${recommendation}`, + type: "function", + function: { + name: "task_complete", + arguments: JSON.stringify({ + summary: finalText, + }), + }, + }, + ], + }; + } else if (contractChildRoute && toolResultCount > 0) { + message = { role: "assistant", content: finalText }; + } else if ( + (contractChildRoute || contractRootRoute) && + (toolResultCount === 0 || + (recommendation === "excluded" && toolResultCount === 1)) + ) { + const command = + recommendation === "excluded" + ? process.platform === "win32" + ? "Get-Content approval-probe.txt | & $runner" + : "printf payload | $runner" + : process.platform === "win32" + ? `New-Item -ItemType Directory -Path ${contractFixtureName( + scope, + recommendation + )}` + : `mkdir ${contractFixtureName(scope, recommendation)}`; + message = { role: "assistant", - content: finalText, - } - : toolResultCount === 1 - ? { - role: "assistant", - content: "", - tool_calls: [ - { - id: "assisted-autopilot-task-complete", - type: "function", - function: { - name: "task_complete", - arguments: JSON.stringify({ - summary: finalText, - }), + content: "", + tool_calls: [ + { + id: + toolResultCount === 0 + ? contractShellCallId(scope, recommendation) + : `${contractShellCallId( + scope, + recommendation + )}-retry`, + type: "function", + function: { + name: SHELL_TOOL, + arguments: JSON.stringify({ + command, + description: "Exercise Assisted permission routing", + }), + }, + }, + ], + }; + } else { + message = { + role: "assistant", + content: "", + tool_calls: [ + { + id: `assisted-contract-task-complete-${recommendation}`, + type: "function", + function: { + name: "task_complete", + arguments: JSON.stringify({ summary: finalText }), + }, + }, + ], + }; + } + } else { + const primeIndex = messages.lastIndexOf("ASSISTED_SESSION_PRIME"); + const shellIndex = messages.lastIndexOf("ASSISTED_SHELL_"); + const pathIndex = messages.lastIndexOf("ASSISTED_PATH_ROUTE"); + const humanIndex = messages.lastIndexOf("ASSISTED_HUMAN_"); + const primeRoute = primeIndex > Math.max(shellIndex, pathIndex, humanIndex); + const humanRoute = humanIndex > Math.max(primeIndex, shellIndex, pathIndex); + const shellRoute = shellIndex > Math.max(primeIndex, pathIndex, humanIndex); + const resumedShellRoute = + messages.lastIndexOf("ASSISTED_SHELL_RESUME_ROUTE") === shellIndex; + const humanApproved = messages.includes("ASSISTED_HUMAN_APPROVE_"); + const humanLifecycle = + messages.includes("ASSISTED_HUMAN_APPROVE_RESUME_ROUTE") || + messages.includes("ASSISTED_HUMAN_DENY_RESUME_ROUTE") + ? "resume" + : "create"; + const finalText = humanRoute + ? humanApproved + ? "human-approved" + : "human-denied" + : shellRoute + ? "shell-approved" + : "approval-probe.txt"; + message = primeRoute + ? { role: "assistant", content: "prime-ready" } + : toolResultCount >= 2 + ? { + role: "assistant", + content: finalText, + } + : toolResultCount === 1 + ? { + role: "assistant", + content: "", + tool_calls: [ + { + id: "assisted-autopilot-task-complete", + type: "function", + function: { + name: "task_complete", + arguments: JSON.stringify({ + summary: finalText, + }), + }, }, - }, - ], - } - : { - role: "assistant", - content: "", - tool_calls: [ - { - id: shellRoute - ? "assisted-autopilot-shell" - : humanRoute - ? "assisted-autopilot-human" - : "assisted-autopilot-glob", - type: "function", - function: - shellRoute || humanRoute - ? { - name: SHELL_TOOL, - arguments: JSON.stringify({ - command: humanRoute - ? process.platform === "win32" - ? `New-Item -ItemType Directory -Path assisted-human-ask-${humanApproved ? "approve" : "deny"}-${humanLifecycle}` - : `mkdir assisted-human-ask-${humanApproved ? "approve" : "deny"}-${humanLifecycle}` - : process.platform === "win32" - ? `New-Item -ItemType Directory -Path assisted-shell-${resumedShellRoute ? "resume" : "create"}` - : `mkdir assisted-shell-${resumedShellRoute ? "resume" : "create"}`, - description: humanRoute - ? "Create the human-reviewed SDK permission fixture" - : "Create the authorized SDK permission fixture", - }), - } - : { - name: "glob", - arguments: JSON.stringify({ - pattern: "*.txt", - path: outsideDir, - }), - }, - }, - ], - }; + ], + } + : { + role: "assistant", + content: "", + tool_calls: [ + { + id: shellRoute + ? "assisted-autopilot-shell" + : humanRoute + ? "assisted-autopilot-human" + : "assisted-autopilot-glob", + type: "function", + function: + shellRoute || humanRoute + ? { + name: SHELL_TOOL, + arguments: JSON.stringify({ + command: humanRoute + ? process.platform === "win32" + ? `New-Item -ItemType Directory -Path assisted-human-ask-${humanApproved ? "approve" : "deny"}-${humanLifecycle}` + : `mkdir assisted-human-ask-${humanApproved ? "approve" : "deny"}-${humanLifecycle}` + : process.platform === "win32" + ? `New-Item -ItemType Directory -Path assisted-shell-${resumedShellRoute ? "resume" : "create"}` + : `mkdir assisted-shell-${resumedShellRoute ? "resume" : "create"}`, + description: humanRoute + ? "Create the human-reviewed SDK permission fixture" + : "Create the authorized SDK permission fixture", + }), + } + : { + name: "glob", + arguments: JSON.stringify({ + pattern: "*.txt", + path: outsideDir, + }), + }, + }, + ], + }; + } } const choice = { @@ -243,11 +455,23 @@ describe("Assisted permission handling in Autopilot", async () => { ] as const; for (const scenario of scenarios) { let permissionCallbacks = 0; + const expectedRecommendation = + scenario.decision === "judge" ? "approve" : "requireApproval"; + const recommendationByToolCallId = new Map(); + const recommendationWaiters = new Map< + string, + (recommendation: string | undefined) => void + >(); const recommendations: string[] = []; const recoveryStatuses: string[] = []; const toolResults: Array<{ success?: boolean; result?: { content?: string } }> = []; const decisionSources: string[] = []; - const taskOutcomes: Array<{ success?: boolean; summary?: string }> = []; + const taskOutcomes: Array<{ + success?: boolean; + summary?: string; + outcome?: string; + reason?: string; + }> = []; const sessionConfig = { model: "local/gpt-5.6-sol", providers, @@ -259,8 +483,26 @@ describe("Assisted permission handling in Autopilot", async () => { AUTO_APPROVAL: true, ASSISTED_PERMISSIONS_V2: true, }, - onPermissionRequest: () => { + onPermissionRequest: async (request: PermissionRequest) => { permissionCallbacks++; + if (!request.toolCallId) { + throw new Error( + "Expected the permission request to identify its tool call" + ); + } + const recommendation = recommendationByToolCallId.has(request.toolCallId) + ? recommendationByToolCallId.get(request.toolCallId) + : await new Promise((resolve) => { + recommendationWaiters.set(request.toolCallId!, resolve); + }); + recommendationByToolCallId.delete(request.toolCallId); + if (recommendation !== expectedRecommendation) { + throw new Error( + `Expected Assisted recommendation ${expectedRecommendation}, got ${String( + recommendation + )}` + ); + } if (scenario.decision === "judge") { return createAttributedPermissionResult( { kind: "approve-once" }, @@ -291,11 +533,15 @@ describe("Assisted permission handling in Autopilot", async () => { await session.sendAndWait({ prompt: "ASSISTED_SESSION_PRIME: Reply with prime-ready without tools.", }); + await configureAssistedAutopilot(session, workDir); + await expectAssistedAutopilotConfigured(session, workDir); await session.disconnect(); session = undefined; session = await client.resumeSession(sessionId, sessionConfig); + await expectAssistedAutopilotConfigured(session, workDir); + } else { + await configureAssistedAutopilot(session, workDir); } - await configureAssistedAutopilot(session, workDir); session.on((event) => { if (event.type === "permission.requested") { const promptRequest = ( @@ -309,6 +555,20 @@ describe("Assisted permission handling in Autopilot", async () => { const recommendation = promptRequest?.assistedApproval?.recommendation ?? promptRequest?.autoApproval?.recommendation; + const toolCallId = ( + event.data as { + permissionRequest?: { toolCallId?: string }; + } + ).permissionRequest?.toolCallId; + if (toolCallId) { + const waiter = recommendationWaiters.get(toolCallId); + if (waiter) { + recommendationWaiters.delete(toolCallId); + waiter(recommendation); + } else { + recommendationByToolCallId.set(toolCallId, recommendation); + } + } if (recommendation) recommendations.push(recommendation); } else if (event.type === "permission.completed") { const source = (event.data as { decisionSource?: string }).decisionSource; @@ -337,12 +597,11 @@ describe("Assisted permission handling in Autopilot", async () => { throw new Error(`${JSON.stringify(scenario)} failed`, { cause: error }); } - const expectedCompletions = scenario.route === "path" ? 2 : 1; + const expectedCompletions = + scenario.route === "path" && scenario.lifecycle === "create" ? 2 : 1; expect(permissionCallbacks, JSON.stringify(scenario)).toBe(expectedCompletions); expect(recommendations, JSON.stringify(scenario)).toEqual( - Array(expectedCompletions).fill( - scenario.decision === "judge" ? "approve" : "requireApproval" - ) + Array(expectedCompletions).fill(expectedRecommendation) ); expect(decisionSources, JSON.stringify(scenario)).toEqual( Array(expectedCompletions).fill( @@ -399,6 +658,380 @@ describe("Assisted permission handling in Autopilot", async () => { ...Array(4).fill(HUMAN_REVIEW_OUTPUT), ]); expect(agentCalls).toBe(scenarios.length * 2 + 4); + + const authorizationJudgeStart = judgeOutputs.length; + let authorizationPermissionCallbacks = 0; + const authorizationRecommendations: string[] = []; + const authorizationDecisionSources: string[] = []; + const authorizationRecoveryStatuses: string[] = []; + const authorizationToolResults: Array<{ toolCallId?: string; success?: boolean }> = []; + const authorizationTaskOutcomes: Array<{ success?: boolean; summary?: string }> = []; + let resolveAuthorizationRecommendation: (recommendation: string | undefined) => void; + const authorizationRecommendation = new Promise((resolve) => { + resolveAuthorizationRecommendation = resolve; + }); + let authorizationSession: CopilotSession | undefined; + try { + authorizationSession = await client.createSession({ + model: "local/gpt-5.6-sol", + providers, + models, + availableTools: [SHELL_TOOL, "task_complete"], + streaming: false, + skipCustomInstructions: true, + featureFlags: { + AUTO_APPROVAL: true, + ASSISTED_PERMISSIONS_V2: true, + }, + onPermissionRequest: async (request) => { + authorizationPermissionCallbacks++; + if (request.toolCallId !== "assisted-authorization-shell") { + throw new Error( + `Expected authorization shell permission, got ${String( + request.toolCallId + )}` + ); + } + const recommendation = await authorizationRecommendation; + if (recommendation !== "approve") { + throw new Error( + `Expected later authorization to reach the judge as approve, got ${String( + recommendation + )}` + ); + } + return createAttributedPermissionResult( + { kind: "approve-once" }, + { + outcome: "auto_approved", + source: "assisted_approval", + surface: "sdk", + responseCapability: "headless", + } + ); + }, + }); + await authorizationSession.sendAndWait({ + prompt: `${EARLIER_RESTRICTION_MARKER}: Do not create the authorization fixture. Reply restriction-recorded without tools.`, + }); + await configureAssistedAutopilot(authorizationSession, workDir); + authorizationSession.on((event) => { + if (event.type === "permission.requested") { + const recommendation = ( + event.data as { + promptRequest?: { + assistedApproval?: { recommendation?: string }; + }; + } + ).promptRequest?.assistedApproval?.recommendation; + if (recommendation) { + authorizationRecommendations.push(recommendation); + } + resolveAuthorizationRecommendation(recommendation); + } else if (event.type === "permission.completed") { + const source = (event.data as { decisionSource?: string }).decisionSource; + if (source) authorizationDecisionSources.push(source); + } else if (event.type === "session.permission_recovery") { + authorizationRecoveryStatuses.push((event.data as { status: string }).status); + } else if (event.type === "tool.execution_complete") { + authorizationToolResults.push({ + toolCallId: event.data.toolCallId, + success: event.data.success, + }); + } else if (event.type === "session.task_complete") { + authorizationTaskOutcomes.push(event.data); + } + }); + + const taskComplete = getNextEventOfType(authorizationSession, "session.task_complete"); + await authorizationSession.send({ + prompt: `${LATER_AUTHORIZATION_MARKER}: The earlier restriction is superseded. Create the authorization fixture now and report authorization-updated.`, + }); + await taskComplete; + + expect(judgeOutputs.slice(authorizationJudgeStart)).toEqual([JUDGE_OUTPUT]); + expect(authorizationJudgeRequests).toHaveLength(1); + const authorizationRequest = authorizationJudgeRequests[0] ?? ""; + expect(authorizationRequest.indexOf(EARLIER_RESTRICTION_MARKER)).toBeGreaterThanOrEqual( + 0 + ); + expect(authorizationRequest.indexOf(LATER_AUTHORIZATION_MARKER)).toBeGreaterThan( + authorizationRequest.indexOf(EARLIER_RESTRICTION_MARKER) + ); + expect(authorizationPermissionCallbacks).toBe(1); + expect(authorizationRecommendations).toEqual(["approve"]); + expect(authorizationDecisionSources).toEqual(["assisted_approval"]); + expect(authorizationRecoveryStatuses).toEqual([]); + expect(authorizationToolResults).toContainEqual({ + toolCallId: "assisted-authorization-shell", + success: true, + }); + expect(authorizationTaskOutcomes).toEqual([ + expect.objectContaining({ + success: true, + summary: "authorization-updated", + }), + ]); + expect(existsSync(join(workDir, AUTHORIZATION_FIXTURE))).toBe(true); + } finally { + if (authorizationSession) { + await authorizationSession.abort(); + await authorizationSession.disconnect(); + } + } + + const contractScenarios = [ + { scope: "root", recommendation: "approve", handler: "registered" }, + { scope: "root", recommendation: "requireApproval", handler: "registered" }, + { scope: "root", recommendation: "excluded", handler: "registered" }, + { scope: "subagent", recommendation: "approve", handler: "registered" }, + { scope: "subagent", recommendation: "requireApproval", handler: "registered" }, + { scope: "root", recommendation: "requireApproval", handler: "none" }, + ] as const satisfies readonly { + scope: ContractScope; + recommendation: ContractRecommendation; + handler: "registered" | "none"; + }[]; + const contractJudgeStart = judgeOutputs.length; + for (const scenario of contractScenarios) { + let permissionCallbacks = 0; + const recommendations: string[] = []; + const recoveryStatuses: string[] = []; + const decisionSources: string[] = []; + const sequence: string[] = []; + const subagentIds = new Set(); + const permissionAgentIds: Array = []; + const toolResults: Array<{ + agentId?: string; + toolCallId?: string; + success?: boolean; + error?: { message?: string }; + result?: unknown; + }> = []; + const taskOutcomes: Array<{ success?: boolean; summary?: string }> = []; + const onPermissionRequest = () => { + permissionCallbacks++; + sequence.push("host"); + if (scenario.recommendation === "approve") { + return createAttributedPermissionResult( + { kind: "approve-once" }, + { + outcome: "auto_approved", + source: "assisted_approval", + surface: "sdk", + responseCapability: "headless", + } + ); + } + if (scenario.recommendation === "requireApproval") { + return createAttributedPermissionResult( + { + kind: "reject", + feedback: HUMAN_REVIEW_OUTPUT.replace(/^DENY:\s*/, ""), + }, + { + outcome: "autopilot_denied", + source: "assisted_approval", + surface: "sdk", + responseCapability: "headless", + } + ); + } + if (scenario.recommendation === "excluded") { + return createAttributedPermissionResult( + { kind: "user-not-available" }, + { + outcome: "autopilot_denied", + source: "unattended_fallback", + surface: "sdk", + responseCapability: "headless", + } + ); + } + throw new Error("Unexpected Assisted permission recommendation"); + }; + const sessionConfig = { + model: "local/gpt-5.6-sol", + providers, + models, + availableTools: [SHELL_TOOL, "task", "task_complete"], + streaming: false, + skipCustomInstructions: true, + featureFlags: { + AUTO_APPROVAL: true, + ASSISTED_PERMISSIONS_V2: true, + }, + ...(scenario.handler === "registered" ? { onPermissionRequest } : {}), + } as const; + let session: CopilotSession | undefined; + try { + session = await client.createSession(sessionConfig); + await configureAssistedAutopilot(session, workDir); + session.on((event) => { + if (event.type === "permission.requested") { + const promptRequest = ( + event.data as { + promptRequest?: { + assistedApproval?: { recommendation?: string }; + autoApproval?: { recommendation?: string }; + }; + } + ).promptRequest; + const recommendation = + promptRequest?.assistedApproval?.recommendation ?? + promptRequest?.autoApproval?.recommendation; + if (recommendation) { + recommendations.push(recommendation); + sequence.push(`permission:${recommendation}`); + } + permissionAgentIds.push(event.agentId); + } else if (event.type === "permission.completed") { + const source = (event.data as { decisionSource?: string }).decisionSource; + if (source) decisionSources.push(source); + } else if (event.type === "session.permission_recovery") { + const status = (event.data as { status: string }).status; + recoveryStatuses.push(status); + sequence.push(`recovery:${status}`); + } else if (event.type === "tool.execution_complete") { + toolResults.push({ + agentId: event.agentId, + toolCallId: event.data.toolCallId, + success: event.data.success, + error: event.data.error, + result: event.data.result, + }); + } else if (event.type === "session.task_complete") { + taskOutcomes.push(event.data); + } else if (event.type === "subagent.started") { + subagentIds.add(event.agentId); + } + }); + + const marker = contractMarker(scenario.recommendation); + const prompt = + scenario.scope === "root" + ? `ASSISTED_CONTRACT_ROOT_${marker}: Run the requested shell command once and report the outcome.` + : `ASSISTED_CONTRACT_SUBAGENT_${marker}: Use the task tool once so a task subagent runs the requested shell command.`; + try { + const taskComplete = getNextEventOfType(session, "session.task_complete"); + await session.send({ prompt }); + await taskComplete; + } catch (error) { + throw new Error(`${JSON.stringify(scenario)} failed`, { cause: error }); + } + + if (scenario.handler === "none") { + expect(permissionCallbacks, JSON.stringify(scenario)).toBe(0); + expect(recommendations, JSON.stringify(scenario)).toEqual([]); + } else if (scenario.recommendation === "approve") { + expect(permissionCallbacks, JSON.stringify(scenario)).toBe(1); + expect(recommendations, JSON.stringify(scenario)).toEqual(["approve"]); + } else if (scenario.recommendation === "requireApproval") { + expect(permissionCallbacks, JSON.stringify(scenario)).toBe(1); + expect(recommendations, JSON.stringify(scenario)).toEqual(["requireApproval"]); + } else { + expect(permissionCallbacks, JSON.stringify(scenario)).toBeGreaterThanOrEqual(1); + expect(recommendations, JSON.stringify(scenario)).toEqual( + Array(permissionCallbacks).fill("excluded") + ); + } + if (scenario.handler === "none") { + expect(decisionSources, JSON.stringify(scenario)).toEqual([]); + expect(recoveryStatuses, JSON.stringify(scenario)).toEqual(["recovering"]); + } else { + expect(decisionSources, JSON.stringify(scenario)).toContain( + scenario.recommendation === "excluded" + ? "unattended_fallback" + : "assisted_approval" + ); + } + if (scenario.recommendation === "excluded") { + expect(recoveryStatuses.at(-1), JSON.stringify(scenario)).toBe("blocked"); + } else if (scenario.handler === "registered") { + expect(recoveryStatuses, JSON.stringify(scenario)).toEqual([]); + } + const hostIndex = sequence.indexOf("host"); + const firstRecoveryIndex = sequence.findIndex((entry) => + entry.startsWith("recovery:") + ); + if (firstRecoveryIndex !== -1 && scenario.handler === "registered") { + expect( + hostIndex, + JSON.stringify({ scenario, sequence }) + ).toBeGreaterThanOrEqual(0); + expect(hostIndex, JSON.stringify({ scenario, sequence })).toBeLessThan( + firstRecoveryIndex + ); + } + + const shellResult = toolResults.find( + (result) => + result.toolCallId === + contractShellCallId(scenario.scope, scenario.recommendation) + ); + expect(shellResult, JSON.stringify({ scenario, toolResults })).toBeDefined(); + expect(shellResult?.success, JSON.stringify(scenario)).toBe( + scenario.recommendation === "approve" && scenario.handler === "registered" + ); + if ( + scenario.recommendation === "requireApproval" && + scenario.handler === "registered" + ) { + expect(shellResult?.error?.message, JSON.stringify(scenario)).toContain( + "Ask the registered human permission handler." + ); + } else if (scenario.handler === "none") { + expect(shellResult?.error?.message, JSON.stringify(scenario)).toContain( + "Permission could not be granted automatically." + ); + } + if (scenario.scope === "subagent") { + expect(subagentIds.size, JSON.stringify(scenario)).toBe(1); + expect( + subagentIds.has(shellResult?.agentId ?? ""), + JSON.stringify(scenario) + ).toBe(true); + for (const agentId of permissionAgentIds) { + expect(subagentIds.has(agentId ?? ""), JSON.stringify(scenario)).toBe(true); + } + } + + expect( + existsSync( + join(workDir, contractFixtureName(scenario.scope, scenario.recommendation)) + ), + JSON.stringify(scenario) + ).toBe(scenario.recommendation === "approve" && scenario.handler === "registered"); + expect( + (await session.rpc.permissions.pendingRequests()).items, + JSON.stringify(scenario) + ).toEqual([]); + expect(taskOutcomes, JSON.stringify(scenario)).toHaveLength(1); + expect(taskOutcomes[0]?.success, JSON.stringify(scenario)).toBe( + scenario.recommendation !== "excluded" && scenario.handler === "registered" + ); + if (scenario.handler === "none") { + expect(taskOutcomes[0], JSON.stringify(scenario)).toMatchObject({ + outcome: "continue", + reason: "Autopilot is still recovering from a required permission.", + }); + } + } finally { + if (session) { + await session.abort(); + await session.disconnect(); + } + } + } + + expect(providerFailures).toEqual([]); + expect(judgeOutputs.slice(contractJudgeStart)).toEqual([ + JUDGE_OUTPUT, + HUMAN_REVIEW_OUTPUT, + JUDGE_OUTPUT, + HUMAN_REVIEW_OUTPUT, + HUMAN_REVIEW_OUTPUT, + ]); }); }); @@ -422,3 +1055,15 @@ async function configureAssistedAutopilot(session: CopilotSession, workDir: stri }); await session.rpc.mode.set({ mode: "autopilot" }); } + +async function expectAssistedAutopilotConfigured( + session: CopilotSession, + workDir: string +): Promise { + expect(await session.rpc.mode.get()).toBe("autopilot"); + expect(await session.rpc.permissions.getMode()).toMatchObject({ mode: "assisted" }); + expect((await session.rpc.permissions.folderTrust.isTrusted({ path: workDir })).trusted).toBe( + true + ); + expect((await session.rpc.permissions.paths.list()).primary).toBe(await realpath(workDir)); +} diff --git a/nodejs/test/e2e/computer_use_oauth.e2e.test.ts b/nodejs/test/e2e/computer_use_oauth.e2e.test.ts new file mode 100644 index 0000000000..76bdd90390 --- /dev/null +++ b/nodejs/test/e2e/computer_use_oauth.e2e.test.ts @@ -0,0 +1,347 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import { execFileSync } from "node:child_process"; +import { mkdir, mkdtemp, readFile, realpath, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { describe, test, type TestContext } from "vitest"; +import { approveAll, CopilotClient, RuntimeConnection } from "../../src/index.js"; +import { startComputerUseOAuthServer } from "../../../test/harness/test-mcp-computer-use-oauth-server.mjs"; +import { createSdkTestContext, DEFAULT_GITHUB_TOKEN } from "./harness/sdkTestContext.js"; + +const TEST_MCP_SERVER = fileURLToPath( + new URL("../../../test/harness/test-mcp-server.mjs", import.meta.url) +); +const SERVER_NAME = "unrelated-oauth"; + +describe("Computer Use OAuth isolation", async () => { + const { env } = await createSdkTestContext(); + + async function createFixture(context: TestContext, preference?: boolean, startup = false) { + // The shared harness clears workDir before this fixture's onTestFinished cleanup. + const directory = await realpath(await mkdtemp(join(tmpdir(), "computer-use-oauth-"))); + const home = join(directory, "home"); + const plugin = join(directory, "computer-use"); + let client: CopilotClient | undefined; + const startingOAuthServer = startComputerUseOAuthServer({ + deferRegistration: !startup, + deferInitialChallenge: startup, + deferAuthorizationMetadata: startup, + preconfiguredClientId: startup ? "app-client" : "", + }); + context.onTestFinished(async () => { + const errors: unknown[] = []; + const [serverStartup] = await Promise.allSettled([startingOAuthServer]); + if (serverStartup.status === "fulfilled") { + serverStartup.value.releaseRegistration(); + serverStartup.value.releaseInitialChallenge(); + serverStartup.value.releaseAuthorizationMetadata(); + } + if (client) { + try { + await readFile(join(plugin, ".plugin", "plugin.json"), "utf8"); + } catch (error) { + errors.push( + new Error( + "Computer Use OAuth fixture was removed before its client stopped", + { + cause: error, + } + ) + ); + } + try { + errors.push(...(await client.stop())); + } catch (error) { + errors.push(error); + } + } + if (serverStartup.status === "fulfilled") { + try { + await serverStartup.value.close(); + } catch (error) { + errors.push(error); + } + } + try { + await rm(directory, { + recursive: true, + force: true, + maxRetries: 10, + retryDelay: 100, + }); + } catch (error) { + errors.push(error); + } + if (errors.length) + throw new AggregateError(errors, "Computer Use OAuth cleanup failed"); + }); + const oauthServer = await startingOAuthServer; + context.signal.throwIfAborted(); + await mkdir(home); + await mkdir(join(plugin, ".plugin"), { recursive: true }); + execFileSync("git", ["init", "--quiet", directory], { windowsHide: true }); + if (preference !== undefined) { + await writeFile( + join(home, "settings.json"), + JSON.stringify({ + enabledPlugins: { "computer-use": preference }, + }) + ); + } + await writeFile( + join(plugin, ".plugin", "plugin.json"), + JSON.stringify({ + name: "computer-use", + version: "1.0.0", + mcpServers: "./.mcp.json", + }) + ); + await writeFile( + join(plugin, ".mcp.json"), + JSON.stringify({ + mcpServers: { + "computer-use": { + command: process.execPath, + args: [TEST_MCP_SERVER, "--server-name", "computer-use"], + cwd: dirname(TEST_MCP_SERVER), + tools: ["*"], + }, + }, + }) + ); + client = new CopilotClient({ + workingDirectory: directory, + env: { + ...env, + COPILOT_HOME: home, + GH_CONFIG_DIR: home, + XDG_CONFIG_HOME: home, + XDG_STATE_HOME: home, + COPILOT_DISABLE_KEYTAR: "1", + }, + gitHubToken: DEFAULT_GITHUB_TOKEN, + connection: RuntimeConnection.forStdio({ path: process.env.COPILOT_CLI_PATH }), + }); + await client.start(); + context.signal.throwIfAborted(); + await client.rpc.plugins.builtin.set({ paths: [plugin] }); + const session = await client.createSession({ + workingDirectory: directory, + onPermissionRequest: approveAll, + onMcpAuthRequest: async () => ({ kind: "cancelled" }), + mcpServers: { + [SERVER_NAME]: { + type: "http", + url: `${oauthServer.url}/mcp`, + tools: ["*"], + ...(startup ? { oauthClientId: "app-client", oauthPublicClient: true } : {}), + }, + }, + }); + return { client, session, oauthServer }; + } + + test.for([ + { preference: "unset", hosted: false }, + { preference: "disabled", hosted: false }, + { preference: "unset", hosted: true }, + { preference: "disabled", hosted: true }, + ] as const)( + "returns the initial OAuth URL across Computer Use toggles ($preference, hosted=$hosted)", + { timeout: 90_000 }, + async ({ preference, hosted }, context) => { + const { expect } = context; + const { client, session, oauthServer } = await createFixture( + context, + preference === "disabled" ? false : undefined + ); + const [initial] = await Promise.all([ + session.rpc.mcp.list(), + session.rpc.plugins.list(), + ]); + expect(initial.servers.map((server) => server.name)).not.toContain("computer-use"); + const login = session.rpc.mcp.oauth + .login({ + serverName: SERVER_NAME, + forceReauth: true, + ...(hosted ? { redirectUri: "https://agent.example.test/oauth/callback" } : {}), + }) + .then( + (result) => ({ result }), + (error: unknown) => ({ error }) + ); + // Registration is after lifetime capture but before the browser URL is returned. + await expect + .poll(() => oauthServer.requests.map((request) => request.path), { + timeout: 60_000, + }) + .toContain("/register"); + for (const enabled of [true, false, true]) { + if (enabled) await client.rpc.plugins.enable({ names: ["computer-use"] }); + else await client.rpc.plugins.disable({ names: ["computer-use"] }); + await expect + .poll( + async () => + (await session.rpc.mcp.list()).servers.find( + (candidate) => candidate.name === "computer-use" + )?.status, + { timeout: 60_000 } + ) + .toBe(enabled ? "connected" : undefined); + } + oauthServer.releaseRegistration(); + const outcome = await login; + if ("error" in outcome) throw outcome.error; + const result = outcome.result; + expect(result.authorizationUrl).toBeDefined(); + const authorization = new URL(result.authorizationUrl!); + expect(authorization.origin).toBe(oauthServer.url); + expect(authorization.searchParams.get("client_id")).toBe("registered-client"); + + await client.rpc.plugins.disable({ names: ["computer-use"] }); + await expect + .poll( + async () => (await session.rpc.mcp.list()).servers.map((server) => server.name), + { timeout: 60_000 } + ) + .not.toContain("computer-use"); + const callback = new URL(authorization.searchParams.get("redirect_uri")!); + callback.searchParams.set("code", "accepted-code"); + callback.searchParams.set("state", authorization.searchParams.get("state")!); + if (hosted) { + expect(result.authorizationId).toBe(authorization.searchParams.get("state")); + expect(callback.origin).toBe("https://agent.example.test"); + await session.rpc.mcp.oauth.complete({ + authorizationId: result.authorizationId!, + callbackUrl: callback.toString(), + }); + } else { + const response = await fetch(callback); + expect(response.ok).toBe(true); + } + await expect + .poll( + async () => + (await session.rpc.mcp.list()).servers.find( + (server) => server.name === SERVER_NAME + )?.status, + { timeout: 60_000 } + ) + .toBe("connected"); + expect( + (await session.rpc.mcp.listTools({ serverName: SERVER_NAME })).tools.map( + (tool) => tool.name + ) + ).toContain("whoami"); + const tokens = oauthServer.requests.filter((request) => request.path === "/token"); + expect(tokens).toHaveLength(1); + expect(new URLSearchParams(tokens[0].body).get("client_id")).toBe("registered-client"); + } + ); + + test.for(["unset", "disabled"] as const)( + "preserves preconfigured-client OAuth overlapping initial discovery (%s preference)", + { timeout: 90_000 }, + async (preference, context) => { + const { expect } = context; + const { client, session, oauthServer } = await createFixture( + context, + preference === "disabled" ? false : undefined, + true + ); + const discovery = session.rpc.mcp.list().then( + (result) => ({ result }), + (error: unknown) => ({ error }) + ); + const login = session.rpc.mcp.oauth.login({ serverName: SERVER_NAME }).then( + (result) => ({ result }), + (error: unknown) => ({ error }) + ); + await expect + .poll(() => oauthServer.requests.filter((request) => request.path === "/mcp"), { + timeout: 60_000, + }) + .not.toHaveLength(0); + await session.rpc.plugins.list(); + oauthServer.releaseInitialChallenge(); + await expect + .poll(() => oauthServer.requests.map((request) => request.path), { + timeout: 60_000, + }) + .toContain("/.well-known/oauth-authorization-server"); + const discovered = await discovery; + if ("error" in discovered) throw discovered.error; + expect(discovered.result.servers.map((server) => server.name)).not.toContain( + "computer-use" + ); + await client.rpc.plugins.enable({ names: ["computer-use"] }); + await expect + .poll( + async () => + (await session.rpc.mcp.list()).servers.find( + (server) => server.name === "computer-use" + )?.status, + { timeout: 60_000 } + ) + .toBe("connected"); + oauthServer.releaseAuthorizationMetadata(); + const outcome = await login; + if ("error" in outcome) throw outcome.error; + const authorization = new URL(outcome.result.authorizationUrl!); + expect(authorization.searchParams.get("client_id")).toBe("app-client"); + const callback = new URL(authorization.searchParams.get("redirect_uri")!); + callback.searchParams.set("code", "accepted-code"); + callback.searchParams.set("state", authorization.searchParams.get("state")!); + expect((await fetch(callback)).ok).toBe(true); + await expect + .poll( + async () => + (await session.rpc.mcp.list()).servers.find( + (server) => server.name === SERVER_NAME + )?.status, + { timeout: 60_000 } + ) + .toBe("connected"); + expect( + (await session.rpc.mcp.listTools({ serverName: SERVER_NAME })).tools.map( + (tool) => tool.name + ) + ).toContain("whoami"); + expect( + oauthServer.requests.filter((request) => request.path === "/register") + ).toHaveLength(0); + const tokens = oauthServer.requests.filter((request) => request.path === "/token"); + expect(tokens).toHaveLength(1); + expect(new URLSearchParams(tokens[0].body).get("client_id")).toBe("app-client"); + } + ); + + test("still cancels initial OAuth when its own server is reloaded", async (context) => { + const { expect } = context; + const { session, oauthServer } = await createFixture(context); + await session.rpc.mcp.list(); + const login = session.rpc.mcp.oauth + .login({ serverName: SERVER_NAME, forceReauth: true }) + .then( + (result) => ({ result }), + (error: unknown) => ({ error }) + ); + await expect + .poll(() => oauthServer.requests.map((request) => request.path), { timeout: 60_000 }) + .toContain("/register"); + await session.rpc.mcp.reload(); + oauthServer.releaseRegistration(); + expect(await login).toEqual({ + error: expect.objectContaining({ + message: expect.stringContaining( + "MCP OAuth was cancelled because its original requester or configuration changed." + ), + }), + }); + expect(oauthServer.requests.filter((request) => request.path === "/token")).toHaveLength(0); + }, 90_000); +}); diff --git a/nodejs/test/e2e/entra_identity_first.e2e.test.ts b/nodejs/test/e2e/entra_identity_first.e2e.test.ts index 2a6e49fff2..38da660fb7 100644 --- a/nodejs/test/e2e/entra_identity_first.e2e.test.ts +++ b/nodejs/test/e2e/entra_identity_first.e2e.test.ts @@ -393,6 +393,20 @@ describe("Entra identity-first resource discovery", () => { configDirectory: profile, onPermissionRequest: approveAll, }); + if (process.platform === "linux") { + await expect(session.rpc.accounts.login.begin({ kind: "entra" })).rejects.toThrow( + "only on Windows and macOS" + ); + expect(grants).toEqual([]); + expect(catalogs).toEqual([]); + expect( + await session.rpc.accounts.get({ query: { kind: "activeAccount" } }) + ).toEqual({ + kind: "activeAccount", + account: null, + }); + return; + } const { flowId } = await session.rpc.accounts.login.begin({ kind: "entra" }); const step = await session.rpc.accounts.login.advance({ flowId }); expect(step.kind).toBe("open-url"); diff --git a/nodejs/test/e2e/entra_renewal.e2e.test.ts b/nodejs/test/e2e/entra_renewal.e2e.test.ts index e040d8a905..82f20c6a27 100644 --- a/nodejs/test/e2e/entra_renewal.e2e.test.ts +++ b/nodejs/test/e2e/entra_renewal.e2e.test.ts @@ -197,6 +197,16 @@ it("requires linked sign-in, adopts same-session re-login, and persists silent r ); expect(modelRequests).toEqual([]); expect(grants).toBe(0); + if (process.platform === "linux") { + await expect(session.rpc.accounts.login.begin({ kind: "entra" })).rejects.toThrow( + "only on Windows and macOS" + ); + expect(signIns).toBe(0); + expect(exchanges).toBe(0); + expect(grants).toBe(0); + expect(modelRequests).toEqual([]); + return; + } const signIn = async () => { const { flowId } = await session.rpc.accounts.login.begin({ kind: "entra" }); diff --git a/nodejs/test/e2e/harness/webSocketResponsesServer.ts b/nodejs/test/e2e/harness/webSocketResponsesServer.ts index 219100a97f..de4810802c 100644 --- a/nodejs/test/e2e/harness/webSocketResponsesServer.ts +++ b/nodejs/test/e2e/harness/webSocketResponsesServer.ts @@ -14,6 +14,9 @@ export async function startWebSocketResponsesServer() { messages: [] as Array>, messageConnectionIds: [] as number[], responses: [] as WebSocketReply[], + /** Scripted HTTP `/responses` SSE replies; when empty, HTTP requests are forwarded. */ + httpResponses: [] as WebSocketEnvelope[][], + httpResponseRequestPaths: [] as string[], openConnectionIds: new Set(), connectionCount: 0, closedConnectionCount: 0, @@ -51,6 +54,24 @@ export async function startWebSocketResponsesServer() { ); return; } + const scriptedHttpEvents = + req.method === "POST" && + new URL(req.url ?? "/", "http://localhost").pathname.endsWith("/responses") + ? state.httpResponses.shift() + : undefined; + if (scriptedHttpEvents) { + state.httpResponseRequestPaths.push(req.url ?? "/"); + req.resume(); + req.on("error", (error) => errors.push(error)); + req.on("end", () => { + res.writeHead(200, { "content-type": "text/event-stream" }); + for (const event of scriptedHttpEvents) { + res.write(`event: ${String(event.type)}\ndata: ${JSON.stringify(event)}\n\n`); + } + res.end(); + }); + return; + } if (!httpTargetUrl) { res.writeHead(503); res.end("The test CAPI proxy has not been attached."); diff --git a/nodejs/test/e2e/managed_permissions_limit_to.e2e.test.ts b/nodejs/test/e2e/managed_permissions_limit_to.e2e.test.ts index 1d02686699..1ec520429d 100644 --- a/nodejs/test/e2e/managed_permissions_limit_to.e2e.test.ts +++ b/nodejs/test/e2e/managed_permissions_limit_to.e2e.test.ts @@ -18,6 +18,123 @@ function closeServer(server: Server): Promise { describe("Managed permissions limitTo", async () => { const { copilotClient: client, workDir } = await createSdkTestContext(); + it("evaluates retained managed network policy without invoking the permission handler", async () => { + let permissionRequests = 0; + const session = await client.createSession({ + managedSettings: { + permissions: { + limitTo: ["Domain(*.example.com)"], + deny: ["Domain(blocked.example.com)"], + ask: ["Domain(prompt.example.com)"], + allow: ["Domain(allowed.example.com)"], + }, + }, + onPermissionRequest: () => { + permissionRequests++; + return { kind: "approve-once" }; + }, + }); + try { + const urls = [ + "https://allowed.example.com/guide", + "https://prompt.example.com/", + "https://blocked.example.com/", + "https://outside.test/", + "http://allowed.example.com:8080/redirect", + ]; + const snapshot = await session.rpc.managedSettings.get(); + expect(snapshot.permissionsContext).toBeDefined(); + const context = snapshot.permissionsContext!; + const operations = urls.map((url) => ({ kind: "url" as const, url })); + const result = await client.rpc.managedSettings.permissions.evaluate({ + context, + operations, + }); + expect(result).toEqual({ + failClosed: false, + results: operations.map((operation, index) => ({ + operation, + verdict: ["allow", "ask", "deny", "deny", "ask"][index], + })), + }); + expect(permissionRequests).toBe(0); + await expect( + client.rpc.managedSettings.permissions.evaluate({ + context, + operations: [{ kind: "url", url: "file:///secret" }], + }) + ).rejects.toMatchObject({ code: -32602 }); + expect( + await client.rpc.managedSettings.permissions.evaluate({ context, operations: [] }) + ).toEqual({ + failClosed: false, + results: [], + }); + expect(snapshot.settings).not.toHaveProperty("sandbox"); + } finally { + await session.disconnect(); + } + }); + + it("evaluates an in-memory permissions context without creating a session", async () => { + await client.start(); + const operations = [ + { kind: "url" as const, url: "https://api.example.com/guide" }, + { kind: "url" as const, url: "https://outside.test/" }, + ]; + const context = { + permissions: { limitTo: ["Domain(api.example.com)"] }, + failClosed: false, + }; + const result = await client.rpc.managedSettings.permissions.evaluate({ + context, + operations, + }); + expect(result).toEqual({ + failClosed: false, + results: [ + { operation: operations[0], verdict: "unmanaged" }, + { operation: operations[1], verdict: "deny" }, + ], + }); + expect( + await client.rpc.managedSettings.permissions.evaluate({ + context: { ...context, failClosed: true }, + operations, + }) + ).toEqual({ + failClosed: true, + results: operations.map((operation) => ({ operation, verdict: "deny" })), + }); + }); + + it("denies every URL for an empty managed boundary", async () => { + const session = await client.createSession({ + managedSettings: { permissions: { limitTo: [] } }, + }); + try { + const snapshot = await session.rpc.managedSettings.get(); + expect(snapshot.permissionsContext).toBeDefined(); + expect( + await client.rpc.managedSettings.permissions.evaluate({ + context: snapshot.permissionsContext!, + operations: [ + { kind: "url", url: "https://example.com/" }, + { kind: "url", url: "https://api.github.com/" }, + ], + }) + ).toEqual({ + failClosed: false, + results: [ + { operation: { kind: "url", url: "https://example.com/" }, verdict: "deny" }, + { operation: { kind: "url", url: "https://api.github.com/" }, verdict: "deny" }, + ], + }); + } finally { + await session.disconnect(); + } + }); + it.skipIf(process.platform !== "darwin")( "admits only the configured dynamic loopback destination", async () => { diff --git a/nodejs/test/e2e/memory_tool_overrides.e2e.test.ts b/nodejs/test/e2e/memory_tool_overrides.e2e.test.ts new file mode 100644 index 0000000000..9bec5aad92 --- /dev/null +++ b/nodejs/test/e2e/memory_tool_overrides.e2e.test.ts @@ -0,0 +1,102 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import { describe, expect, it } from "vitest"; +import { z } from "zod"; +import { defineTool } from "../../src/index.js"; +import type { PermissionRequest, SessionConfig, ToolInvocation } from "../../src/index.js"; +import { createSdkTestContext } from "./harness/sdkTestContext.js"; + +describe("Memory tool overrides", async () => { + const { copilotClient: client } = await createSdkTestContext({ replayOnly: true }); + + it.each(["store_memory", "vote_memory"])( + "routes %s to the host with custom-tool permissions on create and resume", + async (name) => { + const invocations: ToolInvocation[] = []; + const permissions: PermissionRequest[] = []; + let approve = true; + const config = { + memory: { enabled: false }, + onPermissionRequest: (request) => { + permissions.push(request); + return approve ? { kind: "approve-once" } : { kind: "reject" }; + }, + tools: [ + defineTool(name, { + description: "Host-owned memory", + parameters: z.object({ fact: z.string() }), + overridesBuiltInTool: true, + defer: "never", + handler: (_args, invocation) => { + invocations.push(invocation); + return "HOST_MEMORY_HANDLED"; + }, + }), + ], + } satisfies SessionConfig; + let session = await client.createSession(config); + try { + for (const phase of ["create", "resume"]) { + if (phase === "resume") { + const sessionId = session.sessionId; + await session.disconnect(); + session = await client.resumeSession(sessionId, config); + } + await session.rpc.tools.initializeAndValidate(); + const { tools } = await session.rpc.tools.getCurrentMetadata(); + expect(tools.filter((tool) => tool.name === name)).toEqual([ + expect.objectContaining({ + description: "Host-owned memory", + input_schema: expect.objectContaining({ required: ["fact"] }), + }), + ]); + const args = { fact: `Host-owned memory after ${phase}.` }; + const toolCallId = `memory-override-${phase}`; + const result = await session.rpc.tools.execute({ + name, + arguments: args, + toolCallId, + }); + + expect(result, `${name} after ${phase}`).toMatchObject({ + resultType: "success", + textResultForLlm: "HOST_MEMORY_HANDLED", + }); + expect(invocations.at(-1)).toMatchObject({ + toolName: name, + toolCallId, + arguments: args, + }); + expect(permissions.at(-1)).toMatchObject({ + kind: "custom-tool", + toolName: name, + toolCallId, + args, + }); + } + expect(invocations).toHaveLength(2); + expect(permissions).toHaveLength(2); + + approve = false; + const args = { fact: "A rejected memory." }; + const rejected = await session.rpc.tools.execute({ + name, + arguments: args, + toolCallId: "memory-override-rejected", + }); + expect(rejected.resultType).toBe("rejected"); + expect(invocations).toHaveLength(2); + expect(permissions).toHaveLength(3); + expect(permissions.at(-1)).toMatchObject({ + kind: "custom-tool", + toolName: name, + args, + }); + } finally { + await session.disconnect(); + } + } + ); +}); diff --git a/nodejs/test/e2e/monthly_usage.e2e.test.ts b/nodejs/test/e2e/monthly_usage.e2e.test.ts new file mode 100644 index 0000000000..b0704efa33 --- /dev/null +++ b/nodejs/test/e2e/monthly_usage.e2e.test.ts @@ -0,0 +1,229 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import { createServer } from "node:http"; +import { mkdir, writeFile } from "node:fs/promises"; +import { join } from "node:path"; +import { expect, it, onTestFinished } from "vitest"; +import { approveAll, CopilotClient, RuntimeConnection } from "../../src/index.js"; +import { createSdkTestContext } from "./harness/sdkTestContext.js"; + +const { env, workDir, openAiEndpoint } = await createSdkTestContext({ + useStdio: true, + replayOnly: true, + copilotClientOptions: { useLoggedInUser: false, gitHubToken: undefined }, +}); + +it("preserves monthly Microsoft 365 usage without treating it as session spend", async ({ + signal, +}) => { + const profile = join(workDir, "monthly-usage-profile"); + await mkdir(profile); + let usage: Record = {}; + let quotaStatus = 200; + let invalidQuota = false; + const requests: string[] = []; + const server = createServer((request, response) => { + requests.push(`${request.method} ${request.url}`); + expect(request.headers.authorization).toBe("Bearer monthly-usage-token"); + response.setHeader("Content-Type", "application/json"); + if (request.url === "/models") { + response.end( + JSON.stringify({ + data: [{ id: "gpt-5-mini", name: "GPT-5 mini", model_picker_enabled: true }], + }) + ); + } else if (request.url === "/quota") { + if (quotaStatus !== 200) { + response + .writeHead(quotaStatus) + .end(JSON.stringify({ error: { code: "quota_read_failed" } })); + return; + } + if (invalidQuota) { + response.end("not JSON"); + return; + } + response.end( + JSON.stringify({ + quotaSnapshots: { + enterprise: { + source: "enterprise", + service: "GitHubCopilotApp", + accessState: "allowed", + capacityState: "available", + hasQuota: true, + entitledQuantity: 100, + availableQuantity: 13, + ...usage, + }, + }, + }) + ); + } else { + response.writeHead(404).end(); + } + }); + let client: CopilotClient | undefined; + const listening = new Promise((resolve, reject) => { + server.once("error", reject); + server.listen(0, "127.0.0.1", resolve); + }); + onTestFinished(async () => { + try { + await client?.stop(); + } finally { + await listening; + server.closeAllConnections(); + await new Promise((resolve, reject) => + server.close((error) => (error ? reject(error) : resolve())) + ); + } + }); + await listening; + signal.throwIfAborted(); + const address = server.address(); + if (!address || typeof address === "string") throw new Error("Expected a TCP quota fixture"); + const host = `http://127.0.0.1:${address.port}`; + const baseId = "monthly-usage-base"; + const emuToken = "ghu_monthly_usage_emu"; + const account = { host, login: "monthly-user", kind: "loki", derivedFrom: baseId }; + await openAiEndpoint.setCopilotUserByToken(emuToken, { + login: "monthly_emu", + is_staff: true, + copilot_plan: "business", + endpoints: { api: env.COPILOT_API_URL, telemetry: "https://localhost:1/telemetry" }, + }); + await writeFile(join(profile, "settings.json"), JSON.stringify({ storeTokenPlaintext: true })); + await writeFile( + join(profile, "config.json"), + JSON.stringify({ + loggedInUsers: [ + account, + { + host: "https://github.com", + login: "monthly_emu", + kind: "entraEmu", + derivedFrom: baseId, + }, + ], + lastLoggedInUser: account, + authTokens: { + [`entra:${baseId}:entra`]: { + token: JSON.stringify({ hostOwned: { account_id: baseId } }), + }, + [`loki:${baseId}:loki`]: { + token: "monthly-usage-token", + expiresAt: "2099-01-01T00:00:00Z", + accountType: "entra", + }, + "https://github.com:monthly_emu:entra": { + token: emuToken, + expiresAt: "2099-01-01T00:00:00Z", + accountType: "entra", + }, + }, + }) + ); + client = new CopilotClient({ + workingDirectory: workDir, + useLoggedInUser: true, + connection: RuntimeConnection.forStdio({ path: process.env.COPILOT_CLI_PATH }), + env: { + ...env, + COPILOT_HOME: profile, + COPILOT_DISABLE_KEYTAR: "1", + GH_TOKEN: "", + GITHUB_TOKEN: "", + COPILOT_GITHUB_TOKEN: "", + COPILOT_SDK_AUTH_TOKEN: "", + GITHUB_COPILOT_API_TOKEN: "", + COPILOT_HMAC_KEY: "", + CAPI_HMAC_KEY: "", + }, + }); + await using session = await client.createSession({ + configDirectory: profile, + onPermissionRequest: approveAll, + }); + const before = await session.rpc.usage.getMetrics(); + if (process.platform === "linux") { + expect(await session.rpc.gitHubAuth.getStatus()).toMatchObject({ isAuthenticated: false }); + await expect(session.rpc.quota.refresh()).rejects.toThrow("Not authenticated"); + expect((await session.rpc.quota.get()).providerQuotas).toBeUndefined(); + expect((await session.rpc.usage.getMetrics()).totalNanoAiu).toBe(before.totalNanoAiu); + expect(requests).toEqual([]); + return; + } + const initial = await session.rpc.quota.refresh(); + expect( + initial.providerQuotas?.find((state) => state.provider.kind === "loki")?.monthlyUsage + ).toBeUndefined(); + + for (const consumedQuantity of [0, 125.375]) { + usage = { + usageState: "available", + usageUnit: "ai_credits", + usageScope: "user", + consumedQuantity, + usageQueriedAt: "2026-10-08T12:00:00Z", + usageCycleStart: "2026-10-01T00:00:00Z", + usageResetOn: "2026-11-01T00:00:00Z", + }; + const quota = await session.rpc.quota.refresh(); + const state = quota.providerQuotas?.find((state) => state.provider.kind === "loki"); + expect(state).toMatchObject({ + accessState: "allowed", + capacityState: "available", + availableQuantity: 13, + quantityKind: "advisory_balance", + monthlyUsage: { + state: "available", + unit: "ai_credits", + scope: "user", + consumedQuantity, + queriedAt: "2026-10-08T12:00:00Z", + cycleStart: "2026-10-01T00:00:00Z", + resetOn: "2026-11-01T00:00:00Z", + }, + }); + expect((await session.rpc.quota.get()).providerQuotas).toEqual(quota.providerQuotas); + expect(await session.rpc.quota.takeWarnings()).toEqual([]); + } + for (const usageState of ["no_policy", "unavailable"]) { + usage = { usageState, usageUnit: "ai_credits", usageScope: "user" }; + const quota = await session.rpc.quota.refresh(); + expect( + quota.providerQuotas?.find((state) => state.provider.kind === "loki")?.monthlyUsage + ).toEqual({ + state: usageState, + unit: "ai_credits", + scope: "user", + }); + } + for (const status of [401, 403, 404, 429, 503]) { + quotaStatus = status; + const quota = await session.rpc.quota.refresh(); + const state = quota.providerQuotas?.find((state) => state.provider.kind === "loki"); + expect(state).toMatchObject({ + httpStatus: status, + acquisitionStatus: status === 404 ? "unavailable" : "failed", + }); + expect(state?.monthlyUsage).toBeUndefined(); + } + quotaStatus = 200; + invalidQuota = true; + const invalid = await session.rpc.quota.refresh(); + const invalidState = invalid.providerQuotas?.find((state) => state.provider.kind === "loki"); + expect(invalidState).toMatchObject({ + acquisitionStatus: "failed", + acquisitionError: "invalid_json", + }); + expect(invalidState?.monthlyUsage).toBeUndefined(); + expect((await session.rpc.usage.getMetrics()).totalNanoAiu).toBe(before.totalNanoAiu); + expect(requests.length).toBeGreaterThan(0); + expect(requests.every((request) => request === "GET /models" || request === "GET /quota")).toBe( + true + ); +}); diff --git a/nodejs/test/e2e/rpc_server.e2e.test.ts b/nodejs/test/e2e/rpc_server.e2e.test.ts index 07d7ffcf51..0b8049225e 100644 --- a/nodejs/test/e2e/rpc_server.e2e.test.ts +++ b/nodejs/test/e2e/rpc_server.e2e.test.ts @@ -113,6 +113,12 @@ describe("Server-scoped RPC", async () => { const policy = { model: "auto", autoTier: "balance", + permissions: { + limitTo: ["Domain(*.example.com)"], + deny: ["Domain(blocked.example.com)"], + ask: ["Domain(prompt.example.com)"], + allow: ["Domain(allowed.example.com)"], + }, }; const concretePolicy = { model: "gpt-5", @@ -175,6 +181,43 @@ describe("Server-scoped RPC", async () => { const absent = await api.compose({ layers: [{ source: "device" }] }); expect(absent.resolved.source).toBe("none"); + const permissionsContext = resolved.permissionsContext; + if (!permissionsContext) { + throw new Error("Runtime omitted the managed permission evaluation context"); + } + expect( + await api.permissions.evaluate({ + context: permissionsContext, + operations: [ + { kind: "url", url: "https://allowed.example.com/guide" }, + { kind: "url", url: "https://prompt.example.com/" }, + { kind: "url", url: "https://blocked.example.com/" }, + { kind: "url", url: "https://outside.test/" }, + ], + }) + ).toEqual({ + failClosed: false, + results: [ + { + operation: { kind: "url", url: "https://allowed.example.com/guide" }, + verdict: "allow", + }, + { operation: { kind: "url", url: "https://prompt.example.com/" }, verdict: "ask" }, + { + operation: { kind: "url", url: "https://blocked.example.com/" }, + verdict: "deny", + }, + { operation: { kind: "url", url: "https://outside.test/" }, verdict: "deny" }, + ], + }); + await expect( + api.permissions.evaluate({ + context: permissionsContext, + operations: [{ kind: "url", url: "not-a-url" }], + }) + ).rejects.toMatchObject({ code: -32602 }); + await expect(api.resolve({ selectionId: "missing-account" })).rejects.toThrow(); + const managedSession = await policyClient.createSession({ enableManagedSettings: true, model: "auto", diff --git a/nodejs/test/e2e/rpc_server_plugins.e2e.test.ts b/nodejs/test/e2e/rpc_server_plugins.e2e.test.ts index 20575a9114..2ce0800f4a 100644 --- a/nodejs/test/e2e/rpc_server_plugins.e2e.test.ts +++ b/nodejs/test/e2e/rpc_server_plugins.e2e.test.ts @@ -3,15 +3,25 @@ *--------------------------------------------------------------------------------------------*/ import { randomUUID } from "node:crypto"; -import { mkdirSync, rmSync, writeFileSync } from "node:fs"; -import { join } from "node:path"; -import { describe, expect, it } from "vitest"; -import { CopilotClient, RuntimeConnection } from "../../src/index.js"; +import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { join, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; +import { describe, expect, it, onTestFinished } from "vitest"; +import { + approveAll, + CopilotClient, + RuntimeConnection, + type CopilotSession, +} from "../../src/index.js"; import { createSdkTestContext, DEFAULT_GITHUB_TOKEN } from "./harness/sdkTestContext.js"; +import { waitForCondition } from "./harness/sdkTestHelper.js"; const MARKETPLACE_NAME = "csharp-e2e-marketplace"; const PLUGIN_NAME = "csharp-e2e-plugin"; const DIRECT_PLUGIN_NAME = "csharp-e2e-direct"; +const TEST_MCP_SERVER = fileURLToPath( + new URL("../../../test/harness/test-mcp-server.mjs", import.meta.url) +); describe("Server-scoped plugin RPC", async () => { const { env, workDir } = await createSdkTestContext(); @@ -127,6 +137,110 @@ This skill exists so the plugin reports at least one installed skill. writeFileSync(join(pluginDir, "SKILL.md"), skill); } + it( + "keeps unrelated MCP servers running when Computer Use is toggled", + { timeout: 120_000 }, + async ({ expect }) => { + const pluginDir = createUniqueDirectory("computer-use"); + const { client, home } = await createIsolatedStartedClient(); + let session: CopilotSession | undefined; + onTestFinished(async () => { + try { + await session?.disconnect(); + } finally { + await disposeIsolated(client, home, pluginDir); + } + }); + writeFileSync( + join(pluginDir, "plugin.json"), + JSON.stringify({ + name: "computer-use", + version: "1.0.0", + mcpServers: "./.mcp.json", + }) + ); + writeFileSync( + join(pluginDir, ".mcp.json"), + JSON.stringify({ + mcpServers: { + "computer-use": { + command: process.execPath, + args: [TEST_MCP_SERVER, "--server-name", "computer-use"], + cwd: dirname(TEST_MCP_SERVER), + tools: ["*"], + }, + }, + }) + ); + await client.rpc.plugins.builtin.set({ paths: [pluginDir] }); + const serverName = "unrelated-to-computer-use"; + const startupMarker = join(home, "unrelated-mcp-starts.log"); + const mcpSession = await client.createSession({ + onPermissionRequest: approveAll, + mcpServers: { + [serverName]: { + type: "local", + command: process.execPath, + args: [ + TEST_MCP_SERVER, + "--startup-marker", + startupMarker, + "--server-name", + serverName, + ], + workingDirectory: dirname(TEST_MCP_SERVER), + tools: ["*"], + }, + }, + }); + session = mcpSession; + const waitForConnected = (name: string) => + waitForCondition( + async () => + (await mcpSession.rpc.mcp.list()).servers.some( + (server) => server.name === name && server.status === "connected" + ), + { + timeoutMs: 60_000, + intervalMs: 200, + timeoutMessage: `${name} did not connect`, + } + ); + await waitForConnected(serverName); + expect(readFileSync(startupMarker, "utf8")).toBe(`${serverName}\n`); + const toolsBefore = await mcpSession.rpc.mcp.listTools({ serverName }); + expect(toolsBefore.tools.map((tool) => tool.name)).toContain("get_env"); + expect( + (await mcpSession.rpc.mcp.list()).servers.map((server) => server.name) + ).not.toContain("computer-use"); + + for (const enabled of [true, false, true, false]) { + if (enabled) { + await client.rpc.plugins.enable({ names: ["computer-use"] }); + await waitForConnected("computer-use"); + } else { + await client.rpc.plugins.disable({ names: ["computer-use"] }); + await waitForCondition( + async () => + !(await mcpSession.rpc.mcp.list()).servers.some( + (server) => server.name === "computer-use" + ), + { + timeoutMs: 60_000, + intervalMs: 200, + timeoutMessage: "Computer Use MCP server was not removed", + } + ); + } + expect((await mcpSession.rpc.mcp.isServerRunning({ serverName })).running).toBe( + true + ); + expect(await mcpSession.rpc.mcp.listTools({ serverName })).toEqual(toolsBefore); + expect(readFileSync(startupMarker, "utf8")).toBe(`${serverName}\n`); + } + } + ); + it("should install and list plugin from local marketplace", { timeout: 120_000 }, async () => { const marketplaceDir = createLocalMarketplaceFixture(); const { client, home } = await createIsolatedStartedClient(); diff --git a/nodejs/test/e2e/rpc_shell_and_fleet.e2e.test.ts b/nodejs/test/e2e/rpc_shell_and_fleet.e2e.test.ts index 4f8061c960..5df5024b14 100644 --- a/nodejs/test/e2e/rpc_shell_and_fleet.e2e.test.ts +++ b/nodejs/test/e2e/rpc_shell_and_fleet.e2e.test.ts @@ -160,6 +160,113 @@ describe("Shell and fleet RPC", async () => { } ); + it.skipIf(os.platform() === "win32")( + "should release post-root-exit shell pipes and rewind admission at timeout", + async ({ onTestFailed }) => { + const cwd = fs.mkdtempSync(path.join(workDir, "post-exit-shell-")); + let phase = "creating session"; + let rootPid: number | undefined; + let rootExited = false; + let lastRewindState: + | Awaited> + | undefined; + onTestFailed(() => { + console.error("Post-root-exit shell timeout diagnostic:", { + phase, + rootPid, + rootExited, + lastRewindState, + descendantReady: fs.existsSync(path.join(cwd, "descendant.ready")), + terminated: fs.existsSync(path.join(cwd, "terminated")), + }); + }); + const session = await client.createSession({ + enableFileChangeTracking: true, + onPermissionRequest: approveAll, + }); + let processId: string | undefined; + function processExists(pid: number): boolean { + try { + process.kill(pid, 0); + return true; + } catch (error) { + if ((error as NodeJS.ErrnoException).code === "ESRCH") { + return false; + } + throw error; + } + } + try { + phase = "waiting for rewind tracking initialization"; + await waitForCondition( + async () => { + lastRewindState = await session.rpc.history.listRewindPoints(); + return lastRewindState.fileChangeTrackingEnabled; + }, + { timeoutMessage: "Rewind tracking did not initialize" } + ); + phase = "launching post-exit shell"; + // Reader teardown must not SIGPIPE the fixture before its TERM trap records termination. + const result = await session.rpc.shell.exec({ + command: + `sh -c 'trap "" PIPE; trap "printf terminated > terminated; exit 0" TERM; ` + + `printf ready > descendant.ready; sleep 60' & ` + + `echo $$ > root.pending; mv root.pending root.pid; exit 7`, + cwd, + timeout: 10_000, + }); + processId = result.processId; + expect(processId).toBeTruthy(); + phase = "waiting for root reap and descendant readiness"; + await waitForCondition( + () => { + if ( + !fs.existsSync(path.join(cwd, "root.pid")) || + !fs.existsSync(path.join(cwd, "descendant.ready")) + ) { + return false; + } + rootPid = Number(fs.readFileSync(path.join(cwd, "root.pid"), "utf8")); + expect(Number.isInteger(rootPid) && rootPid > 1).toBe(true); + rootExited = !processExists(rootPid); + return rootExited; + }, + { timeoutMessage: "Fixture root did not exit with a ready pipe holder" } + ); + phase = "checking retained rewind lease"; + expect(fs.existsSync(path.join(cwd, "terminated"))).toBe(false); + lastRewindState = await session.rpc.history.listRewindPoints(); + expect(lastRewindState.unavailableReason).toBe("session-busy"); + + // Neither poll sends a kill: the configured timeout must end the + // descendant and release the production sink's operation lease. + phase = "waiting for rewind admission after timeout"; + await waitForCondition( + async () => { + lastRewindState = await session.rpc.history.listRewindPoints(); + return ( + lastRewindState.fileChangeTrackingEnabled && + lastRewindState.unavailableReason === undefined + ); + }, + { timeoutMessage: "Post-exit timeout left rewind admission session-busy" } + ); + phase = "waiting for automatic descendant termination"; + await waitForFileText(path.join(cwd, "terminated"), "terminated"); + phase = "checking registry cleanup"; + expect((await session.rpc.shell.kill({ processId })).killed).toBe(false); + } finally { + try { + if (processId) { + await session.rpc.shell.kill({ processId, signal: "SIGKILL" }); + } + } finally { + await session.disconnect(); + } + } + } + ); + it("should accept a missing shell command and clean up after it exits", async () => { const session = await client.createSession({ onPermissionRequest: approveAll }); const marker = path.join(workDir, `shell-missing-${randomUUID()}.txt`); diff --git a/nodejs/test/e2e/rpc_surface_coverage.e2e.test.ts b/nodejs/test/e2e/rpc_surface_coverage.e2e.test.ts index 9d6836f631..73a239a8df 100644 --- a/nodejs/test/e2e/rpc_surface_coverage.e2e.test.ts +++ b/nodejs/test/e2e/rpc_surface_coverage.e2e.test.ts @@ -327,10 +327,21 @@ describe("Generated RPC surface coverage", () => { ...collectRuntimeFunctions(session.rpc, "session"), ]); - expect(inventory).toHaveLength(405); + expect(inventory).toHaveLength(406); expect(inventory.filter((method) => method.wireMethod === "host.listSessions")).toEqual([ expect.objectContaining({ scope: "server", path: "host.listSessions" }), ]); + expect( + inventory.filter( + (method) => method.wireMethod === "managedSettings.permissions.evaluate" + ) + ).toEqual([ + expect.objectContaining({ + scope: "server", + path: "managedSettings.permissions.evaluate", + parameterCount: 1, + }), + ]); expect(inventory.some((method) => method.wireMethod === "user.settings.reload")).toBe( false ); diff --git a/nodejs/test/e2e/rpc_tasks_and_handlers.e2e.test.ts b/nodejs/test/e2e/rpc_tasks_and_handlers.e2e.test.ts index 5f926f120c..e6e6a18c8f 100644 --- a/nodejs/test/e2e/rpc_tasks_and_handlers.e2e.test.ts +++ b/nodejs/test/e2e/rpc_tasks_and_handlers.e2e.test.ts @@ -7,7 +7,7 @@ import { z } from "zod"; import { approveAll, CopilotRequestHandler } from "../../src/index.js"; import type { SessionEvent, CopilotRequestContext, CopilotSession } from "../../src/index.js"; import { createSdkTestContext } from "./harness/sdkTestContext.js"; -import { waitForCondition } from "./harness/sdkTestHelper.js"; +import { getNextEventOfType, waitForCondition } from "./harness/sdkTestHelper.js"; import { isByokBackend } from "./harness/testBackend"; const capiIt = it.skipIf(isByokBackend); @@ -326,6 +326,96 @@ describe("Session tasks RPC and pending handlers", async () => { } }); + // Shell IDs count up per runtime process, so each attached-shell test owns its + // client: the recorded `shellId: 0` then holds regardless of test order. + async function withRunningAttachedShell( + run: ( + session: CopilotSession, + shellId: string, + eventTypes: SessionEvent["type"][], + replies: string[] + ) => Promise + ): Promise { + const shellClient = createClient(); + try { + const session = await shellClient.createSession({ onPermissionRequest: approveAll }); + const eventTypes: SessionEvent["type"][] = []; + const replies: string[] = []; + const unsubscribe = session.on((event) => { + eventTypes.push(event.type); + if (event.type === "assistant.message") { + replies.push(event.data.content ?? ""); + } + }); + try { + const assistantIdle = getNextEventOfType(session, "assistant.idle"); + await session.send({ + prompt: "Use your shell tool to run `sleep 600` in async mode without detaching. Do not read its output or wait for it. Then reply with exactly SHELL_STARTED.", + }); + await assistantIdle; + expect(replies.at(-1)).toContain("SHELL_STARTED"); + + const shell = (await session.rpc.tasks.list()).tasks.find( + (task) => task.type === "shell" && task.status === "running" + ); + expect(shell).toMatchObject({ attachmentMode: "attached" }); + await run(session, shell!.id, eventTypes, replies); + } finally { + unsubscribe(); + await session.disconnect(); + } + } finally { + await shellClient.stop(); + } + } + + it( + "should emit session idle after cancelling a running attached shell", + { timeout: 120_000 }, + async () => { + await withRunningAttachedShell(async (session, shellId, eventTypes) => { + // The running attached shell holds the turn's session.idle. + expect(eventTypes).not.toContain("session.idle"); + + expect((await session.rpc.tasks.cancel({ id: shellId })).cancelled).toBe(true); + await waitForCondition(() => eventTypes.includes("session.idle"), { + timeoutMessage: `session.idle never followed cancelling shell ${shellId}`, + }); + }); + } + ); + + it( + "should run a queued message after cancelling a running attached shell", + { timeout: 120_000 }, + async () => { + await withRunningAttachedShell(async (session, shellId, eventTypes, replies) => { + // The running attached shell holds idle, so an enqueued message waits behind it. + await session.send({ prompt: "Reply with exactly QUEUED_DONE.", mode: "enqueue" }); + await waitForCondition( + async () => + (await session.rpc.queue.pendingItems()).items.some((item) => + item.displayText.includes("QUEUED_DONE") + ), + { timeoutMessage: "The enqueued message was not parked behind the shell" } + ); + expect(replies.some((reply) => reply.includes("QUEUED_DONE"))).toBe(false); + expect(eventTypes).not.toContain("session.idle"); + + expect((await session.rpc.tasks.cancel({ id: shellId })).cancelled).toBe(true); + await waitForCondition( + () => replies.some((reply) => reply.includes("QUEUED_DONE")), + { + timeoutMessage: `The queued message never ran after cancelling shell ${shellId}`, + } + ); + await waitForCondition(() => eventTypes.includes("session.idle"), { + timeoutMessage: "session.idle never followed the queued message", + }); + }); + } + ); + it( "should apply a custom agent's composed model and effort when started over RPC", { timeout: 240_000 }, diff --git a/nodejs/test/e2e/subagent_prompt_resume.e2e.test.ts b/nodejs/test/e2e/subagent_prompt_resume.e2e.test.ts index 2e82470012..00d0469647 100644 --- a/nodejs/test/e2e/subagent_prompt_resume.e2e.test.ts +++ b/nodejs/test/e2e/subagent_prompt_resume.e2e.test.ts @@ -15,15 +15,19 @@ import type { import { approveAll, CopilotRequestHandler } from "../../src/index.js"; import { createSdkTestContext } from "./harness/sdkTestContext.js"; import { waitForCondition } from "./harness/sdkTestHelper.js"; +import { isByokBackend } from "./harness/testBackend.js"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const TEST_MCP_SERVER = resolve(__dirname, "../../../test/harness/test-mcp-server.mjs"); const TEST_HARNESS_DIR = dirname(TEST_MCP_SERVER); +const capiIt = it.skipIf(isByokBackend); interface InferenceRequest { agentId?: string; parentAgentId?: string; + model: string; + reasoningEffort?: string; systemPrompt: string; toolNames: string[]; } @@ -37,9 +41,16 @@ class RecordingRequestHandler extends CopilotRequestHandler { ): Promise { const body = request.body ? await request.text() : ""; if (isInferenceUrl(request.url)) { + const inference = JSON.parse(body) as { + model: string; + reasoning_effort?: string; + reasoning?: { effort?: string }; + }; this.inferenceRequests.push({ agentId: ctx.agentId, parentAgentId: ctx.parentAgentId, + model: inference.model, + reasoningEffort: inference.reasoning_effort ?? inference.reasoning?.effort, systemPrompt: systemPromptFromRequest(request.url, body), toolNames: toolNamesFromRequest(body), }); @@ -122,6 +133,32 @@ function bootstrapResponse(url: string): Response { }, }, }, + { + id: "gpt-5.4-mini", + name: "GPT-5.4 Mini", + object: "model", + vendor: "OpenAI", + version: "1", + preview: false, + model_picker_enabled: true, + supported_endpoints: ["/chat/completions"], + capabilities: { + type: "chat", + family: "gpt-5.4-mini", + tokenizer: "o200k_base", + limits: { + max_context_window_tokens: 200000, + max_output_tokens: 8192, + }, + supports: { + streaming: true, + tool_calls: true, + parallel_tool_calls: true, + vision: true, + reasoning_effort: ["low", "medium", "high"], + }, + }, + }, ], }); } @@ -225,13 +262,21 @@ describe("Subagent prompt resume", async () => { }, { timeoutMessage: `Agent ${agentId} did not become idle.` } ); + const task = (await session.rpc.tasks.list()).tasks.find( + (candidate) => candidate.id === agentId + ); + if (task?.type !== "agent") { + throw new Error(`Agent task ${agentId} is missing or has the wrong type.`); + } + expect(task.latestResponse ?? task.result).toContain("SUBAGENT_TURN_COMPLETE"); } async function runResumeScenario( trigger: (session: CopilotSession) => Promise, createOptions: Parameters[0] = {}, beforeAgentStart: (session: CopilotSession) => Promise = async () => {}, - agentType = "explore" + agentType = "explore", + agentModel: string | null = "claude-sonnet-5" ): Promise<[InferenceRequest, InferenceRequest]> { await writeFile(join(env.COPILOT_HOME, "settings.json"), "{}"); const requestBaseline = requestHandler.inferenceRequests.length; @@ -248,7 +293,7 @@ describe("Subagent prompt resume", async () => { prompt: "Reply with exactly SUBAGENT_TURN_COMPLETE.", name: "prompt-resume", description: "Exercise an idle subagent follow-up.", - model: "claude-sonnet-5", + ...(agentModel ? { model: agentModel } : {}), }); await waitForIdleAgent(session, agentId); @@ -270,6 +315,7 @@ describe("Subagent prompt resume", async () => { }, { timeoutMessage: "Agent did not complete its follow-up turn." } ); + await waitForIdleAgent(session, agentId); const childRequests = requestHandler.inferenceRequests .slice(requestBaseline) @@ -317,6 +363,61 @@ describe("Subagent prompt resume", async () => { expect(resumed.systemPrompt).toBe(initial.systemPrompt); }); + capiIt.each(["minimal", "max", "xhigh", "none", "high"])( + "reconciles a concrete child's composed %s effort on its first and resumed requests", + async (effort) => { + const requests = await runResumeScenario( + async () => {}, + { + customAgents: [ + { + name: "composed-effort", + prompt: "Reply with exactly SUBAGENT_TURN_COMPLETE.", + model: `gpt-5.4-mini:defaultReasoningEffort=${effort}`, + tools: [], + }, + ], + }, + async () => {}, + "composed-effort", + null + ); + + for (const request of requests) { + expect(request.model).toBe("gpt-5.4-mini"); + expect(request.reasoningEffort).toBe(effort === "high" ? "high" : "medium"); + } + } + ); + + capiIt( + "reconciles an independently declared child effort without changing its model", + async () => { + const requests = await runResumeScenario( + async () => {}, + { + customAgents: [ + { + name: "declared-effort", + prompt: "Reply with exactly SUBAGENT_TURN_COMPLETE.", + model: "gpt-5.4-mini", + reasoningEffort: "max", + tools: [], + }, + ], + }, + async () => {}, + "declared-effort", + null + ); + + for (const request of requests) { + expect(request.model).toBe("gpt-5.4-mini"); + expect(request.reasoningEffort).toBe("medium"); + } + } + ); + it("preserves the adapted prompt after persisted settings rebuild the child context", async () => { const [initial, resumed] = await runResumeScenario(changePersistedSettings); diff --git a/nodejs/test/e2e/websocket_http_fallback.e2e.test.ts b/nodejs/test/e2e/websocket_http_fallback.e2e.test.ts new file mode 100644 index 0000000000..d8cd382285 --- /dev/null +++ b/nodejs/test/e2e/websocket_http_fallback.e2e.test.ts @@ -0,0 +1,143 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import { afterAll, describe, expect, it } from "vitest"; +import { z } from "zod"; +import { approveAll, defineTool, type SessionEvent } from "../../src/index.js"; +import { withTestCleanup } from "../helpers/withTestCleanup.js"; +import { createSdkTestContext, DEFAULT_GITHUB_TOKEN } from "./harness/sdkTestContext.js"; +import { + createCompletedResponse, + startWebSocketResponsesServer, +} from "./harness/webSocketResponsesServer.js"; + +const TOOL_NAME = "ws_fallback_marker"; +const TOOL_RESULT = "WS_FALLBACK_TOOL_RESULT"; +const FINAL = "WS_FALLBACK_FINAL_ANSWER"; +const usage = { + input_tokens: 10, + output_tokens: 5, + total_tokens: 15, + input_tokens_details: { cached_tokens: 0 }, + output_tokens_details: { reasoning_tokens: 0 }, +}; + +describe("WebSocket to HTTP fallback telemetry", async () => { + const upstream = await startWebSocketResponsesServer(); + // Register first so the SDK context stops its client and proxy before this provider. + afterAll(() => upstream.stop()); + const { copilotClient: client, openAiEndpoint } = await createSdkTestContext({ + useStdio: true, + copilotClientOptions: { + gitHubToken: DEFAULT_GITHUB_TOKEN, + env: { + COPILOT_API_URL: upstream.baseUrl, + COPILOT_CLI_DISABLE_WEBSOCKET_RESPONSES: "false", + }, + }, + }); + upstream.forwardHttpTo(openAiEndpoint.url); + + it("describes the WebSocket failure on the downgrading call and keeps it sticky", async () => { + const { state } = upstream; + state.responses.push({ + type: "error", + error: { + code: "service_unavailable", + type: "websocket_error", + message: "controlled WebSocket outage", + }, + }); + state.httpResponses.push( + [ + { + type: "response.completed", + response: { + ...createCompletedResponse("", "resp-http-tool"), + output: [ + { + type: "function_call", + id: "fc-1", + call_id: "call-1", + name: TOOL_NAME, + arguments: JSON.stringify({ input: "ping" }), + status: "completed", + }, + ], + output_text: "", + usage, + }, + }, + ], + [ + { + type: "response.completed", + response: { ...createCompletedResponse(FINAL, "resp-http-final"), usage }, + }, + ] + ); + const session = await client.createSession({ + model: "gpt-5-responses", + onPermissionRequest: approveAll, + tools: [ + defineTool(TOOL_NAME, { + description: "Returns a fixed marker", + parameters: z.object({ input: z.string() }), + handler: () => TOOL_RESULT, + }), + ], + }); + const events: SessionEvent[] = []; + const unsubscribe = session.on((event) => events.push(event)); + await withTestCleanup( + async () => { + const answer = await session.sendAndWait({ prompt: "Use the marker tool." }); + // Validate the final assistant response arrived (guards against truncated captures) + expect(answer?.data.content).toBe(FINAL); + + expect(state.messages).toHaveLength(1); + expect(state.httpResponseRequestPaths).toHaveLength(2); + expect(state.httpResponses).toHaveLength(0); + expect( + events.some( + (event) => + event.type === "tool.execution_complete" && + JSON.stringify(event.data).includes(TOOL_RESULT) + ) + ).toBe(true); + + const usages = events.flatMap((event) => + event.type === "assistant.usage" ? [event.data] : [] + ); + expect(usages).toHaveLength(2); + const descriptors = { + websocketFallbackReason: "api_error", + websocketFallbackErrorKind: "http_status", + websocketFallbackStatusCode: 503, + websocketFallbackReconnectAttempted: false, + }; + expect(usages[0]).toMatchObject({ + ...descriptors, + websocketFallbackStartedThisCall: true, + }); + expect(usages[0].websocketFallbackCloseCode).toBeUndefined(); + expect(usages[1]).toMatchObject({ + ...descriptors, + websocketFallbackStartedThisCall: false, + }); + expect( + usages.every((data) => typeof data.websocketFallbackAfterMs === "number") + ).toBe(true); + }, + unsubscribe, + () => session.disconnect(), + async () => { + const errors = await client.stop(); + if (errors.length > 0) { + throw new AggregateError(errors, "WebSocket fallback client cleanup failed"); + } + } + ); + }); +}); diff --git a/nodejs/test/e2e/workiq_discovery.e2e.test.ts b/nodejs/test/e2e/workiq_discovery.e2e.test.ts index 249d982770..1d30226112 100644 --- a/nodejs/test/e2e/workiq_discovery.e2e.test.ts +++ b/nodejs/test/e2e/workiq_discovery.e2e.test.ts @@ -15,7 +15,7 @@ import { createE2eRequestHandler } from "../../../test/harness/mockHandlers.js"; describe("account-derived WorkIQ", async () => { const { env, workDir, openAiEndpoint } = await createSdkTestContext(); - it("discovers disabled WorkIQ without requesting authentication or persisting a server", async () => { + it("discovers WorkIQ only on supported platforms without requesting authentication or persisting a server", async () => { const profile = join(workDir, "workiq-profile"); await mkdir(profile, { recursive: true }); await writeFile( @@ -53,22 +53,29 @@ describe("account-derived WorkIQ", async () => { ]) ); const discovered = await session.rpc.mcp.list(); - expect(discovered.servers).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - name: "WorkIQ", - source: "account", - status: "disabled", - url: "https://workiq.svc.cloud.microsoft/mcp", - }), - ]) - ); + const expected = + process.platform === "linux" + ? [] + : [ + expect.objectContaining({ + name: "WorkIQ", + source: "account", + status: "disabled", + url: "https://workiq.svc.cloud.microsoft/mcp", + }), + ]; + expect(discovered.servers.filter((server) => server.name === "WorkIQ")).toEqual(expected); expect(discovered).not.toHaveProperty("accountServerConfigs"); - await session.rpc.mcp.reload(); + // Gating off WorkIQ can leave this fixture with no MCP configuration to reload. + if (discovered.servers.length === 0) { + await expect(session.rpc.mcp.reload()).rejects.toThrow( + "MCP config reload not available" + ); + } else { + await session.rpc.mcp.reload(); + } const reloaded = await session.rpc.mcp.list(); - expect(reloaded.servers.find((server) => server.name === "WorkIQ")?.status).toBe( - "disabled" - ); + expect(reloaded.servers.filter((server) => server.name === "WorkIQ")).toEqual(expected); expect(authenticationRequests).toBe(0); await expect(readFile(join(profile, "mcp-config.json"))).rejects.toMatchObject({ code: "ENOENT", @@ -142,7 +149,7 @@ describe("account-derived WorkIQ", async () => { expect(result).not.toHaveProperty("accountServerConfigs"); }); - it.each(["silent", "browser"] as const)( + it.skipIf(process.platform === "linux").each(["silent", "browser"] as const)( "authenticates through %s, persists renewal, and disconnects on parent logout", async (authentication) => { const profile = join(workDir, `workiq-${authentication}-profile`); diff --git a/nodejs/test/ffiRuntimeHost.test.ts b/nodejs/test/ffiRuntimeHost.test.ts index b5badfb27c..f7e19686fd 100644 --- a/nodejs/test/ffiRuntimeHost.test.ts +++ b/nodejs/test/ffiRuntimeHost.test.ts @@ -109,6 +109,18 @@ describe("FfiRuntimeHost callback cleanup", () => { vi.useRealTimers(); }); + it("forwards the CLI login sync integration without a CLI entrypoint", async () => { + const host = FfiRuntimeHost.create("runtime.node", undefined, undefined, [ + "--cli-login-sync-integration-id=github/github-app", + ]); + await host.start(); + + const argv = JSON.parse(ffi.hostStart.async.mock.calls[0][0].toString()) as string[]; + expect(argv).toEqual(["--cli-login-sync-integration-id=github/github-app"]); + + await host.dispose(); + }); + it("finishes disposal after a false close while retaining resources for the detached retry", async () => { ffi.connectionClose.async.mockImplementationOnce((_id, callback) => callback(null, false)); const host = FfiRuntimeHost.create("runtime.node", undefined, undefined, []); diff --git a/nodejs/test/python-codegen.test.ts b/nodejs/test/python-codegen.test.ts index e87cefb5c9..36cb7e3133 100644 --- a/nodejs/test/python-codegen.test.ts +++ b/nodejs/test/python-codegen.test.ts @@ -67,6 +67,19 @@ describe("Python RPC projection compatibility", () => { expect(code).toContain(`return list(await self._client.request("${method}"`); }); + it("keeps the managed permission discriminator independent of MCP URL kinds", () => { + expect(code).toContain("class ManagedPermissionOperationKind(Enum):"); + const operation = code + .split("class ManagedPermissionOperation:")[1] + ?.split("\n\n@dataclass")[0]; + expect(operation).toContain("kind: ManagedPermissionOperationKind"); + expect(operation).toContain('kind = ManagedPermissionOperationKind(obj.get("kind"))'); + expect(operation).toContain( + 'result["kind"] = to_enum(ManagedPermissionOperationKind, self.kind)' + ); + expect(operation).not.toContain("MCPServerCardURLKind"); + }); + it("preserves the existing Workflow checkpoint result API", () => { const result = "SessionWorkflowPauseAtCheckpointResult"; expect(code).toContain(`class ${result}:`); diff --git a/nodejs/test/rust-codegen.test.ts b/nodejs/test/rust-codegen.test.ts index 5f34d804b1..53c471b104 100644 --- a/nodejs/test/rust-codegen.test.ts +++ b/nodejs/test/rust-codegen.test.ts @@ -17,6 +17,45 @@ import { import { legacyRequestSchema } from "./legacy-parameters-fixture.ts"; describe("Rust API type codegen", () => { + it("reuses the named managed operation and kind in request and result fields", () => { + const code = generateApiTypesCode({ + definitions: { + ManagedPermissionOperation: { + anyOf: [ + { + type: "object", + properties: { + kind: { type: "string", const: "url" }, + url: { type: "string" }, + }, + required: ["kind", "url"], + }, + ], + }, + ManagedPermissionsEvaluateRequest: { + type: "object", + properties: { + operations: { + type: "array", + items: { $ref: "#/definitions/ManagedPermissionOperation" }, + }, + }, + required: ["operations"], + }, + ManagedPermissionEvaluation: { + type: "object", + properties: { operation: { $ref: "#/definitions/ManagedPermissionOperation" } }, + required: ["operation"], + }, + }, + } as ApiSchema); + expect(code).toContain("pub operations: Vec,"); + expect(code).toContain("pub operation: ManagedPermissionOperation,"); + expect(code).toContain("pub kind: ManagedPermissionOperationKind,"); + expect(code).not.toContain("ManagedPermissionsEvaluateRequestOperationsItem"); + expect(code).not.toContain("ManagedPermissionEvaluationOperation"); + }); + it("keeps every noncanonical open identifier distinct from the default sentinel", () => { const code = generateApiTypesCode( postProcessSchema({ diff --git a/nodejs/vitest.config.ts b/nodejs/vitest.config.ts index 54c1d1681b..9b1badf4ab 100644 --- a/nodejs/vitest.config.ts +++ b/nodejs/vitest.config.ts @@ -69,6 +69,7 @@ const selfConfiguredBackendE2E = [ "**/test/e2e/per_session_auth.e2e.test.ts", "**/test/e2e/provider_endpoint.e2e.test.ts", "**/test/e2e/subagent_prompt_resume.e2e.test.ts", + "**/test/e2e/websocket_http_fallback.e2e.test.ts", "**/test/e2e/websocket_terminals.e2e.test.ts", ]; diff --git a/python/copilot/client.py b/python/copilot/client.py index fc9ea41718..89a9f940f6 100644 --- a/python/copilot/client.py +++ b/python/copilot/client.py @@ -1752,6 +1752,9 @@ def __init__( self._ffi_host: FfiRuntimeHost | None = None self._inprocess_runtime_path: str | None = None self._inprocess_cli_entrypoint: str | None = None + self._cli_login_sync_integration_id = ( + os.environ.get("GITHUB_COPILOT_INTEGRATION_ID", "").strip() or None + ) if isinstance(connection, UriRuntimeConnection): if connection.connection_token is not None and len(connection.connection_token) == 0: @@ -4811,6 +4814,8 @@ async def _start_inprocess_ffi(self) -> None: args.extend(["--session-idle-timeout", str(opts.session_idle_timeout_seconds)]) if opts.enable_remote_sessions: args.append("--remote") + if self._cli_login_sync_integration_id is not None: + args.append(f"--cli-login-sync-integration-id={self._cli_login_sync_integration_id}") environment: dict[str, str] = {} if opts.github_token: diff --git a/python/copilot/generated/rpc.py b/python/copilot/generated/rpc.py index e496e3addf..9a3ec258af 100644 --- a/python/copilot/generated/rpc.py +++ b/python/copilot/generated/rpc.py @@ -6,7 +6,7 @@ from typing import ClassVar, TYPE_CHECKING -from .session_events import AbortReason, AgentModelPolicy, Attachment, AutoTier, ContextTier, EmbeddedBlobResourceContents, EmbeddedTextResourceContents, IndexedSearchState, ManagedSettingsResolvedSource, McpOauthHttpResponse, McpOauthWWWAuthenticateParams, McpServerMetadata, McpServerSource, McpServerStatus, ModelChangeSource, ModelProviderKind, ModelProviderRef, PermissionDecisionSource, PermissionMode, PermissionPromptRequest, PermissionRule, ProviderQuotaState, ReasoningSummary, RemediationAction, SessionEvent, SessionLimitsConfig, SessionMode, ShutdownType, SkillSource, TaskBlocker, TaskCompletionOutcome, UsageGetMetricsResult, UserToolSessionApproval, Verbosity, _load_Attachment, _load_PermissionPromptRequest, _load_UserToolSessionApproval +from .session_events import AbortReason, AgentModelPolicy, Attachment, AutoTier, ContextTier, EmbeddedBlobResourceContents, EmbeddedTextResourceContents, IndexedSearchState, ManagedPermissionsContext, ManagedSettingsResolvedSource, McpOauthHttpResponse, McpOauthWWWAuthenticateParams, McpServerMetadata, McpServerSource, McpServerStatus, ModelChangeSource, ModelProviderKind, ModelProviderRef, PermissionDecisionSource, PermissionMode, PermissionPromptRequest, PermissionRule, ProviderQuotaState, ReasoningSummary, RemediationAction, SessionEvent, SessionLimitsConfig, SessionMode, ShutdownType, SkillSource, TaskBlocker, TaskCompletionOutcome, UsageGetMetricsResult, UserToolSessionApproval, Verbosity, _load_Attachment, _load_PermissionPromptRequest, _load_UserToolSessionApproval if TYPE_CHECKING: from .._jsonrpc import JsonRpcClient @@ -6483,6 +6483,20 @@ def to_dict(self) -> dict: result["tools"] = from_union([lambda x: from_list(from_str, x), from_none], self.tools) return result +# Experimental: this type is part of an experimental API and may change or be removed. +class ManagedPermissionVerdict(Enum): + """Managed-policy decision only; never bypasses user permissions or other security + controls. + + Managed-policy verdict only: deny blocks the URL, ask requires approval, allow approves + under managed policy, and unmanaged leaves the normal consumer permission flow in effect. + No verdict bypasses other security controls. + """ + ALLOW = "allow" + ASK = "ask" + DENY = "deny" + UNMANAGED = "unmanaged" + # Experimental: this type is part of an experimental API and may change or be removed. class ManagedPluginRetryStatus(Enum): """What the retry did for this plugin. @@ -6633,6 +6647,11 @@ class ManagedSettingsResolvedData: """Whether at least two managed sources supplied permission allowlists, so enforcement intersects them and the flattened settings payload omits `permissions.allow`. """ + permissions_context: ManagedPermissionsContext | None = None + """Reusable retained managed permission policy for managedSettings.permissions.evaluate, + including source composition and session-local injection. Provided by live session + snapshots; absent in older events. Refresh the context when managed policy changes. + """ policy_helper_managed: bool | None = None """Whether the policy-helper managed-settings layer was present. The policy helper is the weakest channel: it fills keys no enterprise source set and can never replace one. @@ -6659,10 +6678,11 @@ def from_dict(obj: Any) -> 'ManagedSettingsResolvedData': source = ManagedSettingsResolvedSource(obj.get("source")) client_managed = from_union([from_bool, from_none], obj.get("clientManaged")) permissions_allow_intersected = from_union([from_bool, from_none], obj.get("permissionsAllowIntersected")) + permissions_context = from_union([ManagedPermissionsContext.from_dict, from_none], obj.get("permissionsContext")) policy_helper_managed = from_union([from_bool, from_none], obj.get("policyHelperManaged")) sandbox_enabled_by_undetermined_policy = from_union([from_bool, from_none], obj.get("sandboxEnabledByUndeterminedPolicy")) settings = obj.get("settings") - return ManagedSettingsResolvedData(bypass_permissions_disabled, device_managed, fail_closed, managed_keys, server_managed, source, client_managed, permissions_allow_intersected, policy_helper_managed, sandbox_enabled_by_undetermined_policy, settings) + return ManagedSettingsResolvedData(bypass_permissions_disabled, device_managed, fail_closed, managed_keys, server_managed, source, client_managed, permissions_allow_intersected, permissions_context, policy_helper_managed, sandbox_enabled_by_undetermined_policy, settings) def to_dict(self) -> dict: result: dict = {} @@ -6676,6 +6696,8 @@ def to_dict(self) -> dict: result["clientManaged"] = from_union([from_bool, from_none], self.client_managed) if self.permissions_allow_intersected is not None: result["permissionsAllowIntersected"] = from_union([from_bool, from_none], self.permissions_allow_intersected) + if self.permissions_context is not None: + result["permissionsContext"] = from_union([lambda x: to_class(ManagedPermissionsContext, x), from_none], self.permissions_context) if self.policy_helper_managed is not None: result["policyHelperManaged"] = from_union([from_bool, from_none], self.policy_helper_managed) if self.sandbox_enabled_by_undetermined_policy is not None: @@ -19114,6 +19136,16 @@ def to_dict(self) -> dict: result["operation"] = from_str(self.operation) return result +# Experimental: this type is part of an experimental API and may change or be removed. +class ConnectorDiscoveryAvailability(Enum): + "Availability." + # Enabled. + ENABLED = "enabled" + # Disabled. + DISABLED = "disabled" + # Unavailable. + UNAVAILABLE = "unavailable" + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class AuthIdentityMetadata: @@ -19235,6 +19267,10 @@ class AccountStatus: selection_id: str """Opaque selection id used to switch to, or log out, this account.""" + auth_source: str | None = None + """Human-readable credential source used to authenticate this account, such as `gh` or + `GITHUB_TOKEN`. + """ derived_from: str | None = None """Opaque id of the account this one was derived from (e.g. an EMU account's base Entra identity); absent for a root account. Matches the base identity account's selectionId, @@ -19249,8 +19285,9 @@ def from_dict(obj: Any) -> 'AccountStatus': kind = AccountKind(obj.get("kind")) login = from_str(obj.get("login")) selection_id = from_str(obj.get("selectionId")) + auth_source = from_union([from_str, from_none], obj.get("authSource")) derived_from = from_union([from_str, from_none], obj.get("derivedFrom")) - return AccountStatus(active, host, kind, login, selection_id, derived_from) + return AccountStatus(active, host, kind, login, selection_id, auth_source, derived_from) def to_dict(self) -> dict: result: dict = {} @@ -19259,6 +19296,8 @@ def to_dict(self) -> dict: result["kind"] = to_enum(AccountKind, self.kind) result["login"] = from_str(self.login) result["selectionId"] = from_str(self.selection_id) + if self.auth_source is not None: + result["authSource"] = from_union([from_str, from_none], self.auth_source) if self.derived_from is not None: result["derivedFrom"] = from_union([from_str, from_none], self.derived_from) return result @@ -19279,6 +19318,10 @@ class ItemElement: active: bool | None = None """Whether this is the active account.""" + auth_source: str | None = None + """Human-readable credential source used to authenticate this account, such as `gh` or + `GITHUB_TOKEN`. + """ derived_from: str | None = None """Opaque id of the account this one was derived from (e.g. an EMU account's base Entra identity); absent for a root account. Matches the base identity account's selectionId, @@ -19304,19 +19347,22 @@ def from_dict(obj: Any) -> 'ItemElement': assert isinstance(obj, dict) kind = AccountKind(obj.get("kind")) active = from_union([from_bool, from_none], obj.get("active")) + auth_source = from_union([from_str, from_none], obj.get("authSource")) derived_from = from_union([from_str, from_none], obj.get("derivedFrom")) host = from_union([from_str, from_none], obj.get("host")) login = from_union([from_str, from_none], obj.get("login")) selection_id = from_union([from_str, from_none], obj.get("selectionId")) available = from_union([from_bool, from_none], obj.get("available")) label = from_union([from_str, from_none], obj.get("label")) - return ItemElement(kind, active, derived_from, host, login, selection_id, available, label) + return ItemElement(kind, active, auth_source, derived_from, host, login, selection_id, available, label) def to_dict(self) -> dict: result: dict = {} result["kind"] = to_enum(AccountKind, self.kind) if self.active is not None: result["active"] = from_union([from_bool, from_none], self.active) + if self.auth_source is not None: + result["authSource"] = from_union([from_str, from_none], self.auth_source) if self.derived_from is not None: result["derivedFrom"] = from_union([from_str, from_none], self.derived_from) if self.host is not None: @@ -33233,6 +33279,40 @@ def to_dict(self) -> dict: result["saved"] = from_union([lambda x: to_class(Saved, x), from_none], self.saved) return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class ConnectorDiscoveryCapabilities: + """Feature availability.""" + + api_version: int + """API version.""" + + availability: ConnectorDiscoveryAvailability + """Availability.""" + + conditional_cache: bool + """Whether results are cached.""" + + opaque_account_selection: bool + """Whether accounts are selected by opaque ID.""" + + @staticmethod + def from_dict(obj: Any) -> 'ConnectorDiscoveryCapabilities': + assert isinstance(obj, dict) + api_version = from_int(obj.get("apiVersion")) + availability = ConnectorDiscoveryAvailability(obj.get("availability")) + conditional_cache = from_bool(obj.get("conditionalCache")) + opaque_account_selection = from_bool(obj.get("opaqueAccountSelection")) + return ConnectorDiscoveryCapabilities(api_version, availability, conditional_cache, opaque_account_selection) + + def to_dict(self) -> dict: + result: dict = {} + result["apiVersion"] = from_int(self.api_version) + result["availability"] = to_enum(ConnectorDiscoveryAvailability, self.availability) + result["conditionalCache"] = from_bool(self.conditional_cache) + result["opaqueAccountSelection"] = from_bool(self.opaque_account_selection) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class ConnectorSessionAccount: @@ -36469,6 +36549,12 @@ class ManagedSettingsResolveResult: meta: ManagedSettingsMeta | None = None """Per-key lock state and provenance for the entries in `values`, using the same key names.""" + permissions_context: ManagedPermissionsContext | None = None + """Reusable source-composed permission policy for managedSettings.permissions.evaluate. + Unlike resolved.settings.permissions, this retains every source's allowlist and + default-prompt semantics. Refresh through resolve when account/device policy changes. + Absent on runtimes that do not support permission evaluation. + """ values: ManagedSettingsValues | None = None """Typed effective values of managed settings, keyed like the managed-settings schema and already resolved across channels, with the `{ "overridable": ... }` wrapper removed. @@ -36484,8 +36570,9 @@ def from_dict(obj: Any) -> 'ManagedSettingsResolveResult': resolved = ManagedSettingsResolvedData.from_dict(obj.get("resolved")) account = from_union([from_str, from_none], obj.get("account")) meta = from_union([ManagedSettingsMeta.from_dict, from_none], obj.get("meta")) + permissions_context = from_union([ManagedPermissionsContext.from_dict, from_none], obj.get("permissionsContext")) values = from_union([ManagedSettingsValues.from_dict, from_none], obj.get("values")) - return ManagedSettingsResolveResult(diagnostics, layers, resolved, account, meta, values) + return ManagedSettingsResolveResult(diagnostics, layers, resolved, account, meta, permissions_context, values) def to_dict(self) -> dict: result: dict = {} @@ -36496,6 +36583,8 @@ def to_dict(self) -> dict: result["account"] = from_union([from_str, from_none], self.account) if self.meta is not None: result["meta"] = from_union([lambda x: to_class(ManagedSettingsMeta, x), from_none], self.meta) + if self.permissions_context is not None: + result["permissionsContext"] = from_union([lambda x: to_class(ManagedPermissionsContext, x), from_none], self.permissions_context) if self.values is not None: result["values"] = from_union([lambda x: to_class(ManagedSettingsValues, x), from_none], self.values) return result @@ -41202,6 +41291,30 @@ def to_dict(self) -> dict: result["session"] = from_union([lambda x: to_class(CanvasSessionContext, x), from_none], self.session) return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class ConnectorDiscoveryAccountList: + """Eligible accounts.""" + + accounts: list[ConnectorDiscoveryAccount] + """Eligible accounts.""" + + availability: ConnectorDiscoveryAvailability + """Availability.""" + + @staticmethod + def from_dict(obj: Any) -> 'ConnectorDiscoveryAccountList': + assert isinstance(obj, dict) + accounts = from_list(ConnectorDiscoveryAccount.from_dict, obj.get("accounts")) + availability = ConnectorDiscoveryAvailability(obj.get("availability")) + return ConnectorDiscoveryAccountList(accounts, availability) + + def to_dict(self) -> dict: + result: dict = {} + result["accounts"] = from_list(lambda x: to_class(ConnectorDiscoveryAccount, x), self.accounts) + result["availability"] = to_enum(ConnectorDiscoveryAvailability, self.availability) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class EnvironmentsGetResult: @@ -45661,64 +45774,6 @@ def to_dict(self) -> dict: result["type"] = from_union([from_none, from_str], self.type) return result -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class ConnectorDiscoveryAccountList: - """Eligible accounts.""" - - accounts: list[ConnectorDiscoveryAccount] - """Eligible accounts.""" - - availability: ConnectorDiscoveryAvailability - """Availability.""" - - @staticmethod - def from_dict(obj: Any) -> 'ConnectorDiscoveryAccountList': - assert isinstance(obj, dict) - accounts = from_list(ConnectorDiscoveryAccount.from_dict, obj.get("accounts")) - availability = ConnectorDiscoveryAvailability(obj.get("availability")) - return ConnectorDiscoveryAccountList(accounts, availability) - - def to_dict(self) -> dict: - result: dict = {} - result["accounts"] = from_list(lambda x: to_class(ConnectorDiscoveryAccount, x), self.accounts) - result["availability"] = to_enum(ConnectorDiscoveryAvailability, self.availability) - return result - -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class ConnectorDiscoveryCapabilities: - """Feature availability.""" - - api_version: int - """API version.""" - - availability: ConnectorDiscoveryAvailability - """Availability.""" - - conditional_cache: bool - """Whether results are cached.""" - - opaque_account_selection: bool - """Whether accounts are selected by opaque ID.""" - - @staticmethod - def from_dict(obj: Any) -> 'ConnectorDiscoveryCapabilities': - assert isinstance(obj, dict) - api_version = from_int(obj.get("apiVersion")) - availability = ConnectorDiscoveryAvailability(obj.get("availability")) - conditional_cache = from_bool(obj.get("conditionalCache")) - opaque_account_selection = from_bool(obj.get("opaqueAccountSelection")) - return ConnectorDiscoveryCapabilities(api_version, availability, conditional_cache, opaque_account_selection) - - def to_dict(self) -> dict: - result: dict = {} - result["apiVersion"] = from_int(self.api_version) - result["availability"] = to_enum(ConnectorDiscoveryAvailability, self.availability) - result["conditionalCache"] = from_bool(self.conditional_cache) - result["opaqueAccountSelection"] = from_bool(self.opaque_account_selection) - return result - # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class CopilotAPITokenAuthInfo: @@ -46295,6 +46350,99 @@ def to_dict(self) -> dict: result["copilotUser"] = from_union([lambda x: to_class(CopilotUserResponse, x), from_none], self.copilot_user) return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class ManagedPermissionOperation: + """Original input operation associated with this verdict.""" + + kind: ManagedPermissionOperationKind + url: str + """Absolute HTTP(S) URL with a host. Invalid URLs reject the entire evaluation batch.""" + + @staticmethod + def from_dict(obj: Any) -> 'ManagedPermissionOperation': + assert isinstance(obj, dict) + kind = ManagedPermissionOperationKind(obj.get("kind")) + url = from_str(obj.get("url")) + return ManagedPermissionOperation(kind, url) + + def to_dict(self) -> dict: + result: dict = {} + result["kind"] = to_enum(ManagedPermissionOperationKind, self.kind) + result["url"] = from_str(self.url) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class ManagedPermissionEvaluation: + operation: ManagedPermissionOperation + """Original input operation associated with this verdict.""" + + verdict: ManagedPermissionVerdict + """Managed-policy decision only; never bypasses user permissions or other security controls.""" + + @staticmethod + def from_dict(obj: Any) -> 'ManagedPermissionEvaluation': + assert isinstance(obj, dict) + operation = ManagedPermissionOperation.from_dict(obj.get("operation")) + verdict = ManagedPermissionVerdict(obj.get("verdict")) + return ManagedPermissionEvaluation(operation, verdict) + + def to_dict(self) -> dict: + result: dict = {} + result["operation"] = to_class(ManagedPermissionOperation, self.operation) + result["verdict"] = to_enum(ManagedPermissionVerdict, self.verdict) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class ManagedPermissionsEvaluateRequest: + """Managed policy context and ordered operations for pure, sessionless evaluation.""" + + context: ManagedPermissionsContext + """Trusted, reusable managed permission policy snapshot; no policy is discovered during + evaluation. + """ + operations: list[ManagedPermissionOperation] + """Operations to evaluate, preserving input order and duplicates. An empty batch is valid.""" + + @staticmethod + def from_dict(obj: Any) -> 'ManagedPermissionsEvaluateRequest': + assert isinstance(obj, dict) + context = ManagedPermissionsContext.from_dict(obj.get("context")) + operations = from_list(ManagedPermissionOperation.from_dict, obj.get("operations")) + return ManagedPermissionsEvaluateRequest(context, operations) + + def to_dict(self) -> dict: + result: dict = {} + result["context"] = to_class(ManagedPermissionsContext, self.context) + result["operations"] = from_list(lambda x: to_class(ManagedPermissionOperation, x), self.operations) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class ManagedPermissionsEvaluateResult: + """Ordered managed permission verdicts and the supplied policy's fail-closed posture.""" + + fail_closed: bool + """Managed permission policy could not be determined; every operation is denied.""" + + results: list[ManagedPermissionEvaluation] + """One verdict per input operation, in the same order, including duplicates.""" + + @staticmethod + def from_dict(obj: Any) -> 'ManagedPermissionsEvaluateResult': + assert isinstance(obj, dict) + fail_closed = from_bool(obj.get("failClosed")) + results = from_list(ManagedPermissionEvaluation.from_dict, obj.get("results")) + return ManagedPermissionsEvaluateResult(fail_closed, results) + + def to_dict(self) -> dict: + result: dict = {} + result["failClosed"] = from_bool(self.fail_closed) + result["results"] = from_list(lambda x: to_class(ManagedPermissionEvaluation, x), self.results) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class ManagedSettingsSchemaResult: @@ -49758,6 +49906,12 @@ def to_dict(self) -> dict: result["terminal"] = from_union([lambda x: to_class(WorkflowRunTerminal, x), from_none], self.terminal) return result +def rpc_from_dict(s: Any) -> RPC: + return RPC.from_dict(s) + +def rpc_to_dict(x: RPC) -> Any: + return to_class(RPC, x) + @dataclass class RPC: abort_request: AbortRequest @@ -50248,6 +50402,12 @@ class RPC: log_result: LogResult lsp_initialize_request: LspInitializeRequest managed_mcp_server_config: ManagedMCPServerConfig + managed_permission_evaluation: ManagedPermissionEvaluation + managed_permission_operation: ManagedPermissionOperation + managed_permission_operation_kind: ManagedPermissionOperationKind + managed_permissions_evaluate_request: ManagedPermissionsEvaluateRequest + managed_permissions_evaluate_result: ManagedPermissionsEvaluateResult + managed_permission_verdict: ManagedPermissionVerdict managed_plugin_retry_entry: ManagedPluginRetryEntry managed_plugin_retry_status: ManagedPluginRetryStatus managed_setting_meta: ManagedSettingMeta @@ -51848,6 +52008,12 @@ def from_dict(obj: Any) -> 'RPC': log_result = LogResult.from_dict(obj.get("LogResult")) lsp_initialize_request = LspInitializeRequest.from_dict(obj.get("LspInitializeRequest")) managed_mcp_server_config = ManagedMCPServerConfig.from_dict(obj.get("ManagedMcpServerConfig")) + managed_permission_evaluation = ManagedPermissionEvaluation.from_dict(obj.get("ManagedPermissionEvaluation")) + managed_permission_operation = ManagedPermissionOperation.from_dict(obj.get("ManagedPermissionOperation")) + managed_permission_operation_kind = ManagedPermissionOperationKind(obj.get("ManagedPermissionOperationKind")) + managed_permissions_evaluate_request = ManagedPermissionsEvaluateRequest.from_dict(obj.get("ManagedPermissionsEvaluateRequest")) + managed_permissions_evaluate_result = ManagedPermissionsEvaluateResult.from_dict(obj.get("ManagedPermissionsEvaluateResult")) + managed_permission_verdict = ManagedPermissionVerdict(obj.get("ManagedPermissionVerdict")) managed_plugin_retry_entry = ManagedPluginRetryEntry.from_dict(obj.get("ManagedPluginRetryEntry")) managed_plugin_retry_status = ManagedPluginRetryStatus(obj.get("ManagedPluginRetryStatus")) managed_setting_meta = ManagedSettingMeta.from_dict(obj.get("ManagedSettingMeta")) @@ -52956,7 +53122,7 @@ def from_dict(obj: Any) -> 'RPC': subagent_settings = from_union([SubagentSettings.from_dict, from_none], obj.get("SubagentSettings")) task_progress = from_union([TaskProgress.from_dict, from_none], obj.get("TaskProgress")) workspace_summary = from_union([WorkspaceSummary.from_dict, from_none], obj.get("WorkspaceSummary")) - return RPC(abort_request, abort_result, accepted_enqueue_command_result, account_all_users, account_auth_info, account_get_all_users_result, account_get_current_auth_result, account_get_quota_request, account_get_quota_result, account_kind, account_login_request, account_login_result, account_logout_request, account_logout_result, account_quota_snapshot, accounts_enumerate_request, accounts_get_request, accounts_set_request, account_status, adaptive_thinking_support, agent_discovery_path, agent_discovery_path_list, agent_discovery_path_scope, agent_get_current_result, agent_info, agent_info_source, agent_list, agent_list_request, agent_registry_live_target_entry, agent_registry_live_target_entry_attention_kind, agent_registry_live_target_entry_kind, agent_registry_live_target_entry_last_terminal_event, agent_registry_live_target_entry_status, agent_registry_log_capture, agent_registry_log_capture_open_error_reason, agent_registry_spawn_error, agent_registry_spawn_permission_mode, agent_registry_spawn_registry_timeout, agent_registry_spawn_request, agent_registry_spawn_result, agent_registry_spawn_spawned, agent_registry_spawn_validation_error, agent_registry_spawn_validation_error_field, agent_registry_spawn_validation_error_reason, agent_reload_result, agents_custom_agent_initial_model_decision_params, agents_custom_agent_initial_model_decision_result, agents_discover_request, agent_select_request, agent_select_result, agent_set_prompt_request, agents_get_available_builtins_request, agents_get_available_builtins_result, agents_get_builtin_definition_request, agents_get_builtin_definition_result, agents_get_builtin_listing_definition_request, agents_get_builtin_listing_definition_result, agents_get_builtins_result, agents_get_discovery_paths_request, api_key_auth_info, auth_enumerate_query, auth_enumerate_value, auth_identity, auth_identity_metadata, auth_info, auth_info_type, auth_login_account, auth_login_advance_request, auth_login_begin_request, auth_login_begun, auth_login_cancel_request, auth_login_result_dto, auth_login_result_status, auth_login_step, auth_read_query, auth_read_value, auth_status_dto, auth_validation_error, auth_validation_errors, auth_write, auth_write_result, autopilot_objective_credit_limit, autopilot_objective_get_state_result, autopilot_objective_state, autopilot_objective_status, auto_tier_descriptor, auto_tier_metadata, auto_tier_status, builtin_agent_summary, built_in_model_catalog, built_in_model_catalog_entry, builtin_tool_descriptor, builtin_tool_format, builtin_tool_format_type, builtin_tool_input_schema, builtin_tool_input_schema_type, builtin_tool_safe_for_telemetry, builtin_tool_safe_telemetry_fields, cancel_user_requested_shell_command_result, canvas_action, canvas_action_invoke_request, canvas_action_invoke_result, canvas_close_request, canvas_host_context, canvas_host_context_capabilities, canvas_json_schema, canvas_list, canvas_list_open_result, canvas_open_request, canvas_provider_close_request, canvas_provider_invoke_action_request, canvas_provider_open_request, canvas_provider_open_result, canvas_provider_register_request, canvas_provider_unregister_request, canvas_session_context, capi_session_options, card_digest, card_digest_algorithm, card_digest_value, catalog_agent_plugin_candidate, catalog_agent_plugin_candidate_kind, catalog_agent_plugin_candidate_provenance, catalog_agent_plugin_compatibility_tag, catalog_agent_plugin_media_type, catalog_ai_skill_candidate, catalog_ai_skill_candidate_kind, catalog_ai_skill_candidate_provenance, catalog_ai_skill_installability, catalog_ai_skill_media_type, catalog_authentication_required_error, catalog_authentication_required_reason, catalog_candidate, catalog_candidate_kind, catalog_candidate_source, catalog_candidate_source_embedded, catalog_candidate_source_url, catalog_capability, catalog_capability_id, catalog_client_contract, catalog_contract_violation_error, catalog_contract_violation_reason, catalog_handle_rejected_error, catalog_handle_rejection_reason, catalog_handle_type, catalog_invalid_request_error, catalog_invalid_request_field, catalog_malformed_card_error, catalog_malformed_card_reason, catalog_mcp_server_candidate, catalog_mcp_server_candidate_kind, catalog_mcp_server_candidate_provenance, catalog_mcp_server_installability, catalog_media_type, catalog_negotiated_contract, catalog_negotiation_refused_error, catalog_negotiation_refused_reason, catalog_network_failure_error, catalog_network_failure_reason, catalog_not_installable_error, catalog_not_installable_reason, catalog_plugin_repository_source, catalog_policy_rejected_error, catalog_resource_identity, catalog_resource_version, catalog_search_page, catalog_search_pagination, catalog_search_request, catalog_search_result, catalog_search_succeeded, catalog_search_total_count_relation, catalog_selection_cancelled, catalog_selection_decision, catalog_selection_declined, catalog_selection_foreign, catalog_selection_invalid, catalog_selection_replayed, catalog_selection_request, catalog_selection_result, catalog_selection_selected, catalog_selection_stale, catalog_selection_timed_out, catalog_selection_wrong_kind, catalog_trust_eligibility, catalog_trust_provenance, catalog_trust_snapshot, catalog_trust_snapshot_absent, catalog_trust_snapshot_absent_status, catalog_trust_snapshot_current, catalog_trust_snapshot_current_status, catalog_trust_snapshot_downgraded, catalog_trust_snapshot_downgraded_status, catalog_trust_snapshot_malformed, catalog_trust_snapshot_malformed_status, catalog_trust_snapshot_revoked, catalog_trust_snapshot_revoked_status, catalog_trust_snapshot_schema_version, catalog_trust_snapshot_stale, catalog_trust_snapshot_stale_status, catalog_trust_snapshot_unsupported, catalog_trust_snapshot_unsupported_status, catalog_trust_source, catalog_trust_tier, catalog_unavailable_error, catalog_unavailable_reason, catalog_unavailable_transport_error, catalog_unavailable_transport_reason, catalog_unsafe_retrieval_error, catalog_unsafe_retrieval_reason, catalog_unsupported_kind_error, client_metadata, client_task_cancel_reason, client_task_cancel_request, client_task_cancel_result, command_list, commands_finalize_invocation_effect_request, commands_finalize_invocation_effect_result, commands_handle_pending_command_request, commands_handle_pending_command_result, commands_invocation_effect_outcome, commands_invocation_origin, commands_invoke_request, commands_list_request, commands_respond_to_queued_command_request, commands_respond_to_queued_command_result, completions_get_trigger_characters_result, completions_request_request, completions_request_result, configure_session_extensions_params, connect_client_info, connected_remote_session_metadata, connected_remote_session_metadata_kind, connected_remote_session_metadata_repository, connector_account_request, connector_authorization_requirement, connector_authorization_scope, connector_availability, connector_capabilities, connector_catalog_entry, connector_catalog_result, connector_catalog_status, connector_connect_request, connector_connect_result, connector_continue_request, connector_disconnect_result, connector_discovery_account, connector_discovery_account_list, connector_discovery_account_request, connector_discovery_auth_info, connector_discovery_availability, connector_discovery_capabilities, connector_discovery_catalog_entry, connector_discovery_catalog_result, connector_mcp_status, connector_reconcile_request, connector_runtime_status, connector_session_account, connector_status, connect_remote_session_params, connect_request, connect_result, content_exclusion_check_paths_request, content_exclusion_check_paths_result, content_exclusion_path_check, content_filter_mode, context_heaviest_message, copilot_api_token_auth_info, copilot_user_response, copilot_user_response_endpoints, copilot_user_response_quota_snapshots, copilot_user_response_quota_snapshots_chat, copilot_user_response_quota_snapshots_completions, copilot_user_response_quota_snapshots_premium_interactions, current_model, current_tool_metadata, customization_reload_outcome, customization_reload_status, customization_reload_subsystem, customizations_reload_result, debug_collect_logs_collected_entry, debug_collect_logs_destination, debug_collect_logs_entry, debug_collect_logs_entry_kind, debug_collect_logs_include, debug_collect_logs_redaction, debug_collect_logs_request, debug_collect_logs_result, debug_collect_logs_result_kind, debug_collect_logs_skipped_entry, debug_collect_logs_source, diagnostic_cursor_status, diagnostic_entry, diagnostic_log_level, diagnostics_configuration, diagnostics_configure_request, diagnostic_severity, diagnostic_source, diagnostic_sources_configuration, diagnostics_read_request, diagnostics_read_result, discovered_canvas, discovered_extension, discovered_extension_mode, discovered_extension_plugin, discovered_extensions, discovered_extensions_disable_request, discovered_extensions_enable_request, discovered_extension_source, discovered_hook, discovered_mcp_server, discovered_mcp_server_type, discovered_model, discovered_model_list, enqueue_command_params, enqueue_command_result, env_auth_info, environment_capabilities, environment_kind, environments_delete_request, environments_delete_result, environments_get_request, environments_get_result, environments_list_request, environments_list_result, event_log_read_request, event_log_release_interest_result, event_log_tail_result, event_log_types, events_agent_scope, events_cursor_status, events_read_direction, events_read_result, execute_command_params, execute_command_result, extension, extension_context_push_input, extension_launch_profile, extension_launch_provider_resolve_request, extension_launch_provider_resolve_result, extension_list, extensions_disable_request, extensions_enable_request, extension_source, extension_status, external_tool_result, external_tool_text_result_for_llm, external_tool_text_result_for_llm_binary_results_for_llm, external_tool_text_result_for_llm_binary_results_for_llm_type, external_tool_text_result_for_llm_content, external_tool_text_result_for_llm_content_audio, external_tool_text_result_for_llm_content_image, external_tool_text_result_for_llm_content_resource, external_tool_text_result_for_llm_content_resource_details, external_tool_text_result_for_llm_content_resource_link, external_tool_text_result_for_llm_content_resource_link_icon, external_tool_text_result_for_llm_content_resource_link_icon_theme, external_tool_text_result_for_llm_content_shell_exit, external_tool_text_result_for_llm_content_terminal, external_tool_text_result_for_llm_content_text, filter_mapping, fleet_start_request, fleet_start_result, folder_trust_add_params, folder_trust_check_params, folder_trust_check_result, gh_cli_auth_info, git_current_branch_remote_result, git_cwd_request, git_hub_environment, git_hub_owner_option, git_hub_owners_cancel_request, git_hub_owners_cancel_result, git_hub_owners_list_request, git_hub_owners_list_result, git_hub_owners_request_id_result, git_hub_repository_at_path_request, git_hub_repository_at_path_result, git_hub_repository_identity, git_hub_telemetry_client_info, git_hub_telemetry_event, git_hub_telemetry_notification, git_hub_token_acquire_reason, git_hub_token_acquire_request, git_hub_token_acquire_result, git_remote_repository, git_repos_from_remotes_request, git_repos_from_remotes_result, global_state_load_for_config_dir_request, global_state_load_result, global_state_write_key_request, handle_pending_tool_call_request, handle_pending_tool_call_result, history_abort_manual_compaction_result, history_cancel_background_compaction_result, history_clear_context_request, history_clear_context_result, history_compact_context_window, history_compact_request, history_compact_result, history_file_restore_skip_reason, history_list_rewind_points_result, history_preview_rewind_request, history_preview_rewind_result, history_rewind_change_type, history_rewind_file_preview, history_rewind_mode, history_rewind_outcome, history_rewind_point, history_rewind_request, history_rewind_result, history_rewind_unavailable_reason, history_skipped_file_restore, history_summarize_for_handoff_result, history_truncate_request, history_truncate_result, hmac_auth_info, hook_invoke_request, hook_invoke_response, hook_origin, hooks_discover_request, hooks_discover_result, hook_type, host_configuration, host_dispose_request, host_empty_result, host_environment_credentials, host_exited_notification, host_exit_reason, host_git_hub_environment_options, host_list_sessions_request, host_list_sessions_result, host_local_server_configuration, host_local_server_options, host_publish_session_request, host_publish_session_result, host_ready_request, host_register_session_request, host_session_create_callback, host_session_create_request, host_session_create_result, host_session_released_notification, host_session_release_request, host_session_summary, host_start_request, host_start_result, installation_catalogue_identity, installation_confirmation_request, installation_confirmation_response, installation_decision, installation_review, installed_plugin, installed_plugin_info, installed_plugin_source, installed_plugin_source_git_hub, installed_plugin_source_local, installed_plugin_source_url, instruction_discovery_path, instruction_discovery_path_kind, instruction_discovery_path_list, instruction_discovery_path_location, instructions_discover_request, instructions_get_discovery_paths_request, instructions_get_sources_result, instruction_source, instruction_source_location, instruction_source_type, interrupt_main_turn_request, interrupt_main_turn_result, json_schema_response_format, llm_inference_headers, llm_inference_http_request_chunk_request, llm_inference_http_request_chunk_result, llm_inference_http_request_start_request, llm_inference_http_request_start_result, llm_inference_http_request_start_transport, llm_inference_http_response_chunk_error, llm_inference_http_response_chunk_request, llm_inference_http_response_chunk_result, llm_inference_http_response_start_request, llm_inference_http_response_start_result, llm_inference_set_provider_result, local_session_metadata_value, logged_in_user, login_provider_kind, log_request, log_result, lsp_initialize_request, managed_mcp_server_config, managed_plugin_retry_entry, managed_plugin_retry_status, managed_setting_meta, managed_settings_channel, managed_settings_compose_layer, managed_settings_compose_request, managed_settings_compose_result, managed_settings_diagnostic, managed_settings_diagnostic_severity, managed_settings_layer, managed_settings_meta, managed_settings_read_result, managed_settings_resolved_data, managed_settings_resolve_request, managed_settings_resolve_result, managed_settings_schema_result, managed_settings_validate_request, managed_settings_validate_result, managed_settings_values, marketplace_add_result, marketplace_browse_result, marketplace_info, marketplace_list_result, marketplace_plugin_info, marketplace_refresh_entry, marketplace_refresh_result, marketplace_remove_result, mcp_allowed_server, mcp_apply_install_request, mcp_apply_uninstall_request, mcp_apps_call_tool_request, mcp_apps_diagnose_capability, mcp_apps_diagnose_request, mcp_apps_diagnose_result, mcp_apps_diagnose_server, mcp_apps_host_context, mcp_apps_host_context_details, mcp_apps_host_context_details_available_display_mode, mcp_apps_host_context_details_display_mode, mcp_apps_host_context_details_platform, mcp_apps_host_context_details_theme, mcp_apps_list_tools_request, mcp_apps_list_tools_result, mcp_apps_read_resource_request, mcp_apps_read_resource_result, mcp_apps_resource_content, mcp_apps_set_host_context_details, mcp_apps_set_host_context_details_available_display_mode, mcp_apps_set_host_context_details_display_mode, mcp_apps_set_host_context_details_platform, mcp_apps_set_host_context_details_theme, mcp_apps_set_host_context_request, mcp_cancel_sampling_execution_params, mcp_cancel_sampling_execution_result, mcp_config_add_request, mcp_config_disable_request, mcp_config_enable_request, mcp_config_list, mcp_config_remove_request, mcp_config_update_request, mcp_configured_server, mcp_configured_server_list, mcp_configured_server_state, mcp_configure_git_hub_request, mcp_configure_git_hub_result, mcp_diagnostic_details, mcp_diagnostic_direction, mcp_diagnostic_kind, mcp_diagnostic_source_configuration, mcp_disable_request, mcp_discover_request, mcp_discover_result, mcp_elicitation_form_mode, mcp_enable_request, mcp_execute_sampling_params, mcp_execute_sampling_request, mcp_execute_sampling_result, mcp_failed_server, mcp_filtered_server, mcp_headers_handle_pending_headers_refresh_request, mcp_headers_handle_pending_headers_refresh_request_request, mcp_headers_handle_pending_headers_refresh_request_result, mcp_host_state, mcp_installation_failure_reason, mcp_installation_input, mcp_installation_management_outcome, mcp_installation_management_result, mcp_installation_operation_request, mcp_installation_operation_status, mcp_installation_outcome, mcp_installation_remote_configuration, mcp_installation_result, mcp_installation_review, mcp_installation_secret, mcp_installation_secret_storage, mcp_installations_request, mcp_installation_state, mcp_installation_summary, mcp_install_plan, mcp_is_server_running_request, mcp_is_server_running_result, mcp_list_tools_request, mcp_list_tools_result, mcp_oauth_authentication_state_changed_request, mcp_oauth_cancel_login_request, mcp_oauth_cancel_login_result, mcp_oauth_complete_request, mcp_oauth_handle_pending_request, mcp_oauth_handle_pending_result, mcp_oauth_login_grant_type, mcp_oauth_login_request, mcp_oauth_login_result, mcp_oauth_pending_request_response, mcp_oauth_prepare_login_request, mcp_oauth_prepare_login_result, mcp_oauth_probe_needs_auth_reason, mcp_oauth_probe_request, mcp_oauth_probe_result, mcp_oauth_respond_request, mcp_oauth_respond_result, mcp_owned_oauth_login_status, mcp_plan_configuration_change, mcp_plan_configuration_operation, mcp_plan_enum_value_type, mcp_plan_install_planned, mcp_plan_install_request, mcp_plan_install_result, mcp_plan_install_source, mcp_plan_install_source_candidate, mcp_plan_install_source_candidate_kind, mcp_plan_install_source_card, mcp_plan_install_source_card_kind, mcp_plan_package_install_method, mcp_plan_package_transport, mcp_plan_policy_decision, mcp_plan_policy_result, mcp_plan_policy_source, mcp_plan_provenance, mcp_plan_remote_install_method, mcp_plan_remote_transport, mcp_plan_required_value, mcp_plan_required_value_enum, mcp_plan_required_value_enum_kind, mcp_plan_required_value_scalar, mcp_plan_required_value_scalar_kind, mcp_plan_resource_identity, mcp_plan_scalar_value_type, mcp_plan_scope, mcp_plan_secret_placeholder, mcp_plan_secret_reference, mcp_plan_target, mcp_plan_transport_choice, mcp_plan_transport_choice_package, mcp_plan_transport_choice_remote, mcp_plan_uninstall_request, mcp_plan_value_category, mcp_prepared_install, mcp_prepare_install_request, mcp_prompt, mcp_prompt_argument, mcp_prompt_icon, mcp_prompt_message, mcp_prompt_role, mcp_prompts_get_request, mcp_prompts_get_result, mcp_prompts_list_request, mcp_prompts_list_result, mcp_register_external_client_request, mcp_reload_config, mcp_reload_with_config_request, mcp_remove_git_hub_result, mcp_resource, mcp_resource_annotations, mcp_resource_content, mcp_resource_icon, mcp_resources_list_request, mcp_resources_list_result, mcp_resources_list_templates_request, mcp_resources_list_templates_result, mcp_resources_read_request, mcp_resources_read_result, mcp_resource_template, mcp_restart_server_request, mcp_safe_for_telemetry, mcp_safe_for_telemetry_fields, mcp_sampling_execution_action, mcp_sampling_execution_result, mcp_serializable_server_config, mcp_server, mcp_server_auth_config, mcp_server_auth_config_redirect_port, mcp_server_card_embedded, mcp_server_card_embedded_kind, mcp_server_card_media_type, mcp_server_card_reference, mcp_server_card_url, mcp_server_card_url_kind, mcp_server_config, mcp_server_config_defer_tools, mcp_server_config_http, mcp_server_config_http_oauth_grant_type, mcp_server_config_http_type, mcp_server_config_memory, mcp_server_config_memory_type, mcp_server_config_stdio, mcp_server_config_stdio_type, mcp_server_failure_info, mcp_server_list, mcp_server_needs_auth_info, mcp_server_ownership, mcp_set_env_value_mode_details, mcp_set_env_value_mode_params, mcp_set_env_value_mode_result, mcp_source_file, mcp_source_plugin, mcp_source_ref, mcp_start_server_request, mcp_start_servers_result, mcp_stop_server_request, mcp_task_metadata, mcp_tools, mcp_tool_ui, mcp_tool_ui_visibility, mcp_uninstall_plan, mcp_unregister_external_client_request, memory_configuration, metadata_context_attribution_result, metadata_context_heaviest_messages_request, metadata_context_heaviest_messages_result, metadata_context_info_request, metadata_context_info_result, metadata_is_processing_result, metadata_recompute_context_tokens_request, metadata_recompute_context_tokens_result, metadata_record_context_change_request, metadata_record_context_change_result, metadata_set_working_directory_request, metadata_set_working_directory_result, metadata_snapshot_current_mode, metadata_snapshot_remote_metadata, metadata_snapshot_remote_metadata_repository, metadata_snapshot_remote_metadata_task_type, metadata_update_client_metadata_request, model, model_apply_startup_overlay_request, model_artifact_details, model_billing, model_billing_promo, model_billing_token_prices, model_billing_token_prices_long_context, model_capabilities, model_capabilities_limits, model_capabilities_limits_vision, model_capabilities_override, model_capabilities_override_limits, model_capabilities_override_limits_vision, model_capabilities_override_supports, model_capabilities_supports, model_clear_startup_seed_request, model_clear_startup_seed_result, model_list, model_list_request, model_message, model_picker_category, model_picker_persistence_request, model_picker_price_category, model_picker_settings_context, model_policy, model_policy_state, model_provider_adapter_catalog, model_provider_adapter_descriptor, model_provider_adapter_operation_descriptor, model_provider_attribution, model_provider_automatic_discovery_mode, model_provider_automatic_discovery_policy, model_provider_configuration_disposition, model_provider_configuration_plan, model_provider_descriptor, model_provider_discover_request, model_provider_discover_result, model_provider_discovery_network_scope, model_provider_get_status_request, model_provider_instance, model_provider_instance_reference, model_provider_models_list_request, model_provider_operation_outcome, model_provider_operation_outcome_code, model_provider_prepare_configuration_request, model_provider_provenance, model_provider_provenance_source, model_provider_status, model_provider_warning, model_set_allowed_models_request, model_set_allowed_models_result, model_set_reasoning_effort_request, model_set_reasoning_effort_result, models_list_request, model_switch_auto_tier_request, model_switch_auto_tier_result, model_switch_auto_tier_status, model_switch_confirmation, model_switch_to_request, model_switch_to_result, model_warning_text, mode_set_request, mode_set_result, move_mcp_loading_to_background_result, named_provider_config, name_get_result, name_set_auto_request, name_set_auto_result, name_set_request, open_canvas_instance, options_update_additional_content_exclusion_policy, options_update_additional_content_exclusion_policy_rule, options_update_additional_content_exclusion_policy_rule_source, options_update_additional_content_exclusion_policy_scope, options_update_context_tier, options_update_env_value_mode, options_update_reasoning_summary, options_update_tool_filter_precedence, pending_external_tool_request, pending_external_tool_request_list, pending_permission_request, pending_permission_request_list, permission_decision, permission_decision_approved, permission_decision_approved_for_location, permission_decision_approved_for_session, permission_decision_approve_for_location, permission_decision_approve_for_location_approval, permission_decision_approve_for_location_approval_commands, permission_decision_approve_for_location_approval_custom_tool, permission_decision_approve_for_location_approval_extension_env_access, permission_decision_approve_for_location_approval_extension_management, permission_decision_approve_for_location_approval_extension_permission_access, permission_decision_approve_for_location_approval_mcp, permission_decision_approve_for_location_approval_mcp_sampling, permission_decision_approve_for_location_approval_memory, permission_decision_approve_for_location_approval_read, permission_decision_approve_for_location_approval_workflow, permission_decision_approve_for_location_approval_write, permission_decision_approve_for_session, permission_decision_approve_for_session_approval, permission_decision_approve_for_session_approval_commands, permission_decision_approve_for_session_approval_custom_tool, permission_decision_approve_for_session_approval_extension_env_access, permission_decision_approve_for_session_approval_extension_management, permission_decision_approve_for_session_approval_extension_permission_access, permission_decision_approve_for_session_approval_mcp, permission_decision_approve_for_session_approval_mcp_sampling, permission_decision_approve_for_session_approval_memory, permission_decision_approve_for_session_approval_read, permission_decision_approve_for_session_approval_workflow, permission_decision_approve_for_session_approval_write, permission_decision_approve_once, permission_decision_approve_permanently, permission_decision_approve_read_only_for_session, permission_decision_cancelled, permission_decision_context, permission_decision_denied_by_content_exclusion_policy, permission_decision_denied_by_permission_request_hook, permission_decision_denied_by_rules, permission_decision_denied_interactively_by_user, permission_decision_denied_no_approval_rule_and_could_not_request_from_user, permission_decision_outcome, permission_decision_reject, permission_decision_request, permission_decision_surface, permission_decision_user_not_available, permission_location_add_tool_approval_params, permission_location_apply_params, permission_location_apply_result, permission_location_resolve_params, permission_location_resolve_result, permission_location_type, permission_mode_source, permission_paths_add_params, permission_paths_allowed_check_params, permission_paths_allowed_check_result, permission_paths_config, permission_paths_list, permission_paths_update_primary_params, permission_paths_workspace_check_params, permission_paths_workspace_check_result, permission_prompt_shown_notification, permission_request_result, permission_response_capability, permission_rules_set, permissions_configure_additional_content_exclusion_policy, permissions_configure_additional_content_exclusion_policy_rule, permissions_configure_additional_content_exclusion_policy_rule_source, permissions_configure_additional_content_exclusion_policy_scope, permissions_configure_params, permissions_configure_result, permissions_folder_trust_add_trusted_result, permissions_get_mode_request, permissions_get_mode_result, permissions_locations_add_tool_approval_details, permissions_locations_add_tool_approval_details_commands, permissions_locations_add_tool_approval_details_custom_tool, permissions_locations_add_tool_approval_details_extension_env_access, permissions_locations_add_tool_approval_details_extension_management, permissions_locations_add_tool_approval_details_extension_permission_access, permissions_locations_add_tool_approval_details_mcp, permissions_locations_add_tool_approval_details_mcp_sampling, permissions_locations_add_tool_approval_details_memory, permissions_locations_add_tool_approval_details_read, permissions_locations_add_tool_approval_details_workflow, permissions_locations_add_tool_approval_details_write, permissions_locations_add_tool_approval_result, permissions_modify_rules_params, permissions_modify_rules_result, permissions_modify_rules_scope, permissions_notify_prompt_shown_result, permissions_paths_add_result, permissions_paths_list_request, permissions_paths_update_primary_result, permissions_pending_requests_request, permissions_reset_session_approvals_request, permissions_reset_session_approvals_result, permissions_set_approve_all_request, permissions_set_approve_all_result, permissions_set_approve_all_source, permissions_set_mode_request, permissions_set_mode_result, permissions_set_required_request, permissions_set_required_result, permissions_urls_set_unrestricted_mode_result, permission_urls_config, permission_urls_set_unrestricted_mode_params, ping_request, ping_result, plan_read_result, plan_read_sql_todos_result, plan_read_sql_todos_with_dependencies_result, plan_sql_todo_dependency, plan_sql_todos_row, plan_update_request, plugin, plugin_install_result, plugin_install_staging_mode, plugin_list, plugin_list_result, plugins_builtin_set_request, plugins_disable_request, plugins_enable_request, plugins_install_request, plugins_marketplaces_add_request, plugins_marketplaces_browse_request, plugins_marketplaces_refresh_request, plugins_marketplaces_remove_request, plugins_reload_request, plugins_uninstall_request, plugins_update_request, plugin_update_all_entry, plugin_update_all_result, plugin_update_result, protocol_append_mode, protocol_customize_mode, protocol_external_tool_defer, protocol_external_tool_definition, protocol_marker_section_override, protocol_replace_mode, protocol_section_override, protocol_static_section_action, protocol_static_section_override, protocol_system_message_append_config, protocol_system_message_config, protocol_system_message_customize_config, protocol_system_message_replace_config, provider_add_request, provider_add_result, provider_config, provider_config_azure, provider_config_model_provider, provider_config_transport, provider_config_type, provider_config_wire_api, provider_descriptor, provider_endpoint, provider_endpoint_transport, provider_endpoint_type, provider_endpoint_wire_api, provider_get_endpoint_request, provider_model_config, provider_session_token, provider_sync_request, provider_sync_result, provider_token_acquire_request, provider_token_acquire_result, provider_withdraw_request, provider_withdraw_result, push_attachment, push_attachment_blob, push_attachment_directory, push_attachment_file, push_attachment_file_line_range, push_attachment_git_hub_actions_job, push_attachment_git_hub_commit, push_attachment_git_hub_file, push_attachment_git_hub_file_diff, push_attachment_git_hub_file_diff_side, push_attachment_git_hub_reference, push_attachment_git_hub_reference_type, push_attachment_git_hub_release, push_attachment_git_hub_repository, push_attachment_git_hub_snippet, push_attachment_git_hub_tree_comparison, push_attachment_git_hub_tree_comparison_side, push_attachment_git_hub_url, push_attachment_selection, push_attachment_selection_details, push_attachment_selection_details_end, push_attachment_selection_details_start, push_git_hub_repo_ref, queue_append_steering_request, queue_begin_deferred_idle_drain_request, queue_begin_deferred_idle_drain_result, queue_consume_system_notifications_request, queued_command_handled, queued_command_not_handled, queued_command_result, queue_defer_session_idle_request, queue_duplicate_at_request, queue_duplicate_at_result, queue_enqueue_resume_pending_result, queue_finish_deferred_idle_drain_request, queue_finish_deferred_idle_drain_result, queue_has_pending_result, queue_insert_at_request, queue_insert_at_result, queue_insert_message, queue_move_item_request, queue_move_item_result, queue_pending_items, queue_pending_items_kind, queue_pending_items_result, queue_remove_at_request, queue_remove_at_result, queue_remove_most_recent_result, queue_send_now_request, queue_send_now_result, queue_set_drain_paused_request, queue_snapshot_result, queue_update_text_request, queue_update_text_result, queue_withdraw_message_request, queue_withdraw_message_result, quota_take_warnings_result, quota_warning_projection, register_event_interest_params, register_event_interest_result, release_event_interest_params, remote_control_config, remote_control_config_existing_mc_session, remote_control_status, remote_control_status_active, remote_control_status_connecting, remote_control_status_error, remote_control_status_off, remote_control_status_result, remote_control_stop_result, remote_control_transfer_result, remote_enable_request, remote_enable_result, remote_notify_steerable_changed_request, remote_notify_steerable_changed_result, remote_session_connection_result, remote_session_host_status, remote_session_metadata_repository, remote_session_metadata_task_type, remote_session_metadata_value, remote_session_mode, remote_session_repository, response_format, sandbox_config, sandbox_config_auth, sandbox_config_source, sandbox_config_user_policy, sandbox_config_user_policy_experimental, sandbox_config_user_policy_experimental_seatbelt, sandbox_config_user_policy_filesystem, sandbox_config_user_policy_network, sandbox_config_user_policy_network_proxy, sandbox_config_user_policy_seatbelt, sandbox_credentials_config, sandbox_disable_for_session_request, sandbox_disable_for_session_result, sandbox_enforcement_status, sandbox_grant_path_for_request_request, sandbox_grant_path_for_request_result, sandbox_host_capability, sandbox_host_capability_name, sandbox_host_support, sandbox_masked_env_var, sandbox_proxy_ca_create_result, sandbox_proxy_ca_request, sandbox_proxy_ca_state, sandbox_proxy_ca_status, sandbox_session_change, schedule_add_at_request, schedule_add_cron_request, schedule_add_request, schedule_add_result, schedule_add_self_paced_request, schedule_entry, schedule_has_self_paced_result, schedule_list, schedule_rearm_self_paced_request, schedule_stop_request, schedule_stop_result, secrets_add_filter_values_request, secrets_add_filter_values_result, send_agent_mode, send_attachments_to_message_params, send_message_item, send_messages_request, send_messages_result, send_mode, send_request, send_result, send_system_notification_request, server_agent_list, server_instruction_source_list, server_skill, server_skill_list, session_activity, session_agent_list_request, session_auth_login_request, session_auth_logout_user_request, session_auth_status, session_auth_switch_request, session_bulk_delete_result, session_cancel_all_background_agents_result, session_capability, session_commands_list_request, session_completion_item, session_connected_ide_info, session_context, session_context_host_type, session_enrich_metadata_result, session_fs_append_file_request, session_fs_error, session_fs_error_code, session_fs_exists_request, session_fs_exists_result, session_fs_mkdir_request, session_fs_readdir_request, session_fs_readdir_result, session_fs_readdir_with_types_entry, session_fs_readdir_with_types_entry_type, session_fs_readdir_with_types_request, session_fs_readdir_with_types_result, session_fs_read_file_bytes_request, session_fs_read_file_bytes_result, session_fs_read_file_request, session_fs_read_file_result, session_fs_rename_request, session_fs_rm_request, session_fs_set_provider_capabilities, session_fs_set_provider_conventions, session_fs_set_provider_request, session_fs_set_provider_result, session_fs_sqlite_exists_request, session_fs_sqlite_exists_result, session_fs_sqlite_query_request, session_fs_sqlite_query_result, session_fs_sqlite_query_type, session_fs_sqlite_transaction_error, session_fs_sqlite_transaction_error_class, session_fs_sqlite_transaction_request, session_fs_sqlite_transaction_result, session_fs_sqlite_transaction_statement, session_fs_stat_request, session_fs_stat_result, session_fs_write_file_bytes_request, session_fs_write_file_request, session_git_hub_auth_get_all_auth_available_result, session_git_hub_auth_logout_result, session_git_hub_auth_logout_user_result, session_history_compact_request, session_installed_plugin, session_installed_plugin_source, session_installed_plugin_source_git_hub, session_installed_plugin_source_local, session_installed_plugin_source_url, session_limit_prediction_baseline_data, session_limit_prediction_client_type, session_limit_prediction_details, session_limit_prediction_predict_request, session_limit_prediction_request, session_limit_prediction_result, session_limit_prediction_source, session_limit_prediction_tier, session_limit_prediction_tier_option, session_limit_prediction_unavailable_reason, session_list, session_list_entry, session_list_filter, session_load_deferred_repo_hooks_result, session_log_level, session_managed_permissions, session_managed_settings, session_mcp_apps_call_tool_result, session_mcp_oauth_cancel_login_request, session_mcp_oauth_cancel_login_result, session_mcp_oauth_prepare_login_request, session_mcp_oauth_prepare_login_result, session_mcp_set_connected_ide_info_params, session_metadata_snapshot, session_mode, session_model_clear_startup_seed_request, session_model_clear_startup_seed_result, session_model_list, session_model_list_request, session_model_price_category, session_open_options, session_open_options_additional_content_exclusion_policy, session_open_options_additional_content_exclusion_policy_rule, session_open_options_additional_content_exclusion_policy_rule_source, session_open_options_additional_content_exclusion_policy_scope, session_open_options_env_value_mode, session_open_options_reasoning_summary, session_open_params, session_open_result, session_plugins_disable_request, session_plugins_enable_request, session_plugins_install_request, session_plugins_marketplaces_refresh_request, session_plugins_reload_request, session_plugins_retry_managed_request, session_plugins_retry_managed_result, session_provider_get_endpoint_request, session_prune_result, session_quota_delegate_warning, session_quota_get_result, session_quota_plan_tier, session_quota_projection, session_quota_refresh_result, session_quota_snapshot, session_quota_take_warnings_result, sessions_bulk_delete_request, sessions_check_in_use_request, sessions_check_in_use_result, sessions_client_metadata_entry, sessions_close_request, sessions_close_result, sessions_create_workspace_request, sessions_create_workspace_result, sessions_delete_request, sessions_enrich_metadata_request, session_set_credentials_params, session_set_credentials_result, session_settings_built_in_tool_availability_snapshot, session_settings_evaluate_predicate_request, session_settings_evaluate_predicate_result, session_settings_job_snapshot, session_settings_model_snapshot, session_settings_online_evaluation_snapshot, session_settings_predicate_name, session_settings_repo_snapshot, session_settings_snapshot, session_settings_validation_snapshot, sessions_find_by_prefix_request, sessions_find_by_prefix_result, sessions_find_by_task_id_request, sessions_find_by_task_id_result, sessions_fork_request, sessions_fork_result, sessions_get_board_entry_count_request, sessions_get_board_entry_count_result, sessions_get_client_metadata_request, sessions_get_client_metadata_result, sessions_get_event_file_path_request, sessions_get_event_file_path_result, sessions_get_last_for_context_request, sessions_get_last_for_context_result, sessions_get_metadata_request, sessions_get_metadata_result, sessions_get_persisted_remote_steerable_request, sessions_get_persisted_remote_steerable_result, session_sizes, sessions_list_non_empty_session_ids_request, sessions_list_non_empty_session_ids_result, sessions_list_request, sessions_load_deferred_repo_hooks_request, sessions_load_workspace_request, sessions_load_workspace_result, sessions_open_attach, sessions_open_cloud, sessions_open_create, sessions_open_handoff, sessions_open_handoff_task_type, sessions_open_progress, sessions_open_progress_status, sessions_open_progress_step, sessions_open_remote, sessions_open_resume, sessions_open_resume_last, sessions_open_status, session_source, sessions_prune_old_request, sessions_read_persisted_events_request, sessions_release_lock_request, sessions_release_lock_result, sessions_reload_plugin_hooks_request, sessions_reload_plugin_hooks_result, sessions_save_request, sessions_save_result, sessions_set_additional_plugins_request, sessions_set_additional_plugins_result, sessions_set_remote_control_steering_request, sessions_start_remote_control_request, sessions_stop_remote_control_request, sessions_transfer_remote_control_request, sessions_update_workspace_fields_request, sessions_update_workspace_fields_result, session_telemetry_engagement, session_update_options_params, session_update_options_result, session_usage_set_code_changes_request, session_visibility_status, session_workflow_pause_at_checkpoint_result, session_working_directory_context, session_working_directory_context_host_type, session_working_directory_context_with_client, settable_auth_info, settable_token_auth_info, shell_cancel_user_requested_request, shell_credentials, shell_exec_request, shell_exec_result, shell_execute_user_requested_request, shell_init_profile, shell_init_script, shell_init_script_shell, shell_kill_request, shell_kill_result, shell_kill_signal, shell_options, shutdown_request, skill, skill_apply_install_request, skill_apply_uninstall_request, skill_discovery_path, skill_discovery_path_list, skill_discovery_scope, skill_installation_failure_reason, skill_installation_file_review, skill_installation_location, skill_installation_management_outcome, skill_installation_management_result, skill_installation_operation_request, skill_installation_operation_status, skill_installation_outcome, skill_installation_ownership_state, skill_installation_result, skill_installation_review, skill_installation_scope, skill_installation_session_state, skill_installation_source, skill_installations_request, skill_installation_summary, skill_install_plan, skill_list, skill_plan_install_request, skill_plan_uninstall_request, skill_provider_descriptor, skill_provider_list_request, skill_provider_list_result, skill_provider_read_request, skill_provider_read_result, skills_config_set_disabled_skills_request, skills_config_set_skill_disabled_request, skills_disable_request, skills_discover_request, skills_enable_request, skill_set_enabled_request, skills_get_discovery_paths_request, skills_get_invoked_result, skills_invoked_skill, skills_load_diagnostics, skill_uninstall_plan, slash_command_add_timeline_entry_result, slash_command_agent_prompt_result, slash_command_completed_result, slash_command_info, slash_command_input, slash_command_input_choice, slash_command_input_completion, slash_command_invocation_result, slash_command_kind, slash_command_model_picker_dialog, slash_command_select_subcommand_option, slash_command_select_subcommand_result, slash_command_set_model_result, slash_command_set_plan_model_result, slash_command_show_dialog_result, slash_command_text_result, slash_command_timeline_entry, subagent_settings_entry, subagent_settings_entry_context_tier, system_message_block, task_agent_info, task_agent_progress, task_client_active_status, task_client_execution_mode, task_client_info, task_client_owner, task_client_owner_kind, task_client_owner_presence, task_client_progress, task_client_status, task_client_type, task_client_update, task_complete_data, task_completion_decision, task_execution_mode, task_info, task_kind, task_list, task_progress_line, tasks_cancel_request, tasks_cancel_result, tasks_get_current_promotable_result, tasks_get_progress_request, tasks_get_progress_result, task_shell_info, task_shell_info_attachment_mode, task_shell_progress, tasks_promote_current_to_background_result, tasks_promote_to_background_request, tasks_promote_to_background_result, tasks_refresh_result, tasks_register_request, tasks_register_result, tasks_remove_request, tasks_remove_result, tasks_send_message_request, tasks_send_message_result, tasks_start_agent_request, tasks_start_agent_result, task_status, tasks_update_request, tasks_update_result, tasks_wait_for_pending_result, telemetry_set_feature_overrides_request, token_auth_info, token_provider_auth_info, tool, tool_list, tool_result, tool_result_expanded, tool_result_new_message, tool_result_type, tools_execute_request, tools_get_builtin_descriptors_request, tools_get_builtin_descriptors_result, tools_get_current_metadata_result, tools_initialize_and_validate_result, tools_list_pending_requests_request, tools_list_request, tools_set_request, tools_set_result, tools_shell_descriptor_config, tools_task_complete_event_data_request, tools_update_subagent_settings_result, ui_auto_mode_switch_response, ui_elicitation_array_any_of_field, ui_elicitation_array_any_of_field_items, ui_elicitation_array_any_of_field_items_any_of, ui_elicitation_array_enum_field, ui_elicitation_array_enum_field_items, ui_elicitation_field_value, ui_elicitation_request, ui_elicitation_response, ui_elicitation_response_action, ui_elicitation_response_content, ui_elicitation_result, ui_elicitation_schema, ui_elicitation_schema_property, ui_elicitation_schema_property_boolean, ui_elicitation_schema_property_number, ui_elicitation_schema_property_number_type, ui_elicitation_schema_property_string, ui_elicitation_schema_property_string_format, ui_elicitation_string_enum_field, ui_elicitation_string_one_of_field, ui_elicitation_string_one_of_field_one_of, ui_ephemeral_query_request, ui_ephemeral_query_result, ui_exit_plan_mode_action, ui_exit_plan_mode_response, ui_handle_pending_auto_mode_switch_request, ui_handle_pending_elicitation_request, ui_handle_pending_exit_plan_mode_request, ui_handle_pending_result, ui_handle_pending_sampling_request, ui_handle_pending_sampling_response, ui_handle_pending_session_limits_exhausted_request, ui_handle_pending_user_input_request, ui_register_direct_auto_mode_switch_handler_result, ui_session_limits_exhausted_response, ui_session_limits_exhausted_response_action, ui_unregister_direct_auto_mode_switch_handler_request, ui_unregister_direct_auto_mode_switch_handler_result, ui_user_input_response, unsupported_enqueue_command_result, update_subagent_settings_request, usage_get_metrics_result, usage_set_code_changes_request, user_auth_info, user_requested_shell_command_result, user_setting_metadata, user_settings_get_result, user_settings_set_request, visibility_get_result, visibility_set_request, visibility_set_result, workflow_abort_request, workflow_ack_result, workflow_agent_options, workflow_agent_request, workflow_agent_result, workflow_agent_summary, workflow_cancel_request, workflow_current_phase, workflow_declared_limits, workflow_durable_operation, workflow_execute_request, workflow_execute_result, workflow_get_run_progress_request, workflow_get_run_request, workflow_journal_get_request, workflow_journal_get_result, workflow_journal_put_request, workflow_list_runs_request, workflow_list_runs_result, workflow_log_line, workflow_log_line_kind, workflow_log_request, workflow_pause_checkpoint_action, workflow_pause_checkpoint_request, workflow_pause_checkpoint_result, workflow_pause_info, workflow_pause_request, workflow_phase_observation, workflow_phase_status, workflow_progress_line, workflow_progress_page, workflow_resume_request, workflow_resume_result, workflow_run_consumed, workflow_run_detail, workflow_run_failure, workflow_run_failure_kind, workflow_run_limits, workflow_run_options, workflow_run_request, workflow_run_result, workflow_run_status, workflow_run_summary, workflow_run_terminal, workflow_tool_resume_request, workflow_tool_run_options, workflow_tool_run_request, workspace_diff_contents, workspace_diff_file_change, workspace_diff_file_change_type, workspace_diff_mode, workspace_diff_result, workspaces_add_summary_request, workspaces_add_summary_result, workspaces_autopilot_objective_exists_result, workspaces_checkpoints, workspaces_create_directory_request, workspaces_create_file_request, workspaces_delete_autopilot_objective_result, workspaces_diff_request, workspaces_ensure_request, workspaces_get_workspace_result, workspaces_list_checkpoints_result, workspaces_list_files_result, workspaces_read_autopilot_objective_result, workspaces_read_checkpoint_request, workspaces_read_checkpoint_result, workspaces_read_file_request, workspaces_read_file_result, workspaces_remove_path_request, workspaces_rename_path_request, workspaces_save_large_paste_request, workspaces_save_large_paste_result, workspaces_stat_file_request, workspaces_stat_file_result, workspaces_truncate_summaries_request, workspace_summary_host_type, workspaces_update_metadata_request, workspaces_workspace_details_host_type, workspaces_write_autopilot_objective_request, workspaces_write_autopilot_objective_result, connector_session_account_result, session_auth_info_result, session_context_attribution, session_context_info, subagent_settings, task_progress, workspace_summary) + return RPC(abort_request, abort_result, accepted_enqueue_command_result, account_all_users, account_auth_info, account_get_all_users_result, account_get_current_auth_result, account_get_quota_request, account_get_quota_result, account_kind, account_login_request, account_login_result, account_logout_request, account_logout_result, account_quota_snapshot, accounts_enumerate_request, accounts_get_request, accounts_set_request, account_status, adaptive_thinking_support, agent_discovery_path, agent_discovery_path_list, agent_discovery_path_scope, agent_get_current_result, agent_info, agent_info_source, agent_list, agent_list_request, agent_registry_live_target_entry, agent_registry_live_target_entry_attention_kind, agent_registry_live_target_entry_kind, agent_registry_live_target_entry_last_terminal_event, agent_registry_live_target_entry_status, agent_registry_log_capture, agent_registry_log_capture_open_error_reason, agent_registry_spawn_error, agent_registry_spawn_permission_mode, agent_registry_spawn_registry_timeout, agent_registry_spawn_request, agent_registry_spawn_result, agent_registry_spawn_spawned, agent_registry_spawn_validation_error, agent_registry_spawn_validation_error_field, agent_registry_spawn_validation_error_reason, agent_reload_result, agents_custom_agent_initial_model_decision_params, agents_custom_agent_initial_model_decision_result, agents_discover_request, agent_select_request, agent_select_result, agent_set_prompt_request, agents_get_available_builtins_request, agents_get_available_builtins_result, agents_get_builtin_definition_request, agents_get_builtin_definition_result, agents_get_builtin_listing_definition_request, agents_get_builtin_listing_definition_result, agents_get_builtins_result, agents_get_discovery_paths_request, api_key_auth_info, auth_enumerate_query, auth_enumerate_value, auth_identity, auth_identity_metadata, auth_info, auth_info_type, auth_login_account, auth_login_advance_request, auth_login_begin_request, auth_login_begun, auth_login_cancel_request, auth_login_result_dto, auth_login_result_status, auth_login_step, auth_read_query, auth_read_value, auth_status_dto, auth_validation_error, auth_validation_errors, auth_write, auth_write_result, autopilot_objective_credit_limit, autopilot_objective_get_state_result, autopilot_objective_state, autopilot_objective_status, auto_tier_descriptor, auto_tier_metadata, auto_tier_status, builtin_agent_summary, built_in_model_catalog, built_in_model_catalog_entry, builtin_tool_descriptor, builtin_tool_format, builtin_tool_format_type, builtin_tool_input_schema, builtin_tool_input_schema_type, builtin_tool_safe_for_telemetry, builtin_tool_safe_telemetry_fields, cancel_user_requested_shell_command_result, canvas_action, canvas_action_invoke_request, canvas_action_invoke_result, canvas_close_request, canvas_host_context, canvas_host_context_capabilities, canvas_json_schema, canvas_list, canvas_list_open_result, canvas_open_request, canvas_provider_close_request, canvas_provider_invoke_action_request, canvas_provider_open_request, canvas_provider_open_result, canvas_provider_register_request, canvas_provider_unregister_request, canvas_session_context, capi_session_options, card_digest, card_digest_algorithm, card_digest_value, catalog_agent_plugin_candidate, catalog_agent_plugin_candidate_kind, catalog_agent_plugin_candidate_provenance, catalog_agent_plugin_compatibility_tag, catalog_agent_plugin_media_type, catalog_ai_skill_candidate, catalog_ai_skill_candidate_kind, catalog_ai_skill_candidate_provenance, catalog_ai_skill_installability, catalog_ai_skill_media_type, catalog_authentication_required_error, catalog_authentication_required_reason, catalog_candidate, catalog_candidate_kind, catalog_candidate_source, catalog_candidate_source_embedded, catalog_candidate_source_url, catalog_capability, catalog_capability_id, catalog_client_contract, catalog_contract_violation_error, catalog_contract_violation_reason, catalog_handle_rejected_error, catalog_handle_rejection_reason, catalog_handle_type, catalog_invalid_request_error, catalog_invalid_request_field, catalog_malformed_card_error, catalog_malformed_card_reason, catalog_mcp_server_candidate, catalog_mcp_server_candidate_kind, catalog_mcp_server_candidate_provenance, catalog_mcp_server_installability, catalog_media_type, catalog_negotiated_contract, catalog_negotiation_refused_error, catalog_negotiation_refused_reason, catalog_network_failure_error, catalog_network_failure_reason, catalog_not_installable_error, catalog_not_installable_reason, catalog_plugin_repository_source, catalog_policy_rejected_error, catalog_resource_identity, catalog_resource_version, catalog_search_page, catalog_search_pagination, catalog_search_request, catalog_search_result, catalog_search_succeeded, catalog_search_total_count_relation, catalog_selection_cancelled, catalog_selection_decision, catalog_selection_declined, catalog_selection_foreign, catalog_selection_invalid, catalog_selection_replayed, catalog_selection_request, catalog_selection_result, catalog_selection_selected, catalog_selection_stale, catalog_selection_timed_out, catalog_selection_wrong_kind, catalog_trust_eligibility, catalog_trust_provenance, catalog_trust_snapshot, catalog_trust_snapshot_absent, catalog_trust_snapshot_absent_status, catalog_trust_snapshot_current, catalog_trust_snapshot_current_status, catalog_trust_snapshot_downgraded, catalog_trust_snapshot_downgraded_status, catalog_trust_snapshot_malformed, catalog_trust_snapshot_malformed_status, catalog_trust_snapshot_revoked, catalog_trust_snapshot_revoked_status, catalog_trust_snapshot_schema_version, catalog_trust_snapshot_stale, catalog_trust_snapshot_stale_status, catalog_trust_snapshot_unsupported, catalog_trust_snapshot_unsupported_status, catalog_trust_source, catalog_trust_tier, catalog_unavailable_error, catalog_unavailable_reason, catalog_unavailable_transport_error, catalog_unavailable_transport_reason, catalog_unsafe_retrieval_error, catalog_unsafe_retrieval_reason, catalog_unsupported_kind_error, client_metadata, client_task_cancel_reason, client_task_cancel_request, client_task_cancel_result, command_list, commands_finalize_invocation_effect_request, commands_finalize_invocation_effect_result, commands_handle_pending_command_request, commands_handle_pending_command_result, commands_invocation_effect_outcome, commands_invocation_origin, commands_invoke_request, commands_list_request, commands_respond_to_queued_command_request, commands_respond_to_queued_command_result, completions_get_trigger_characters_result, completions_request_request, completions_request_result, configure_session_extensions_params, connect_client_info, connected_remote_session_metadata, connected_remote_session_metadata_kind, connected_remote_session_metadata_repository, connector_account_request, connector_authorization_requirement, connector_authorization_scope, connector_availability, connector_capabilities, connector_catalog_entry, connector_catalog_result, connector_catalog_status, connector_connect_request, connector_connect_result, connector_continue_request, connector_disconnect_result, connector_discovery_account, connector_discovery_account_list, connector_discovery_account_request, connector_discovery_auth_info, connector_discovery_availability, connector_discovery_capabilities, connector_discovery_catalog_entry, connector_discovery_catalog_result, connector_mcp_status, connector_reconcile_request, connector_runtime_status, connector_session_account, connector_status, connect_remote_session_params, connect_request, connect_result, content_exclusion_check_paths_request, content_exclusion_check_paths_result, content_exclusion_path_check, content_filter_mode, context_heaviest_message, copilot_api_token_auth_info, copilot_user_response, copilot_user_response_endpoints, copilot_user_response_quota_snapshots, copilot_user_response_quota_snapshots_chat, copilot_user_response_quota_snapshots_completions, copilot_user_response_quota_snapshots_premium_interactions, current_model, current_tool_metadata, customization_reload_outcome, customization_reload_status, customization_reload_subsystem, customizations_reload_result, debug_collect_logs_collected_entry, debug_collect_logs_destination, debug_collect_logs_entry, debug_collect_logs_entry_kind, debug_collect_logs_include, debug_collect_logs_redaction, debug_collect_logs_request, debug_collect_logs_result, debug_collect_logs_result_kind, debug_collect_logs_skipped_entry, debug_collect_logs_source, diagnostic_cursor_status, diagnostic_entry, diagnostic_log_level, diagnostics_configuration, diagnostics_configure_request, diagnostic_severity, diagnostic_source, diagnostic_sources_configuration, diagnostics_read_request, diagnostics_read_result, discovered_canvas, discovered_extension, discovered_extension_mode, discovered_extension_plugin, discovered_extensions, discovered_extensions_disable_request, discovered_extensions_enable_request, discovered_extension_source, discovered_hook, discovered_mcp_server, discovered_mcp_server_type, discovered_model, discovered_model_list, enqueue_command_params, enqueue_command_result, env_auth_info, environment_capabilities, environment_kind, environments_delete_request, environments_delete_result, environments_get_request, environments_get_result, environments_list_request, environments_list_result, event_log_read_request, event_log_release_interest_result, event_log_tail_result, event_log_types, events_agent_scope, events_cursor_status, events_read_direction, events_read_result, execute_command_params, execute_command_result, extension, extension_context_push_input, extension_launch_profile, extension_launch_provider_resolve_request, extension_launch_provider_resolve_result, extension_list, extensions_disable_request, extensions_enable_request, extension_source, extension_status, external_tool_result, external_tool_text_result_for_llm, external_tool_text_result_for_llm_binary_results_for_llm, external_tool_text_result_for_llm_binary_results_for_llm_type, external_tool_text_result_for_llm_content, external_tool_text_result_for_llm_content_audio, external_tool_text_result_for_llm_content_image, external_tool_text_result_for_llm_content_resource, external_tool_text_result_for_llm_content_resource_details, external_tool_text_result_for_llm_content_resource_link, external_tool_text_result_for_llm_content_resource_link_icon, external_tool_text_result_for_llm_content_resource_link_icon_theme, external_tool_text_result_for_llm_content_shell_exit, external_tool_text_result_for_llm_content_terminal, external_tool_text_result_for_llm_content_text, filter_mapping, fleet_start_request, fleet_start_result, folder_trust_add_params, folder_trust_check_params, folder_trust_check_result, gh_cli_auth_info, git_current_branch_remote_result, git_cwd_request, git_hub_environment, git_hub_owner_option, git_hub_owners_cancel_request, git_hub_owners_cancel_result, git_hub_owners_list_request, git_hub_owners_list_result, git_hub_owners_request_id_result, git_hub_repository_at_path_request, git_hub_repository_at_path_result, git_hub_repository_identity, git_hub_telemetry_client_info, git_hub_telemetry_event, git_hub_telemetry_notification, git_hub_token_acquire_reason, git_hub_token_acquire_request, git_hub_token_acquire_result, git_remote_repository, git_repos_from_remotes_request, git_repos_from_remotes_result, global_state_load_for_config_dir_request, global_state_load_result, global_state_write_key_request, handle_pending_tool_call_request, handle_pending_tool_call_result, history_abort_manual_compaction_result, history_cancel_background_compaction_result, history_clear_context_request, history_clear_context_result, history_compact_context_window, history_compact_request, history_compact_result, history_file_restore_skip_reason, history_list_rewind_points_result, history_preview_rewind_request, history_preview_rewind_result, history_rewind_change_type, history_rewind_file_preview, history_rewind_mode, history_rewind_outcome, history_rewind_point, history_rewind_request, history_rewind_result, history_rewind_unavailable_reason, history_skipped_file_restore, history_summarize_for_handoff_result, history_truncate_request, history_truncate_result, hmac_auth_info, hook_invoke_request, hook_invoke_response, hook_origin, hooks_discover_request, hooks_discover_result, hook_type, host_configuration, host_dispose_request, host_empty_result, host_environment_credentials, host_exited_notification, host_exit_reason, host_git_hub_environment_options, host_list_sessions_request, host_list_sessions_result, host_local_server_configuration, host_local_server_options, host_publish_session_request, host_publish_session_result, host_ready_request, host_register_session_request, host_session_create_callback, host_session_create_request, host_session_create_result, host_session_released_notification, host_session_release_request, host_session_summary, host_start_request, host_start_result, installation_catalogue_identity, installation_confirmation_request, installation_confirmation_response, installation_decision, installation_review, installed_plugin, installed_plugin_info, installed_plugin_source, installed_plugin_source_git_hub, installed_plugin_source_local, installed_plugin_source_url, instruction_discovery_path, instruction_discovery_path_kind, instruction_discovery_path_list, instruction_discovery_path_location, instructions_discover_request, instructions_get_discovery_paths_request, instructions_get_sources_result, instruction_source, instruction_source_location, instruction_source_type, interrupt_main_turn_request, interrupt_main_turn_result, json_schema_response_format, llm_inference_headers, llm_inference_http_request_chunk_request, llm_inference_http_request_chunk_result, llm_inference_http_request_start_request, llm_inference_http_request_start_result, llm_inference_http_request_start_transport, llm_inference_http_response_chunk_error, llm_inference_http_response_chunk_request, llm_inference_http_response_chunk_result, llm_inference_http_response_start_request, llm_inference_http_response_start_result, llm_inference_set_provider_result, local_session_metadata_value, logged_in_user, login_provider_kind, log_request, log_result, lsp_initialize_request, managed_mcp_server_config, managed_permission_evaluation, managed_permission_operation, managed_permission_operation_kind, managed_permissions_evaluate_request, managed_permissions_evaluate_result, managed_permission_verdict, managed_plugin_retry_entry, managed_plugin_retry_status, managed_setting_meta, managed_settings_channel, managed_settings_compose_layer, managed_settings_compose_request, managed_settings_compose_result, managed_settings_diagnostic, managed_settings_diagnostic_severity, managed_settings_layer, managed_settings_meta, managed_settings_read_result, managed_settings_resolved_data, managed_settings_resolve_request, managed_settings_resolve_result, managed_settings_schema_result, managed_settings_validate_request, managed_settings_validate_result, managed_settings_values, marketplace_add_result, marketplace_browse_result, marketplace_info, marketplace_list_result, marketplace_plugin_info, marketplace_refresh_entry, marketplace_refresh_result, marketplace_remove_result, mcp_allowed_server, mcp_apply_install_request, mcp_apply_uninstall_request, mcp_apps_call_tool_request, mcp_apps_diagnose_capability, mcp_apps_diagnose_request, mcp_apps_diagnose_result, mcp_apps_diagnose_server, mcp_apps_host_context, mcp_apps_host_context_details, mcp_apps_host_context_details_available_display_mode, mcp_apps_host_context_details_display_mode, mcp_apps_host_context_details_platform, mcp_apps_host_context_details_theme, mcp_apps_list_tools_request, mcp_apps_list_tools_result, mcp_apps_read_resource_request, mcp_apps_read_resource_result, mcp_apps_resource_content, mcp_apps_set_host_context_details, mcp_apps_set_host_context_details_available_display_mode, mcp_apps_set_host_context_details_display_mode, mcp_apps_set_host_context_details_platform, mcp_apps_set_host_context_details_theme, mcp_apps_set_host_context_request, mcp_cancel_sampling_execution_params, mcp_cancel_sampling_execution_result, mcp_config_add_request, mcp_config_disable_request, mcp_config_enable_request, mcp_config_list, mcp_config_remove_request, mcp_config_update_request, mcp_configured_server, mcp_configured_server_list, mcp_configured_server_state, mcp_configure_git_hub_request, mcp_configure_git_hub_result, mcp_diagnostic_details, mcp_diagnostic_direction, mcp_diagnostic_kind, mcp_diagnostic_source_configuration, mcp_disable_request, mcp_discover_request, mcp_discover_result, mcp_elicitation_form_mode, mcp_enable_request, mcp_execute_sampling_params, mcp_execute_sampling_request, mcp_execute_sampling_result, mcp_failed_server, mcp_filtered_server, mcp_headers_handle_pending_headers_refresh_request, mcp_headers_handle_pending_headers_refresh_request_request, mcp_headers_handle_pending_headers_refresh_request_result, mcp_host_state, mcp_installation_failure_reason, mcp_installation_input, mcp_installation_management_outcome, mcp_installation_management_result, mcp_installation_operation_request, mcp_installation_operation_status, mcp_installation_outcome, mcp_installation_remote_configuration, mcp_installation_result, mcp_installation_review, mcp_installation_secret, mcp_installation_secret_storage, mcp_installations_request, mcp_installation_state, mcp_installation_summary, mcp_install_plan, mcp_is_server_running_request, mcp_is_server_running_result, mcp_list_tools_request, mcp_list_tools_result, mcp_oauth_authentication_state_changed_request, mcp_oauth_cancel_login_request, mcp_oauth_cancel_login_result, mcp_oauth_complete_request, mcp_oauth_handle_pending_request, mcp_oauth_handle_pending_result, mcp_oauth_login_grant_type, mcp_oauth_login_request, mcp_oauth_login_result, mcp_oauth_pending_request_response, mcp_oauth_prepare_login_request, mcp_oauth_prepare_login_result, mcp_oauth_probe_needs_auth_reason, mcp_oauth_probe_request, mcp_oauth_probe_result, mcp_oauth_respond_request, mcp_oauth_respond_result, mcp_owned_oauth_login_status, mcp_plan_configuration_change, mcp_plan_configuration_operation, mcp_plan_enum_value_type, mcp_plan_install_planned, mcp_plan_install_request, mcp_plan_install_result, mcp_plan_install_source, mcp_plan_install_source_candidate, mcp_plan_install_source_candidate_kind, mcp_plan_install_source_card, mcp_plan_install_source_card_kind, mcp_plan_package_install_method, mcp_plan_package_transport, mcp_plan_policy_decision, mcp_plan_policy_result, mcp_plan_policy_source, mcp_plan_provenance, mcp_plan_remote_install_method, mcp_plan_remote_transport, mcp_plan_required_value, mcp_plan_required_value_enum, mcp_plan_required_value_enum_kind, mcp_plan_required_value_scalar, mcp_plan_required_value_scalar_kind, mcp_plan_resource_identity, mcp_plan_scalar_value_type, mcp_plan_scope, mcp_plan_secret_placeholder, mcp_plan_secret_reference, mcp_plan_target, mcp_plan_transport_choice, mcp_plan_transport_choice_package, mcp_plan_transport_choice_remote, mcp_plan_uninstall_request, mcp_plan_value_category, mcp_prepared_install, mcp_prepare_install_request, mcp_prompt, mcp_prompt_argument, mcp_prompt_icon, mcp_prompt_message, mcp_prompt_role, mcp_prompts_get_request, mcp_prompts_get_result, mcp_prompts_list_request, mcp_prompts_list_result, mcp_register_external_client_request, mcp_reload_config, mcp_reload_with_config_request, mcp_remove_git_hub_result, mcp_resource, mcp_resource_annotations, mcp_resource_content, mcp_resource_icon, mcp_resources_list_request, mcp_resources_list_result, mcp_resources_list_templates_request, mcp_resources_list_templates_result, mcp_resources_read_request, mcp_resources_read_result, mcp_resource_template, mcp_restart_server_request, mcp_safe_for_telemetry, mcp_safe_for_telemetry_fields, mcp_sampling_execution_action, mcp_sampling_execution_result, mcp_serializable_server_config, mcp_server, mcp_server_auth_config, mcp_server_auth_config_redirect_port, mcp_server_card_embedded, mcp_server_card_embedded_kind, mcp_server_card_media_type, mcp_server_card_reference, mcp_server_card_url, mcp_server_card_url_kind, mcp_server_config, mcp_server_config_defer_tools, mcp_server_config_http, mcp_server_config_http_oauth_grant_type, mcp_server_config_http_type, mcp_server_config_memory, mcp_server_config_memory_type, mcp_server_config_stdio, mcp_server_config_stdio_type, mcp_server_failure_info, mcp_server_list, mcp_server_needs_auth_info, mcp_server_ownership, mcp_set_env_value_mode_details, mcp_set_env_value_mode_params, mcp_set_env_value_mode_result, mcp_source_file, mcp_source_plugin, mcp_source_ref, mcp_start_server_request, mcp_start_servers_result, mcp_stop_server_request, mcp_task_metadata, mcp_tools, mcp_tool_ui, mcp_tool_ui_visibility, mcp_uninstall_plan, mcp_unregister_external_client_request, memory_configuration, metadata_context_attribution_result, metadata_context_heaviest_messages_request, metadata_context_heaviest_messages_result, metadata_context_info_request, metadata_context_info_result, metadata_is_processing_result, metadata_recompute_context_tokens_request, metadata_recompute_context_tokens_result, metadata_record_context_change_request, metadata_record_context_change_result, metadata_set_working_directory_request, metadata_set_working_directory_result, metadata_snapshot_current_mode, metadata_snapshot_remote_metadata, metadata_snapshot_remote_metadata_repository, metadata_snapshot_remote_metadata_task_type, metadata_update_client_metadata_request, model, model_apply_startup_overlay_request, model_artifact_details, model_billing, model_billing_promo, model_billing_token_prices, model_billing_token_prices_long_context, model_capabilities, model_capabilities_limits, model_capabilities_limits_vision, model_capabilities_override, model_capabilities_override_limits, model_capabilities_override_limits_vision, model_capabilities_override_supports, model_capabilities_supports, model_clear_startup_seed_request, model_clear_startup_seed_result, model_list, model_list_request, model_message, model_picker_category, model_picker_persistence_request, model_picker_price_category, model_picker_settings_context, model_policy, model_policy_state, model_provider_adapter_catalog, model_provider_adapter_descriptor, model_provider_adapter_operation_descriptor, model_provider_attribution, model_provider_automatic_discovery_mode, model_provider_automatic_discovery_policy, model_provider_configuration_disposition, model_provider_configuration_plan, model_provider_descriptor, model_provider_discover_request, model_provider_discover_result, model_provider_discovery_network_scope, model_provider_get_status_request, model_provider_instance, model_provider_instance_reference, model_provider_models_list_request, model_provider_operation_outcome, model_provider_operation_outcome_code, model_provider_prepare_configuration_request, model_provider_provenance, model_provider_provenance_source, model_provider_status, model_provider_warning, model_set_allowed_models_request, model_set_allowed_models_result, model_set_reasoning_effort_request, model_set_reasoning_effort_result, models_list_request, model_switch_auto_tier_request, model_switch_auto_tier_result, model_switch_auto_tier_status, model_switch_confirmation, model_switch_to_request, model_switch_to_result, model_warning_text, mode_set_request, mode_set_result, move_mcp_loading_to_background_result, named_provider_config, name_get_result, name_set_auto_request, name_set_auto_result, name_set_request, open_canvas_instance, options_update_additional_content_exclusion_policy, options_update_additional_content_exclusion_policy_rule, options_update_additional_content_exclusion_policy_rule_source, options_update_additional_content_exclusion_policy_scope, options_update_context_tier, options_update_env_value_mode, options_update_reasoning_summary, options_update_tool_filter_precedence, pending_external_tool_request, pending_external_tool_request_list, pending_permission_request, pending_permission_request_list, permission_decision, permission_decision_approved, permission_decision_approved_for_location, permission_decision_approved_for_session, permission_decision_approve_for_location, permission_decision_approve_for_location_approval, permission_decision_approve_for_location_approval_commands, permission_decision_approve_for_location_approval_custom_tool, permission_decision_approve_for_location_approval_extension_env_access, permission_decision_approve_for_location_approval_extension_management, permission_decision_approve_for_location_approval_extension_permission_access, permission_decision_approve_for_location_approval_mcp, permission_decision_approve_for_location_approval_mcp_sampling, permission_decision_approve_for_location_approval_memory, permission_decision_approve_for_location_approval_read, permission_decision_approve_for_location_approval_workflow, permission_decision_approve_for_location_approval_write, permission_decision_approve_for_session, permission_decision_approve_for_session_approval, permission_decision_approve_for_session_approval_commands, permission_decision_approve_for_session_approval_custom_tool, permission_decision_approve_for_session_approval_extension_env_access, permission_decision_approve_for_session_approval_extension_management, permission_decision_approve_for_session_approval_extension_permission_access, permission_decision_approve_for_session_approval_mcp, permission_decision_approve_for_session_approval_mcp_sampling, permission_decision_approve_for_session_approval_memory, permission_decision_approve_for_session_approval_read, permission_decision_approve_for_session_approval_workflow, permission_decision_approve_for_session_approval_write, permission_decision_approve_once, permission_decision_approve_permanently, permission_decision_approve_read_only_for_session, permission_decision_cancelled, permission_decision_context, permission_decision_denied_by_content_exclusion_policy, permission_decision_denied_by_permission_request_hook, permission_decision_denied_by_rules, permission_decision_denied_interactively_by_user, permission_decision_denied_no_approval_rule_and_could_not_request_from_user, permission_decision_outcome, permission_decision_reject, permission_decision_request, permission_decision_surface, permission_decision_user_not_available, permission_location_add_tool_approval_params, permission_location_apply_params, permission_location_apply_result, permission_location_resolve_params, permission_location_resolve_result, permission_location_type, permission_mode_source, permission_paths_add_params, permission_paths_allowed_check_params, permission_paths_allowed_check_result, permission_paths_config, permission_paths_list, permission_paths_update_primary_params, permission_paths_workspace_check_params, permission_paths_workspace_check_result, permission_prompt_shown_notification, permission_request_result, permission_response_capability, permission_rules_set, permissions_configure_additional_content_exclusion_policy, permissions_configure_additional_content_exclusion_policy_rule, permissions_configure_additional_content_exclusion_policy_rule_source, permissions_configure_additional_content_exclusion_policy_scope, permissions_configure_params, permissions_configure_result, permissions_folder_trust_add_trusted_result, permissions_get_mode_request, permissions_get_mode_result, permissions_locations_add_tool_approval_details, permissions_locations_add_tool_approval_details_commands, permissions_locations_add_tool_approval_details_custom_tool, permissions_locations_add_tool_approval_details_extension_env_access, permissions_locations_add_tool_approval_details_extension_management, permissions_locations_add_tool_approval_details_extension_permission_access, permissions_locations_add_tool_approval_details_mcp, permissions_locations_add_tool_approval_details_mcp_sampling, permissions_locations_add_tool_approval_details_memory, permissions_locations_add_tool_approval_details_read, permissions_locations_add_tool_approval_details_workflow, permissions_locations_add_tool_approval_details_write, permissions_locations_add_tool_approval_result, permissions_modify_rules_params, permissions_modify_rules_result, permissions_modify_rules_scope, permissions_notify_prompt_shown_result, permissions_paths_add_result, permissions_paths_list_request, permissions_paths_update_primary_result, permissions_pending_requests_request, permissions_reset_session_approvals_request, permissions_reset_session_approvals_result, permissions_set_approve_all_request, permissions_set_approve_all_result, permissions_set_approve_all_source, permissions_set_mode_request, permissions_set_mode_result, permissions_set_required_request, permissions_set_required_result, permissions_urls_set_unrestricted_mode_result, permission_urls_config, permission_urls_set_unrestricted_mode_params, ping_request, ping_result, plan_read_result, plan_read_sql_todos_result, plan_read_sql_todos_with_dependencies_result, plan_sql_todo_dependency, plan_sql_todos_row, plan_update_request, plugin, plugin_install_result, plugin_install_staging_mode, plugin_list, plugin_list_result, plugins_builtin_set_request, plugins_disable_request, plugins_enable_request, plugins_install_request, plugins_marketplaces_add_request, plugins_marketplaces_browse_request, plugins_marketplaces_refresh_request, plugins_marketplaces_remove_request, plugins_reload_request, plugins_uninstall_request, plugins_update_request, plugin_update_all_entry, plugin_update_all_result, plugin_update_result, protocol_append_mode, protocol_customize_mode, protocol_external_tool_defer, protocol_external_tool_definition, protocol_marker_section_override, protocol_replace_mode, protocol_section_override, protocol_static_section_action, protocol_static_section_override, protocol_system_message_append_config, protocol_system_message_config, protocol_system_message_customize_config, protocol_system_message_replace_config, provider_add_request, provider_add_result, provider_config, provider_config_azure, provider_config_model_provider, provider_config_transport, provider_config_type, provider_config_wire_api, provider_descriptor, provider_endpoint, provider_endpoint_transport, provider_endpoint_type, provider_endpoint_wire_api, provider_get_endpoint_request, provider_model_config, provider_session_token, provider_sync_request, provider_sync_result, provider_token_acquire_request, provider_token_acquire_result, provider_withdraw_request, provider_withdraw_result, push_attachment, push_attachment_blob, push_attachment_directory, push_attachment_file, push_attachment_file_line_range, push_attachment_git_hub_actions_job, push_attachment_git_hub_commit, push_attachment_git_hub_file, push_attachment_git_hub_file_diff, push_attachment_git_hub_file_diff_side, push_attachment_git_hub_reference, push_attachment_git_hub_reference_type, push_attachment_git_hub_release, push_attachment_git_hub_repository, push_attachment_git_hub_snippet, push_attachment_git_hub_tree_comparison, push_attachment_git_hub_tree_comparison_side, push_attachment_git_hub_url, push_attachment_selection, push_attachment_selection_details, push_attachment_selection_details_end, push_attachment_selection_details_start, push_git_hub_repo_ref, queue_append_steering_request, queue_begin_deferred_idle_drain_request, queue_begin_deferred_idle_drain_result, queue_consume_system_notifications_request, queued_command_handled, queued_command_not_handled, queued_command_result, queue_defer_session_idle_request, queue_duplicate_at_request, queue_duplicate_at_result, queue_enqueue_resume_pending_result, queue_finish_deferred_idle_drain_request, queue_finish_deferred_idle_drain_result, queue_has_pending_result, queue_insert_at_request, queue_insert_at_result, queue_insert_message, queue_move_item_request, queue_move_item_result, queue_pending_items, queue_pending_items_kind, queue_pending_items_result, queue_remove_at_request, queue_remove_at_result, queue_remove_most_recent_result, queue_send_now_request, queue_send_now_result, queue_set_drain_paused_request, queue_snapshot_result, queue_update_text_request, queue_update_text_result, queue_withdraw_message_request, queue_withdraw_message_result, quota_take_warnings_result, quota_warning_projection, register_event_interest_params, register_event_interest_result, release_event_interest_params, remote_control_config, remote_control_config_existing_mc_session, remote_control_status, remote_control_status_active, remote_control_status_connecting, remote_control_status_error, remote_control_status_off, remote_control_status_result, remote_control_stop_result, remote_control_transfer_result, remote_enable_request, remote_enable_result, remote_notify_steerable_changed_request, remote_notify_steerable_changed_result, remote_session_connection_result, remote_session_host_status, remote_session_metadata_repository, remote_session_metadata_task_type, remote_session_metadata_value, remote_session_mode, remote_session_repository, response_format, sandbox_config, sandbox_config_auth, sandbox_config_source, sandbox_config_user_policy, sandbox_config_user_policy_experimental, sandbox_config_user_policy_experimental_seatbelt, sandbox_config_user_policy_filesystem, sandbox_config_user_policy_network, sandbox_config_user_policy_network_proxy, sandbox_config_user_policy_seatbelt, sandbox_credentials_config, sandbox_disable_for_session_request, sandbox_disable_for_session_result, sandbox_enforcement_status, sandbox_grant_path_for_request_request, sandbox_grant_path_for_request_result, sandbox_host_capability, sandbox_host_capability_name, sandbox_host_support, sandbox_masked_env_var, sandbox_proxy_ca_create_result, sandbox_proxy_ca_request, sandbox_proxy_ca_state, sandbox_proxy_ca_status, sandbox_session_change, schedule_add_at_request, schedule_add_cron_request, schedule_add_request, schedule_add_result, schedule_add_self_paced_request, schedule_entry, schedule_has_self_paced_result, schedule_list, schedule_rearm_self_paced_request, schedule_stop_request, schedule_stop_result, secrets_add_filter_values_request, secrets_add_filter_values_result, send_agent_mode, send_attachments_to_message_params, send_message_item, send_messages_request, send_messages_result, send_mode, send_request, send_result, send_system_notification_request, server_agent_list, server_instruction_source_list, server_skill, server_skill_list, session_activity, session_agent_list_request, session_auth_login_request, session_auth_logout_user_request, session_auth_status, session_auth_switch_request, session_bulk_delete_result, session_cancel_all_background_agents_result, session_capability, session_commands_list_request, session_completion_item, session_connected_ide_info, session_context, session_context_host_type, session_enrich_metadata_result, session_fs_append_file_request, session_fs_error, session_fs_error_code, session_fs_exists_request, session_fs_exists_result, session_fs_mkdir_request, session_fs_readdir_request, session_fs_readdir_result, session_fs_readdir_with_types_entry, session_fs_readdir_with_types_entry_type, session_fs_readdir_with_types_request, session_fs_readdir_with_types_result, session_fs_read_file_bytes_request, session_fs_read_file_bytes_result, session_fs_read_file_request, session_fs_read_file_result, session_fs_rename_request, session_fs_rm_request, session_fs_set_provider_capabilities, session_fs_set_provider_conventions, session_fs_set_provider_request, session_fs_set_provider_result, session_fs_sqlite_exists_request, session_fs_sqlite_exists_result, session_fs_sqlite_query_request, session_fs_sqlite_query_result, session_fs_sqlite_query_type, session_fs_sqlite_transaction_error, session_fs_sqlite_transaction_error_class, session_fs_sqlite_transaction_request, session_fs_sqlite_transaction_result, session_fs_sqlite_transaction_statement, session_fs_stat_request, session_fs_stat_result, session_fs_write_file_bytes_request, session_fs_write_file_request, session_git_hub_auth_get_all_auth_available_result, session_git_hub_auth_logout_result, session_git_hub_auth_logout_user_result, session_history_compact_request, session_installed_plugin, session_installed_plugin_source, session_installed_plugin_source_git_hub, session_installed_plugin_source_local, session_installed_plugin_source_url, session_limit_prediction_baseline_data, session_limit_prediction_client_type, session_limit_prediction_details, session_limit_prediction_predict_request, session_limit_prediction_request, session_limit_prediction_result, session_limit_prediction_source, session_limit_prediction_tier, session_limit_prediction_tier_option, session_limit_prediction_unavailable_reason, session_list, session_list_entry, session_list_filter, session_load_deferred_repo_hooks_result, session_log_level, session_managed_permissions, session_managed_settings, session_mcp_apps_call_tool_result, session_mcp_oauth_cancel_login_request, session_mcp_oauth_cancel_login_result, session_mcp_oauth_prepare_login_request, session_mcp_oauth_prepare_login_result, session_mcp_set_connected_ide_info_params, session_metadata_snapshot, session_mode, session_model_clear_startup_seed_request, session_model_clear_startup_seed_result, session_model_list, session_model_list_request, session_model_price_category, session_open_options, session_open_options_additional_content_exclusion_policy, session_open_options_additional_content_exclusion_policy_rule, session_open_options_additional_content_exclusion_policy_rule_source, session_open_options_additional_content_exclusion_policy_scope, session_open_options_env_value_mode, session_open_options_reasoning_summary, session_open_params, session_open_result, session_plugins_disable_request, session_plugins_enable_request, session_plugins_install_request, session_plugins_marketplaces_refresh_request, session_plugins_reload_request, session_plugins_retry_managed_request, session_plugins_retry_managed_result, session_provider_get_endpoint_request, session_prune_result, session_quota_delegate_warning, session_quota_get_result, session_quota_plan_tier, session_quota_projection, session_quota_refresh_result, session_quota_snapshot, session_quota_take_warnings_result, sessions_bulk_delete_request, sessions_check_in_use_request, sessions_check_in_use_result, sessions_client_metadata_entry, sessions_close_request, sessions_close_result, sessions_create_workspace_request, sessions_create_workspace_result, sessions_delete_request, sessions_enrich_metadata_request, session_set_credentials_params, session_set_credentials_result, session_settings_built_in_tool_availability_snapshot, session_settings_evaluate_predicate_request, session_settings_evaluate_predicate_result, session_settings_job_snapshot, session_settings_model_snapshot, session_settings_online_evaluation_snapshot, session_settings_predicate_name, session_settings_repo_snapshot, session_settings_snapshot, session_settings_validation_snapshot, sessions_find_by_prefix_request, sessions_find_by_prefix_result, sessions_find_by_task_id_request, sessions_find_by_task_id_result, sessions_fork_request, sessions_fork_result, sessions_get_board_entry_count_request, sessions_get_board_entry_count_result, sessions_get_client_metadata_request, sessions_get_client_metadata_result, sessions_get_event_file_path_request, sessions_get_event_file_path_result, sessions_get_last_for_context_request, sessions_get_last_for_context_result, sessions_get_metadata_request, sessions_get_metadata_result, sessions_get_persisted_remote_steerable_request, sessions_get_persisted_remote_steerable_result, session_sizes, sessions_list_non_empty_session_ids_request, sessions_list_non_empty_session_ids_result, sessions_list_request, sessions_load_deferred_repo_hooks_request, sessions_load_workspace_request, sessions_load_workspace_result, sessions_open_attach, sessions_open_cloud, sessions_open_create, sessions_open_handoff, sessions_open_handoff_task_type, sessions_open_progress, sessions_open_progress_status, sessions_open_progress_step, sessions_open_remote, sessions_open_resume, sessions_open_resume_last, sessions_open_status, session_source, sessions_prune_old_request, sessions_read_persisted_events_request, sessions_release_lock_request, sessions_release_lock_result, sessions_reload_plugin_hooks_request, sessions_reload_plugin_hooks_result, sessions_save_request, sessions_save_result, sessions_set_additional_plugins_request, sessions_set_additional_plugins_result, sessions_set_remote_control_steering_request, sessions_start_remote_control_request, sessions_stop_remote_control_request, sessions_transfer_remote_control_request, sessions_update_workspace_fields_request, sessions_update_workspace_fields_result, session_telemetry_engagement, session_update_options_params, session_update_options_result, session_usage_set_code_changes_request, session_visibility_status, session_workflow_pause_at_checkpoint_result, session_working_directory_context, session_working_directory_context_host_type, session_working_directory_context_with_client, settable_auth_info, settable_token_auth_info, shell_cancel_user_requested_request, shell_credentials, shell_exec_request, shell_exec_result, shell_execute_user_requested_request, shell_init_profile, shell_init_script, shell_init_script_shell, shell_kill_request, shell_kill_result, shell_kill_signal, shell_options, shutdown_request, skill, skill_apply_install_request, skill_apply_uninstall_request, skill_discovery_path, skill_discovery_path_list, skill_discovery_scope, skill_installation_failure_reason, skill_installation_file_review, skill_installation_location, skill_installation_management_outcome, skill_installation_management_result, skill_installation_operation_request, skill_installation_operation_status, skill_installation_outcome, skill_installation_ownership_state, skill_installation_result, skill_installation_review, skill_installation_scope, skill_installation_session_state, skill_installation_source, skill_installations_request, skill_installation_summary, skill_install_plan, skill_list, skill_plan_install_request, skill_plan_uninstall_request, skill_provider_descriptor, skill_provider_list_request, skill_provider_list_result, skill_provider_read_request, skill_provider_read_result, skills_config_set_disabled_skills_request, skills_config_set_skill_disabled_request, skills_disable_request, skills_discover_request, skills_enable_request, skill_set_enabled_request, skills_get_discovery_paths_request, skills_get_invoked_result, skills_invoked_skill, skills_load_diagnostics, skill_uninstall_plan, slash_command_add_timeline_entry_result, slash_command_agent_prompt_result, slash_command_completed_result, slash_command_info, slash_command_input, slash_command_input_choice, slash_command_input_completion, slash_command_invocation_result, slash_command_kind, slash_command_model_picker_dialog, slash_command_select_subcommand_option, slash_command_select_subcommand_result, slash_command_set_model_result, slash_command_set_plan_model_result, slash_command_show_dialog_result, slash_command_text_result, slash_command_timeline_entry, subagent_settings_entry, subagent_settings_entry_context_tier, system_message_block, task_agent_info, task_agent_progress, task_client_active_status, task_client_execution_mode, task_client_info, task_client_owner, task_client_owner_kind, task_client_owner_presence, task_client_progress, task_client_status, task_client_type, task_client_update, task_complete_data, task_completion_decision, task_execution_mode, task_info, task_kind, task_list, task_progress_line, tasks_cancel_request, tasks_cancel_result, tasks_get_current_promotable_result, tasks_get_progress_request, tasks_get_progress_result, task_shell_info, task_shell_info_attachment_mode, task_shell_progress, tasks_promote_current_to_background_result, tasks_promote_to_background_request, tasks_promote_to_background_result, tasks_refresh_result, tasks_register_request, tasks_register_result, tasks_remove_request, tasks_remove_result, tasks_send_message_request, tasks_send_message_result, tasks_start_agent_request, tasks_start_agent_result, task_status, tasks_update_request, tasks_update_result, tasks_wait_for_pending_result, telemetry_set_feature_overrides_request, token_auth_info, token_provider_auth_info, tool, tool_list, tool_result, tool_result_expanded, tool_result_new_message, tool_result_type, tools_execute_request, tools_get_builtin_descriptors_request, tools_get_builtin_descriptors_result, tools_get_current_metadata_result, tools_initialize_and_validate_result, tools_list_pending_requests_request, tools_list_request, tools_set_request, tools_set_result, tools_shell_descriptor_config, tools_task_complete_event_data_request, tools_update_subagent_settings_result, ui_auto_mode_switch_response, ui_elicitation_array_any_of_field, ui_elicitation_array_any_of_field_items, ui_elicitation_array_any_of_field_items_any_of, ui_elicitation_array_enum_field, ui_elicitation_array_enum_field_items, ui_elicitation_field_value, ui_elicitation_request, ui_elicitation_response, ui_elicitation_response_action, ui_elicitation_response_content, ui_elicitation_result, ui_elicitation_schema, ui_elicitation_schema_property, ui_elicitation_schema_property_boolean, ui_elicitation_schema_property_number, ui_elicitation_schema_property_number_type, ui_elicitation_schema_property_string, ui_elicitation_schema_property_string_format, ui_elicitation_string_enum_field, ui_elicitation_string_one_of_field, ui_elicitation_string_one_of_field_one_of, ui_ephemeral_query_request, ui_ephemeral_query_result, ui_exit_plan_mode_action, ui_exit_plan_mode_response, ui_handle_pending_auto_mode_switch_request, ui_handle_pending_elicitation_request, ui_handle_pending_exit_plan_mode_request, ui_handle_pending_result, ui_handle_pending_sampling_request, ui_handle_pending_sampling_response, ui_handle_pending_session_limits_exhausted_request, ui_handle_pending_user_input_request, ui_register_direct_auto_mode_switch_handler_result, ui_session_limits_exhausted_response, ui_session_limits_exhausted_response_action, ui_unregister_direct_auto_mode_switch_handler_request, ui_unregister_direct_auto_mode_switch_handler_result, ui_user_input_response, unsupported_enqueue_command_result, update_subagent_settings_request, usage_get_metrics_result, usage_set_code_changes_request, user_auth_info, user_requested_shell_command_result, user_setting_metadata, user_settings_get_result, user_settings_set_request, visibility_get_result, visibility_set_request, visibility_set_result, workflow_abort_request, workflow_ack_result, workflow_agent_options, workflow_agent_request, workflow_agent_result, workflow_agent_summary, workflow_cancel_request, workflow_current_phase, workflow_declared_limits, workflow_durable_operation, workflow_execute_request, workflow_execute_result, workflow_get_run_progress_request, workflow_get_run_request, workflow_journal_get_request, workflow_journal_get_result, workflow_journal_put_request, workflow_list_runs_request, workflow_list_runs_result, workflow_log_line, workflow_log_line_kind, workflow_log_request, workflow_pause_checkpoint_action, workflow_pause_checkpoint_request, workflow_pause_checkpoint_result, workflow_pause_info, workflow_pause_request, workflow_phase_observation, workflow_phase_status, workflow_progress_line, workflow_progress_page, workflow_resume_request, workflow_resume_result, workflow_run_consumed, workflow_run_detail, workflow_run_failure, workflow_run_failure_kind, workflow_run_limits, workflow_run_options, workflow_run_request, workflow_run_result, workflow_run_status, workflow_run_summary, workflow_run_terminal, workflow_tool_resume_request, workflow_tool_run_options, workflow_tool_run_request, workspace_diff_contents, workspace_diff_file_change, workspace_diff_file_change_type, workspace_diff_mode, workspace_diff_result, workspaces_add_summary_request, workspaces_add_summary_result, workspaces_autopilot_objective_exists_result, workspaces_checkpoints, workspaces_create_directory_request, workspaces_create_file_request, workspaces_delete_autopilot_objective_result, workspaces_diff_request, workspaces_ensure_request, workspaces_get_workspace_result, workspaces_list_checkpoints_result, workspaces_list_files_result, workspaces_read_autopilot_objective_result, workspaces_read_checkpoint_request, workspaces_read_checkpoint_result, workspaces_read_file_request, workspaces_read_file_result, workspaces_remove_path_request, workspaces_rename_path_request, workspaces_save_large_paste_request, workspaces_save_large_paste_result, workspaces_stat_file_request, workspaces_stat_file_result, workspaces_truncate_summaries_request, workspace_summary_host_type, workspaces_update_metadata_request, workspaces_workspace_details_host_type, workspaces_write_autopilot_objective_request, workspaces_write_autopilot_objective_result, connector_session_account_result, session_auth_info_result, session_context_attribution, session_context_info, subagent_settings, task_progress, workspace_summary) def to_dict(self) -> dict: result: dict = {} @@ -53448,6 +53614,12 @@ def to_dict(self) -> dict: result["LogResult"] = to_class(LogResult, self.log_result) result["LspInitializeRequest"] = to_class(LspInitializeRequest, self.lsp_initialize_request) result["ManagedMcpServerConfig"] = to_class(ManagedMCPServerConfig, self.managed_mcp_server_config) + result["ManagedPermissionEvaluation"] = to_class(ManagedPermissionEvaluation, self.managed_permission_evaluation) + result["ManagedPermissionOperation"] = to_class(ManagedPermissionOperation, self.managed_permission_operation) + result["ManagedPermissionOperationKind"] = to_enum(ManagedPermissionOperationKind, self.managed_permission_operation_kind) + result["ManagedPermissionsEvaluateRequest"] = to_class(ManagedPermissionsEvaluateRequest, self.managed_permissions_evaluate_request) + result["ManagedPermissionsEvaluateResult"] = to_class(ManagedPermissionsEvaluateResult, self.managed_permissions_evaluate_result) + result["ManagedPermissionVerdict"] = to_enum(ManagedPermissionVerdict, self.managed_permission_verdict) result["ManagedPluginRetryEntry"] = to_class(ManagedPluginRetryEntry, self.managed_plugin_retry_entry) result["ManagedPluginRetryStatus"] = to_enum(ManagedPluginRetryStatus, self.managed_plugin_retry_status) result["ManagedSettingMeta"] = to_class(ManagedSettingMeta, self.managed_setting_meta) @@ -54558,21 +54730,10 @@ def to_dict(self) -> dict: result["WorkspaceSummary"] = from_union([lambda x: to_class(WorkspaceSummary, x), from_none], self.workspace_summary) return result -def rpc_from_dict(s: Any) -> RPC: - return RPC.from_dict(s) - -def rpc_to_dict(x: RPC) -> Any: - return to_class(RPC, x) - # Experimental: this type is part of an experimental API and may change or be removed. -class ConnectorDiscoveryAvailability(Enum): - "Availability." - # Enabled. - ENABLED = "enabled" - # Disabled. - DISABLED = "disabled" - # Unavailable. - UNAVAILABLE = "unavailable" +class ManagedPermissionOperationKind(Enum): + "Operation to evaluate. Currently only url is supported." + URL = "url" # Outcome of an agentRegistry.spawn call. AgentRegistrySpawnResult = AgentRegistrySpawnSpawned | AgentRegistrySpawnError | AgentRegistrySpawnRegistryTimeout | AgentRegistrySpawnValidationError @@ -55621,10 +55782,22 @@ def __init__(self, client: "JsonRpcClient"): self.settings = ServerUserSettingsApi(client) +# Experimental: this API group is experimental and may change or be removed. +class ServerManagedSettingsPermissionsApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def evaluate(self, params: ManagedPermissionsEvaluateRequest, *, timeout: float | None = None) -> ManagedPermissionsEvaluateResult: + "Pure, sessionless evaluation of operations against a supplied permissionsContext. Performs no policy discovery, I/O, prompting, navigation, permission grants, or sandbox changes. Obtain the context from managedSettings.resolve or session.managedSettings.get, or reuse an in-memory context. Results preserve input order and duplicates. Consumers must block deny, obtain approval for ask, and use their normal permission flow for unmanaged. Unknown policy returns failClosed with every operation denied. This is not a substitute for user permissions or other security controls.\n\nArgs:\n params: Managed policy context and ordered operations for pure, sessionless evaluation.\n\nReturns:\n Ordered managed permission verdicts and the supplied policy's fail-closed posture." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return ManagedPermissionsEvaluateResult.from_dict(await self._client.request("managedSettings.permissions.evaluate", params_dict, **_timeout_kwargs(timeout))) + + # Experimental: this API group is experimental and may change or be removed. class ServerManagedSettingsApi: def __init__(self, client: "JsonRpcClient"): self._client = client + self.permissions = ServerManagedSettingsPermissionsApi(client) async def read(self, *, timeout: float | None = None) -> ManagedSettingsReadResult: "Discovers device-managed settings from production MDM and managed-file sources, validates them against the runtime-owned managed-settings schema, and returns the canonical JSON without requiring a session. `managedSettings.resolve` returns the same device settings together with the account's server policy.\n\nReturns:\n Validated device-managed settings discovered before a session exists." @@ -59672,6 +59845,12 @@ async def handle_installations_confirm(params: dict) -> dict | None: "MCPUninstallPlan", "MCPUnregisterExternalClientRequest", "ManagedMCPServerConfig", + "ManagedPermissionEvaluation", + "ManagedPermissionOperation", + "ManagedPermissionOperationKind", + "ManagedPermissionVerdict", + "ManagedPermissionsEvaluateRequest", + "ManagedPermissionsEvaluateResult", "ManagedPluginRetryEntry", "ManagedPluginRetryStatus", "ManagedSettingMeta", @@ -60222,6 +60401,7 @@ async def handle_installations_confirm(params: dict) -> dict | None: "ServerInstructionsApi", "ServerLlmInferenceApi", "ServerManagedSettingsApi", + "ServerManagedSettingsPermissionsApi", "ServerMcpApi", "ServerMcpConfigApi", "ServerMcpInstallationsApi", diff --git a/python/copilot/generated/session_events.py b/python/copilot/generated/session_events.py index 8de79749b4..3ef3b61685 100644 --- a/python/copilot/generated/session_events.py +++ b/python/copilot/generated/session_events.py @@ -1788,6 +1788,54 @@ def to_dict(self) -> dict: return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class ProviderMonthlyUsage: + "An authoritative monthly usage reading for the observation's provider, account, and service." + scope: ProviderMonthlyUsageScope + state: ProviderMonthlyUsageState + unit: ProviderQuotaUnit + consumed_quantity: float | None = None + cycle_start: str | None = None + queried_at: str | None = None + reset_on: str | None = None + + @staticmethod + def from_dict(obj: Any) -> "ProviderMonthlyUsage": + assert isinstance(obj, dict) + scope = parse_enum(ProviderMonthlyUsageScope, obj.get("scope")) + state = parse_enum(ProviderMonthlyUsageState, obj.get("state")) + unit = parse_enum(ProviderQuotaUnit, obj.get("unit")) + consumed_quantity = from_union([from_none, from_float], obj.get("consumedQuantity")) + cycle_start = from_union([from_none, from_str], obj.get("cycleStart")) + queried_at = from_union([from_none, from_str], obj.get("queriedAt")) + reset_on = from_union([from_none, from_str], obj.get("resetOn")) + return ProviderMonthlyUsage( + scope=scope, + state=state, + unit=unit, + consumed_quantity=consumed_quantity, + cycle_start=cycle_start, + queried_at=queried_at, + reset_on=reset_on, + ) + + def to_dict(self) -> dict: + result: dict = {} + result["scope"] = to_enum(ProviderMonthlyUsageScope, self.scope) + result["state"] = to_enum(ProviderMonthlyUsageState, self.state) + result["unit"] = to_enum(ProviderQuotaUnit, self.unit) + if self.consumed_quantity is not None: + result["consumedQuantity"] = from_union([from_none, to_float], self.consumed_quantity) + if self.cycle_start is not None: + result["cycleStart"] = from_union([from_none, from_str], self.cycle_start) + if self.queried_at is not None: + result["queriedAt"] = from_union([from_none, from_str], self.queried_at) + if self.reset_on is not None: + result["resetOn"] = from_union([from_none, from_str], self.reset_on) + return result + + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class ProviderQuotaState: @@ -1805,6 +1853,7 @@ class ProviderQuotaState: entitled_quantity: int | None = None has_quota: bool | None = None http_status: int | None = None + monthly_usage: ProviderMonthlyUsage | None = None observation_kind: ProviderQuotaObservationKind | None = None observed_at: str | None = None quantity_kind: ProviderQuotaQuantityKind | None = None @@ -1828,6 +1877,7 @@ def from_dict(obj: Any) -> "ProviderQuotaState": entitled_quantity = from_union([from_none, from_int], obj.get("entitledQuantity")) has_quota = from_union([from_none, from_bool], obj.get("hasQuota")) http_status = from_union([from_none, from_int], obj.get("httpStatus")) + monthly_usage = from_union([from_none, ProviderMonthlyUsage.from_dict], obj.get("monthlyUsage")) observation_kind = from_union([from_none, lambda x: parse_enum(ProviderQuotaObservationKind, x)], obj.get("observationKind")) observed_at = from_union([from_none, from_str], obj.get("observedAt")) quantity_kind = from_union([from_none, lambda x: parse_enum(ProviderQuotaQuantityKind, x)], obj.get("quantityKind")) @@ -1848,6 +1898,7 @@ def from_dict(obj: Any) -> "ProviderQuotaState": entitled_quantity=entitled_quantity, has_quota=has_quota, http_status=http_status, + monthly_usage=monthly_usage, observation_kind=observation_kind, observed_at=observed_at, quantity_kind=quantity_kind, @@ -1879,6 +1930,8 @@ def to_dict(self) -> dict: result["hasQuota"] = from_union([from_none, from_bool], self.has_quota) if self.http_status is not None: result["httpStatus"] = from_union([from_none, to_int], self.http_status) + if self.monthly_usage is not None: + result["monthlyUsage"] = from_union([from_none, lambda x: to_class(ProviderMonthlyUsage, x)], self.monthly_usage) if self.observation_kind is not None: result["observationKind"] = from_union([from_none, lambda x: to_enum(ProviderQuotaObservationKind, x)], self.observation_kind) if self.observed_at is not None: @@ -2636,6 +2689,7 @@ class SessionManagedSettingsResolvedData: source: ManagedSettingsResolvedSource client_managed: bool | None = None permissions_allow_intersected: bool | None = None + permissions_context: ManagedPermissionsContext | None = None policy_helper_managed: bool | None = None sandbox_enabled_by_undetermined_policy: bool | None = None settings: Any = None @@ -2651,6 +2705,7 @@ def from_dict(obj: Any) -> "SessionManagedSettingsResolvedData": source = parse_enum(ManagedSettingsResolvedSource, obj.get("source")) client_managed = from_union([from_none, from_bool], obj.get("clientManaged")) permissions_allow_intersected = from_union([from_none, from_bool], obj.get("permissionsAllowIntersected")) + permissions_context = from_union([from_none, ManagedPermissionsContext.from_dict], obj.get("permissionsContext")) policy_helper_managed = from_union([from_none, from_bool], obj.get("policyHelperManaged")) sandbox_enabled_by_undetermined_policy = from_union([from_none, from_bool], obj.get("sandboxEnabledByUndeterminedPolicy")) settings = obj.get("settings") @@ -2663,6 +2718,7 @@ def from_dict(obj: Any) -> "SessionManagedSettingsResolvedData": source=source, client_managed=client_managed, permissions_allow_intersected=permissions_allow_intersected, + permissions_context=permissions_context, policy_helper_managed=policy_helper_managed, sandbox_enabled_by_undetermined_policy=sandbox_enabled_by_undetermined_policy, settings=settings, @@ -2680,6 +2736,8 @@ def to_dict(self) -> dict: result["clientManaged"] = from_union([from_none, from_bool], self.client_managed) if self.permissions_allow_intersected is not None: result["permissionsAllowIntersected"] = from_union([from_none, from_bool], self.permissions_allow_intersected) + if self.permissions_context is not None: + result["permissionsContext"] = from_union([from_none, lambda x: to_class(ManagedPermissionsContext, x)], self.permissions_context) if self.policy_helper_managed is not None: result["policyHelperManaged"] = from_union([from_none, from_bool], self.policy_helper_managed) if self.sandbox_enabled_by_undetermined_policy is not None: @@ -3708,6 +3766,8 @@ class AssistantUsageData: reasoning_tokens: int | None = None rejected_prediction_tokens: int | None = None request_body_bytes: int | None = None + request_body_encoding: ModelCallRequestBodyEncoding | None = None + request_body_wire_bytes: int | None = None rte: bool | None = None service_request_id: str | None = None # Internal: this field is an internal SDK API and is not part of the public surface. @@ -3721,7 +3781,12 @@ class AssistantUsageData: _tool_token_count: int | None = None transport: AssistantUsageTransport | None = None websocket_fallback_after: timedelta | None = None + websocket_fallback_close_code: int | None = None + websocket_fallback_error_kind: ModelCallWebSocketFallbackErrorKind | None = None websocket_fallback_reason: ModelCallWebSocketFallbackReason | None = None + websocket_fallback_reconnect_attempted: bool | None = None + websocket_fallback_started_this_call: bool | None = None + websocket_fallback_status_code: int | None = None @staticmethod def from_dict(obj: Any) -> "AssistantUsageData": @@ -3768,6 +3833,8 @@ def from_dict(obj: Any) -> "AssistantUsageData": reasoning_tokens = from_union([from_none, from_int], obj.get("reasoningTokens")) rejected_prediction_tokens = from_union([from_none, from_int], obj.get("rejectedPredictionTokens")) request_body_bytes = from_union([from_none, from_int], obj.get("requestBodyBytes")) + request_body_encoding = from_union([from_none, lambda x: parse_enum(ModelCallRequestBodyEncoding, x)], obj.get("requestBodyEncoding")) + request_body_wire_bytes = from_union([from_none, from_int], obj.get("requestBodyWireBytes")) rte = from_union([from_none, from_bool], obj.get("rte")) service_request_id = from_union([from_none, from_str], obj.get("serviceRequestId")) _thinking_dropped_blocks = from_union([from_none, from_int], obj.get("thinkingDroppedBlocks")) @@ -3777,7 +3844,12 @@ def from_dict(obj: Any) -> "AssistantUsageData": _tool_token_count = from_union([from_none, from_int], obj.get("toolTokenCount")) transport = from_union([from_none, lambda x: parse_enum(AssistantUsageTransport, x)], obj.get("transport")) websocket_fallback_after = from_union([from_none, from_timedelta], obj.get("websocketFallbackAfterMs")) + websocket_fallback_close_code = from_union([from_none, from_int], obj.get("websocketFallbackCloseCode")) + websocket_fallback_error_kind = from_union([from_none, lambda x: parse_enum(ModelCallWebSocketFallbackErrorKind, x)], obj.get("websocketFallbackErrorKind")) websocket_fallback_reason = from_union([from_none, lambda x: parse_enum(ModelCallWebSocketFallbackReason, x)], obj.get("websocketFallbackReason")) + websocket_fallback_reconnect_attempted = from_union([from_none, from_bool], obj.get("websocketFallbackReconnectAttempted")) + websocket_fallback_started_this_call = from_union([from_none, from_bool], obj.get("websocketFallbackStartedThisCall")) + websocket_fallback_status_code = from_union([from_none, from_int], obj.get("websocketFallbackStatusCode")) return AssistantUsageData( model=model, accepted_prediction_tokens=accepted_prediction_tokens, @@ -3821,6 +3893,8 @@ def from_dict(obj: Any) -> "AssistantUsageData": reasoning_tokens=reasoning_tokens, rejected_prediction_tokens=rejected_prediction_tokens, request_body_bytes=request_body_bytes, + request_body_encoding=request_body_encoding, + request_body_wire_bytes=request_body_wire_bytes, rte=rte, service_request_id=service_request_id, _thinking_dropped_blocks=_thinking_dropped_blocks, @@ -3830,7 +3904,12 @@ def from_dict(obj: Any) -> "AssistantUsageData": _tool_token_count=_tool_token_count, transport=transport, websocket_fallback_after=websocket_fallback_after, + websocket_fallback_close_code=websocket_fallback_close_code, + websocket_fallback_error_kind=websocket_fallback_error_kind, websocket_fallback_reason=websocket_fallback_reason, + websocket_fallback_reconnect_attempted=websocket_fallback_reconnect_attempted, + websocket_fallback_started_this_call=websocket_fallback_started_this_call, + websocket_fallback_status_code=websocket_fallback_status_code, ) def to_dict(self) -> dict: @@ -3918,6 +3997,10 @@ def to_dict(self) -> dict: result["rejectedPredictionTokens"] = from_union([from_none, to_int], self.rejected_prediction_tokens) if self.request_body_bytes is not None: result["requestBodyBytes"] = from_union([from_none, to_int], self.request_body_bytes) + if self.request_body_encoding is not None: + result["requestBodyEncoding"] = from_union([from_none, lambda x: to_enum(ModelCallRequestBodyEncoding, x)], self.request_body_encoding) + if self.request_body_wire_bytes is not None: + result["requestBodyWireBytes"] = from_union([from_none, to_int], self.request_body_wire_bytes) if self.rte is not None: result["rte"] = from_union([from_none, from_bool], self.rte) if self.service_request_id is not None: @@ -3936,8 +4019,18 @@ def to_dict(self) -> dict: result["transport"] = from_union([from_none, lambda x: to_enum(AssistantUsageTransport, x)], self.transport) if self.websocket_fallback_after is not None: result["websocketFallbackAfterMs"] = from_union([from_none, to_timedelta_int], self.websocket_fallback_after) + if self.websocket_fallback_close_code is not None: + result["websocketFallbackCloseCode"] = from_union([from_none, to_int], self.websocket_fallback_close_code) + if self.websocket_fallback_error_kind is not None: + result["websocketFallbackErrorKind"] = from_union([from_none, lambda x: to_enum(ModelCallWebSocketFallbackErrorKind, x)], self.websocket_fallback_error_kind) if self.websocket_fallback_reason is not None: result["websocketFallbackReason"] = from_union([from_none, lambda x: to_enum(ModelCallWebSocketFallbackReason, x)], self.websocket_fallback_reason) + if self.websocket_fallback_reconnect_attempted is not None: + result["websocketFallbackReconnectAttempted"] = from_union([from_none, from_bool], self.websocket_fallback_reconnect_attempted) + if self.websocket_fallback_started_this_call is not None: + result["websocketFallbackStartedThisCall"] = from_union([from_none, from_bool], self.websocket_fallback_started_this_call) + if self.websocket_fallback_status_code is not None: + result["websocketFallbackStatusCode"] = from_union([from_none, to_int], self.websocket_fallback_status_code) return result @@ -5885,6 +5978,30 @@ def to_dict(self) -> dict: return result +@dataclass +class ManagedPermissionsContext: + "Reusable managed permission evaluation context. Treat permissions as runtime-owned policy data and retain it verbatim; it includes source-aware composition metadata. This is a snapshot, not a capability or approval token; only use contexts obtained from trusted policy sources." + fail_closed: bool + permissions: Any = None + + @staticmethod + def from_dict(obj: Any) -> "ManagedPermissionsContext": + assert isinstance(obj, dict) + fail_closed = from_bool(obj.get("failClosed")) + permissions = obj.get("permissions") + return ManagedPermissionsContext( + fail_closed=fail_closed, + permissions=permissions, + ) + + def to_dict(self) -> dict: + result: dict = {} + result["failClosed"] = from_bool(self.fail_closed) + if self.permissions is not None: + result["permissions"] = self.permissions + return result + + @dataclass class McpAppToolCallCompleteData: "MCP App view called a tool on a connected MCP server (SEP-1865)" @@ -6388,6 +6505,8 @@ class ModelCallFailureData: _quota_snapshots: dict[str, _AssistantUsageQuotaSnapshot] | None = None reasoning_effort: str | None = None request_body_bytes: int | None = None + request_body_encoding: ModelCallRequestBodyEncoding | None = None + request_body_wire_bytes: int | None = None request_fingerprint: ModelCallFailureRequestFingerprint | None = None retry_attempt: int | None = None rte: bool | None = None @@ -6395,7 +6514,12 @@ class ModelCallFailureData: status_code: int | None = None transport: ModelCallFailureTransport | None = None websocket_fallback_after: timedelta | None = None + websocket_fallback_close_code: int | None = None + websocket_fallback_error_kind: ModelCallWebSocketFallbackErrorKind | None = None websocket_fallback_reason: ModelCallWebSocketFallbackReason | None = None + websocket_fallback_reconnect_attempted: bool | None = None + websocket_fallback_started_this_call: bool | None = None + websocket_fallback_status_code: int | None = None @staticmethod def from_dict(obj: Any) -> "ModelCallFailureData": @@ -6424,6 +6548,8 @@ def from_dict(obj: Any) -> "ModelCallFailureData": _quota_snapshots = from_union([from_none, lambda x: from_dict(_AssistantUsageQuotaSnapshot.from_dict, x)], obj.get("quotaSnapshots")) reasoning_effort = from_union([from_none, from_str], obj.get("reasoningEffort")) request_body_bytes = from_union([from_none, from_int], obj.get("requestBodyBytes")) + request_body_encoding = from_union([from_none, lambda x: parse_enum(ModelCallRequestBodyEncoding, x)], obj.get("requestBodyEncoding")) + request_body_wire_bytes = from_union([from_none, from_int], obj.get("requestBodyWireBytes")) request_fingerprint = from_union([from_none, ModelCallFailureRequestFingerprint.from_dict], obj.get("requestFingerprint")) retry_attempt = from_union([from_none, from_int], obj.get("retryAttempt")) rte = from_union([from_none, from_bool], obj.get("rte")) @@ -6431,7 +6557,12 @@ def from_dict(obj: Any) -> "ModelCallFailureData": status_code = from_union([from_none, from_int], obj.get("statusCode")) transport = from_union([from_none, lambda x: parse_enum(ModelCallFailureTransport, x)], obj.get("transport")) websocket_fallback_after = from_union([from_none, from_timedelta], obj.get("websocketFallbackAfterMs")) + websocket_fallback_close_code = from_union([from_none, from_int], obj.get("websocketFallbackCloseCode")) + websocket_fallback_error_kind = from_union([from_none, lambda x: parse_enum(ModelCallWebSocketFallbackErrorKind, x)], obj.get("websocketFallbackErrorKind")) websocket_fallback_reason = from_union([from_none, lambda x: parse_enum(ModelCallWebSocketFallbackReason, x)], obj.get("websocketFallbackReason")) + websocket_fallback_reconnect_attempted = from_union([from_none, from_bool], obj.get("websocketFallbackReconnectAttempted")) + websocket_fallback_started_this_call = from_union([from_none, from_bool], obj.get("websocketFallbackStartedThisCall")) + websocket_fallback_status_code = from_union([from_none, from_int], obj.get("websocketFallbackStatusCode")) return ModelCallFailureData( source=source, api_call_id=api_call_id, @@ -6457,6 +6588,8 @@ def from_dict(obj: Any) -> "ModelCallFailureData": _quota_snapshots=_quota_snapshots, reasoning_effort=reasoning_effort, request_body_bytes=request_body_bytes, + request_body_encoding=request_body_encoding, + request_body_wire_bytes=request_body_wire_bytes, request_fingerprint=request_fingerprint, retry_attempt=retry_attempt, rte=rte, @@ -6464,7 +6597,12 @@ def from_dict(obj: Any) -> "ModelCallFailureData": status_code=status_code, transport=transport, websocket_fallback_after=websocket_fallback_after, + websocket_fallback_close_code=websocket_fallback_close_code, + websocket_fallback_error_kind=websocket_fallback_error_kind, websocket_fallback_reason=websocket_fallback_reason, + websocket_fallback_reconnect_attempted=websocket_fallback_reconnect_attempted, + websocket_fallback_started_this_call=websocket_fallback_started_this_call, + websocket_fallback_status_code=websocket_fallback_status_code, ) def to_dict(self) -> dict: @@ -6516,6 +6654,10 @@ def to_dict(self) -> dict: result["reasoningEffort"] = from_union([from_none, from_str], self.reasoning_effort) if self.request_body_bytes is not None: result["requestBodyBytes"] = from_union([from_none, to_int], self.request_body_bytes) + if self.request_body_encoding is not None: + result["requestBodyEncoding"] = from_union([from_none, lambda x: to_enum(ModelCallRequestBodyEncoding, x)], self.request_body_encoding) + if self.request_body_wire_bytes is not None: + result["requestBodyWireBytes"] = from_union([from_none, to_int], self.request_body_wire_bytes) if self.request_fingerprint is not None: result["requestFingerprint"] = from_union([from_none, lambda x: to_class(ModelCallFailureRequestFingerprint, x)], self.request_fingerprint) if self.retry_attempt is not None: @@ -6530,8 +6672,18 @@ def to_dict(self) -> dict: result["transport"] = from_union([from_none, lambda x: to_enum(ModelCallFailureTransport, x)], self.transport) if self.websocket_fallback_after is not None: result["websocketFallbackAfterMs"] = from_union([from_none, to_timedelta_int], self.websocket_fallback_after) + if self.websocket_fallback_close_code is not None: + result["websocketFallbackCloseCode"] = from_union([from_none, to_int], self.websocket_fallback_close_code) + if self.websocket_fallback_error_kind is not None: + result["websocketFallbackErrorKind"] = from_union([from_none, lambda x: to_enum(ModelCallWebSocketFallbackErrorKind, x)], self.websocket_fallback_error_kind) if self.websocket_fallback_reason is not None: result["websocketFallbackReason"] = from_union([from_none, lambda x: to_enum(ModelCallWebSocketFallbackReason, x)], self.websocket_fallback_reason) + if self.websocket_fallback_reconnect_attempted is not None: + result["websocketFallbackReconnectAttempted"] = from_union([from_none, from_bool], self.websocket_fallback_reconnect_attempted) + if self.websocket_fallback_started_this_call is not None: + result["websocketFallbackStartedThisCall"] = from_union([from_none, from_bool], self.websocket_fallback_started_this_call) + if self.websocket_fallback_status_code is not None: + result["websocketFallbackStatusCode"] = from_union([from_none, to_int], self.websocket_fallback_status_code) return result @@ -15221,6 +15373,44 @@ class ModelCallFinishedOutcome(Enum): REJECTED = "rejected" +class ModelCallRequestBodyEncoding(Enum): + "Content-Encoding applied to the request body sent on the wire" + # The request body was sent uncompressed (including every WebSocket request). + IDENTITY = "identity" + # The request body was sent gzip-compressed. + GZIP = "gzip" + # The request body was sent zstd-compressed. + ZSTD = "zstd" + + +class ModelCallWebSocketFallbackErrorKind(Enum): + "Normalized cause of the WebSocket failure that triggered the HTTP fallback" + # DNS resolution of the WebSocket host failed. + DNS = "dns" + # The TLS handshake or a TLS record failed. + TLS = "tls" + # A WebSocket connect or read timed out. + TIMEOUT = "timeout" + # The peer refused the TCP connection. + CONNECTION_REFUSED = "connection_refused" + # The connection was reset, aborted, or ended mid-stream without a close. + CONNECTION_RESET = "connection_reset" + # The peer closed the WebSocket. + CLOSED_BY_PEER = "closed_by_peer" + # The runtime closed the WebSocket itself. + CLOSED_LOCALLY = "closed_locally" + # The socket was already closed before it was used. + NOT_CONNECTED = "not_connected" + # The upgrade or request was rejected with an HTTP status. + HTTP_STATUS = "http_status" + # A WebSocket protocol violation or an undecodable frame. + PROTOCOL = "protocol" + # The WebSocket request could not be built. + CONFIGURATION = "configuration" + # A failure that maps onto none of the other kinds. + OTHER = "other" + + class ModelCallWebSocketFallbackReason(Enum): "Why a WebSocket-capable model call was carried by the HTTP fallback" # The WebSocket connection could not be established. @@ -15547,6 +15737,26 @@ class PlanChangedOperation(Enum): DELETE = "delete" +class ProviderMonthlyUsageScope(Enum): + "Identity scope of a monthly usage reading." + # Consumption of the authenticated user within the parent observation's service and returned cycle. + USER = "user" + # The service did not establish a recognized usage scope. + UNKNOWN = "unknown" + + +class ProviderMonthlyUsageState(Enum): + "Availability of a service's monthly consumption reading." + # The service reported a usable consumption reading, including an explicit zero. + AVAILABLE = "available" + # The service found no usage policy; no consumption amount is known. + NO_POLICY = "no_policy" + # The read failed or its data could not be used; consumption is unknown. + UNAVAILABLE = "unavailable" + # The service reported an unrecognized usage state. + UNKNOWN = "unknown" + + class ProviderQuotaAccessState(Enum): "Access policy reported by the quota service." # Access is allowed. @@ -16474,6 +16684,7 @@ def session_event_to_dict(x: SessionEvent) -> Any: "IndexedSearchIncrementalPhase", "IndexedSearchOutcome", "IndexedSearchState", + "ManagedPermissionsContext", "ManagedPluginProgressPhase", "ManagedSettingsEnforcedAction", "ManagedSettingsEnforcedEscalation", @@ -16511,7 +16722,9 @@ def session_event_to_dict(x: SessionEvent) -> Any: "ModelCallFinalResultData", "ModelCallFinishedData", "ModelCallFinishedOutcome", + "ModelCallRequestBodyEncoding", "ModelCallStartData", + "ModelCallWebSocketFallbackErrorKind", "ModelCallWebSocketFallbackReason", "ModelChangeSource", "ModelDeselectedReason", @@ -16601,6 +16814,9 @@ def session_event_to_dict(x: SessionEvent) -> Any: "PersistedBinaryResult", "PlanChangedOperation", "PromptCacheBreakData", + "ProviderMonthlyUsage", + "ProviderMonthlyUsageScope", + "ProviderMonthlyUsageState", "ProviderQuotaAccessState", "ProviderQuotaAcquisitionStatus", "ProviderQuotaBudgetMetadata", diff --git a/python/test_client.py b/python/test_client.py index 5badf26ee6..95e80c1b0e 100644 --- a/python/test_client.py +++ b/python/test_client.py @@ -16,6 +16,7 @@ import pytest +import copilot.client as client_module from copilot import ( CanvasProviderIdentity, CapiSessionOptions, @@ -87,6 +88,29 @@ def test_inprocess_connection_has_no_child_process_options(): assert not hasattr(connection, "args") +@pytest.mark.asyncio +async def test_inprocess_forwards_integration_id_to_native_host( + monkeypatch: pytest.MonkeyPatch, tmp_path +): + monkeypatch.setenv("GITHUB_COPILOT_INTEGRATION_ID", " microsoft/vscode ") + monkeypatch.setattr( + "copilot._cli_download.ensure_runtime_wrapper", + lambda: str(tmp_path / "copilot-runtime"), + ) + host = Mock() + host.process = Mock() + host.start_blocking = Mock() + create_host = Mock(return_value=host) + monkeypatch.setattr(client_module.FfiRuntimeHost, "create", create_host) + client = CopilotClient(connection=RuntimeConnection.for_inprocess()) + + await client._start_inprocess_ffi() + + assert ( + "--cli-login-sync-integration-id=microsoft/vscode" in create_host.call_args.kwargs["args"] + ) + + def test_explicit_child_process_path_does_not_require_runtime_bundle(tmp_path): explicit = tmp_path / "copilot" connection = RuntimeConnection.for_stdio(path=str(explicit)) diff --git a/rust/src/ffi.rs b/rust/src/ffi.rs index df0269b0b8..3d7bbf4401 100644 --- a/rust/src/ffi.rs +++ b/rust/src/ffi.rs @@ -245,6 +245,7 @@ impl AsyncWrite for FfiWriter { pub(crate) struct FfiHost { library_path: PathBuf, cli_entrypoint: Option, + integration_id: Option, environment: Vec<(String, String)>, args: Vec, host_start: HostStartFn, @@ -263,6 +264,7 @@ impl FfiHost { pub(crate) fn create( runtime_entrypoint: &Path, cli_entrypoint: Option<&Path>, + integration_id: Option<&str>, environment: Vec<(String, String)>, args: Vec, ) -> Result { @@ -307,6 +309,7 @@ impl FfiHost { Ok(Self { library_path, cli_entrypoint, + integration_id: integration_id.map(str::to_owned), environment, args, host_start, @@ -330,7 +333,11 @@ impl FfiHost { } fn start_blocking(self) -> Result<(FfiReader, FfiWriter, Arc), Error> { - let argv = build_argv_json(self.cli_entrypoint.as_deref(), &self.args); + let argv = build_argv_json( + self.cli_entrypoint.as_deref(), + self.integration_id.as_deref(), + &self.args, + ); let env = build_env_json(&self.environment); let (env_ptr, env_len) = match &env { @@ -561,7 +568,11 @@ fn path_for_child_process(path: PathBuf) -> PathBuf { path } -fn build_argv_json(entrypoint: Option<&Path>, extra_args: &[String]) -> Vec { +fn build_argv_json( + entrypoint: Option<&Path>, + integration_id: Option<&str>, + extra_args: &[String], +) -> Vec { let mut argv = Vec::new(); if let Some(entrypoint) = entrypoint { let entrypoint_str = entrypoint.to_string_lossy().into_owned(); @@ -578,6 +589,9 @@ fn build_argv_json(entrypoint: Option<&Path>, extra_args: &[String]) -> Vec "--no-auto-update".to_string(), ]); } + if let Some(integration_id) = integration_id { + argv.push(format!("--cli-login-sync-integration-id={integration_id}")); + } argv.extend_from_slice(extra_args); serde_json::to_vec(&argv).expect("argv serializes") } diff --git a/rust/src/ffi/tests.rs b/rust/src/ffi/tests.rs index 5662dc4e5b..5fbd0929fc 100644 --- a/rust/src/ffi/tests.rs +++ b/rust/src/ffi/tests.rs @@ -36,6 +36,7 @@ unsafe extern "C" fn test_connection_close(_connection_id: u32) -> bool { #[test] fn argv_without_entrypoint_contains_only_client_options() { let argv: Vec = serde_json::from_slice(&build_argv_json( + None, None, &["--log-level".into(), "debug".into()], )) @@ -46,12 +47,22 @@ fn argv_without_entrypoint_contains_only_client_options() { #[test] fn explicit_javascript_entrypoint_uses_node() { - let argv: Vec = - serde_json::from_slice(&build_argv_json(Some(Path::new("index.js")), &[])).unwrap(); + let argv: Vec = serde_json::from_slice(&build_argv_json( + Some(Path::new("index.js")), + Some("microsoft/vscode"), + &[], + )) + .unwrap(); assert_eq!( argv, - ["node", "index.js", "--embedded-host", "--no-auto-update"] + [ + "node", + "index.js", + "--embedded-host", + "--no-auto-update", + "--cli-login-sync-integration-id=microsoft/vscode", + ] ); } diff --git a/rust/src/generated/api_types.rs b/rust/src/generated/api_types.rs index e6a4b6f6bc..10d4e963b1 100644 --- a/rust/src/generated/api_types.rs +++ b/rust/src/generated/api_types.rs @@ -11,12 +11,13 @@ use serde::{Deserialize, Serialize}; pub use super::session_events::{ AbortReason, AgentModelPolicy, AutoTier, ContextTier, IndexedSearchState, - ManagedSettingsResolvedSource, McpOauthHttpResponse, McpOauthWWWAuthenticateParams, - McpServerMetadata, McpServerSource, McpServerStatus, ModelChangeSource, ModelProviderKind, - ModelProviderRef, OmittedBinaryOmittedReason, PermissionDecisionSource, PermissionMode, - PermissionPromptRequest, PermissionRule, ProviderQuotaState, ReasoningSummary, - RemediationAction, SessionLimitsConfig, SessionMode, ShutdownType, SkillSource, TaskBlocker, - TaskCompletionOutcome, UsageGetMetricsResult, UserToolSessionApproval, Verbosity, + ManagedPermissionsContext, ManagedSettingsResolvedSource, McpOauthHttpResponse, + McpOauthWWWAuthenticateParams, McpServerMetadata, McpServerSource, McpServerStatus, + ModelChangeSource, ModelProviderKind, ModelProviderRef, OmittedBinaryOmittedReason, + PermissionDecisionSource, PermissionMode, PermissionPromptRequest, PermissionRule, + ProviderQuotaState, ReasoningSummary, RemediationAction, SessionLimitsConfig, SessionMode, + ShutdownType, SkillSource, TaskBlocker, TaskCompletionOutcome, UsageGetMetricsResult, + UserToolSessionApproval, Verbosity, }; use crate::types::{RequestId, SessionEvent, SessionId}; @@ -231,6 +232,8 @@ pub mod rpc_methods { pub const MANAGEDSETTINGS_CLEARCACHE: &str = "managedSettings.clearCache"; /// `managedSettings.resolve` pub const MANAGEDSETTINGS_RESOLVE: &str = "managedSettings.resolve"; + /// `managedSettings.permissions.evaluate` + pub const MANAGEDSETTINGS_PERMISSIONS_EVALUATE: &str = "managedSettings.permissions.evaluate"; /// `managedSettings.schema` pub const MANAGEDSETTINGS_SCHEMA: &str = "managedSettings.schema"; /// `managedSettings.validate` @@ -2041,6 +2044,9 @@ pub struct AccountsSetRequest { pub struct AccountStatus { /// Whether this is the active account. pub active: bool, + /// Human-readable credential source used to authenticate this account, such as `gh` or `GITHUB_TOKEN`. + #[serde(skip_serializing_if = "Option::is_none")] + pub auth_source: Option, /// Opaque id of the account this one was derived from (e.g. an EMU account's base Entra identity); absent for a root account. Matches the base identity account's selectionId, forming the derivation edge. #[serde(skip_serializing_if = "Option::is_none")] pub derived_from: Option, @@ -11110,6 +11116,72 @@ pub struct ManagedMcpServerConfig { pub url: String, } +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ManagedPermissionOperation { + /// Operation to evaluate. Currently only url is supported. + pub kind: ManagedPermissionOperationKind, + /// Absolute HTTP(S) URL with a host. Invalid URLs reject the entire evaluation batch. + pub url: String, +} + +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ManagedPermissionEvaluation { + /// Original input operation associated with this verdict. + pub operation: ManagedPermissionOperation, + /// Managed-policy decision only; never bypasses user permissions or other security controls. + pub verdict: ManagedPermissionVerdict, +} + +/// Managed policy context and ordered operations for pure, sessionless evaluation. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ManagedPermissionsEvaluateRequest { + /// Trusted, reusable managed permission policy snapshot; no policy is discovered during evaluation. + pub context: ManagedPermissionsContext, + /// Operations to evaluate, preserving input order and duplicates. An empty batch is valid. + pub operations: Vec, +} + +/// Ordered managed permission verdicts and the supplied policy's fail-closed posture. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ManagedPermissionsEvaluateResult { + /// Managed permission policy could not be determined; every operation is denied. + pub fail_closed: bool, + /// One verdict per input operation, in the same order, including duplicates. + pub results: Vec, +} + /// Retry outcome for one plugin required by managed settings. /// ///
@@ -11270,6 +11342,9 @@ pub struct ManagedSettingsResolvedData { /// Whether at least two managed sources supplied permission allowlists, so enforcement intersects them and the flattened settings payload omits `permissions.allow`. #[serde(skip_serializing_if = "Option::is_none")] pub permissions_allow_intersected: Option, + /// Reusable retained managed permission policy for managedSettings.permissions.evaluate, including source composition and session-local injection. Provided by live session snapshots; absent in older events. Refresh the context when managed policy changes. + #[serde(skip_serializing_if = "Option::is_none")] + pub permissions_context: Option, /// Whether the policy-helper managed-settings layer was present. The policy helper is the weakest channel: it fills keys no enterprise source set and can never replace one. #[serde(skip_serializing_if = "Option::is_none")] pub policy_helper_managed: Option, @@ -11400,6 +11475,9 @@ pub struct ManagedSettingsResolveResult { /// Per-key lock state and provenance for the entries in `values`, using the same key names. #[serde(skip_serializing_if = "Option::is_none")] pub meta: Option, + /// Reusable source-composed permission policy for managedSettings.permissions.evaluate. Unlike resolved.settings.permissions, this retains every source's allowlist and default-prompt semantics. Refresh through resolve when account/device policy changes. Absent on runtimes that do not support permission evaluation. + #[serde(skip_serializing_if = "Option::is_none")] + pub permissions_context: Option, /// Effective managed settings from the device and account (server) channels, in the same shape as `session.managedSettings.get`, excluding session-local injection. pub resolved: ManagedSettingsResolvedData, /// Typed effective values of managed settings, keyed like the managed-settings schema and already resolved across channels, with the `{ "overridable": ... }` wrapper removed. Present when policy sets at least one typed key. Keys not typed here are available in `resolved.settings`. @@ -30912,6 +30990,23 @@ pub struct GitWorkingDirectoryContextResult { pub repository_host: Option, } +/// Ordered managed permission verdicts and the supplied policy's fail-closed posture. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ManagedSettingsPermissionsEvaluateResult { + /// Managed permission policy could not be determined; every operation is denied. + pub fail_closed: bool, + /// One verdict per input operation, in the same order, including duplicates. + pub results: Vec, +} + /// Result of opening a session. /// ///
@@ -34913,6 +35008,9 @@ pub struct SessionManagedSettingsGetResult { /// Whether at least two managed sources supplied permission allowlists, so enforcement intersects them and the flattened settings payload omits `permissions.allow`. #[serde(skip_serializing_if = "Option::is_none")] pub permissions_allow_intersected: Option, + /// Reusable retained managed permission policy for managedSettings.permissions.evaluate, including source composition and session-local injection. Provided by live session snapshots; absent in older events. Refresh the context when managed policy changes. + #[serde(skip_serializing_if = "Option::is_none")] + pub permissions_context: Option, /// Whether the policy-helper managed-settings layer was present. The policy helper is the weakest channel: it fills keys no enterprise source set and can never replace one. #[serde(skip_serializing_if = "Option::is_none")] pub policy_helper_managed: Option, @@ -42597,6 +42695,42 @@ pub enum SessionLogLevel { Unknown, } +/// Operation to evaluate. Currently only url is supported. +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum ManagedPermissionOperationKind { + #[serde(rename = "url")] + #[default] + Url, +} + +/// Managed-policy verdict only: deny blocks the URL, ask requires approval, allow approves under managed policy, and unmanaged leaves the normal consumer permission flow in effect. No verdict bypasses other security controls. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum ManagedPermissionVerdict { + /// Managed policy prohibits the operation; do not offer approval. + #[serde(rename = "deny")] + Deny, + /// Managed policy requires the consumer to obtain approval. + #[serde(rename = "ask")] + Ask, + /// Managed policy allows the operation, subject to other security controls. + #[serde(rename = "allow")] + Allow, + /// Managed policy does not decide the operation; use the consumer's normal permission flow. + #[serde(rename = "unmanaged")] + Unmanaged, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + /// What retrying did for one plugin required by managed settings. /// ///
diff --git a/rust/src/generated/rpc.rs b/rust/src/generated/rpc.rs index 518b3d0208..2af2f66e82 100644 --- a/rust/src/generated/rpc.rs +++ b/rust/src/generated/rpc.rs @@ -1998,6 +1998,13 @@ pub struct ClientRpcManagedSettings<'a> { } impl<'a> ClientRpcManagedSettings<'a> { + /// `managedSettings.permissions.*` sub-namespace. + pub fn permissions(&self) -> ClientRpcManagedSettingsPermissions<'a> { + ClientRpcManagedSettingsPermissions { + client: self.client, + } + } + /// Discovers device-managed settings from production MDM and managed-file sources, validates them against the runtime-owned managed-settings schema, and returns the canonical JSON without requiring a session. `managedSettings.resolve` returns the same device settings together with the account's server policy. /// /// Wire method: `managedSettings.read`. @@ -2184,6 +2191,48 @@ impl<'a> ClientRpcManagedSettings<'a> { } } +/// `managedSettings.permissions.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcManagedSettingsPermissions<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcManagedSettingsPermissions<'a> { + /// Pure, sessionless evaluation of operations against a supplied permissionsContext. Performs no policy discovery, I/O, prompting, navigation, permission grants, or sandbox changes. Obtain the context from managedSettings.resolve or session.managedSettings.get, or reuse an in-memory context. Results preserve input order and duplicates. Consumers must block deny, obtain approval for ask, and use their normal permission flow for unmanaged. Unknown policy returns failClosed with every operation denied. This is not a substitute for user permissions or other security controls. + /// + /// Wire method: `managedSettings.permissions.evaluate`. + /// + /// # Parameters + /// + /// * `params` - Managed policy context and ordered operations for pure, sessionless evaluation. + /// + /// # Returns + /// + /// Ordered managed permission verdicts and the supplied policy's fail-closed posture. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn evaluate( + &self, + params: ManagedPermissionsEvaluateRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call( + rpc_methods::MANAGEDSETTINGS_PERMISSIONS_EVALUATE, + Some(wire_params), + ) + .await?; + Ok(serde_json::from_value(_value)?) + } +} + /// `mcp.*` RPCs. #[derive(Clone, Copy)] pub struct ClientRpcMcp<'a> { diff --git a/rust/src/generated/session_events.rs b/rust/src/generated/session_events.rs index 4872f9ab0d..8d3f7a844a 100644 --- a/rust/src/generated/session_events.rs +++ b/rust/src/generated/session_events.rs @@ -2273,6 +2273,37 @@ pub struct ProviderQuotaBudgetMetadata { pub usage_allowed_when_exhausted: bool, } +/// An authoritative monthly usage reading for the observation's provider, account, and service. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ProviderMonthlyUsage { + /// Nonnegative finite consumption reported by the service, preserving zero and fractions. Present only when state is available; never computed from tokens or balance differences. + #[serde(skip_serializing_if = "Option::is_none")] + pub consumed_quantity: Option, + /// Start of the service-reported monthly billing cycle, in UTC RFC 3339. + #[serde(skip_serializing_if = "Option::is_none")] + pub cycle_start: Option, + /// Service read time in UTC RFC 3339, not a ledger reconciliation watermark or confirmation of the latest inference charge. + #[serde(skip_serializing_if = "Option::is_none")] + pub queried_at: Option, + /// End of the service-reported monthly billing cycle, in UTC RFC 3339. + #[serde(skip_serializing_if = "Option::is_none")] + pub reset_on: Option, + /// Identity scope of the reading within its provider and service. + pub scope: ProviderMonthlyUsageScope, + /// Availability of monthly consumption. Missing or unavailable usage must never be interpreted as zero. + pub state: ProviderMonthlyUsageState, + /// Unit of consumedQuantity; independent of the parent observation's balance unit. + pub unit: ProviderQuotaUnit, +} + /// An account quota reading. Absence of a quantity is unknown, never zero. /// ///
@@ -2312,6 +2343,9 @@ pub struct ProviderQuotaState { /// HTTP status from acquisition, when available. #[serde(skip_serializing_if = "Option::is_none")] pub http_status: Option, + /// Service-reported monthly consumption, independent of quota balances and per-call or session cost. Omitted when the service does not report monthly usage. + #[serde(skip_serializing_if = "Option::is_none")] + pub monthly_usage: Option, /// Whether this is a GET account reading or a pre-response admission observation. Observations are never merged across kinds. #[serde(skip_serializing_if = "Option::is_none")] pub observation_kind: Option, @@ -2349,7 +2383,7 @@ pub struct ProviderQuotaState { #[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct SessionQuotaObservationData { - /// The admitted provider's state observation. Admission observations never contain quantities or reset/percentage semantics. + /// The admitted provider's state observation. Admission balances and percentages remain absent; separate monthly usage may report its own amount and cycle. pub observation: ProviderQuotaState, } @@ -4096,9 +4130,15 @@ pub struct AssistantUsageData { /// Number of rejected speculative prediction tokens #[serde(skip_serializing_if = "Option::is_none")] pub rejected_prediction_tokens: Option, - /// Serialized (uncompressed) byte length of the request body. A content-free size signal. + /// Serialized (uncompressed) byte length of the request body, before any Content-Encoding. A content-free size signal. #[serde(skip_serializing_if = "Option::is_none")] pub request_body_bytes: Option, + /// Content-Encoding applied to the request body of the attempt that produced this outcome; identity when uncompressed + #[serde(skip_serializing_if = "Option::is_none")] + pub request_body_encoding: Option, + /// Byte length of the request body actually sent on the wire for the attempt that produced this outcome, after any Content-Encoding. Equals requestBodyBytes when the body was not compressed. + #[serde(skip_serializing_if = "Option::is_none")] + pub request_body_wire_bytes: Option, /// Per-request treatment/eligibility signal returned by the Copilot API in the `X-GitHub-Copilot-Request-TE` response header for the associated model call; `false` when the header was absent or unparseable. #[serde(skip_serializing_if = "Option::is_none")] pub rte: Option, @@ -4130,9 +4170,24 @@ pub struct AssistantUsageData { /// Milliseconds spent on the WebSocket attempt before falling back to HTTP #[serde(skip_serializing_if = "Option::is_none")] pub websocket_fallback_after_ms: Option, + /// WebSocket close code received before the HTTP fallback + #[serde(skip_serializing_if = "Option::is_none")] + pub websocket_fallback_close_code: Option, + /// Normalized cause of the WebSocket failure that triggered the HTTP fallback; absent when no fallback occurred or the cause is unknown + #[serde(skip_serializing_if = "Option::is_none")] + pub websocket_fallback_error_kind: Option, /// Why the call was carried by the HTTP fallback of a WebSocket-capable dispatcher; absent when no fallback occurred #[serde(skip_serializing_if = "Option::is_none")] pub websocket_fallback_reason: Option, + /// Whether a WebSocket reconnect was attempted before falling back to HTTP + #[serde(skip_serializing_if = "Option::is_none")] + pub websocket_fallback_reconnect_attempted: Option, + /// Whether the HTTP fallback started during this model call, rather than being inherited from an earlier call + #[serde(skip_serializing_if = "Option::is_none")] + pub websocket_fallback_started_this_call: Option, + /// HTTP status of the WebSocket upgrade rejection or WebSocket API error that triggered the HTTP fallback + #[serde(skip_serializing_if = "Option::is_none")] + pub websocket_fallback_status_code: Option, } /// Session event "prompt_cache_break". A detected loss of a previously cached prompt prefix @@ -4333,9 +4388,15 @@ pub struct ModelCallFailureData { /// Reasoning effort level used for the failed model call, if applicable #[serde(skip_serializing_if = "Option::is_none")] pub reasoning_effort: Option, - /// Serialized (uncompressed) byte length of the failed request body. A content-free size signal. + /// Serialized (uncompressed) byte length of the failed request body, before any Content-Encoding. A content-free size signal. #[serde(skip_serializing_if = "Option::is_none")] pub request_body_bytes: Option, + /// Content-Encoding applied to the failed request body; identity when uncompressed + #[serde(skip_serializing_if = "Option::is_none")] + pub request_body_encoding: Option, + /// Byte length of the failed request body actually sent on the wire, after any Content-Encoding. Equals requestBodyBytes when the body was not compressed. + #[serde(skip_serializing_if = "Option::is_none")] + pub request_body_wire_bytes: Option, /// Content-free structural summary of the failing request. Contains only counts and shape flags (no prompt content), so it is safe for unrestricted telemetry. Populated only for client-error (4xx) failures. #[serde(skip_serializing_if = "Option::is_none")] pub request_fingerprint: Option, @@ -4359,9 +4420,24 @@ pub struct ModelCallFailureData { /// Milliseconds spent on the WebSocket attempt before falling back to HTTP #[serde(skip_serializing_if = "Option::is_none")] pub websocket_fallback_after_ms: Option, + /// WebSocket close code received before the HTTP fallback + #[serde(skip_serializing_if = "Option::is_none")] + pub websocket_fallback_close_code: Option, + /// Normalized cause of the WebSocket failure that triggered the HTTP fallback; absent when no fallback occurred or the cause is unknown + #[serde(skip_serializing_if = "Option::is_none")] + pub websocket_fallback_error_kind: Option, /// Why the failed call was carried by the HTTP fallback of a WebSocket-capable dispatcher; absent when no fallback occurred #[serde(skip_serializing_if = "Option::is_none")] pub websocket_fallback_reason: Option, + /// Whether a WebSocket reconnect was attempted before falling back to HTTP + #[serde(skip_serializing_if = "Option::is_none")] + pub websocket_fallback_reconnect_attempted: Option, + /// Whether the HTTP fallback started during this model call, rather than being inherited from an earlier call + #[serde(skip_serializing_if = "Option::is_none")] + pub websocket_fallback_started_this_call: Option, + /// HTTP status of the WebSocket upgrade rejection or WebSocket API error that triggered the HTTP fallback + #[serde(skip_serializing_if = "Option::is_none")] + pub websocket_fallback_status_code: Option, } /// Session event "model.call_final_result". Internal telemetry result for one logical model operation after all orchestrator-owned retries settle @@ -8002,6 +8078,17 @@ pub struct SessionManagedPluginProgressData { pub plugin_specs: Vec, } +/// Reusable managed permission evaluation context. Treat permissions as runtime-owned policy data and retain it verbatim; it includes source-aware composition metadata. This is a snapshot, not a capability or approval token; only use contexts obtained from trusted policy sources. +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ManagedPermissionsContext { + /// Policy could not be determined; evaluation must deny every operation. + pub fail_closed: bool, + /// Runtime-owned composed permissions object. Absent when no permission policy is configured. + #[serde(skip_serializing_if = "Option::is_none")] + pub permissions: Option, +} + /// Session event "session.managed_settings_resolved". Effective enterprise managed settings applied to the session and their contributing channels. Emitted whenever managed policy is applied or reapplied, including session start, resume, and account switch. This ephemeral live snapshot is delivered to subscribers but not persisted to the session event log; initial resolution occurs before session.start. /// ///
@@ -8027,6 +8114,9 @@ pub struct SessionManagedSettingsResolvedData { /// Whether at least two managed sources supplied permission allowlists, so enforcement intersects them and the flattened settings payload omits `permissions.allow`. #[serde(skip_serializing_if = "Option::is_none")] pub permissions_allow_intersected: Option, + /// Reusable retained managed permission policy for managedSettings.permissions.evaluate, including source composition and session-local injection. Provided by live session snapshots; absent in older events. Refresh the context when managed policy changes. + #[serde(skip_serializing_if = "Option::is_none")] + pub permissions_context: Option, /// Whether the policy-helper managed-settings layer was present. The policy helper is the weakest channel: it fills keys no enterprise source set and can never replace one. #[serde(skip_serializing_if = "Option::is_none")] pub policy_helper_managed: Option, @@ -9452,33 +9542,36 @@ pub enum ProviderQuotaCapacityState { Unknown, } -/// Timing and purpose of a provider quota observation. +/// Identity scope of a monthly usage reading. #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] -pub enum ProviderQuotaObservationKind { - /// An explicit account read; consumption may still be subject to service aggregation delay. - #[serde(rename = "account_snapshot")] - AccountSnapshot, - /// A verdict attached before an inference response. May be cached; never a post-charge balance. - #[serde(rename = "admission_state")] - AdmissionState, +pub enum ProviderMonthlyUsageScope { + /// Consumption of the authenticated user within the parent observation's service and returned cycle. + #[serde(rename = "user")] + User, + /// The service did not establish a recognized usage scope. + #[serde(rename = "unknown")] + UnknownValue, /// Unknown variant for forward compatibility. #[default] #[serde(other)] Unknown, } -/// Interpretation permitted for independently reported quantities. +/// Availability of a service's monthly consumption reading. #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] -pub enum ProviderQuotaQuantityKind { - /// Quantities form an authoritative available-of-entitled budget suitable for percentage presentation. - #[serde(rename = "authoritative_budget")] - AuthoritativeBudget, - /// Raw advisory quantities; do not infer permission, usage percentage, reset cadence, or post-charge balance. - #[serde(rename = "advisory_balance")] - AdvisoryBalance, - /// No quantity measurement, as with admission-only response headers. - #[serde(rename = "none")] - None, +pub enum ProviderMonthlyUsageState { + /// The service reported a usable consumption reading, including an explicit zero. + #[serde(rename = "available")] + Available, + /// The service found no usage policy; no consumption amount is known. + #[serde(rename = "no_policy")] + NoPolicy, + /// The read failed or its data could not be used; consumption is unknown. + #[serde(rename = "unavailable")] + Unavailable, + /// The service reported an unrecognized usage state. + #[serde(rename = "unknown")] + UnknownValue, /// Unknown variant for forward compatibility. #[default] #[serde(other)] @@ -9506,6 +9599,39 @@ pub enum ProviderQuotaUnit { Unknown, } +/// Timing and purpose of a provider quota observation. +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum ProviderQuotaObservationKind { + /// An explicit account read; consumption may still be subject to service aggregation delay. + #[serde(rename = "account_snapshot")] + AccountSnapshot, + /// A verdict attached before an inference response. May be cached; never a post-charge balance. + #[serde(rename = "admission_state")] + AdmissionState, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + +/// Interpretation permitted for independently reported quantities. +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum ProviderQuotaQuantityKind { + /// Quantities form an authoritative available-of-entitled budget suitable for percentage presentation. + #[serde(rename = "authoritative_budget")] + AuthoritativeBudget, + /// Raw advisory quantities; do not infer permission, usage percentage, reset cadence, or post-charge balance. + #[serde(rename = "advisory_balance")] + AdvisoryBalance, + /// No quantity measurement, as with admission-only response headers. + #[serde(rename = "none")] + None, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + /// What initiated a conversation compaction #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] pub enum CompactionTrigger { @@ -10108,6 +10234,24 @@ pub enum AssistantUsageApiEndpoint { Unknown, } +/// Content-Encoding applied to the request body sent on the wire +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum ModelCallRequestBodyEncoding { + /// The request body was sent uncompressed (including every WebSocket request). + #[serde(rename = "identity")] + Identity, + /// The request body was sent gzip-compressed. + #[serde(rename = "gzip")] + Gzip, + /// The request body was sent zstd-compressed. + #[serde(rename = "zstd")] + Zstd, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + /// Transport used for a successful model call #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] pub enum AssistantUsageTransport { @@ -10123,6 +10267,51 @@ pub enum AssistantUsageTransport { Unknown, } +/// Normalized cause of the WebSocket failure that triggered the HTTP fallback +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum ModelCallWebSocketFallbackErrorKind { + /// DNS resolution of the WebSocket host failed. + #[serde(rename = "dns")] + Dns, + /// The TLS handshake or a TLS record failed. + #[serde(rename = "tls")] + Tls, + /// A WebSocket connect or read timed out. + #[serde(rename = "timeout")] + Timeout, + /// The peer refused the TCP connection. + #[serde(rename = "connection_refused")] + ConnectionRefused, + /// The connection was reset, aborted, or ended mid-stream without a close. + #[serde(rename = "connection_reset")] + ConnectionReset, + /// The peer closed the WebSocket. + #[serde(rename = "closed_by_peer")] + ClosedByPeer, + /// The runtime closed the WebSocket itself. + #[serde(rename = "closed_locally")] + ClosedLocally, + /// The socket was already closed before it was used. + #[serde(rename = "not_connected")] + NotConnected, + /// The upgrade or request was rejected with an HTTP status. + #[serde(rename = "http_status")] + HttpStatus, + /// A WebSocket protocol violation or an undecodable frame. + #[serde(rename = "protocol")] + Protocol, + /// The WebSocket request could not be built. + #[serde(rename = "configuration")] + Configuration, + /// A failure that maps onto none of the other kinds. + #[serde(rename = "other")] + Other, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + /// Why a WebSocket-capable model call was carried by the HTTP fallback #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] pub enum ModelCallWebSocketFallbackReason { diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 93790a94b8..090bbaf85f 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1634,12 +1634,17 @@ impl Client { if !use_logged_in_user { args.push("--no-auto-login".to_string()); } + let integration_id = std::env::var("GITHUB_COPILOT_INTEGRATION_ID") + .ok() + .map(|value| value.trim().to_owned()) + .filter(|value| !value.is_empty()); let explicit_cli = std::env::var_os("COPILOT_CLI_PATH") .map(PathBuf::from) .filter(|path| path.is_file()); let host = crate::ffi::FfiHost::create( &program, explicit_cli.as_deref(), + integration_id.as_deref(), environment, args, )?; diff --git a/rust/tests/api_types_test.rs b/rust/tests/api_types_test.rs index 2941c8f692..d8b705f075 100644 --- a/rust/tests/api_types_test.rs +++ b/rust/tests/api_types_test.rs @@ -11,6 +11,7 @@ use github_copilot_sdk::rpc::{ CustomizationReloadOutcome, CustomizationReloadStatus, CustomizationReloadSubsystem, EnqueueCommandResult, Extension, ExtensionList, ExtensionSource, ExtensionStatus, ExtensionsDisableRequest, ExtensionsEnableRequest, FleetStartRequest, FleetStartResult, + ManagedPermissionEvaluation, ManagedPermissionOperationKind, ManagedPermissionsEvaluateRequest, McpConfiguredServer, McpConfiguredServerList, McpConfiguredServerState, McpDisableRequest, McpEnableOptions, McpEnableRequest, McpInstallationOperationStatus, McpOauthLoginOptions, McpOauthLoginRequest, McpServer, McpStopServerRequest, ModelSetAllowedModelsRequest, @@ -25,6 +26,30 @@ use github_copilot_sdk::session_events::{ }; use github_copilot_sdk::{AutoTier, AutoTierPreference, SetModelOptions}; +#[test] +fn managed_permission_results_reuse_operations_without_reconstruction() { + let evaluation: ManagedPermissionEvaluation = serde_json::from_value(serde_json::json!({ + "operation": {"kind": "url", "url": "https://example.com/a"}, + "verdict": "allow", + })) + .unwrap(); + let request = ManagedPermissionsEvaluateRequest { + context: serde_json::from_value(serde_json::json!({"failClosed": false})).unwrap(), + operations: vec![evaluation.operation], + }; + assert_eq!( + request.operations[0].kind, + ManagedPermissionOperationKind::Url + ); + assert_eq!( + serde_json::to_value(request).unwrap(), + serde_json::json!({ + "context": {"failClosed": false}, + "operations": [{"kind": "url", "url": "https://example.com/a"}], + }) + ); +} + #[test] fn extensible_tier_unknown_literal_retains_its_provider_identity() { let wire = serde_json::json!("Unknown"); diff --git a/scripts/codegen/python.ts b/scripts/codegen/python.ts index 237ebf216f..a30a96b011 100644 --- a/scripts/codegen/python.ts +++ b/scripts/codegen/python.ts @@ -3436,6 +3436,25 @@ async function generateRpc(schemaPath?: string, sessionEventsSchema?: JSONSchema const allDefinitions = combinedSchema.definitions! as Record; preservePythonRpcStringDateFields(allDefinitions); + const managedOperationProperties = resolveObjectSchema( + allDefinitions.ManagedPermissionOperation, + rpcDefinitions + )?.properties; + const managedOperationKind = managedOperationProperties?.kind; + if (managedOperationProperties && managedOperationKind && typeof managedOperationKind === "object") { + const values = + managedOperationKind.enum ?? + (typeof managedOperationKind.const === "string" ? [managedOperationKind.const] : undefined); + if (!values?.every((value): value is string => typeof value === "string")) { + throw new Error("Expected a string discriminator for ManagedPermissionOperation.kind"); + } + allDefinitions.ManagedPermissionOperationKind = { + type: "string", + enum: values, + description: managedOperationKind.description, + }; + managedOperationProperties.kind = { $ref: "#/definitions/ManagedPermissionOperationKind" }; + } const allDefinitionCollections: DefinitionCollections = { definitions: { ...(combinedSchema.$defs ?? {}), ...allDefinitions }, $defs: { ...allDefinitions, ...(combinedSchema.$defs ?? {}) }, @@ -3455,13 +3474,13 @@ async function generateRpc(schemaPath?: string, sessionEventsSchema?: JSONSchema }; const externalRefs = rewriteExternalRefsForPython(singleSchema as JSONSchema7 & { definitions?: Record }); const externalEnumNames = collectPythonExternalEnumNames(sessionEventsSchema, externalRefs.placeholderNames); - // Discovery and session availability are independently versioned despite identical values. - // Hide the discovery enum from quicktype's enum merging, then restore it with our enum emitter. + // Independently versioned enums must not be structurally merged by quicktype. + // Hide them from quicktype's enum merging, then restore them with our enum emitter. const distinctEnums: Pick = { enumsByName: new Map(), enums: [], }; - for (const name of ["ConnectorDiscoveryAvailability"]) { + for (const name of ["ConnectorDiscoveryAvailability", "ManagedPermissionOperationKind"]) { const definition = allDefinitions[name]; if (!definition) continue; if (!definition.enum?.every((value): value is string => typeof value === "string")) { diff --git a/scripts/codegen/rust.ts b/scripts/codegen/rust.ts index 9ce9f54511..aad957837d 100644 --- a/scripts/codegen/rust.ts +++ b/scripts/codegen/rust.ts @@ -804,8 +804,11 @@ function resolveRustType( ); return wrapOption(typeName, isRequired); } - if (isObjectSchema(resolved)) { - emitRustStruct(typeName, resolved, ctx); + const namedObject = typeName === "ManagedPermissionOperation" + ? resolveObjectSchema(resolved, ctx.definitions) + : resolved; + if (namedObject && isObjectSchema(namedObject)) { + emitRustStruct(typeName, { ...resolved, ...namedObject }, ctx); return wrapOption(typeName, isRequired); } return resolveRustType( diff --git a/test/harness/test-mcp-computer-use-oauth-server.mjs b/test/harness/test-mcp-computer-use-oauth-server.mjs new file mode 100644 index 0000000000..2b8dc3c82f --- /dev/null +++ b/test/harness/test-mcp-computer-use-oauth-server.mjs @@ -0,0 +1,173 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import http from "node:http"; + +export async function startComputerUseOAuthServer({ + deferRegistration = false, + deferInitialChallenge = false, + deferAuthorizationMetadata = false, + preconfiguredClientId = "", +} = {}) { + let clientId = preconfiguredClientId; + let releaseRegistration = () => {}; + const registration = deferRegistration + ? new Promise((resolve) => { + releaseRegistration = resolve; + }) + : Promise.resolve(); + let releaseInitialChallenge = () => {}; + const initialChallenge = deferInitialChallenge + ? new Promise((resolve) => { + releaseInitialChallenge = resolve; + }) + : Promise.resolve(); + let releaseAuthorizationMetadata = () => {}; + const authorizationMetadata = deferAuthorizationMetadata + ? new Promise((resolve) => { + releaseAuthorizationMetadata = resolve; + }) + : Promise.resolve(); + const requests = []; + const token = "computer-use-isolation-token"; + const server = http.createServer(async (request, response) => { + const url = new URL(request.url ?? "/", `http://${request.headers.host}`); + const chunks = []; + for await (const chunk of request) chunks.push(chunk); + const body = Buffer.concat(chunks).toString("utf8"); + requests.push({ + method: request.method, + path: url.pathname, + authorization: request.headers.authorization ?? null, + body, + }); + const respond = (status, value, headers = {}) => { + response.writeHead(status, { "content-type": "application/json", ...headers }); + response.end(JSON.stringify(value)); + }; + if (request.method === "GET" && url.pathname === "/.well-known/oauth-protected-resource") { + respond(200, { + resource: `${url.origin}/mcp`, + authorization_servers: [url.origin], + scopes_supported: ["mcp.read"], + bearer_methods_supported: ["header"], + }); + return; + } + if (request.method === "GET" && url.pathname === "/.well-known/oauth-authorization-server") { + await authorizationMetadata; + respond(200, { + issuer: url.origin, + authorization_endpoint: `${url.origin}/authorize`, + token_endpoint: `${url.origin}/token`, + registration_endpoint: `${url.origin}/register`, + response_types_supported: ["code"], + grant_types_supported: ["authorization_code"], + }); + return; + } + if (request.method === "POST" && url.pathname === "/register") { + await registration; + clientId = "registered-client"; + respond(201, { client_id: clientId, client_id_issued_at: Math.floor(Date.now() / 1000) }); + return; + } + if (request.method === "POST" && url.pathname === "/token") { + const form = new URLSearchParams(body); + if (!clientId || form.get("client_id") !== clientId) { + respond(400, { error: "invalid_client" }); + return; + } + if ( + form.get("grant_type") !== "authorization_code" || + form.get("code") !== "accepted-code" || + !form.get("code_verifier") + ) { + respond(400, { error: "invalid_grant" }); + return; + } + respond(200, { access_token: token, token_type: "Bearer", expires_in: 3600 }); + return; + } + if (url.pathname !== "/mcp") { + respond(404, { error: "not_found" }); + return; + } + if (request.headers.authorization !== `Bearer ${token}`) { + await initialChallenge; + respond( + 401, + { error: "unauthorized" }, + { + "www-authenticate": `Bearer resource_metadata="${url.origin}/.well-known/oauth-protected-resource", scope="mcp.read"`, + }, + ); + return; + } + if (request.method !== "POST") { + respond(405, { error: "method_not_allowed" }); + return; + } + let message; + try { + message = JSON.parse(body); + } catch { + respond(400, { error: "invalid_json" }); + return; + } + if (message.id === undefined) { + response.writeHead(202); + response.end(); + return; + } + let result; + if (message.method === "initialize") { + result = { + protocolVersion: "2025-03-26", + capabilities: { tools: {} }, + serverInfo: { name: "computer-use-oauth-isolation", version: "1.0.0" }, + }; + } else if (message.method === "tools/list") { + result = { + tools: [ + { + name: "whoami", + description: "Reports an authenticated connection", + inputSchema: { type: "object", properties: {}, additionalProperties: false }, + }, + ], + }; + } else if (message.method === "ping") { + result = {}; + } else { + respond(200, { jsonrpc: "2.0", id: message.id, error: { code: -32601, message: "Method not found" } }); + return; + } + respond(200, { jsonrpc: "2.0", id: message.id, result }, { "mcp-session-id": "computer-use-oauth-isolation" }); + }); + await new Promise((resolve, reject) => { + server.once("error", reject); + server.listen(0, "127.0.0.1", () => { + server.off("error", reject); + resolve(); + }); + }); + const address = server.address(); + if (!address || typeof address === "string") throw new Error("Expected TCP server address"); + return { + url: `http://127.0.0.1:${address.port}`, + requests, + releaseRegistration, + releaseInitialChallenge, + releaseAuthorizationMetadata, + close: () => + new Promise((resolve, reject) => { + releaseRegistration(); + releaseInitialChallenge(); + releaseAuthorizationMetadata(); + server.close((error) => (error ? reject(error) : resolve())); + server.closeAllConnections(); + }), + }; +} diff --git a/test/snapshots/rpc_tasks_and_handlers/should_emit_session_idle_after_cancelling_a_running_attached_shell.yaml b/test/snapshots/rpc_tasks_and_handlers/should_emit_session_idle_after_cancelling_a_running_attached_shell.yaml new file mode 100644 index 0000000000..d22c9aefea --- /dev/null +++ b/test/snapshots/rpc_tasks_and_handlers/should_emit_session_idle_after_cancelling_a_running_attached_shell.yaml @@ -0,0 +1,21 @@ +models: + - claude-sonnet-5 +conversations: + - messages: + - role: system + content: ${system} + - role: user + content: Use your shell tool to run `sleep 600` in async mode without detaching. Do not read its output or wait for it. + Then reply with exactly SHELL_STARTED. + - role: assistant + tool_calls: + - id: toolcall_0 + type: function + function: + name: ${shell} + arguments: '{"command":"sleep 600","description":"Sleep for 600 seconds","mode":"async"}' + - role: tool + tool_call_id: toolcall_0 + content: "" + - role: assistant + content: SHELL_STARTED diff --git a/test/snapshots/rpc_tasks_and_handlers/should_run_a_queued_message_after_cancelling_a_running_attached_shell.yaml b/test/snapshots/rpc_tasks_and_handlers/should_run_a_queued_message_after_cancelling_a_running_attached_shell.yaml new file mode 100644 index 0000000000..d2dbce4e77 --- /dev/null +++ b/test/snapshots/rpc_tasks_and_handlers/should_run_a_queued_message_after_cancelling_a_running_attached_shell.yaml @@ -0,0 +1,25 @@ +models: + - claude-sonnet-5 +conversations: + - messages: + - role: system + content: ${system} + - role: user + content: Use your shell tool to run `sleep 600` in async mode without detaching. Do not read its output or wait for it. + Then reply with exactly SHELL_STARTED. + - role: assistant + tool_calls: + - id: toolcall_0 + type: function + function: + name: ${shell} + arguments: '{"command":"sleep 600","description":"Sleep for 600 seconds","mode":"async","initial_wait":10}' + - role: tool + tool_call_id: toolcall_0 + content: "" + - role: assistant + content: SHELL_STARTED + - role: user + content: Reply with exactly QUEUED_DONE. + - role: assistant + content: QUEUED_DONE From 0f7ab2dc70d23b51379a159176e6c833a30c0e57 Mon Sep 17 00:00:00 2001 From: "copilot-cli-release-app[bot]" Date: Sat, 10 Oct 2026 00:19:04 +0000 Subject: [PATCH 5/9] Update SDK snapshot for Copilot CLI 1.0.96-1 --- dotnet/src/Generated/Rpc.cs | 339 +++++-- dotnet/src/Generated/SessionEvents.cs | 4 +- go/rpc/zrpc.go | 284 +++++- go/rpc/zsession_events.go | 4 +- .../SessionManagedSettingsResolvedEvent.java | 4 +- .../generated/rpc/GlobalStateLoadResult.java | 2 - .../rpc/ManagedSettingsResolvedData.java | 4 +- .../rpc/McpRegistryCancelParams.java | 30 + .../rpc/McpRegistryCancelResult.java | 31 + .../rpc/McpRegistryRequestIdResult.java | 31 + .../rpc/McpRegistrySearchParams.java | 38 + .../rpc/McpRegistrySearchResult.java | 31 + .../McpShouldExcludeGitHubToolsParams.java | 35 + .../McpShouldExcludeGitHubToolsResult.java | 31 + .../rpc/SandboxCredentialSuggestion.java | 34 + .../generated/rpc/ServerGlobalStateApi.java | 2 +- .../copilot/generated/rpc/ServerMcpApi.java | 14 + .../generated/rpc/ServerMcpRegistryApi.java | 62 ++ .../rpc/SessionManagedSettingsGetResult.java | 4 +- .../generated/rpc/SessionSandboxApi.java | 11 + ...SandboxGetCredentialSuggestionsParams.java | 30 + ...SandboxGetCredentialSuggestionsResult.java | 31 + nodejs/package.json | 2 +- nodejs/src/cliVersion.ts | 2 +- nodejs/src/generated/rpc.ts | 229 ++++- nodejs/src/generated/session-events.ts | 4 +- .../test/e2e/auto_fusion_routing.e2e.test.ts | 904 ++++++++++++++++++ .../e2e/browser_shadow_reload.e2e.test.ts | 143 +++ nodejs/test/e2e/compaction.e2e.test.ts | 539 ++++++++++- .../test/e2e/mcp_scoped_sign_in.e2e.test.ts | 17 +- .../test/e2e/rpc_surface_coverage.e2e.test.ts | 2 +- nodejs/test/e2e/session_fs.e2e.test.ts | 87 +- nodejs/test/e2e/skill_provider.e2e.test.ts | 87 +- python/copilot/generated/rpc.py | 369 ++++++- rust/src/generated/api_types.rs | 268 +++++- rust/src/generated/rpc.rs | 167 +++- rust/src/generated/session_events.rs | 4 +- ..._cold_resume_with_reordered_discovery.yaml | 14 + 38 files changed, 3701 insertions(+), 193 deletions(-) create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistryCancelParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistryCancelResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistryRequestIdResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistrySearchParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistrySearchResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpShouldExcludeGitHubToolsParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpShouldExcludeGitHubToolsResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxCredentialSuggestion.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpRegistryApi.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSandboxGetCredentialSuggestionsParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSandboxGetCredentialSuggestionsResult.java create mode 100644 nodejs/test/e2e/auto_fusion_routing.e2e.test.ts create mode 100644 nodejs/test/e2e/browser_shadow_reload.e2e.test.ts create mode 100644 test/snapshots/skill_provider/should_preserve_skill_prompt_bytes_across_cold_resume_with_reordered_discovery.yaml diff --git a/dotnet/src/Generated/Rpc.cs b/dotnet/src/Generated/Rpc.cs index 6652e3755f..a9b486d94c 100644 --- a/dotnet/src/Generated/Rpc.cs +++ b/dotnet/src/Generated/Rpc.cs @@ -2149,6 +2149,32 @@ internal sealed class McpDiscoverRequest public string? WorkingDirectory { get; set; } } +/// Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by the request. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpShouldExcludeGitHubToolsResult +{ + /// True only when both halves hold: the session's filters still reach the platform shell tool, and the host actually has the `gh` those tools would be replaced by. Feed it straight back as the `excludeGhReplaceableTools` build option. + [JsonPropertyName("excludeGhReplaceableTools")] + public bool ExcludeGhReplaceableTools { get; set; } +} + +/// The session tool filters that decide whether the session still has a shell to run `gh` with. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpShouldExcludeGitHubToolsRequest +{ + /// The session's tool allowlist, when it set one. Omitted means the session constrains nothing this way. + [JsonPropertyName("availableTools")] + public IList? AvailableTools { get; set; } + + /// The session's tool denylist, when it set one. Omitted means the session constrains nothing this way. + [JsonPropertyName("excludedTools")] + public IList? ExcludedTools { get; set; } + + /// How the allowlist and denylist combine when both are set. Omitted means the default every session gets, so a caller that never chose a precedence is answered as its sessions behave. + [JsonPropertyName("toolFilterPrecedence")] + public OptionsUpdateToolFilterPrecedence? ToolFilterPrecedence { get; set; } +} + /// Outcome of an mcp.planInstall call: either a normalised plan, or one typed refusal. Nothing is written in either case. /// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] @@ -4118,6 +4144,67 @@ internal sealed class McpConfigDisableRequest public IList Names { get => field ??= []; set; } } +/// Request id naming a cancellable registry search. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpRegistryRequestIdResult +{ + /// Request ID for `mcp.registry.search` and `mcp.registry.cancel`. It serves one search. Allocation can reclaim unused IDs at the 1,024-ID reservation limit. + [JsonPropertyName("requestId")] + public long RequestId { get; set; } +} + +/// Servers selected from the registry response. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpRegistrySearchResult +{ + /// The server objects, carried opaquely. The runtime follows pages, keeps the newest entry per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub stars. Each server object remains unchanged because the registry owns that shape. + [JsonPropertyName("servers")] + public JsonElement Servers { get; set; } +} + +/// Registry search terms, the credential to search under, and the request id that makes the search cancellable. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpRegistrySearchRequest +{ + /// The credential the search runs under, carried opaquely. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. + [JsonPropertyName("authInfo")] + public JsonElement AuthInfo { get; set; } + + /// Maximum number of servers to return. + [JsonPropertyName("limit")] + public long Limit { get; set; } + + /// Free-text query. Omitted or empty asks the registry for its top servers rather than searching. A value that is not a string is refused. + [JsonPropertyName("query")] + public string? Query { get; set; } + + /// Repository used for the policy lookup, as `owner/name`. The policy selects the registry URL and whether the user token goes to the registry. The registry receives this repository only when the policy entry lists it as required context. A value that is not a string is refused. + [JsonPropertyName("repository")] + public string? Repository { get; set; } + + /// Request ID from `mcp.registry.allocateRequestId`. The search refuses unknown, reclaimed, or canceled IDs and IDs that another search or request already uses. + [JsonPropertyName("requestId")] + public long RequestId { get; set; } +} + +/// Whether the cancel reached a live search. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpRegistryCancelResult +{ + /// True when the cancel stopped a running search. False for unknown or reclaimed IDs, completed or canceled searches, and unused reservations. The cancel releases an unused reservation. + [JsonPropertyName("canceled")] + public bool Canceled { get; set; } +} + +/// Registry search to abandon. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpRegistryCancelRequest +{ + /// Request ID from `mcp.registry.allocateRequestId` that the search uses. + [JsonPropertyName("requestId")] + public long RequestId { get; set; } +} + /// New-work inventory or recovery request under an explicitly selected existing session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] internal sealed class McpInstallationsRequest @@ -7127,10 +7214,6 @@ internal sealed class LoggedInUser [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] internal sealed class GlobalStateLoadResult { - /// Whether the user has answered the prompt suggesting they install the desktop app. - [JsonPropertyName("appInstallNudgeResponded")] - public bool? AppInstallNudgeResponded { get; set; } - /// Whether the app tip has been shown. [JsonPropertyName("appTipShown")] public bool? AppTipShown { get; set; } @@ -7649,7 +7732,7 @@ public sealed class ManagedSettingsMeta [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] public sealed class ManagedSettingsResolvedData { - /// Whether enterprise policy disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers, and forced on when `failClosed` is true. + /// Whether an explicit enterprise policy restriction disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers; an unresolved policy does not force this on by itself. [JsonPropertyName("bypassPermissionsDisabled")] public bool BypassPermissionsDisabled { get; set; } @@ -7661,7 +7744,7 @@ public sealed class ManagedSettingsResolvedData [JsonPropertyName("deviceManaged")] public bool DeviceManaged { get; set; } - /// Whether managed policy could not be determined (e.g. a failed server fetch) and the session fell back to the fail-closed restriction. When true, restrictions such as disabling bypass-permissions are enforced even though `settings` may be absent. + /// Whether managed policy could not be determined (e.g. a failed server fetch) and unresolved-policy safeguards remain active. This does not by itself disable bypass-permissions; `bypassPermissionsDisabled` reports only an explicit policy restriction. [JsonPropertyName("failClosed")] public bool FailClosed { get; set; } @@ -11033,6 +11116,37 @@ internal sealed class SessionSandboxGetEnforcementStatusRequest public string SessionId { get; set; } = string.Empty; } +/// A possible secret-bearing environment variable and optional locally suggested HTTPS injection hosts. This is a draft for user review, not an active grant. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SandboxCredentialSuggestion +{ + /// Environment variable name. The secret value is never returned. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// HTTPS hostnames suggested by a local known-provider mapping. An empty list requires the user to supply injection hosts before adding a masking entry. These suggestions do not allow network access. + [JsonPropertyName("suggestedInjectHosts")] + public IList SuggestedInjectHosts { get => field ??= []; set; } +} + +/// Possible unconfigured secrets in the sandbox shell environment, sorted by variable name, with no secret values. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SandboxCredentialSuggestionsResult +{ + /// Candidates for user review. Empty when sandboxing is disabled or no unconfigured candidates are present. + [JsonPropertyName("suggestions")] + public IList Suggestions { get => field ??= []; set; } +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionSandboxGetCredentialSuggestionsRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + /// Result of attempting to disable sandboxing for the current session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] public sealed class SandboxDisableForSessionResult @@ -28765,6 +28879,69 @@ public override void Write(Utf8JsonWriter writer, DiscoveredMcpServerType value, } +/// Controls how availableTools (allowlist) and excludedTools (denylist) combine when both are set. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct OptionsUpdateToolFilterPrecedence : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public OptionsUpdateToolFilterPrecedence(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// If availableTools is set, it is the only constraint that applies (excludedTools is ignored). Preserves CLI / pre-existing client behavior. Default. + public static OptionsUpdateToolFilterPrecedence Available { get; } = new("available"); + + /// A tool is enabled if and only if it matches the allowlist (or the allowlist is unset) AND it does not match the denylist. Makes 'all except X' expressible by combining the two lists. + public static OptionsUpdateToolFilterPrecedence Excluded { get; } = new("excluded"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(OptionsUpdateToolFilterPrecedence left, OptionsUpdateToolFilterPrecedence right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(OptionsUpdateToolFilterPrecedence left, OptionsUpdateToolFilterPrecedence right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is OptionsUpdateToolFilterPrecedence other && Equals(other); + + /// + public bool Equals(OptionsUpdateToolFilterPrecedence other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override OptionsUpdateToolFilterPrecedence Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, OptionsUpdateToolFilterPrecedence value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(OptionsUpdateToolFilterPrecedence)); + } + } +} + + /// A wire feature a caller can require of the catalog surface, negotiated per request. A grant means the runtime understands the feature's contract, not that the deployment has enabled the operation; typed unavailable results report availability separately. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] @@ -40111,69 +40288,6 @@ public override void Write(Utf8JsonWriter writer, ShellInitScriptShell value, Js } -/// Controls how availableTools (allowlist) and excludedTools (denylist) combine when both are set. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct OptionsUpdateToolFilterPrecedence : IEquatable -{ - private readonly string? _value; - - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public OptionsUpdateToolFilterPrecedence(string value) - { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; - } - - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// If availableTools is set, it is the only constraint that applies (excludedTools is ignored). Preserves CLI / pre-existing client behavior. Default. - public static OptionsUpdateToolFilterPrecedence Available { get; } = new("available"); - - /// A tool is enabled if and only if it matches the allowlist (or the allowlist is unset) AND it does not match the denylist. Makes 'all except X' expressible by combining the two lists. - public static OptionsUpdateToolFilterPrecedence Excluded { get; } = new("excluded"); - - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(OptionsUpdateToolFilterPrecedence left, OptionsUpdateToolFilterPrecedence right) => left.Equals(right); - - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(OptionsUpdateToolFilterPrecedence left, OptionsUpdateToolFilterPrecedence right) => !(left == right); - - /// - public override bool Equals(object? obj) => obj is OptionsUpdateToolFilterPrecedence other && Equals(other); - - /// - public bool Equals(OptionsUpdateToolFilterPrecedence other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - - /// - public override string ToString() => Value; - - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter - { - /// - public override OptionsUpdateToolFilterPrecedence Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } - - /// - public override void Write(Utf8JsonWriter writer, OptionsUpdateToolFilterPrecedence value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(OptionsUpdateToolFilterPrecedence)); - } - } -} - - /// Discovery source: project (.github/extensions/), user (~/.copilot/extensions/), plugin (installed plugin), or session (session-state/<id>/extensions/). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] @@ -44235,6 +44349,18 @@ public async Task DiscoverAsync(string? workingDirectory = nu return await CopilotClient.InvokeRpcAsync(_rpc, "mcp.discover", [request], cancellationToken); } + /// Reports whether the gh-replaceable GitHub MCP tools may be clipped for a session, which a host feeds back as the `excludeGhReplaceableTools` build option. The tools are redundant only when the session can reach a shell *and* the host has the `gh` that would replace them, so both halves are decided here. The shell half runs the platform shell tool through the runtime's own tool-filter matcher, so entry forms like `builtin:bash` and `builtin:*` behave exactly as they do when a session builds its tool catalog. The host half probes for `gh`, and is skipped entirely when the filters already rule the shell out. Host presence alone is not enough: a session restricted to, say, `view` would otherwise lose the built-in issue-read fallback while having no shell to replace it with. The answer describes the host the runtime runs on, so it is never forwarded to a remote engine. + /// The session's tool allowlist, when it set one. Omitted means the session constrains nothing this way. + /// The session's tool denylist, when it set one. Omitted means the session constrains nothing this way. + /// How the allowlist and denylist combine when both are set. Omitted means the default every session gets, so a caller that never chose a precedence is answered as its sessions behave. + /// The to monitor for cancellation requests. The default is . + /// Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by the request. + internal async Task ShouldExcludeGitHubToolsAsync(IList? availableTools = null, IList? excludedTools = null, OptionsUpdateToolFilterPrecedence? toolFilterPrecedence = null, CancellationToken cancellationToken = default) + { + var request = new McpShouldExcludeGitHubToolsRequest { AvailableTools = availableTools, ExcludedTools = excludedTools, ToolFilterPrecedence = toolFilterPrecedence }; + return await CopilotClient.InvokeRpcAsync(_rpc, "mcp.shouldExcludeGitHubTools", [request], cancellationToken); + } + /// Requests a side-effect-free MCP install plan from a catalog candidate handle or a caller-supplied card. This host-implemented server method is available through SDK/TUI hosts; standalone and C-ABI runtimes whose host does not implement server-method dispatch return JSON-RPC MethodNotFound. A runtime with planning available returns a normalised plan and opaque single-use plan handle; a runtime without it returns the typed planning-unavailable result. A completed plan reports resource identity, provenance, eligible transport choices, the user-scope target, required typed values and secret placeholders, the policy result, the configuration changes installing would make, and whether a reload would be needed. Planning never writes configuration, stores a secret, or reloads MCP servers, so abandoning a plan needs no call and leaves nothing behind. /// Protocol version and capabilities the caller requires. /// What to plan: either a candidate handle from a previous search, or a card supplied directly. @@ -44347,6 +44473,12 @@ public async Task ApplyUninstallAsync(CatalogClientContra Interlocked.CompareExchange(ref field, new(_rpc), null) ?? field; + /// Registry APIs. + public ServerMcpRegistryApi Registry => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + /// Installations APIs. public ServerMcpInstallationsApi Installations => field ?? @@ -44441,6 +44573,52 @@ public async Task ReloadAsync(CancellationToken cancellationToken = default) } } +/// Provides server-scoped McpRegistry APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerMcpRegistryApi +{ + private readonly JsonRpc _rpc; + + internal ServerMcpRegistryApi(JsonRpc rpc) + { + _rpc = rpc; + } + + /// Allocates an ID for one cancellable MCP registry search. The ID exists before the search starts, so callers can cancel before it starts. The networking stack supplies the cancellation namespace. The runtime retains at most 1,024 unused IDs. At capacity, another allocation can reclaim an unused ID. Active searches retain their IDs until they finish. + /// The to monitor for cancellation requests. The default is . + /// Request id naming a cancellable registry search. + internal async Task AllocateRequestIdAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "mcp.registry.allocateRequestId", [], cancellationToken); + } + + /// Searches the MCP registry the supplied credential may read, resolving the registry endpoint from policy first. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. The runtime follows registry pages, keeps the newest entry per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub stars. Each server object is carried opaquely. + /// Request ID from `mcp.registry.allocateRequestId`. The search refuses unknown, reclaimed, or canceled IDs and IDs that another search or request already uses. + /// The credential the search runs under, carried opaquely. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. + /// Maximum number of servers to return. + /// Free-text query. Omitted or empty asks the registry for its top servers rather than searching. A value that is not a string is refused. + /// Repository used for the policy lookup, as `owner/name`. The policy selects the registry URL and whether the user token goes to the registry. The registry receives this repository only when the policy entry lists it as required context. A value that is not a string is refused. + /// The to monitor for cancellation requests. The default is . + /// Servers selected from the registry response. + internal async Task SearchAsync(long requestId, object authInfo, long limit, string? query = null, string? repository = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(authInfo); + + var request = new McpRegistrySearchRequest { RequestId = requestId, AuthInfo = CopilotClient.ToJsonElementForWire(authInfo)!.Value, Limit = limit, Query = query, Repository = repository }; + return await CopilotClient.InvokeRpcAsync(_rpc, "mcp.registry.search", [request], cancellationToken); + } + + /// Abandons the registry search that uses the given request ID. It acts only on IDs from `mcp.registry.allocateRequestId`, so it never cancels another component's request. Answers `canceled: true` when it stops a running search. Answers `canceled: false` for unknown or reclaimed IDs, completed or canceled searches, and unused reservations. It releases an unused reservation, so a later search with that ID is refused. + /// Request ID from `mcp.registry.allocateRequestId` that the search uses. + /// The to monitor for cancellation requests. The default is . + /// Whether the cancel reached a live search. + internal async Task CancelAsync(long requestId, CancellationToken cancellationToken = default) + { + var request = new McpRegistryCancelRequest { RequestId = requestId }; + return await CopilotClient.InvokeRpcAsync(_rpc, "mcp.registry.cancel", [request], cancellationToken); + } +} + /// Provides server-scoped McpInstallations APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] public sealed class ServerMcpInstallationsApi @@ -45189,7 +45367,7 @@ internal async Task LoadForConfigDirAsync(string? configD return await CopilotClient.InvokeRpcAsync(_rpc, "globalState.loadForConfigDir", [request], cancellationToken); } - /// Records one top-level key in the host's machine-wide state, the counterpart to `globalState.load`. A host calls this to remember that it has shown an onboarding step, asked a one-off question, or completed a migration, so the next run can skip it. Only the named key is replaced and the rest of the document is preserved, which lets two writers record different flags without overwriting each other; passing no value removes the key instead. Only the keys a host records itself are writable: `appInstallNudgeResponded`, `appTipShown`, `askedSetupTerminals`, `autoFeedbackLastPromptedAt`, `firstLaunchAt`, `recentModelIds`, `sandboxCredentialProxyCaDeclined` and `sandboxOnboardingShown`. Every other key is refused, including `installedPlugins`, the stored credentials, `trustedFolders`, the staff flags and the signed-in accounts. Plugin enablement must use the plugin APIs, which apply repository and managed-policy checks. + /// Records one top-level key in the host's machine-wide state, the counterpart to `globalState.load`. A host calls this to remember that it has shown an onboarding step, asked a one-off question, or completed a migration, so the next run can skip it. Only the named key is replaced and the rest of the document is preserved, which lets two writers record different flags without overwriting each other; passing no value removes the key instead. Only the keys a host records itself are writable: `appTipShown`, `askedSetupTerminals`, `autoFeedbackLastPromptedAt`, `firstLaunchAt`, `recentModelIds`, `sandboxCredentialProxyCaDeclined` and `sandboxOnboardingShown`. Every other key is refused, including `installedPlugins`, the stored credentials, `trustedFolders`, the staff flags and the signed-in accounts. Plugin enablement must use the plugin APIs, which apply repository and managed-policy checks. /// Top-level key to write, named as it appears in the result of `globalState.load`. It must be one of the writable keys that `globalState.writeKey` lists. /// Copilot configuration directory to write the state document in, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to write the directory the server resolved for itself. Mirrors `globalState.loadForConfigDir`, so a caller can read and write the same directory. /// Value to store for the key. Omit it, or pass null, to remove the key instead. @@ -46673,6 +46851,17 @@ public async Task GetEnforcementStatusAsync(Cancellati return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.sandbox.getEnforcementStatus", [request], cancellationToken); } + /// Lists possible secret-bearing environment variables available to new sandboxed shells that are not already covered by credential masking. Uses local name rules and known-provider host suggestions, never returns secret values, and changes no settings or network permissions. Returns no suggestions while the session is not sandboxed. + /// The to monitor for cancellation requests. The default is . + /// Possible unconfigured secrets in the sandbox shell environment, sorted by variable name, with no secret values. + public async Task GetCredentialSuggestionsAsync(CancellationToken cancellationToken = default) + { + _session.ThrowIfDisposed(); + + var request = new SessionSandboxGetCredentialSuggestionsRequest { SessionId = _session.SessionId }; + return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.sandbox.getCredentialSuggestions", [request], cancellationToken); + } + /// Disables sandboxing for the remainder of the current session and approves the referenced pending sandbox-bypass permission request. The request is rejected unless the exact request is still pending and the effective sandbox policy permits bypass. /// Identifier of the exact pending sandbox-bypass permission request that authorized the session opt-out. /// Optional attribution for the permission decision. @@ -53167,6 +53356,11 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(McpPromptsListRequest))] [JsonSerializable(typeof(McpPromptsListResult))] [JsonSerializable(typeof(McpRegisterExternalClientRequest))] +[JsonSerializable(typeof(McpRegistryCancelRequest))] +[JsonSerializable(typeof(McpRegistryCancelResult))] +[JsonSerializable(typeof(McpRegistryRequestIdResult))] +[JsonSerializable(typeof(McpRegistrySearchRequest))] +[JsonSerializable(typeof(McpRegistrySearchResult))] [JsonSerializable(typeof(McpReloadWithConfigRequest))] [JsonSerializable(typeof(McpRemoveGitHubResult))] [JsonSerializable(typeof(McpResource))] @@ -53191,6 +53385,8 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(McpServerOwnership))] [JsonSerializable(typeof(McpSetEnvValueModeParams))] [JsonSerializable(typeof(McpSetEnvValueModeResult))] +[JsonSerializable(typeof(McpShouldExcludeGitHubToolsRequest))] +[JsonSerializable(typeof(McpShouldExcludeGitHubToolsResult))] [JsonSerializable(typeof(McpSourceFile))] [JsonSerializable(typeof(McpSourcePlugin))] [JsonSerializable(typeof(McpSourceRef))] @@ -53457,6 +53653,8 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(SandboxConfigUserPolicyNetwork))] [JsonSerializable(typeof(SandboxConfigUserPolicyNetworkProxy))] [JsonSerializable(typeof(SandboxConfigUserPolicySeatbelt))] +[JsonSerializable(typeof(SandboxCredentialSuggestion))] +[JsonSerializable(typeof(SandboxCredentialSuggestionsResult))] [JsonSerializable(typeof(SandboxCredentialsConfig))] [JsonSerializable(typeof(SandboxDisableForSessionRequest))] [JsonSerializable(typeof(SandboxDisableForSessionResult))] @@ -53644,6 +53842,7 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(SessionQuotaSnapshot))] [JsonSerializable(typeof(SessionQuotaTakeWarningsRequest))] [JsonSerializable(typeof(SessionRemoteDisableRequest))] +[JsonSerializable(typeof(SessionSandboxGetCredentialSuggestionsRequest))] [JsonSerializable(typeof(SessionSandboxGetEnforcementStatusRequest))] [JsonSerializable(typeof(SessionScheduleHasSelfPacedRequest))] [JsonSerializable(typeof(SessionScheduleHydrateRequest))] diff --git a/dotnet/src/Generated/SessionEvents.cs b/dotnet/src/Generated/SessionEvents.cs index b114c14840..6d7d21e0f7 100644 --- a/dotnet/src/Generated/SessionEvents.cs +++ b/dotnet/src/Generated/SessionEvents.cs @@ -7365,7 +7365,7 @@ public sealed partial class SessionManagedPluginProgressData [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] public sealed partial class SessionManagedSettingsResolvedData { - /// Whether enterprise policy disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers, and forced on when `failClosed` is true. + /// Whether an explicit enterprise policy restriction disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers; an unresolved policy does not force this on by itself. [JsonPropertyName("bypassPermissionsDisabled")] public required bool BypassPermissionsDisabled { get; set; } @@ -7378,7 +7378,7 @@ public sealed partial class SessionManagedSettingsResolvedData [JsonPropertyName("deviceManaged")] public required bool DeviceManaged { get; set; } - /// Whether managed policy could not be determined (e.g. a failed server fetch) and the session fell back to the fail-closed restriction. When true, restrictions such as disabling bypass-permissions are enforced even though `settings` may be absent. + /// Whether managed policy could not be determined (e.g. a failed server fetch) and unresolved-policy safeguards remain active. This does not by itself disable bypass-permissions; `bypassPermissionsDisabled` reports only an explicit policy restriction. [JsonPropertyName("failClosed")] public required bool FailClosed { get; set; } diff --git a/go/rpc/zrpc.go b/go/rpc/zrpc.go index 810998664e..fd534106e1 100644 --- a/go/rpc/zrpc.go +++ b/go/rpc/zrpc.go @@ -5392,8 +5392,6 @@ type GlobalStateLoadForConfigDirRequest struct { // Internal: GlobalStateLoadResult is an internal SDK API and is not part of the public // surface. type GlobalStateLoadResult struct { - // Whether the user has answered the prompt suggesting they install the desktop app. - AppInstallNudgeResponded *bool `json:"appInstallNudgeResponded,omitempty"` // Whether the app tip has been shown. AppTipShown *bool `json:"appTipShown,omitempty"` // Terminals the user has already been asked to set up, so the host does not ask twice. @@ -6991,16 +6989,18 @@ type ManagedSettingsReadResult struct { // Experimental: ManagedSettingsResolvedData is part of an experimental API and may change // or be removed. type ManagedSettingsResolvedData struct { - // Whether enterprise policy disables bypass-permissions ("yolo") mode for this session. - // Deny-wins across layers, and forced on when `failClosed` is true. + // Whether an explicit enterprise policy restriction disables bypass-permissions ("yolo") + // mode for this session. Deny-wins across layers; an unresolved policy does not force this + // on by itself. BypassPermissionsDisabled bool `json:"bypassPermissionsDisabled"` // Whether a session-local permissions layer injected by the SDK host was present ClientManaged *bool `json:"clientManaged,omitempty"` // Whether an actual device MDM/plist/registry/file managed-settings layer was present DeviceManaged bool `json:"deviceManaged"` - // Whether managed policy could not be determined (e.g. a failed server fetch) and the - // session fell back to the fail-closed restriction. When true, restrictions such as - // disabling bypass-permissions are enforced even though `settings` may be absent. + // Whether managed policy could not be determined (e.g. a failed server fetch) and + // unresolved-policy safeguards remain active. This does not by itself disable + // bypass-permissions; `bypassPermissionsDisabled` reports only an explicit policy + // restriction. FailClosed bool `json:"failClosed"` // The setting keys under enterprise management in the effective managed settings (e.g. // `model`, `enabledPlugins`, `permissions`). Empty when no managed settings are in force. @@ -9319,6 +9319,67 @@ type MCPRegisterExternalClientRequest struct { Transport any `json:"transport"` } +// Registry search to abandon. +// Experimental: MCPRegistryCancelRequest is part of an experimental API and may change or +// be removed. +type MCPRegistryCancelRequest struct { + // Request ID from `mcp.registry.allocateRequestId` that the search uses. + RequestID int64 `json:"requestId"` +} + +// Whether the cancel reached a live search. +// Experimental: MCPRegistryCancelResult is part of an experimental API and may change or be +// removed. +type MCPRegistryCancelResult struct { + // True when the cancel stopped a running search. False for unknown or reclaimed IDs, + // completed or canceled searches, and unused reservations. The cancel releases an unused + // reservation. + Canceled bool `json:"canceled"` +} + +// Request id naming a cancellable registry search. +// Experimental: MCPRegistryRequestIDResult is part of an experimental API and may change or +// be removed. +type MCPRegistryRequestIDResult struct { + // Request ID for `mcp.registry.search` and `mcp.registry.cancel`. It serves one search. + // Allocation can reclaim unused IDs at the 1,024-ID reservation limit. + RequestID int64 `json:"requestId"` +} + +// Registry search terms, the credential to search under, and the request id that makes the +// search cancellable. +// Experimental: MCPRegistrySearchRequest is part of an experimental API and may change or +// be removed. +type MCPRegistrySearchRequest struct { + // The credential the search runs under, carried opaquely. Hosts usually send + // credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a + // token, while `env` and `gh-cli` identities can use a token embedded in the request first. + AuthInfo any `json:"authInfo"` + // Maximum number of servers to return. + Limit int64 `json:"limit"` + // Free-text query. Omitted or empty asks the registry for its top servers rather than + // searching. A value that is not a string is refused. + Query *string `json:"query,omitempty"` + // Repository used for the policy lookup, as `owner/name`. The policy selects the registry + // URL and whether the user token goes to the registry. The registry receives this + // repository only when the policy entry lists it as required context. A value that is not a + // string is refused. + Repository *string `json:"repository,omitempty"` + // Request ID from `mcp.registry.allocateRequestId`. The search refuses unknown, reclaimed, + // or canceled IDs and IDs that another search or request already uses. + RequestID int64 `json:"requestId"` +} + +// Servers selected from the registry response. +// Experimental: MCPRegistrySearchResult is part of an experimental API and may change or be +// removed. +type MCPRegistrySearchResult struct { + // The server objects, carried opaquely. The runtime follows pages, keeps the newest entry + // per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub + // stars. Each server object remains unchanged because the registry owns that shape. + Servers any `json:"servers"` +} + // In-process MCP reload configuration. // Experimental: MCPReloadConfig is part of an experimental API and may change or be removed. type MCPReloadConfig struct { @@ -9966,6 +10027,34 @@ type MCPSetEnvValueModeResult struct { Mode MCPSetEnvValueModeDetails `json:"mode"` } +// The session tool filters that decide whether the session still has a shell to run `gh` +// with. +// Experimental: MCPShouldExcludeGitHubToolsRequest is part of an experimental API and may +// change or be removed. +type MCPShouldExcludeGitHubToolsRequest struct { + // The session's tool allowlist, when it set one. Omitted means the session constrains + // nothing this way. + AvailableTools []string `json:"availableTools,omitzero"` + // The session's tool denylist, when it set one. Omitted means the session constrains + // nothing this way. + ExcludedTools []string `json:"excludedTools,omitzero"` + // How the allowlist and denylist combine when both are set. Omitted means the default every + // session gets, so a caller that never chose a precedence is answered as its sessions + // behave. + ToolFilterPrecedence *OptionsUpdateToolFilterPrecedence `json:"toolFilterPrecedence,omitempty"` +} + +// Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by +// the request. +// Experimental: MCPShouldExcludeGitHubToolsResult is part of an experimental API and may +// change or be removed. +type MCPShouldExcludeGitHubToolsResult struct { + // True only when both halves hold: the session's filters still reach the platform shell + // tool, and the host actually has the `gh` those tools would be replaced by. Feed it + // straight back as the `excludeGhReplaceableTools` build option. + ExcludeGhReplaceableTools bool `json:"excludeGhReplaceableTools"` +} + // Concrete configuration file containing an MCP server declaration. // Experimental: MCPSourceFile is part of an experimental API and may change or be removed. type MCPSourceFile struct { @@ -14771,6 +14860,29 @@ type SandboxCredentialsConfig struct { EnvVars map[string]SandboxMaskedEnvVar `json:"envVars"` } +// A possible secret-bearing environment variable and optional locally suggested HTTPS +// injection hosts. This is a draft for user review, not an active grant. +// Experimental: SandboxCredentialSuggestion is part of an experimental API and may change +// or be removed. +type SandboxCredentialSuggestion struct { + // Environment variable name. The secret value is never returned. + Name string `json:"name"` + // HTTPS hostnames suggested by a local known-provider mapping. An empty list requires the + // user to supply injection hosts before adding a masking entry. These suggestions do not + // allow network access. + SuggestedInjectHosts []string `json:"suggestedInjectHosts"` +} + +// Possible unconfigured secrets in the sandbox shell environment, sorted by variable name, +// with no secret values. +// Experimental: SandboxCredentialSuggestionsResult is part of an experimental API and may +// change or be removed. +type SandboxCredentialSuggestionsResult struct { + // Candidates for user review. Empty when sandboxing is disabled or no unconfigured + // candidates are present. + Suggestions []SandboxCredentialSuggestion `json:"suggestions"` +} + // Request to disable sandboxing for the current session while resolving an active // sandbox-bypass permission prompt. // Experimental: SandboxDisableForSessionRequest is part of an experimental API and may @@ -31257,12 +31369,12 @@ func (a *InternalServerGlobalStateAPI) LoadForConfigDir(ctx context.Context, par // asked a one-off question, or completed a migration, so the next run can skip it. Only the // named key is replaced and the rest of the document is preserved, which lets two writers // record different flags without overwriting each other; passing no value removes the key -// instead. Only the keys a host records itself are writable: `appInstallNudgeResponded`, -// `appTipShown`, `askedSetupTerminals`, `autoFeedbackLastPromptedAt`, `firstLaunchAt`, -// `recentModelIds`, `sandboxCredentialProxyCaDeclined` and `sandboxOnboardingShown`. Every -// other key is refused, including `installedPlugins`, the stored credentials, -// `trustedFolders`, the staff flags and the signed-in accounts. Plugin enablement must use -// the plugin APIs, which apply repository and managed-policy checks. +// instead. Only the keys a host records itself are writable: `appTipShown`, +// `askedSetupTerminals`, `autoFeedbackLastPromptedAt`, `firstLaunchAt`, `recentModelIds`, +// `sandboxCredentialProxyCaDeclined` and `sandboxOnboardingShown`. Every other key is +// refused, including `installedPlugins`, the stored credentials, `trustedFolders`, the +// staff flags and the signed-in accounts. Plugin enablement must use the plugin APIs, which +// apply repository and managed-policy checks. // // RPC method: globalState.writeKey. // @@ -31396,6 +31508,127 @@ func (a *InternalServerHostAPI) ReleaseSession(ctx context.Context, params *Host return &result, nil } +// Experimental: InternalServerMCPAPI contains experimental APIs that may change or be +// removed. +type InternalServerMCPAPI internalServerAPI + +// ShouldExcludeGitHubTools reports whether the gh-replaceable GitHub MCP tools may be +// clipped for a session, which a host feeds back as the `excludeGhReplaceableTools` build +// option. The tools are redundant only when the session can reach a shell *and* the host +// has the `gh` that would replace them, so both halves are decided here. The shell half +// runs the platform shell tool through the runtime's own tool-filter matcher, so entry +// forms like `builtin:bash` and `builtin:*` behave exactly as they do when a session builds +// its tool catalog. The host half probes for `gh`, and is skipped entirely when the filters +// already rule the shell out. Host presence alone is not enough: a session restricted to, +// say, `view` would otherwise lose the built-in issue-read fallback while having no shell +// to replace it with. The answer describes the host the runtime runs on, so it is never +// forwarded to a remote engine. +// +// RPC method: mcp.shouldExcludeGitHubTools. +// +// Parameters: The session tool filters that decide whether the session still has a shell to +// run `gh` with. +// +// Returns: Whether the gh-replaceable GitHub MCP tools may be clipped for the session +// described by the request. +// Internal: ShouldExcludeGitHubTools is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerMCPAPI) ShouldExcludeGitHubTools(ctx context.Context, params *MCPShouldExcludeGitHubToolsRequest) (*MCPShouldExcludeGitHubToolsResult, error) { + raw, err := a.client.Request(ctx, "mcp.shouldExcludeGitHubTools", params) + if err != nil { + return nil, err + } + var result MCPShouldExcludeGitHubToolsResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: InternalServerMCPRegistryAPI contains experimental APIs that may change or +// be removed. +type InternalServerMCPRegistryAPI internalServerAPI + +// AllocateRequestId allocates an ID for one cancellable MCP registry search. The ID exists +// before the search starts, so callers can cancel before it starts. The networking stack +// supplies the cancellation namespace. The runtime retains at most 1,024 unused IDs. At +// capacity, another allocation can reclaim an unused ID. Active searches retain their IDs +// until they finish. +// +// RPC method: mcp.registry.allocateRequestId. +// +// Returns: Request id naming a cancellable registry search. +// Internal: AllocateRequestId is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerMCPRegistryAPI) AllocateRequestId(ctx context.Context) (*MCPRegistryRequestIDResult, error) { + raw, err := a.client.Request(ctx, "mcp.registry.allocateRequestId", nil) + if err != nil { + return nil, err + } + var result MCPRegistryRequestIDResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Cancel abandons the registry search that uses the given request ID. It acts only on IDs +// from `mcp.registry.allocateRequestId`, so it never cancels another component's request. +// Answers `canceled: true` when it stops a running search. Answers `canceled: false` for +// unknown or reclaimed IDs, completed or canceled searches, and unused reservations. It +// releases an unused reservation, so a later search with that ID is refused. +// +// RPC method: mcp.registry.cancel. +// +// Parameters: Registry search to abandon. +// +// Returns: Whether the cancel reached a live search. +// Internal: Cancel is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerMCPRegistryAPI) Cancel(ctx context.Context, params *MCPRegistryCancelRequest) (*MCPRegistryCancelResult, error) { + raw, err := a.client.Request(ctx, "mcp.registry.cancel", params) + if err != nil { + return nil, err + } + var result MCPRegistryCancelResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Searches the MCP registry the supplied credential may read, resolving the registry +// endpoint from policy first. Hosts usually send credential-free `AuthIdentity`; a `token` +// identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities +// can use a token embedded in the request first. The runtime follows registry pages, keeps +// the newest entry per server name, cuts the list to `limit`, and sorts an empty-query +// result by GitHub stars. Each server object is carried opaquely. +// +// RPC method: mcp.registry.search. +// +// Parameters: Registry search terms, the credential to search under, and the request id +// that makes the search cancellable. +// +// Returns: Servers selected from the registry response. +// Internal: Search is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerMCPRegistryAPI) Search(ctx context.Context, params *MCPRegistrySearchRequest) (*MCPRegistrySearchResult, error) { + raw, err := a.client.Request(ctx, "mcp.registry.search", params) + if err != nil { + return nil, err + } + var result MCPRegistrySearchResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: Registry returns experimental APIs that may change or be removed. +func (s *InternalServerMCPAPI) Registry() *InternalServerMCPRegistryAPI { + return (*InternalServerMCPRegistryAPI)(s) +} + // Experimental: InternalServerSessionsAPI contains experimental APIs that may change or be // removed. type InternalServerSessionsAPI internalServerAPI @@ -31655,6 +31888,7 @@ type InternalServerRPC struct { GitHubRepository *InternalServerGitHubRepositoryAPI GlobalState *InternalServerGlobalStateAPI Host *InternalServerHostAPI + MCP *InternalServerMCPAPI Sessions *InternalServerSessionsAPI } @@ -31696,6 +31930,7 @@ func NewInternalServerRPC(client *jsonrpc2.Client) *InternalServerRPC { r.GitHubRepository = (*InternalServerGitHubRepositoryAPI)(&r.common) r.GlobalState = (*InternalServerGlobalStateAPI)(&r.common) r.Host = (*InternalServerHostAPI)(&r.common) + r.MCP = (*InternalServerMCPAPI)(&r.common) r.Sessions = (*InternalServerSessionsAPI)(&r.common) return r } @@ -37075,6 +37310,29 @@ func (a *SandboxAPI) DisableForSession(ctx context.Context, params *SandboxDisab return &result, nil } +// GetCredentialSuggestions lists possible secret-bearing environment variables available to +// new sandboxed shells that are not already covered by credential masking. Uses local name +// rules and known-provider host suggestions, never returns secret values, and changes no +// settings or network permissions. Returns no suggestions while the session is not +// sandboxed. +// +// RPC method: session.sandbox.getCredentialSuggestions. +// +// Returns: Possible unconfigured secrets in the sandbox shell environment, sorted by +// variable name, with no secret values. +func (a *SandboxAPI) GetCredentialSuggestions(ctx context.Context) (*SandboxCredentialSuggestionsResult, error) { + req := map[string]any{"sessionId": a.sessionID} + raw, err := a.client.Request(ctx, "session.sandbox.getCredentialSuggestions", req) + if err != nil { + return nil, err + } + var result SandboxCredentialSuggestionsResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // GetEnforcementStatus returns whether managed policy requires sandbox enforcement and // whether an enforcement failure has permanently blocked the session. // diff --git a/go/rpc/zsession_events.go b/go/rpc/zsession_events.go index 8ee7565f13..cef0367976 100644 --- a/go/rpc/zsession_events.go +++ b/go/rpc/zsession_events.go @@ -895,13 +895,13 @@ func (*MCPHeadersRefreshRequiredData) Type() SessionEventType { // Effective enterprise managed settings and contributing channels. Session events report applied policy; sessionless resolve reports an account/device snapshot, and compose reports a non-applying preview of candidate documents. Device values take precedence over server values, then the policy helper, per ordinary key, while permissions compose restrictively. Session-local SDK-client policy is included only in session results. Marked experimental while the managed-settings surface stabilizes. // Experimental: SessionManagedSettingsResolvedData is part of an experimental API and may change or be removed. type SessionManagedSettingsResolvedData struct { - // Whether enterprise policy disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers, and forced on when `failClosed` is true. + // Whether an explicit enterprise policy restriction disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers; an unresolved policy does not force this on by itself. BypassPermissionsDisabled bool `json:"bypassPermissionsDisabled"` // Whether a session-local permissions layer injected by the SDK host was present ClientManaged *bool `json:"clientManaged,omitempty"` // Whether an actual device MDM/plist/registry/file managed-settings layer was present DeviceManaged bool `json:"deviceManaged"` - // Whether managed policy could not be determined (e.g. a failed server fetch) and the session fell back to the fail-closed restriction. When true, restrictions such as disabling bypass-permissions are enforced even though `settings` may be absent. + // Whether managed policy could not be determined (e.g. a failed server fetch) and unresolved-policy safeguards remain active. This does not by itself disable bypass-permissions; `bypassPermissionsDisabled` reports only an explicit policy restriction. FailClosed bool `json:"failClosed"` // The setting keys under enterprise management in the effective managed settings (e.g. `model`, `enabledPlugins`, `permissions`). Empty when no managed settings are in force. ManagedKeys []string `json:"managedKeys"` diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionManagedSettingsResolvedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionManagedSettingsResolvedEvent.java index b80820d47a..007e911ef8 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionManagedSettingsResolvedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionManagedSettingsResolvedEvent.java @@ -52,11 +52,11 @@ public record SessionManagedSettingsResolvedEventData( @JsonProperty("clientManaged") Boolean clientManaged, /** Whether the policy-helper managed-settings layer was present. The policy helper is the weakest channel: it fills keys no enterprise source set and can never replace one. */ @JsonProperty("policyHelperManaged") Boolean policyHelperManaged, - /** Whether managed policy could not be determined (e.g. a failed server fetch) and the session fell back to the fail-closed restriction. When true, restrictions such as disabling bypass-permissions are enforced even though `settings` may be absent. */ + /** Whether managed policy could not be determined (e.g. a failed server fetch) and unresolved-policy safeguards remain active. This does not by itself disable bypass-permissions; `bypassPermissionsDisabled` reports only an explicit policy restriction. */ @JsonProperty("failClosed") Boolean failClosed, /** Whether the effective sandbox policy forces the sandbox on *only* because managed policy could not be determined, rather than because the policy requires it. Lets clients tell a user whose `--no-sandbox` was overridden that the sandbox stayed on as a fail-closed fallback, instead of attributing it to an administrator who set no such policy. */ @JsonProperty("sandboxEnabledByUndeterminedPolicy") Boolean sandboxEnabledByUndeterminedPolicy, - /** Whether enterprise policy disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers, and forced on when `failClosed` is true. */ + /** Whether an explicit enterprise policy restriction disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers; an unresolved policy does not force this on by itself. */ @JsonProperty("bypassPermissionsDisabled") Boolean bypassPermissionsDisabled, /** Whether at least two managed sources supplied permission allowlists, so enforcement intersects them and the flattened settings payload omits `permissions.allow`. */ @JsonProperty("permissionsAllowIntersected") Boolean permissionsAllowIntersected, diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GlobalStateLoadResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GlobalStateLoadResult.java index 0b6dbb9d53..9db799b57e 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GlobalStateLoadResult.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GlobalStateLoadResult.java @@ -58,8 +58,6 @@ record GlobalStateLoadResult( @JsonProperty("staffUpdateChannelMigrationAt") String staffUpdateChannelMigrationAt, /** Folders the user has marked as trusted. */ @JsonProperty("trustedFolders") List trustedFolders, - /** Whether the user has answered the prompt suggesting they install the desktop app. */ - @JsonProperty("appInstallNudgeResponded") Boolean appInstallNudgeResponded, /** When the Auto-feedback hint was last shown, as an ISO 8601 timestamp. It enforces the once-per-day cap for non-staff users across restarts. */ @JsonProperty("autoFeedbackLastPromptedAt") String autoFeedbackLastPromptedAt ) { diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolvedData.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolvedData.java index 35e11c4ad9..aaef086d58 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolvedData.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolvedData.java @@ -39,11 +39,11 @@ public record ManagedSettingsResolvedData( @JsonProperty("clientManaged") Boolean clientManaged, /** Whether the policy-helper managed-settings layer was present. The policy helper is the weakest channel: it fills keys no enterprise source set and can never replace one. */ @JsonProperty("policyHelperManaged") Boolean policyHelperManaged, - /** Whether managed policy could not be determined (e.g. a failed server fetch) and the session fell back to the fail-closed restriction. When true, restrictions such as disabling bypass-permissions are enforced even though `settings` may be absent. */ + /** Whether managed policy could not be determined (e.g. a failed server fetch) and unresolved-policy safeguards remain active. This does not by itself disable bypass-permissions; `bypassPermissionsDisabled` reports only an explicit policy restriction. */ @JsonProperty("failClosed") Boolean failClosed, /** Whether the effective sandbox policy forces the sandbox on *only* because managed policy could not be determined, rather than because the policy requires it. Lets clients tell a user whose `--no-sandbox` was overridden that the sandbox stayed on as a fail-closed fallback, instead of attributing it to an administrator who set no such policy. */ @JsonProperty("sandboxEnabledByUndeterminedPolicy") Boolean sandboxEnabledByUndeterminedPolicy, - /** Whether enterprise policy disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers, and forced on when `failClosed` is true. */ + /** Whether an explicit enterprise policy restriction disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers; an unresolved policy does not force this on by itself. */ @JsonProperty("bypassPermissionsDisabled") Boolean bypassPermissionsDisabled, /** Whether at least two managed sources supplied permission allowlists, so enforcement intersects them and the flattened settings payload omits `permissions.allow`. */ @JsonProperty("permissionsAllowIntersected") Boolean permissionsAllowIntersected, diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistryCancelParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistryCancelParams.java new file mode 100644 index 0000000000..0a12a5c26b --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistryCancelParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Registry search to abandon. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record McpRegistryCancelParams( + /** Request ID from `mcp.registry.allocateRequestId` that the search uses. */ + @JsonProperty("requestId") Long requestId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistryCancelResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistryCancelResult.java new file mode 100644 index 0000000000..c7f581f4cc --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistryCancelResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Whether the cancel reached a live search. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record McpRegistryCancelResult( + /** True when the cancel stopped a running search. False for unknown or reclaimed IDs, completed or canceled searches, and unused reservations. The cancel releases an unused reservation. */ + @JsonProperty("canceled") Boolean canceled +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistryRequestIdResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistryRequestIdResult.java new file mode 100644 index 0000000000..53234b3598 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistryRequestIdResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Request id naming a cancellable registry search. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record McpRegistryRequestIdResult( + /** Request ID for `mcp.registry.search` and `mcp.registry.cancel`. It serves one search. Allocation can reclaim unused IDs at the 1,024-ID reservation limit. */ + @JsonProperty("requestId") Long requestId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistrySearchParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistrySearchParams.java new file mode 100644 index 0000000000..e222f69adc --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistrySearchParams.java @@ -0,0 +1,38 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Registry search terms, the credential to search under, and the request id that makes the search cancellable. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record McpRegistrySearchParams( + /** Request ID from `mcp.registry.allocateRequestId`. The search refuses unknown, reclaimed, or canceled IDs and IDs that another search or request already uses. */ + @JsonProperty("requestId") Long requestId, + /** The credential the search runs under, carried opaquely. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. */ + @JsonProperty("authInfo") Object authInfo, + /** Free-text query. Omitted or empty asks the registry for its top servers rather than searching. A value that is not a string is refused. */ + @JsonProperty("query") String query, + /** Repository used for the policy lookup, as `owner/name`. The policy selects the registry URL and whether the user token goes to the registry. The registry receives this repository only when the policy entry lists it as required context. A value that is not a string is refused. */ + @JsonProperty("repository") String repository, + /** Maximum number of servers to return. */ + @JsonProperty("limit") Long limit +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistrySearchResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistrySearchResult.java new file mode 100644 index 0000000000..2682402d76 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistrySearchResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Servers selected from the registry response. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record McpRegistrySearchResult( + /** The server objects, carried opaquely. The runtime follows pages, keeps the newest entry per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub stars. Each server object remains unchanged because the registry owns that shape. */ + @JsonProperty("servers") Object servers +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpShouldExcludeGitHubToolsParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpShouldExcludeGitHubToolsParams.java new file mode 100644 index 0000000000..bb435663bf --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpShouldExcludeGitHubToolsParams.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The session tool filters that decide whether the session still has a shell to run `gh` with. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record McpShouldExcludeGitHubToolsParams( + /** The session's tool allowlist, when it set one. Omitted means the session constrains nothing this way. */ + @JsonProperty("availableTools") List availableTools, + /** The session's tool denylist, when it set one. Omitted means the session constrains nothing this way. */ + @JsonProperty("excludedTools") List excludedTools, + /** How the allowlist and denylist combine when both are set. Omitted means the default every session gets, so a caller that never chose a precedence is answered as its sessions behave. */ + @JsonProperty("toolFilterPrecedence") OptionsUpdateToolFilterPrecedence toolFilterPrecedence +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpShouldExcludeGitHubToolsResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpShouldExcludeGitHubToolsResult.java new file mode 100644 index 0000000000..05f92ab309 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpShouldExcludeGitHubToolsResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by the request. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record McpShouldExcludeGitHubToolsResult( + /** True only when both halves hold: the session's filters still reach the platform shell tool, and the host actually has the `gh` those tools would be replaced by. Feed it straight back as the `excludeGhReplaceableTools` build option. */ + @JsonProperty("excludeGhReplaceableTools") Boolean excludeGhReplaceableTools +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxCredentialSuggestion.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxCredentialSuggestion.java new file mode 100644 index 0000000000..927dcdf5e9 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxCredentialSuggestion.java @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * A possible secret-bearing environment variable and optional locally suggested HTTPS injection hosts. This is a draft for user review, not an active grant. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SandboxCredentialSuggestion( + /** Environment variable name. The secret value is never returned. */ + @JsonProperty("name") String name, + /** HTTPS hostnames suggested by a local known-provider mapping. An empty list requires the user to supply injection hosts before adding a masking entry. These suggestions do not allow network access. */ + @JsonProperty("suggestedInjectHosts") List suggestedInjectHosts +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerGlobalStateApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerGlobalStateApi.java index 3c215395b8..2d41182ae0 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerGlobalStateApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerGlobalStateApi.java @@ -49,7 +49,7 @@ CompletableFuture loadForConfigDir(GlobalStateLoadForConf } /** - * Records one top-level key in the host's machine-wide state, the counterpart to `globalState.load`. A host calls this to remember that it has shown an onboarding step, asked a one-off question, or completed a migration, so the next run can skip it. Only the named key is replaced and the rest of the document is preserved, which lets two writers record different flags without overwriting each other; passing no value removes the key instead. Only the keys a host records itself are writable: `appInstallNudgeResponded`, `appTipShown`, `askedSetupTerminals`, `autoFeedbackLastPromptedAt`, `firstLaunchAt`, `recentModelIds`, `sandboxCredentialProxyCaDeclined` and `sandboxOnboardingShown`. Every other key is refused, including `installedPlugins`, the stored credentials, `trustedFolders`, the staff flags and the signed-in accounts. Plugin enablement must use the plugin APIs, which apply repository and managed-policy checks. + * Records one top-level key in the host's machine-wide state, the counterpart to `globalState.load`. A host calls this to remember that it has shown an onboarding step, asked a one-off question, or completed a migration, so the next run can skip it. Only the named key is replaced and the rest of the document is preserved, which lets two writers record different flags without overwriting each other; passing no value removes the key instead. Only the keys a host records itself are writable: `appTipShown`, `askedSetupTerminals`, `autoFeedbackLastPromptedAt`, `firstLaunchAt`, `recentModelIds`, `sandboxCredentialProxyCaDeclined` and `sandboxOnboardingShown`. Every other key is refused, including `installedPlugins`, the stored credentials, `trustedFolders`, the staff flags and the signed-in accounts. Plugin enablement must use the plugin APIs, which apply repository and managed-policy checks. * * @apiNote This method is experimental and may change in a future version. * @since 1.0.0 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpApi.java index 553a644214..05e517d864 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpApi.java @@ -24,6 +24,8 @@ public final class ServerMcpApi { /** API methods for the {@code mcp.config} sub-namespace. */ public final ServerMcpConfigApi config; + /** API methods for the {@code mcp.registry} sub-namespace. */ + final ServerMcpRegistryApi registry; /** API methods for the {@code mcp.installations} sub-namespace. */ public final ServerMcpInstallationsApi installations; @@ -31,6 +33,7 @@ public final class ServerMcpApi { ServerMcpApi(RpcCaller caller) { this.caller = caller; this.config = new ServerMcpConfigApi(caller); + this.registry = new ServerMcpRegistryApi(caller); this.installations = new ServerMcpInstallationsApi(caller); } @@ -45,6 +48,17 @@ public CompletableFuture discover(McpDiscoverParams params) { return caller.invoke("mcp.discover", params, McpDiscoverResult.class); } + /** + * Reports whether the gh-replaceable GitHub MCP tools may be clipped for a session, which a host feeds back as the `excludeGhReplaceableTools` build option. The tools are redundant only when the session can reach a shell *and* the host has the `gh` that would replace them, so both halves are decided here. The shell half runs the platform shell tool through the runtime's own tool-filter matcher, so entry forms like `builtin:bash` and `builtin:*` behave exactly as they do when a session builds its tool catalog. The host half probes for `gh`, and is skipped entirely when the filters already rule the shell out. Host presence alone is not enough: a session restricted to, say, `view` would otherwise lose the built-in issue-read fallback while having no shell to replace it with. The answer describes the host the runtime runs on, so it is never forwarded to a remote engine. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture shouldExcludeGitHubTools(McpShouldExcludeGitHubToolsParams params) { + return caller.invoke("mcp.shouldExcludeGitHubTools", params, McpShouldExcludeGitHubToolsResult.class); + } + /** * Requests a side-effect-free MCP install plan from a catalog candidate handle or a caller-supplied card. This host-implemented server method is available through SDK/TUI hosts; standalone and C-ABI runtimes whose host does not implement server-method dispatch return JSON-RPC MethodNotFound. A runtime with planning available returns a normalised plan and opaque single-use plan handle; a runtime without it returns the typed planning-unavailable result. A completed plan reports resource identity, provenance, eligible transport choices, the user-scope target, required typed values and secret placeholders, the policy result, the configuration changes installing would make, and whether a reload would be needed. Planning never writes configuration, stores a secret, or reloads MCP servers, so abandoning a plan needs no call and leaves nothing behind. * diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpRegistryApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpRegistryApi.java new file mode 100644 index 0000000000..26b7b2cc7f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpRegistryApi.java @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code mcp.registry} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerMcpRegistryApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerMcpRegistryApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Allocates an ID for one cancellable MCP registry search. The ID exists before the search starts, so callers can cancel before it starts. The networking stack supplies the cancellation namespace. The runtime retains at most 1,024 unused IDs. At capacity, another allocation can reclaim an unused ID. Active searches retain their IDs until they finish. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture allocateRequestId() { + return caller.invoke("mcp.registry.allocateRequestId", java.util.Map.of(), McpRegistryRequestIdResult.class); + } + + /** + * Searches the MCP registry the supplied credential may read, resolving the registry endpoint from policy first. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. The runtime follows registry pages, keeps the newest entry per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub stars. Each server object is carried opaquely. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture search(McpRegistrySearchParams params) { + return caller.invoke("mcp.registry.search", params, McpRegistrySearchResult.class); + } + + /** + * Abandons the registry search that uses the given request ID. It acts only on IDs from `mcp.registry.allocateRequestId`, so it never cancels another component's request. Answers `canceled: true` when it stops a running search. Answers `canceled: false` for unknown or reclaimed IDs, completed or canceled searches, and unused reservations. It releases an unused reservation, so a later search with that ID is refused. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture cancel(McpRegistryCancelParams params) { + return caller.invoke("mcp.registry.cancel", params, McpRegistryCancelResult.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionManagedSettingsGetResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionManagedSettingsGetResult.java index a20c0c6200..cdd674ab24 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionManagedSettingsGetResult.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionManagedSettingsGetResult.java @@ -38,11 +38,11 @@ public record SessionManagedSettingsGetResult( @JsonProperty("clientManaged") Boolean clientManaged, /** Whether the policy-helper managed-settings layer was present. The policy helper is the weakest channel: it fills keys no enterprise source set and can never replace one. */ @JsonProperty("policyHelperManaged") Boolean policyHelperManaged, - /** Whether managed policy could not be determined (e.g. a failed server fetch) and the session fell back to the fail-closed restriction. When true, restrictions such as disabling bypass-permissions are enforced even though `settings` may be absent. */ + /** Whether managed policy could not be determined (e.g. a failed server fetch) and unresolved-policy safeguards remain active. This does not by itself disable bypass-permissions; `bypassPermissionsDisabled` reports only an explicit policy restriction. */ @JsonProperty("failClosed") Boolean failClosed, /** Whether the effective sandbox policy forces the sandbox on *only* because managed policy could not be determined, rather than because the policy requires it. Lets clients tell a user whose `--no-sandbox` was overridden that the sandbox stayed on as a fail-closed fallback, instead of attributing it to an administrator who set no such policy. */ @JsonProperty("sandboxEnabledByUndeterminedPolicy") Boolean sandboxEnabledByUndeterminedPolicy, - /** Whether enterprise policy disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers, and forced on when `failClosed` is true. */ + /** Whether an explicit enterprise policy restriction disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers; an unresolved policy does not force this on by itself. */ @JsonProperty("bypassPermissionsDisabled") Boolean bypassPermissionsDisabled, /** Whether at least two managed sources supplied permission allowlists, so enforcement intersects them and the flattened settings payload omits `permissions.allow`. */ @JsonProperty("permissionsAllowIntersected") Boolean permissionsAllowIntersected, diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSandboxApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSandboxApi.java index 2ace81bb8e..b780e59b38 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSandboxApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSandboxApi.java @@ -41,6 +41,17 @@ public CompletableFuture getEnforcemen return caller.invoke("session.sandbox.getEnforcementStatus", java.util.Map.of("sessionId", this.sessionId), SessionSandboxGetEnforcementStatusResult.class); } + /** + * Lists possible secret-bearing environment variables available to new sandboxed shells that are not already covered by credential masking. Uses local name rules and known-provider host suggestions, never returns secret values, and changes no settings or network permissions. Returns no suggestions while the session is not sandboxed. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture getCredentialSuggestions() { + return caller.invoke("session.sandbox.getCredentialSuggestions", java.util.Map.of("sessionId", this.sessionId), SessionSandboxGetCredentialSuggestionsResult.class); + } + /** * Disables sandboxing for the remainder of the current session and approves the referenced pending sandbox-bypass permission request. The request is rejected unless the exact request is still pending and the effective sandbox policy permits bypass. *

diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSandboxGetCredentialSuggestionsParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSandboxGetCredentialSuggestionsParams.java new file mode 100644 index 0000000000..c587908619 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSandboxGetCredentialSuggestionsParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Identifies the target session. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionSandboxGetCredentialSuggestionsParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSandboxGetCredentialSuggestionsResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSandboxGetCredentialSuggestionsResult.java new file mode 100644 index 0000000000..2f883728f1 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionSandboxGetCredentialSuggestionsResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Possible unconfigured secrets in the sandbox shell environment, sorted by variable name, with no secret values. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionSandboxGetCredentialSuggestionsResult( + /** Candidates for user review. Empty when sandboxing is disabled or no unconfigured candidates are present. */ + @JsonProperty("suggestions") List suggestions +) { +} diff --git a/nodejs/package.json b/nodejs/package.json index e869d2b304..a0d1e8e5dd 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -5,7 +5,7 @@ "url": "https://github.com/github/copilot-sdk.git" }, "version": "0.0.0-dev", - "copilotCliVersion": "1.0.96-0", + "copilotCliVersion": "1.0.96-1", "description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC", "main": "./dist/cjs/index.js", "types": "./dist/index.d.ts", diff --git a/nodejs/src/cliVersion.ts b/nodejs/src/cliVersion.ts index 3c1f791005..196f9326fb 100644 --- a/nodejs/src/cliVersion.ts +++ b/nodejs/src/cliVersion.ts @@ -1,3 +1,3 @@ -export const COPILOT_CLI_VERSION = "1.0.96-0"; +export const COPILOT_CLI_VERSION = "1.0.96-1"; export const COPILOT_CLI_USE_NPM_PACKAGE = false; diff --git a/nodejs/src/generated/rpc.ts b/nodejs/src/generated/rpc.ts index f4fbe69cfd..68d1021d1f 100644 --- a/nodejs/src/generated/rpc.ts +++ b/nodejs/src/generated/rpc.ts @@ -3596,6 +3596,18 @@ export type McpSetEnvValueModeDetails = | "direct" /** Treat MCP server environment values as host-side references to resolve before launch. */ | "indirect"; +/** + * Controls how availableTools (allowlist) and excludedTools (denylist) combine when both are set. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "OptionsUpdateToolFilterPrecedence". + */ +/** @experimental */ +export type OptionsUpdateToolFilterPrecedence = + /** If availableTools is set, it is the only constraint that applies (excludedTools is ignored). Preserves CLI / pre-existing client behavior. Default. */ + | "available" + /** A tool is enabled if and only if it matches the allowlist (or the allowlist is unset) AND it does not match the denylist. Makes 'all except X' expressible by combining the two lists. */ + | "excluded"; /** * Per-source context-window attribution, or null if the session has not yet been initialized (no system prompt or tool metadata cached). * @@ -4107,18 +4119,6 @@ export type OptionsUpdateReasoningSummary = | "concise" /** Request a detailed summary of model reasoning. */ | "detailed"; -/** - * Controls how availableTools (allowlist) and excludedTools (denylist) combine when both are set. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "OptionsUpdateToolFilterPrecedence". - */ -/** @experimental */ -export type OptionsUpdateToolFilterPrecedence = - /** If availableTools is set, it is the only constraint that applies (excludedTools is ignored). Preserves CLI / pre-existing client behavior. Default. */ - | "available" - /** A tool is enabled if and only if it matches the allowlist (or the allowlist is unset) AND it does not match the denylist. Makes 'all except X' expressible by combining the two lists. */ - | "excluded"; /** * The client's response to the pending permission prompt * @@ -12576,10 +12576,6 @@ export interface GlobalStateLoadResult { * Folders the user has marked as trusted. */ trustedFolders?: string[]; - /** - * Whether the user has answered the prompt suggesting they install the desktop app. - */ - appInstallNudgeResponded?: boolean; /** * When the Auto-feedback hint was last shown, as an ISO 8601 timestamp. It enforces the once-per-day cap for non-staff users across restarts. */ @@ -17090,6 +17086,92 @@ export interface McpRegisterExternalClientRequest { */ config: OpaqueInProcessValue; } +/** + * Registry search to abandon. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpRegistryCancelRequest". + */ +/** @experimental */ +/** @internal */ +export interface McpRegistryCancelRequest { + /** + * Request ID from `mcp.registry.allocateRequestId` that the search uses. + */ + requestId: number; +} +/** + * Whether the cancel reached a live search. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpRegistryCancelResult". + */ +/** @experimental */ +/** @internal */ +export interface McpRegistryCancelResult { + /** + * True when the cancel stopped a running search. False for unknown or reclaimed IDs, completed or canceled searches, and unused reservations. The cancel releases an unused reservation. + */ + canceled: boolean; +} +/** + * Request id naming a cancellable registry search. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpRegistryRequestIdResult". + */ +/** @experimental */ +/** @internal */ +export interface McpRegistryRequestIdResult { + /** + * Request ID for `mcp.registry.search` and `mcp.registry.cancel`. It serves one search. Allocation can reclaim unused IDs at the 1,024-ID reservation limit. + */ + requestId: number; +} +/** + * Registry search terms, the credential to search under, and the request id that makes the search cancellable. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpRegistrySearchRequest". + */ +/** @experimental */ +/** @internal */ +export interface McpRegistrySearchRequest { + /** + * Request ID from `mcp.registry.allocateRequestId`. The search refuses unknown, reclaimed, or canceled IDs and IDs that another search or request already uses. + */ + requestId: number; + /** + * The credential the search runs under, carried opaquely. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. + */ + authInfo: JsonValue; + /** + * Free-text query. Omitted or empty asks the registry for its top servers rather than searching. A value that is not a string is refused. + */ + query?: string; + /** + * Repository used for the policy lookup, as `owner/name`. The policy selects the registry URL and whether the user token goes to the registry. The registry receives this repository only when the policy entry lists it as required context. A value that is not a string is refused. + */ + repository?: string; + /** + * Maximum number of servers to return. + */ + limit: number; +} +/** + * Servers selected from the registry response. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpRegistrySearchResult". + */ +/** @experimental */ +/** @internal */ +export interface McpRegistrySearchResult { + /** + * The server objects, carried opaquely. The runtime follows pages, keeps the newest entry per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub stars. Each server object remains unchanged because the registry owns that shape. + */ + servers: JsonValue; +} /** * In-process MCP reload configuration. * @@ -17624,6 +17706,42 @@ export interface McpSetEnvValueModeParams { export interface McpSetEnvValueModeResult { mode: McpSetEnvValueModeDetails; } +/** + * The session tool filters that decide whether the session still has a shell to run `gh` with. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpShouldExcludeGitHubToolsRequest". + */ +/** @experimental */ +/** @internal */ +export interface McpShouldExcludeGitHubToolsRequest { + /** + * The session's tool allowlist, when it set one. Omitted means the session constrains nothing this way. + */ + availableTools?: string[]; + /** + * The session's tool denylist, when it set one. Omitted means the session constrains nothing this way. + */ + excludedTools?: string[]; + /** + * How the allowlist and denylist combine when both are set. Omitted means the default every session gets, so a caller that never chose a precedence is answered as its sessions behave. + */ + toolFilterPrecedence?: OptionsUpdateToolFilterPrecedence | null; +} +/** + * Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by the request. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpShouldExcludeGitHubToolsResult". + */ +/** @experimental */ +/** @internal */ +export interface McpShouldExcludeGitHubToolsResult { + /** + * True only when both halves hold: the session's filters still reach the platform shell tool, and the host actually has the `gh` those tools would be replaced by. Feed it straight back as the `excludeGhReplaceableTools` build option. + */ + excludeGhReplaceableTools: boolean; +} /** * Server name and optional configuration for an individual MCP server start. Omit `config` for a config-free start-by-name of an already-configured server. * @@ -23196,6 +23314,36 @@ export interface SandboxMaskedEnvVar { */ injectHosts: string[]; } +/** + * A possible secret-bearing environment variable and optional locally suggested HTTPS injection hosts. This is a draft for user review, not an active grant. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SandboxCredentialSuggestion". + */ +/** @experimental */ +export interface SandboxCredentialSuggestion { + /** + * Environment variable name. The secret value is never returned. + */ + name: string; + /** + * HTTPS hostnames suggested by a local known-provider mapping. An empty list requires the user to supply injection hosts before adding a masking entry. These suggestions do not allow network access. + */ + suggestedInjectHosts: string[]; +} +/** + * Possible unconfigured secrets in the sandbox shell environment, sorted by variable name, with no secret values. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SandboxCredentialSuggestionsResult". + */ +/** @experimental */ +export interface SandboxCredentialSuggestionsResult { + /** + * Candidates for user review. Empty when sandboxing is disabled or no unconfigured candidates are present. + */ + suggestions: SandboxCredentialSuggestion[]; +} /** * Request to disable sandboxing for the current session while resolving an active sandbox-bypass permission prompt. * @@ -33275,6 +33423,46 @@ export function createInternalServerRpc(connection: MessageConnection) { connect: async (params: ConnectRequest): Promise => connection.sendRequest("connect", params), /** @experimental */ + mcp: { + /** @experimental */ + registry: { + /** + * Allocates an ID for one cancellable MCP registry search. The ID exists before the search starts, so callers can cancel before it starts. The networking stack supplies the cancellation namespace. The runtime retains at most 1,024 unused IDs. At capacity, another allocation can reclaim an unused ID. Active searches retain their IDs until they finish. + * + * @returns Request id naming a cancellable registry search. + */ + allocateRequestId: async (): Promise => + connection.sendRequest("mcp.registry.allocateRequestId", {}), + /** + * Searches the MCP registry the supplied credential may read, resolving the registry endpoint from policy first. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. The runtime follows registry pages, keeps the newest entry per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub stars. Each server object is carried opaquely. + * + * @param params Registry search terms, the credential to search under, and the request id that makes the search cancellable. + * + * @returns Servers selected from the registry response. + */ + search: async (params: McpRegistrySearchRequest): Promise => + connection.sendRequest("mcp.registry.search", params), + /** + * Abandons the registry search that uses the given request ID. It acts only on IDs from `mcp.registry.allocateRequestId`, so it never cancels another component's request. Answers `canceled: true` when it stops a running search. Answers `canceled: false` for unknown or reclaimed IDs, completed or canceled searches, and unused reservations. It releases an unused reservation, so a later search with that ID is refused. + * + * @param params Registry search to abandon. + * + * @returns Whether the cancel reached a live search. + */ + cancel: async (params: McpRegistryCancelRequest): Promise => + connection.sendRequest("mcp.registry.cancel", params), + }, + /** + * Reports whether the gh-replaceable GitHub MCP tools may be clipped for a session, which a host feeds back as the `excludeGhReplaceableTools` build option. The tools are redundant only when the session can reach a shell *and* the host has the `gh` that would replace them, so both halves are decided here. The shell half runs the platform shell tool through the runtime's own tool-filter matcher, so entry forms like `builtin:bash` and `builtin:*` behave exactly as they do when a session builds its tool catalog. The host half probes for `gh`, and is skipped entirely when the filters already rule the shell out. Host presence alone is not enough: a session restricted to, say, `view` would otherwise lose the built-in issue-read fallback while having no shell to replace it with. The answer describes the host the runtime runs on, so it is never forwarded to a remote engine. + * + * @param params The session tool filters that decide whether the session still has a shell to run `gh` with. + * + * @returns Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by the request. + */ + shouldExcludeGitHubTools: async (params: McpShouldExcludeGitHubToolsRequest): Promise => + connection.sendRequest("mcp.shouldExcludeGitHubTools", params), + }, + /** @experimental */ agents: { /** * Lists the agents this runtime ships, by name. A consumer separating shipped agents from ones the user or a plugin authored should compare against these names rather than against `AgentInfo.source`: an authored agent may carry the `builtin` source while not being one of these, and the runtime treats the two as separate questions. `disableableNames` is the subset a user may turn off, which a client needs to decide whether to offer a toggle. `yamlBasedNames` is the subset backed by a shipped YAML definition, which a client needs before asking the runtime to load one. @@ -33339,7 +33527,7 @@ export function createInternalServerRpc(connection: MessageConnection) { loadForConfigDir: async (params: GlobalStateLoadForConfigDirRequest): Promise => connection.sendRequest("globalState.loadForConfigDir", params), /** - * Records one top-level key in the host's machine-wide state, the counterpart to `globalState.load`. A host calls this to remember that it has shown an onboarding step, asked a one-off question, or completed a migration, so the next run can skip it. Only the named key is replaced and the rest of the document is preserved, which lets two writers record different flags without overwriting each other; passing no value removes the key instead. Only the keys a host records itself are writable: `appInstallNudgeResponded`, `appTipShown`, `askedSetupTerminals`, `autoFeedbackLastPromptedAt`, `firstLaunchAt`, `recentModelIds`, `sandboxCredentialProxyCaDeclined` and `sandboxOnboardingShown`. Every other key is refused, including `installedPlugins`, the stored credentials, `trustedFolders`, the staff flags and the signed-in accounts. Plugin enablement must use the plugin APIs, which apply repository and managed-policy checks. + * Records one top-level key in the host's machine-wide state, the counterpart to `globalState.load`. A host calls this to remember that it has shown an onboarding step, asked a one-off question, or completed a migration, so the next run can skip it. Only the named key is replaced and the rest of the document is preserved, which lets two writers record different flags without overwriting each other; passing no value removes the key instead. Only the keys a host records itself are writable: `appTipShown`, `askedSetupTerminals`, `autoFeedbackLastPromptedAt`, `firstLaunchAt`, `recentModelIds`, `sandboxCredentialProxyCaDeclined` and `sandboxOnboardingShown`. Every other key is refused, including `installedPlugins`, the stored credentials, `trustedFolders`, the staff flags and the signed-in accounts. Plugin enablement must use the plugin APIs, which apply repository and managed-policy checks. * * @param params A single top-level key to record in the host's machine-wide state. The write replaces only that key and leaves the rest of the document untouched, so two writers recording different one-off flags do not overwrite each other. The stored credential keys cannot be written through this method. */ @@ -33598,6 +33786,13 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin */ getEnforcementStatus: async (): Promise => connection.sendRequest("session.sandbox.getEnforcementStatus", { sessionId }), + /** + * Lists possible secret-bearing environment variables available to new sandboxed shells that are not already covered by credential masking. Uses local name rules and known-provider host suggestions, never returns secret values, and changes no settings or network permissions. Returns no suggestions while the session is not sandboxed. + * + * @returns Possible unconfigured secrets in the sandbox shell environment, sorted by variable name, with no secret values. + */ + getCredentialSuggestions: async (): Promise => + connection.sendRequest("session.sandbox.getCredentialSuggestions", { sessionId }), /** * Disables sandboxing for the remainder of the current session and approves the referenced pending sandbox-bypass permission request. The request is rejected unless the exact request is still pending and the effective sandbox policy permits bypass. * diff --git a/nodejs/src/generated/session-events.ts b/nodejs/src/generated/session-events.ts index 77f15629ee..3b15ae7d4f 100644 --- a/nodejs/src/generated/session-events.ts +++ b/nodejs/src/generated/session-events.ts @@ -12923,7 +12923,7 @@ export interface ManagedSettingsResolvedEvent { /** @experimental */ export interface ManagedSettingsResolvedData { /** - * Whether enterprise policy disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers, and forced on when `failClosed` is true. + * Whether an explicit enterprise policy restriction disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers; an unresolved policy does not force this on by itself. */ bypassPermissionsDisabled: boolean; /** @@ -12935,7 +12935,7 @@ export interface ManagedSettingsResolvedData { */ deviceManaged: boolean; /** - * Whether managed policy could not be determined (e.g. a failed server fetch) and the session fell back to the fail-closed restriction. When true, restrictions such as disabling bypass-permissions are enforced even though `settings` may be absent. + * Whether managed policy could not be determined (e.g. a failed server fetch) and unresolved-policy safeguards remain active. This does not by itself disable bypass-permissions; `bypassPermissionsDisabled` reports only an explicit policy restriction. */ failClosed: boolean; /** diff --git a/nodejs/test/e2e/auto_fusion_routing.e2e.test.ts b/nodejs/test/e2e/auto_fusion_routing.e2e.test.ts new file mode 100644 index 0000000000..798b450028 --- /dev/null +++ b/nodejs/test/e2e/auto_fusion_routing.e2e.test.ts @@ -0,0 +1,904 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import { beforeEach, describe, expect, it, onTestFailed } from "vitest"; +import { approveAll, CopilotRequestHandler, type SessionEvent } from "../../src/index.js"; +import { createSdkTestContext, DEFAULT_GITHUB_TOKEN } from "./harness/sdkTestContext.js"; +import { isByokBackend } from "./harness/testBackend.js"; + +const MODEL = "gpt-5.6-sol"; +const REPLY = "AUTO_FUSION_EXECUTION_DONE"; + +class AutoFusionRequestHandler extends CopilotRequestHandler { + readonly plans: Record[] = []; + readonly auto: Record[] = []; + readonly inference: Record[] = []; + failRoute = false; + disabled = false; + constituentsEnabled = true; + inferenceGate?: { + entered: ReturnType>; + release: ReturnType>; + }; + + constructor( + private readonly planVersion: "1" | "2", + private readonly executionModel = MODEL + ) { + super(); + } + + protected override async sendRequest(request: Request): Promise { + const path = new URL(request.url).pathname; + const models = { + data: [...new Set([MODEL, this.executionModel])].map((id) => ({ + id, + name: id, + model_picker_enabled: this.constituentsEnabled, + policy: { state: this.constituentsEnabled ? "enabled" : "disabled" }, + supported_endpoints: ["/chat/completions"], + capabilities: { + supports: { streaming: true, tool_calls: true, vision: true }, + limits: { + max_prompt_tokens: 128000, + max_output_tokens: 16384, + max_context_window_tokens: 144384, + }, + }, + })), + }; + if (path === "/models") return Response.json(models); + if (path === "/meta") { + return Response.json({ + models, + auto: { + default_tier: "Balance-V2", + tiers: [ + { + id: "Balance-V2", + display_name: "Balance", + description: "", + type: "auto", + status: { enabled: true }, + }, + { + id: "Other-V2", + display_name: "Ordinary Auto", + description: "", + type: "auto", + status: { enabled: !this.disabled, message: "Contact admin" }, + }, + ...["hydrafusion", "hydrafusion-max"].map((id) => ({ + id, + display_name: id, + description: "", + type: "fusion", + status: { enabled: !this.disabled, message: "Contact admin" }, + })), + { + id: "future-fusion", + display_name: "Future", + description: "", + type: "fusion", + status: { enabled: true }, + }, + { + id: "future-type", + display_name: "Unknown", + description: "", + type: "ensemble", + status: { enabled: true }, + }, + ], + }, + }); + } + if (path === "/model/fusion") { + const body = (await request.json()) as Record; + this.plans.push(body); + if (this.failRoute) + return Response.json({ message: "Route unavailable" }, { status: 500 }); + return Response.json({ + fusion_mode: body.fusion_mode, + fusion_pattern: "solo", + plan_version: this.planVersion, + steps: [{ role: "generation", model_id: this.executionModel }], + session: { token: "jwt.fake.auto.fusion.plan", expires_at: 0 }, + }); + } + if (path === "/auto") { + this.auto.push((await request.json()) as Record); + return Response.json({ + selected_model: models.data[0], + session_token: "jwt.fake.auto.fusion.reset", + expires_at: Math.floor(Date.now() / 1000) + 3600, + }); + } + if (path === "/chat/completions") { + const body = (await request.json()) as Record; + this.inference.push(body); + const gate = this.inferenceGate; + if (gate) { + gate.entered.resolve(); + await gate.release.promise; + } + if (body.model !== MODEL && body.model !== this.executionModel) + throw new Error(`Synthetic model escaped to inference: ${body.model}`); + const completion = { + id: "chatcmpl-auto-fusion", + object: "chat.completion", + created: 0, + model: body.model, + choices: [ + { + index: 0, + message: { role: "assistant", content: REPLY }, + finish_reason: "stop", + }, + ], + usage: { prompt_tokens: 11, completion_tokens: 7, total_tokens: 18 }, + }; + if (!body.stream) return Response.json(completion); + return new Response( + `data: ${JSON.stringify({ + ...completion, + object: "chat.completion.chunk", + choices: [ + { + index: 0, + delta: { role: "assistant", content: REPLY }, + finish_reason: "stop", + }, + ], + })}\n\ndata: [DONE]\n\n`, + { headers: { "content-type": "text/event-stream" } } + ); + } + throw new Error(`Unexpected routing request: ${request.method} ${path}`); + } +} + +describe.skipIf(isByokBackend).each([ + { mode: "hydrafusion", version: "1" as const }, + { mode: "hydrafusion", version: "2" as const }, + { mode: "hydrafusion-max", version: "2" as const }, +])("Metadata Auto execution: $mode v$version", async ({ mode, version }) => { + const executionModel = mode === "hydrafusion" ? "claude-sonnet-5" : MODEL; + const handler = new AutoFusionRequestHandler(version, executionModel); + const { + copilotClient: client, + createClient, + workDir, + } = await createSdkTestContext({ + useStdio: true, + copilotClientOptions: { + gitHubToken: DEFAULT_GITHUB_TOKEN, + requestHandler: handler, + env: { + DYNAMIC_AUTO_TIERS: "false", + COPILOT_EXP_COPILOT_CLI_DYNAMIC_AUTO_TIERS: "false", + HYDRAFUSION: "false", + HYDRAFUSION_ROLLOUT: "false", + COPILOT_EXP_COPILOT_CLI_HYDRAFUSION_ROLLOUT: "false", + HYDRAFUSION_PLAN_V2: String(version === "2"), + COPILOT_EXP_COPILOT_CLI_HYDRAFUSION_PLAN_V2: String(version === "2"), + }, + }, + }); + const config = { + model: "auto", + workingDirectory: workDir, + expAssignments: { + Features: [], + Flights: {}, + Configs: [{ Id: "default", Parameters: { copilot_cli_dynamic_auto_tiers: true } }], + AssignmentContext: "metadata-fusion-treatment", + }, + capi: { enableWebSocketResponses: false }, + onPermissionRequest: approveAll, + }; + beforeEach(() => { + handler.plans.length = 0; + handler.auto.length = 0; + handler.inference.length = 0; + handler.failRoute = false; + handler.disabled = false; + handler.constituentsEnabled = true; + handler.inferenceGate = undefined; + }); + + it("routes only the selected preference, commits it, resumes cold and resets to Auto", async () => { + const diagnosticStart = performance.now(); + const phases: { phase: string; elapsedMs: number }[] = []; + const markPhase = (phase: string) => + phases.push({ phase, elapsedMs: Math.round(performance.now() - diagnosticStart) }); + onTestFailed(() => { + process.stderr.write( + `${JSON.stringify({ + test: "metadata Auto create/resume/reset", + mode, + version, + phases, + planCount: handler.plans.length, + autoCount: handler.auto.length, + inferenceCount: handler.inference.length, + })}\n` + ); + }); + markPhase("creating session"); + const session = await client.createSession(config); + markPhase("listing models"); + const catalog = await session.rpc.model.list(); + expect(catalog.auto?.tiers.some((tier) => tier.id === mode)).toBe(true); + expect( + catalog.list.some( + (model) => + typeof model === "object" && + model !== null && + "id" in model && + typeof model.id === "string" && + model.id.startsWith("hydrafusion") + ) + ).toBe(false); + expect(handler.plans).toEqual([]); + await expect(session.setAutoTier("future-fusion")).rejects.toThrow("unsupported execution"); + await expect(session.setAutoTier("future-type")).rejects.toThrow("unsupported execution"); + await expect(session.setAutoTier("HydraFusion")).rejects.toThrow("unavailable"); + const pending = await session.setAutoTier(mode); + markPhase("first turn"); + expect(pending.pendingAutoTier).toBe(mode); + expect((await session.rpc.model.getCurrent()).autoTier).toBeUndefined(); + const events: SessionEvent[] = []; + session.on((event) => events.push(event)); + expect( + ( + await session.sendAndWait({ + prompt: "What is the chemical symbol for gold? Do not use tools.", + }) + )?.data.content + ).toBe(REPLY); + expect(handler.plans).toEqual([ + expect.objectContaining({ + fusion_mode: mode, + ...(version === "2" ? { plan_version: version } : {}), + }), + ]); + if (version === "1") expect(handler.plans[0]).not.toHaveProperty("plan_version"); + expect(handler.auto).toEqual([]); + expect(events.some((event) => event.type === "session.fusion_route_failed")).toBe(false); + expect(events).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + type: "session.fusion_completed", + data: expect.objectContaining({ syntheticModel: mode }), + }), + ]) + ); + expect(events).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + type: "session.fusion_resolved", + data: expect.objectContaining({ + syntheticModel: mode, + policy: mode === "hydrafusion" ? "standard" : "max", + primaryModel: executionModel, + }), + }), + ]) + ); + expect(await session.rpc.model.getCurrent()).toMatchObject({ + modelId: "auto", + autoTier: mode, + }); + const sessionId = session.sessionId; + markPhase("cold client shutdown"); + await session.disconnect(); + await client.stop(); + const coldClient = createClient({ requestHandler: handler }); + try { + markPhase("cold resume"); + const resumed = await coldClient.resumeSession(sessionId, config); + markPhase("cold structured-output admission"); + expect(await resumed.rpc.model.getCurrent()).toMatchObject({ + modelId: "auto", + autoTier: mode, + }); + await expect( + resumed.sendAndWait({ + prompt: "Return a structured chemical symbol before the resumed turn.", + responseSchema: { type: "object", properties: { symbol: { type: "string" } } }, + }) + ).rejects.toThrow("responseFormat is not supported"); + expect(handler.plans).toHaveLength(1); + + markPhase("resumed turn"); + expect( + ( + await resumed.sendAndWait({ + prompt: "What is the chemical symbol for silver? Do not use tools.", + }) + )?.data.content + ).toBe(REPLY); + expect(handler.plans).toHaveLength(2); + markPhase("switch concrete then auto"); + await resumed.setModel(MODEL); + expect((await resumed.rpc.model.getCurrent()).autoTier).toBe(mode); + await resumed.setModel("auto"); + expect( + ( + await resumed.sendAndWait({ + prompt: "Name the chemical symbol for iron. Do not use tools.", + }) + )?.data.content + ).toBe(REPLY); + expect(handler.plans).toHaveLength(3); + markPhase("switch ordinary auto"); + await resumed.setModel("auto", { autoTier: "Balance-V2" }); + expect((await resumed.rpc.model.getCurrent()).autoTier).toBe(mode); + expect( + ( + await resumed.sendAndWait({ + prompt: "What is the chemical symbol for copper? Do not use tools.", + }) + )?.data.content + ).toBe(REPLY); + expect(handler.plans).toHaveLength(3); + expect(handler.auto.at(-1)).toMatchObject({ tier: "Balance-V2" }); + expect(await resumed.rpc.model.getCurrent()).toMatchObject({ + modelId: "auto", + autoTier: "Balance-V2", + }); + await resumed.setAutoTier(null); + markPhase("reset turn"); + expect( + ( + await resumed.sendAndWait({ + prompt: "Name the chemical symbol for lead. Do not use tools.", + }) + )?.data.content + ).toBe(REPLY); + expect((await resumed.rpc.model.getCurrent()).autoTier).toBeUndefined(); + expect(handler.plans).toHaveLength(3); + await resumed.disconnect(); + } finally { + markPhase("cold client cleanup"); + await coldClient.stop(); + } + markPhase("complete"); + }); + + it("executes explicit create and atomic Auto selection without rewriting the logical model", async () => { + const created = await client.createSession({ + ...config, + capi: { ...config.capi, autoTier: mode }, + }); + expect( + ( + await created.sendAndWait({ + prompt: "Name the chemical symbol for gold. Do not use tools.", + }) + )?.data.content + ).toBe(REPLY); + expect(await created.rpc.model.getCurrent()).toMatchObject({ + modelId: "auto", + autoTier: mode, + }); + await created.disconnect(); + const switched = await client.createSession({ ...config, model: MODEL }); + await switched.setModel("auto", { autoTier: mode }); + expect((await switched.rpc.model.getCurrent()).pendingAutoTier).toBe(mode); + expect( + ( + await switched.sendAndWait({ + prompt: "Name the chemical symbol for silver. Do not use tools.", + }) + )?.data.content + ).toBe(REPLY); + expect(await switched.rpc.model.getCurrent()).toMatchObject({ + modelId: "auto", + autoTier: mode, + }); + expect(handler.plans).toHaveLength(2); + expect( + handler.plans.every( + (plan) => + plan.fusion_mode === mode && + plan.plan_version === (version === "2" ? version : undefined) + ) + ).toBe(true); + expect(handler.auto).toEqual([]); + await switched.disconnect(); + }); + + it("retains typed Fusion route-failure fallback and commits only the concrete response", async () => { + handler.failRoute = true; + const session = await client.createSession(config); + await session.setAutoTier(mode); + const events: SessionEvent[] = []; + session.on((event) => events.push(event)); + expect( + ( + await session.sendAndWait({ + prompt: "What is the chemical symbol for gold? Do not use tools.", + }) + )?.data.content + ).toBe(REPLY); + expect(events.some((event) => event.type === "session.fusion_route_failed")).toBe(true); + expect(events.filter((event) => event.type === "assistant.message")).toHaveLength(1); + expect(await session.rpc.model.getCurrent()).toMatchObject({ + modelId: "auto", + autoTier: mode, + }); + expect(handler.plans).toHaveLength(1); + expect(handler.auto).toEqual([]); + await session.disconnect(); + }); + + it("applies reasoning-effort constraints consistently to dedicated Fusion setters", async () => { + const session = await client.createSession(config); + await session.rpc.model.setReasoningEffort({ reasoningEffort: "high" }); + await expect(session.setAutoTier(mode)).rejects.toThrow("do not support reasoning effort"); + expect((await session.rpc.model.getCurrent()).reasoningEffort).toBe("high"); + expect((await session.rpc.model.getCurrent()).pendingAutoTier).toBeUndefined(); + await session.rpc.model.setReasoningEffort({ reasoningEffort: "none" }); + await session.setAutoTier(mode); + await expect( + session.rpc.model.setReasoningEffort({ reasoningEffort: "high" }) + ).rejects.toThrow("do not support reasoning effort"); + await session.rpc.model.setReasoningEffort({ reasoningEffort: "none" }); + await session.setAutoTier(null); + await session.rpc.model.setReasoningEffort({ reasoningEffort: "high" }); + expect((await session.rpc.model.getCurrent()).reasoningEffort).toBe("high"); + await session.disconnect(); + }); + + it("retains the staged Fusion preference when the first inference is cancelled", async () => { + const session = await client.createSession({ + ...config, + capi: { ...config.capi, autoTier: "Balance-V2" }, + }); + const events: SessionEvent[] = []; + session.on((event) => events.push(event)); + await session.setAutoTier(mode); + const gate = { + entered: Promise.withResolvers(), + release: Promise.withResolvers(), + }; + handler.inferenceGate = gate; + const turn = session + .sendAndWait({ + prompt: "What is the chemical symbol for gold? Do not use tools.", + }) + .then( + (reply) => ({ reply, error: undefined }), + (error: Error) => ({ reply: undefined, error }) + ); + try { + await gate.entered.promise; + expect((await session.rpc.model.getCurrent()).activatingAutoTier).toBe(mode); + await session.abort(); + } finally { + gate.release.resolve(); + handler.inferenceGate = undefined; + } + await turn; + expect(await session.rpc.model.getCurrent()).toMatchObject({ + modelId: "auto", + autoTier: "Balance-V2", + pendingAutoTier: mode, + }); + expect((await session.rpc.model.getCurrent()).activatingAutoTier).toBeUndefined(); + expect(events.some((event) => event.type === "session.auto_tier_switch_failed")).toBe( + false + ); + expect( + ( + await session.sendAndWait({ + prompt: "What is the chemical symbol for silver? Do not use tools.", + }) + )?.data.content + ).toBe(REPLY); + expect(handler.plans).toHaveLength(2); + expect(handler.auto).toEqual([]); + expect(await session.rpc.model.getCurrent()).toMatchObject({ + modelId: "auto", + autoTier: mode, + }); + await session.disconnect(); + }); + + it.each(["fusion", "auto"] as const)( + "settles an invalidated pending %s preference once and preserves the incumbent", + async (execution) => { + await client.stop(); + const session = await client.createSession({ + ...config, + capi: { ...config.capi, autoTier: "Balance-V2" }, + }); + const events: SessionEvent[] = []; + session.on((event) => events.push(event)); + const requested = execution === "fusion" ? mode : "Other-V2"; + await session.setAutoTier(requested); + expect((await session.rpc.model.getCurrent()).pendingAutoTier).toBe(requested); + handler.disabled = true; + await session.rpc.model.list({ skipCache: true }); + await session + .sendAndWait({ + prompt: "What is the chemical symbol for gold? Do not use tools.", + }) + .then( + (reply) => expect(reply?.data.content).toBe(REPLY), + (error: unknown) => { + expect(error).toBeInstanceOf(Error); + expect((error as Error).message).toContain("Contact admin"); + } + ); + const current = await session.rpc.model.getCurrent(); + expect(current.autoTier).toBe("Balance-V2"); + expect(current.pendingAutoTier).toBeUndefined(); + expect(current.activatingAutoTier).toBeUndefined(); + expect( + events.filter((event) => event.type === "session.auto_tier_switch_failed") + ).toEqual([ + expect.objectContaining({ + data: expect.objectContaining({ + requestedAutoTier: requested, + effectiveAutoTier: "Balance-V2", + reason: "unsupported", + }), + }), + ]); + expect( + ( + await session.sendAndWait({ + prompt: "What is the chemical symbol for silver? Do not use tools.", + }) + )?.data.content + ).toBe(REPLY); + expect(handler.plans).toEqual([]); + expect(handler.auto.every((body) => body.tier === "Balance-V2")).toBe(true); + expect( + events.filter((event) => event.type === "session.auto_tier_switch_failed") + ).toHaveLength(1); + await session.disconnect(); + } + ); + + it("reports setup failure after claiming Fusion and clears only the failed request", async () => { + await client.stop(); + const session = await client.createSession({ + ...config, + capi: { ...config.capi, autoTier: "Balance-V2" }, + }); + const events: SessionEvent[] = []; + const failedTurnIdle = Promise.withResolvers(); + let failureObserved = false; + session.on((event) => { + events.push(event); + if (event.type === "session.error") failureObserved = true; + if (event.type === "session.idle" && failureObserved) failedTurnIdle.resolve(); + }); + await session.setAutoTier(mode); + handler.constituentsEnabled = false; + await session.rpc.model.list({ skipCache: true }); + await expect( + session.sendAndWait({ + prompt: "What is the chemical symbol for gold? Do not use tools.", + }) + ).rejects.toThrow("no executable constituent"); + // sendAndWait rejects on session.error before that failed turn's idle tail settles. + await failedTurnIdle.promise; + // Host-forwarded error/idle can overtake this event's recorded-stream delivery. + await expect + .poll(() => events.filter((event) => event.type === "session.auto_tier_switch_failed")) + .toEqual([ + expect.objectContaining({ + data: expect.objectContaining({ + requestedAutoTier: mode, + effectiveAutoTier: "Balance-V2", + reason: "setup_failed", + }), + }), + ]); + expect(await session.rpc.model.getCurrent()).toMatchObject({ + modelId: "auto", + autoTier: "Balance-V2", + }); + expect((await session.rpc.model.getCurrent()).pendingAutoTier).toBeUndefined(); + expect((await session.rpc.model.getCurrent()).activatingAutoTier).toBeUndefined(); + expect(handler.plans).toEqual([]); + expect(handler.inference).toEqual([]); + handler.constituentsEnabled = true; + await session.rpc.model.list({ skipCache: true }); + expect( + ( + await session.sendAndWait({ + prompt: "What is the chemical symbol for silver? Do not use tools.", + }) + )?.data.content + ).toBe(REPLY); + expect(handler.plans).toEqual([]); + expect( + events.filter((event) => event.type === "session.auto_tier_switch_failed") + ).toHaveLength(1); + await session.disconnect(); + }); + + it("rejects unsupported context and structured output before Fusion activation", async () => { + const session = await client.createSession(config); + await expect( + session.rpc.model.switchTo({ + modelId: "auto", + autoTier: mode, + contextTier: "long", + }) + ).rejects.toThrow("do not support context tiers"); + expect((await session.rpc.model.getCurrent()).autoTier).toBeUndefined(); + await session.setAutoTier(mode); + await expect( + session.sendAndWait({ + prompt: "Return the chemical symbol for gold as structured JSON.", + responseSchema: { + type: "object", + properties: { symbol: { type: "string" } }, + required: ["symbol"], + additionalProperties: false, + }, + }) + ).rejects.toThrow("responseFormat is not supported"); + expect(await session.rpc.model.getCurrent()).toMatchObject({ + modelId: "auto", + pendingAutoTier: mode, + }); + expect((await session.rpc.model.getCurrent()).autoTier).toBeUndefined(); + expect(handler.plans).toEqual([]); + expect(handler.auto).toEqual([]); + expect(handler.inference).toEqual([]); + expect((await session.rpc.queue.pendingItems()).items).toEqual([]); + expect( + (await session.getEvents()).filter( + (event) => event.type === "user.message" || event.type === "session.error" + ) + ).toEqual([]); + await session.disconnect(); + }); +}); + +describe.skipIf(isByokBackend).each(["1", "2"] as const)( + "Manual HydraFusion plan-version control: %s", + async (version) => { + const handler = new AutoFusionRequestHandler(version); + const { copilotClient: client, workDir } = await createSdkTestContext({ + useStdio: true, + copilotClientOptions: { + gitHubToken: DEFAULT_GITHUB_TOKEN, + requestHandler: handler, + env: { + DYNAMIC_AUTO_TIERS: "false", + COPILOT_EXP_COPILOT_CLI_DYNAMIC_AUTO_TIERS: "false", + HYDRAFUSION: "true", + HYDRAFUSION_ROLLOUT: "true", + HYDRAFUSION_PLAN_V2: String(version === "2"), + COPILOT_EXP_COPILOT_CLI_HYDRAFUSION_PLAN_V2: String(version === "2"), + }, + }, + }); + it("retains the manual v1 Max and v2 Standard execution mapping", async () => { + const session = await client.createSession({ + model: "hydrafusion", + enableExperimentalMode: true, + workingDirectory: workDir, + capi: { enableWebSocketResponses: false }, + onPermissionRequest: approveAll, + }); + const events: SessionEvent[] = []; + session.on((event) => events.push(event)); + expect( + ( + await session.sendAndWait({ + prompt: "What is the chemical symbol for gold? Do not use tools.", + }) + )?.data.content + ).toBe(REPLY); + expect(handler.plans).toEqual([ + expect.objectContaining({ + fusion_mode: version === "1" ? "hydrafusion-max" : "hydrafusion", + ...(version === "2" ? { plan_version: "2" } : {}), + }), + ]); + expect(events).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + type: "session.fusion_resolved", + data: expect.objectContaining({ + policy: version === "1" ? "max" : "standard", + }), + }), + ]) + ); + expect(events.some((event) => event.type === "session.fusion_route_failed")).toBe( + false + ); + expect((await session.rpc.model.getCurrent()).modelId).toBe("hydrafusion"); + await session.disconnect(); + }); + + if (version === "1") { + it("routes metadata Standard independently of manual Max history and resumes same-policy reuse", async () => { + const planStart = handler.plans.length; + const config = { + model: "hydrafusion", + enableExperimentalMode: true, + workingDirectory: workDir, + capi: { enableWebSocketResponses: false }, + onPermissionRequest: approveAll, + expAssignments: { + Features: [], + Flights: {}, + Configs: [ + { + Id: "default", + Parameters: { + copilot_cli_dynamic_auto_tiers: true, + copilot_cli_hydrafusion_turn_policy: "initial_only", + }, + }, + ], + AssignmentContext: "policy-scoped-fusion-history", + }, + }; + const session = await client.createSession(config); + const events: SessionEvent[] = []; + session.on((event) => events.push(event)); + expect( + ( + await session.sendAndWait({ + prompt: "Name the chemical symbol for gold. Do not use tools.", + }) + )?.data.content + ).toBe(REPLY); + expect(handler.plans.slice(planStart)).toEqual([ + expect.objectContaining({ fusion_mode: "hydrafusion-max" }), + ]); + await session.setModel("auto", { autoTier: "hydrafusion" }); + expect( + ( + await session.sendAndWait({ + prompt: "Name the chemical symbol for silver. Do not use tools.", + }) + )?.data.content + ).toBe(REPLY); + expect(handler.plans.slice(planStart)).toEqual([ + expect.objectContaining({ fusion_mode: "hydrafusion-max" }), + expect.objectContaining({ fusion_mode: "hydrafusion" }), + ]); + expect( + events + .filter((event) => event.type === "session.fusion_resolved") + .map((event) => event.data.policy) + ).toEqual(["max", "standard"]); + expect(await session.rpc.model.getCurrent()).toMatchObject({ + modelId: "auto", + autoTier: "hydrafusion", + }); + const sessionId = session.sessionId; + await session.disconnect(); + await client.stop(); + const resumed = await client.resumeSession(sessionId, { + ...config, + model: "auto", + }); + expect( + ( + await resumed.sendAndWait({ + prompt: "Name the chemical symbol for copper. Do not use tools.", + }) + )?.data.content + ).toBe(REPLY); + expect(handler.plans.slice(planStart)).toHaveLength(2); + expect(await resumed.rpc.model.getCurrent()).toMatchObject({ + modelId: "auto", + autoTier: "hydrafusion", + }); + await resumed.disconnect(); + }); + } + } +); + +describe.skipIf(isByokBackend)("Metadata Fusion rejection before activation", async () => { + const handler = new AutoFusionRequestHandler("1"); + const { copilotClient: client, workDir } = await createSdkTestContext({ + useStdio: true, + copilotClientOptions: { + gitHubToken: DEFAULT_GITHUB_TOKEN, + requestHandler: handler, + env: { + DYNAMIC_AUTO_TIERS: "true", + HYDRAFUSION_PLAN_V2: "false", + COPILOT_EXP_COPILOT_CLI_HYDRAFUSION_PLAN_V2: "false", + }, + }, + }); + + it("rejects Max with actionable plan-v2 guidance without changing incumbent or calling endpoints", async () => { + const config = { + model: "auto", + workingDirectory: workDir, + capi: { autoTier: "Balance-V2" }, + onPermissionRequest: approveAll, + }; + await expect( + client.createSession({ ...config, capi: { autoTier: "hydrafusion-max" } }) + ).rejects.toThrow("HYDRAFUSION_PLAN_V2"); + const session = await client.createSession(config); + await expect(session.setAutoTier("hydrafusion-max")).rejects.toThrow("HYDRAFUSION_PLAN_V2"); + await expect(session.setModel("auto", { autoTier: "hydrafusion-max" })).rejects.toThrow( + "HYDRAFUSION_PLAN_V2" + ); + expect(await session.rpc.model.getCurrent()).toMatchObject({ + modelId: "auto", + autoTier: "Balance-V2", + }); + expect((await session.rpc.model.getCurrent()).pendingAutoTier).toBeUndefined(); + expect(handler.plans).toEqual([]); + expect(handler.auto).toEqual([]); + expect(handler.inference).toEqual([]); + handler.disabled = true; + await session.rpc.model.list({ skipCache: true }); + await expect(session.setAutoTier("hydrafusion")).rejects.toThrow("Contact admin"); + await expect(session.setAutoTier("Other-V2")).rejects.toThrow("Contact admin"); + expect((await session.rpc.model.getCurrent()).autoTier).toBe("Balance-V2"); + await session.disconnect(); + }); + + it("does not settle pending Auto intent when structured-output admission rejects metadata", async () => { + await client.stop(); + handler.disabled = false; + const session = await client.createSession({ + model: "auto", + workingDirectory: workDir, + capi: { autoTier: "Balance-V2", enableWebSocketResponses: false }, + onPermissionRequest: approveAll, + }); + await session.setAutoTier("Other-V2"); + handler.disabled = true; + await session.rpc.model.list({ skipCache: true }); + const before = await session.getEvents(); + await expect( + session.sendAndWait({ + prompt: "Return the chemical symbol for gold as structured JSON.", + responseSchema: { + type: "object", + properties: { symbol: { type: "string" } }, + }, + }) + ).rejects.toThrow("Contact admin"); + expect(await session.rpc.model.getCurrent()).toMatchObject({ + modelId: "auto", + autoTier: "Balance-V2", + pendingAutoTier: "Other-V2", + }); + expect((await session.rpc.model.getCurrent()).activatingAutoTier).toBeUndefined(); + expect((await session.rpc.queue.pendingItems()).items).toEqual([]); + expect(await session.getEvents()).toEqual(before); + expect(handler.plans).toEqual([]); + expect(handler.inference).toEqual([]); + handler.disabled = false; + await session.rpc.model.list({ skipCache: true }); + expect( + ( + await session.sendAndWait({ + prompt: "What is the chemical symbol for silver? Do not use tools.", + }) + )?.data.content + ).toBe(REPLY); + expect(handler.auto.at(-1)).toMatchObject({ tier: "Other-V2" }); + expect(await session.rpc.model.getCurrent()).toMatchObject({ + modelId: "auto", + autoTier: "Other-V2", + }); + await session.disconnect(); + }); +}); diff --git a/nodejs/test/e2e/browser_shadow_reload.e2e.test.ts b/nodejs/test/e2e/browser_shadow_reload.e2e.test.ts new file mode 100644 index 0000000000..82a005528d --- /dev/null +++ b/nodejs/test/e2e/browser_shadow_reload.e2e.test.ts @@ -0,0 +1,143 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import { mkdirSync, readFileSync, writeFileSync } from "node:fs"; +import { dirname, join, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import { describe, expect, it } from "vitest"; +import { approveAll, RuntimeConnection } from "../../src/index.js"; +import { createSdkTestContext } from "./harness/sdkTestContext.js"; +import { waitForCondition } from "./harness/sdkTestHelper.js"; + +const BROWSER_NAME = "github-copilot-browser"; +const SHADOW_SERVER = "installed-browser-shadow"; +const TEST_MCP_SERVER = resolve( + dirname(fileURLToPath(import.meta.url)), + "../../../test/harness/test-mcp-server.mjs" +); + +describe("Browser shadow reload", async () => { + const { createClient, workDir, env } = await createSdkTestContext({ useStdio: true }); + + it( + "observes another process's install, disable and removal on a warm session", + { timeout: 90_000 }, + async () => { + const bundle = join(workDir, "bundle"); + const shadow = join(workDir, "shadow"); + for (const [directory, server] of [ + [bundle, BROWSER_NAME], + [shadow, SHADOW_SERVER], + ]) { + mkdirSync(join(directory, ".plugin"), { recursive: true }); + writeFileSync( + join(directory, ".plugin", "plugin.json"), + JSON.stringify({ + name: BROWSER_NAME, + version: "0.0.3", + mcpServers: "./.mcp.json", + }) + ); + writeFileSync( + join(directory, ".mcp.json"), + JSON.stringify({ + mcpServers: { + [server]: { + command: process.execPath, + args: [TEST_MCP_SERVER], + tools: ["*"], + }, + }, + }) + ); + } + writeFileSync( + join(env.COPILOT_HOME, "settings.json"), + JSON.stringify({ enabledPlugins: { [BROWSER_NAME]: true }, disableAllHooks: true }) + ); + await using owner = createClient({ + connection: RuntimeConnection.forStdio(), + builtinPluginDirectories: [bundle], + }); + await using writer = createClient({ connection: RuntimeConnection.forStdio() }); + await owner.start(); + await writer.start(); + await writer.rpc.plugins.builtin.set({ paths: [] }); + // Exercise persisted MCP discovery, not a host-owned effective-plugin snapshot. + const session = await owner.createSession({ + onPermissionRequest: approveAll, + enableConfigDiscovery: false, + mcpServers: { + peer: { + type: "local", + command: process.execPath, + args: [TEST_MCP_SERVER], + tools: ["*"], + }, + }, + }); + try { + const connected = async (serverName: string) => { + await waitForCondition( + async () => + (await session.rpc.mcp.list()).servers.some( + (server) => + server.name === serverName && server.status === "connected" + ), + { timeoutMs: 30_000, timeoutMessage: `${serverName} did not connect` } + ).catch(async (error: unknown) => { + const current = (await session.rpc.mcp.list()).servers.map( + ({ name, status }) => ({ name, status }) + ); + const installed = (await writer.rpc.plugins.list()).plugins.filter( + (plugin) => plugin.name === BROWSER_NAME + ); + const discovered = ( + await owner.rpc.mcp.discover({ workingDirectory: workDir }) + ).servers.map(({ name, enabled }) => ({ name, enabled })); + throw new Error( + `${serverName} did not connect: ${JSON.stringify({ current, installed, discovered })}`, + { cause: error } + ); + }); + expect((await session.rpc.mcp.listTools({ serverName })).tools).toEqual( + expect.arrayContaining([expect.objectContaining({ name: "get_env" })]) + ); + }; + const absent = async (serverName: string) => { + expect( + (await session.rpc.mcp.list()).servers.some( + (server) => server.name === serverName + ) + ).toBe(false); + }; + await connected("peer"); + await connected(BROWSER_NAME); + + const installed = await writer.rpc.plugins.install({ source: shadow }); + expect(installed.plugin.name).toBe(BROWSER_NAME); + expect(installed.plugin.enabled).toBe(true); + await session.rpc.mcp.reload(); + await connected(SHADOW_SERVER); + await absent(BROWSER_NAME); + + await writer.rpc.plugins.disable({ names: [BROWSER_NAME] }); + await session.rpc.mcp.reload(); + await absent(SHADOW_SERVER); + await absent(BROWSER_NAME); + + await writer.rpc.plugins.uninstall({ name: BROWSER_NAME }); + expect( + JSON.parse(readFileSync(join(env.COPILOT_HOME, "settings.json"), "utf8")) + .enabledPlugins[BROWSER_NAME] + ).toBe(true); + await session.rpc.mcp.reload(); + await connected(BROWSER_NAME); + await absent(SHADOW_SERVER); + } finally { + await session.disconnect(); + } + } + ); +}); diff --git a/nodejs/test/e2e/compaction.e2e.test.ts b/nodejs/test/e2e/compaction.e2e.test.ts index 4c8141b5e6..fa9cc328fe 100644 --- a/nodejs/test/e2e/compaction.e2e.test.ts +++ b/nodejs/test/e2e/compaction.e2e.test.ts @@ -2,7 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. *--------------------------------------------------------------------------------------------*/ -import { describe, expect, it } from "vitest"; +import { describe, expect, it, onTestFailed } from "vitest"; import { existsSync } from "node:fs"; import * as fs from "node:fs/promises"; import { join } from "node:path"; @@ -18,8 +18,32 @@ import { testBackend } from "./harness/testBackend.js"; const compactionTimeoutMs = 60_000; +interface CacheWireBlock { + text?: string; + cache_control?: unknown; + copilot_cache_control?: unknown; +} + +interface CacheWireRequest extends CacheWireBlock { + model: string; + max_tokens: number; + stream?: boolean; + system?: CacheWireBlock[]; + tools?: CacheWireBlock[]; + tool_choice?: unknown; + messages: (CacheWireBlock & { role: string; content: string | CacheWireBlock[] })[]; +} + class RefusalBudgetReplayHandler extends CopilotRequestHandler { - readonly requests: { model: string; max_tokens: number }[] = []; + readonly requests: CacheWireRequest[] = []; + readonly requestUrls: string[] = []; + + constructor( + private readonly endpoint: "/v1/messages" | "/chat/completions" = "/v1/messages", + private readonly fusionCritic = false + ) { + super(); + } protected override async sendRequest(request: Request): Promise { const path = new URL(request.url).pathname; @@ -28,6 +52,7 @@ class RefusalBudgetReplayHandler extends CopilotRequestHandler { data: [ ["claude-sonnet-5.5", 250_000, 384_000, 128_000], ["claude-sonnet-5", 112_000, 128_000, 64_000], + ...(this.fusionCritic ? [["claude-opus-5", 112_000, 128_000, 64_000]] : []), ].map(([id, prompt, context, output]) => ({ id, name: id, @@ -35,7 +60,21 @@ class RefusalBudgetReplayHandler extends CopilotRequestHandler { vendor: "Anthropic", version: "1", model_picker_enabled: true, - supported_endpoints: ["/v1/messages"], + policy: { state: "enabled" }, + supported_endpoints: [this.endpoint], + // Synthetic prices exercise TTL eligibility, not measured savings. + billing: { + token_prices: { + batch_size: 1_000_000, + default: { + input_price: 3, + output_price: 15, + cache_read_price: 0.3, + cache_write_price: 1, + cache_write_1h_price: 2, + }, + }, + }, capabilities: { type: "chat", family: id, @@ -50,17 +89,75 @@ class RefusalBudgetReplayHandler extends CopilotRequestHandler { })), }); } + if (this.fusionCritic && path === "/model/fusion") { + return Response.json({ + fusion_mode: "hydrafusion-max", + fusion_pattern: "critique", + plan_version: "1", + steps: [ + { role: "draft", model_id: "claude-opus-5" }, + { role: "critic", model_id: "claude-opus-5" }, + { role: "revision", model_id: "claude-opus-5" }, + ], + session: { token: "jwt.fake.cache-wire-fusion", expires_at: 0 }, + }); + } if (path.endsWith("/models/session")) return Response.json({}); if (path.includes("/policy")) return Response.json({ state: "enabled" }); - expect(path).toBe("/v1/messages"); - const body = (await request.json()) as { - model: string; - max_tokens: number; - stream?: boolean; - }; + expect(path).toBe(this.endpoint); + const body = (await request.json()) as CacheWireRequest; this.requests.push(body); + this.requestUrls.push(request.url); const refuses = body.model === "claude-sonnet-5.5"; - const content = refuses ? "PRIMARY_REFUSAL" : "FALLBACK_BUDGET_OK"; + const content = refuses + ? "PRIMARY_REFUSAL" + : this.fusionCritic && !body.tools?.length + ? JSON.stringify({ assessment: "approve", feedback: "" }) + : "FALLBACK_BUDGET_OK"; + const compaction = + Boolean(body.tools?.length) && + (body.tool_choice === "none" || + (typeof body.tool_choice === "object" && + body.tool_choice !== null && + "type" in body.tool_choice && + body.tool_choice.type === "none")); + // Model a warm tools/system prefix; this is accounting coverage, not a measured hit. + const cacheReadTokens = compaction ? 50 : 0; + if (this.endpoint === "/chat/completions") { + const usage = { + prompt_tokens: 100 + cacheReadTokens, + completion_tokens: 10, + total_tokens: 110 + cacheReadTokens, + prompt_tokens_details: { + cached_tokens: cacheReadTokens, + cache_creation_tokens: 0, + }, + }; + const choice = { + index: 0, + message: { role: "assistant", content }, + finish_reason: "stop", + }; + if (!body.stream) { + return Response.json({ + id: "cache-wire-replay", + object: "chat.completion", + model: body.model, + choices: [choice], + usage, + }); + } + const chunk = { + id: "cache-wire-replay", + object: "chat.completion.chunk", + model: body.model, + choices: [{ index: 0, delta: { content }, finish_reason: "stop" }], + usage, + }; + return new Response(`data: ${JSON.stringify(chunk)}\n\ndata: [DONE]\n\n`, { + headers: { "content-type": "text/event-stream" }, + }); + } const message = { id: "refusal-budget-replay", type: "message", @@ -69,7 +166,12 @@ class RefusalBudgetReplayHandler extends CopilotRequestHandler { content: [{ type: "text", text: content }], stop_reason: refuses ? "refusal" : "end_turn", stop_sequence: null, - usage: { input_tokens: 100, output_tokens: 10 }, + usage: { + input_tokens: 100, + output_tokens: 10, + cache_read_input_tokens: cacheReadTokens, + cache_creation_input_tokens: 0, + }, }; if (!body.stream) return Response.json(message); const events = [ @@ -104,6 +206,421 @@ class RefusalBudgetReplayHandler extends CopilotRequestHandler { } } +function expectNoConversationCacheMarkers(request: CacheWireRequest): void { + expect(request.cache_control).toBeUndefined(); + expect(Boolean(request.copilot_cache_control)).toBe(false); + for (const message of request.messages.filter(({ role }) => role !== "system")) { + expect(Boolean(message.copilot_cache_control)).toBe(false); + if (typeof message.content !== "string") { + for (const block of message.content) { + expect(block.cache_control).toBeUndefined(); + } + } + } +} + +function systemCacheMarkers(request: CacheWireRequest): unknown[] { + return [ + ...(request.system ?? []).map(({ cache_control }) => cache_control), + ...request.messages + .filter(({ role }) => role === "system") + .map(({ copilot_cache_control }) => copilot_cache_control), + ].filter(Boolean); +} + +for (const oneHour of [false, true]) { + describe(`Disposable Anthropic prompt caching (one-hour ${oneHour})`, async () => { + const { createClient } = await createSdkTestContext({ + replayOnly: true, + logLevel: "debug", + }); + + it.each(["CAPI Messages", "CAPI Chat", "BYOK Messages"] as const)( + "keeps reusable prefixes but not disposable writes on %s", + async (route) => { + const handler = new RefusalBudgetReplayHandler( + route === "CAPI Chat" ? "/chat/completions" : "/v1/messages" + ); + const cacheClient = createClient({ requestHandler: handler }); + let phase = "create session"; + const events: string[] = []; + onTestFailed(() => { + console.error( + `[cache-wire-progress] ${JSON.stringify({ + phase, + events: events.slice(-20), + requests: handler.requests.map((request, index) => ({ + endpoint: new URL(handler.requestUrls[index]!).pathname, + model: request.model, + stream: request.stream, + messages: request.messages.length, + hasTools: Boolean(request.tools?.length), + toolChoice: request.tool_choice, + })), + })}` + ); + }); + try { + const session = await cacheClient.createSession({ + onPermissionRequest: approveAll, + model: "claude-sonnet-5", + contextTier: "default", + featureFlags: { ANTHROPIC_1_HOUR_PROMPT_CACHE: oneHour }, + expAssignments: { + Features: ["copilot_cli_anthropic_1_hour_prompt_cache"], + Flights: { + copilot_cli_anthropic_1_hour_prompt_cache: String(oneHour), + }, + Configs: [ + { + Id: "default", + Parameters: { + copilot_cli_anthropic_1_hour_prompt_cache: oneHour, + }, + }, + ], + AssignmentContext: `cache-wire-one-hour-${oneHour}`, + }, + ...(route === "BYOK Messages" + ? { + provider: { + type: "anthropic" as const, + baseUrl: "https://cache-wire-replay.invalid", + apiKey: "fake-cache-wire-key", + modelId: "claude-sonnet-5", + }, + } + : { providers: [] }), + systemMessage: { + mode: "replace", + content: "Reusable agent policy. ".repeat(4_096), + }, + streaming: false, + infiniteSessions: { enabled: false }, + }); + session.on((event) => events.push(event.type)); + phase = "initial turn"; + expect( + ( + await session.sendAndWait({ + prompt: "Initialize the reusable conversation.", + }) + )?.data.content + ).toBe("FALLBACK_BUDGET_OK"); + const initial = handler.requests.at(-1)!; + expect( + new URL(handler.requestUrls.at(-1)!).hostname === + "cache-wire-replay.invalid" + ).toBe(route === "BYOK Messages"); + const marker = { + type: "ephemeral", + ...(oneHour && route !== "BYOK Messages" ? { ttl: "1h" } : {}), + }; + expect(systemCacheMarkers(initial)).toContainEqual(marker); + expect( + initial.tools?.some((tool) => + Boolean(tool.cache_control ?? tool.copilot_cache_control) + ) + ).toBe(true); + + const beforeSampling = handler.requests.length; + phase = "sampling and concurrent turn"; + const [sampling, concurrentTurn] = await Promise.all([ + session.rpc.mcp.executeSampling({ + requestId: "cache-wire-sampling", + serverName: "cache-wire-server", + mcpRequestId: "cache-wire-mcp", + request: { + systemPrompt: "Disposable caller-owned policy. ".repeat(4_096), + messages: [ + { + role: "user", + content: { + type: "text", + text: "Compute a sampling result.", + }, + }, + ], + maxTokens: 4096, + }, + }), + session.sendAndWait({ + prompt: "Continue while sampling runs independently.", + }), + ]); + expect(concurrentTurn?.data.content).toBe("FALLBACK_BUDGET_OK"); + expect(sampling).toMatchObject({ + action: "success", + result: { content: { type: "text", text: "FALLBACK_BUDGET_OK" } }, + }); + const concurrentRequests = handler.requests.slice(beforeSampling); + expect(concurrentRequests).toHaveLength(2); + const sampled = concurrentRequests.find((request) => !request.tools?.length)!; + const continued = concurrentRequests.find((request) => + Boolean(request.tools?.length) + )!; + expect(systemCacheMarkers(sampled)).toEqual([]); + expectNoConversationCacheMarkers(sampled); + expect(systemCacheMarkers(continued)).toContainEqual(marker); + + phase = "handoff summary"; + expect(await session.rpc.history.summarizeForHandoff()).toMatchObject({ + summary: "FALLBACK_BUDGET_OK", + }); + expect(systemCacheMarkers(handler.requests.at(-1)!)).toEqual([]); + expectNoConversationCacheMarkers(handler.requests.at(-1)!); + + phase = "manual compaction"; + const completed = getNextSessionEvent( + session, + "session.compaction_complete", + "manual cache compaction" + ); + const [compacted, completionEvent] = await Promise.all([ + session.rpc.history.compact({ trigger: "manual" }), + completed, + ]); + expect(compacted).toMatchObject({ + success: true, + summaryContent: "FALLBACK_BUDGET_OK", + }); + expect(completionEvent.data.compactionTokensUsed).toMatchObject({ + inputTokens: 150, + outputTokens: 10, + cacheReadTokens: 50, + cacheWriteTokens: 0, + }); + const compacting = handler.requests.at(-1)!; + expect(systemCacheMarkers(compacting)).toEqual(systemCacheMarkers(initial)); + expect(compacting.tools).toEqual(initial.tools); + expect(compacting.tool_choice).toEqual( + route === "CAPI Chat" ? "none" : { type: "none" } + ); + expectNoConversationCacheMarkers(compacting); + + phase = "post-compaction turn"; + expect( + (await session.sendAndWait({ prompt: "Continue after compaction." }))?.data + .content + ).toBe("FALLBACK_BUDGET_OK"); + expect(systemCacheMarkers(handler.requests.at(-1)!)).toContainEqual(marker); + phase = "disconnect session"; + await session.disconnect(); + } finally { + phase = `stop client (after ${phase})`; + await cacheClient.stop(); + } + } + ); + }); +} + +describe("Disposable Anthropic prompt caching during automatic compaction", async () => { + const { createClient } = await createSdkTestContext({ replayOnly: true }); + it.each(["CAPI Messages", "CAPI Chat", "BYOK Messages"] as const)( + "avoids discarded transcript writes during automatic compaction on %s", + async (route) => { + const handler = new RefusalBudgetReplayHandler( + route === "CAPI Chat" ? "/chat/completions" : "/v1/messages" + ); + const cacheClient = createClient({ requestHandler: handler }); + try { + const session = await cacheClient.createSession({ + onPermissionRequest: approveAll, + model: "claude-sonnet-5", + ...(route === "BYOK Messages" + ? { + provider: { + type: "anthropic" as const, + baseUrl: "https://cache-wire-replay.invalid", + apiKey: "fake-cache-wire-key", + modelId: "claude-sonnet-5", + }, + } + : { providers: [] }), + systemMessage: { + mode: "replace", + content: "Reusable automatic policy. ".repeat(600), + }, + streaming: false, + infiniteSessions: { + enabled: true, + backgroundCompactionThreshold: 0.005, + bufferExhaustionThreshold: 0.01, + }, + }); + const completed = getNextSessionEvent( + session, + "session.compaction_complete", + "automatic cache compaction" + ); + const [, completionEvent] = await Promise.all([ + (async () => { + expect( + ( + await session.sendAndWait({ + prompt: "Start the automatic compaction scenario.", + }) + )?.data.content + ).toBe("FALLBACK_BUDGET_OK"); + expect( + ( + await session.sendAndWait({ + prompt: "Continue the automatic compaction scenario.", + }) + )?.data.content + ).toBe("FALLBACK_BUDGET_OK"); + })(), + completed, + ]); + expect(completionEvent.data).toMatchObject({ + success: true, + summaryContent: "FALLBACK_BUDGET_OK", + compactionTokensUsed: { + inputTokens: 150, + outputTokens: 10, + cacheReadTokens: 50, + cacheWriteTokens: 0, + }, + }); + const compactions = handler.requests.filter(({ tool_choice }) => + route === "CAPI Chat" + ? tool_choice === "none" + : typeof tool_choice === "object" && + tool_choice !== null && + "type" in tool_choice && + tool_choice.type === "none" + ); + expect(compactions.length).toBeGreaterThan(0); + for (const request of compactions) { + expect(systemCacheMarkers(request)).not.toEqual([]); + expect(request.tools).toEqual(handler.requests[0].tools); + expectNoConversationCacheMarkers(request); + } + await session.disconnect(); + } finally { + await cacheClient.stop(); + } + } + ); +}); + +describe("Disposable Anthropic prompt caching during refusal fallback", async () => { + const { createClient } = await createSdkTestContext({ + replayOnly: true, + copilotClientOptions: { + env: { + ANTHROPIC_REFUSAL_FALLBACK: "true", + COPILOT_EXP_COPILOT_CLI_ANTHROPIC_REFUSAL_FALLBACK: "true", + }, + }, + }); + + it("preserves single-use cache intent across refusal fallback", async () => { + const handler = new RefusalBudgetReplayHandler(); + const cacheClient = createClient({ requestHandler: handler }); + try { + const session = await cacheClient.createSession({ + onPermissionRequest: approveAll, + model: "claude-sonnet-5.5", + providers: [], + infiniteSessions: { enabled: false }, + }); + const sampled = await session.rpc.mcp.executeSampling({ + requestId: "fallback-cache-sampling", + serverName: "cache-wire-server", + mcpRequestId: "fallback-cache-mcp", + request: { + systemPrompt: "Disposable fallback policy. ".repeat(4_096), + messages: [ + { + role: "user", + content: { type: "text", text: "Compute a sampling result." }, + }, + ], + maxTokens: 4096, + }, + }); + expect(sampled).toMatchObject({ + action: "success", + result: { content: { text: "FALLBACK_BUDGET_OK" } }, + }); + expect(handler.requests.map(({ model }) => model)).toEqual([ + "claude-sonnet-5.5", + "claude-sonnet-5", + ]); + for (const request of handler.requests) { + expect(systemCacheMarkers(request)).toEqual([]); + expectNoConversationCacheMarkers(request); + } + await session.disconnect(); + } finally { + await cacheClient.stop(); + } + }); +}); + +describe("Disposable Anthropic prompt caching during Fusion review", async () => { + const { createClient } = await createSdkTestContext({ replayOnly: true }); + it("avoids tool-less critic writes without disabling the solver cache", async () => { + const handler = new RefusalBudgetReplayHandler("/v1/messages", true); + const cacheClient = createClient({ requestHandler: handler }); + try { + const session = await cacheClient.createSession({ + onPermissionRequest: approveAll, + model: "hydrafusion-max", + providers: [], + enableExperimentalMode: true, + featureFlags: { + HYDRAFUSION: true, + HYDRAFUSION_ROLLOUT: true, + HYDRAFUSION_PLAN_V2: true, + }, + expAssignments: { + Features: [], + Flights: {}, + Configs: [], + AssignmentContext: "cache-wire-fusion-review", + }, + infiniteSessions: { enabled: false }, + }); + const events: SessionEvent[] = []; + expect((await session.rpc.model.getCurrent()).modelId).toBe("hydrafusion-max"); + const unsubscribe = session.on((event) => events.push(event)); + try { + expect( + ( + await session.sendAndWait({ + prompt: "Answer the cache policy review scenario without using tools.", + }) + )?.data.content + ).toBe("FALLBACK_BUDGET_OK"); + expect( + events.filter((event) => event.type === "session.fusion_route_failed") + ).toEqual([]); + expect( + events + .filter((event) => event.type === "assistant.fusion_phase_completed") + .map((event) => event.data.phaseKind) + ).toEqual(["draft", "critic"]); + expect(handler.requests).toHaveLength(2); + expect(systemCacheMarkers(handler.requests[0])).not.toEqual([]); + expect(handler.requests[0].tools?.length).toBeGreaterThan(0); + const critic = handler.requests[1]; + expect(critic.model).toBe("claude-opus-5"); + expect(critic.tools ?? []).toEqual([]); + expect(systemCacheMarkers(critic)).toEqual([]); + expectNoConversationCacheMarkers(critic); + } finally { + unsubscribe(); + await session.disconnect(); + } + } finally { + await cacheClient.stop(); + } + }); +}); + class BudgetReplayHandler extends CopilotRequestHandler { readonly requests: unknown[] = []; diff --git a/nodejs/test/e2e/mcp_scoped_sign_in.e2e.test.ts b/nodejs/test/e2e/mcp_scoped_sign_in.e2e.test.ts index 4139e17bfe..d872e2c1c2 100644 --- a/nodejs/test/e2e/mcp_scoped_sign_in.e2e.test.ts +++ b/nodejs/test/e2e/mcp_scoped_sign_in.e2e.test.ts @@ -104,6 +104,7 @@ describe("MCP sign-in for one server", async () => { const events: SessionEvent[] = []; const session = await client.createSession({ onPermissionRequest: approveAll, + onEvent: (event) => events.push(event), mcpServers: { alpha: { type: "local", @@ -122,8 +123,6 @@ describe("MCP sign-in for one server", async () => { }, }); onTestFinished(() => disconnectSession(session)); - session.on((event) => events.push(event)); - await waitForMcpServerStatus(session, "alpha", "connected"); await waitForMcpServerStatus(session, "bravo", "needs-auth"); await waitForMcpServerStatus(session, "delta", "needs-auth"); @@ -132,6 +131,20 @@ describe("MCP sign-in for one server", async () => { redirectUri: REDIRECT_URI, }); expect(deltaLogin.authorizationId).toBeDefined(); + // Live status can precede its asynchronous event, so observe startup before measuring peer changes. + await waitForCondition( + () => + events.some( + (event) => + event.type === "session.mcp_server_status_changed" && + event.data.serverName === "alpha" && + event.data.status === "connected" + ), + { + timeoutMs: STEP_TIMEOUT_MS, + timeoutMessage: "alpha's initial connected event did not arrive", + } + ); const baseline = events.length; return { diff --git a/nodejs/test/e2e/rpc_surface_coverage.e2e.test.ts b/nodejs/test/e2e/rpc_surface_coverage.e2e.test.ts index 73a239a8df..1b71849db7 100644 --- a/nodejs/test/e2e/rpc_surface_coverage.e2e.test.ts +++ b/nodejs/test/e2e/rpc_surface_coverage.e2e.test.ts @@ -327,7 +327,7 @@ describe("Generated RPC surface coverage", () => { ...collectRuntimeFunctions(session.rpc, "session"), ]); - expect(inventory).toHaveLength(406); + expect(inventory).toHaveLength(407); expect(inventory.filter((method) => method.wireMethod === "host.listSessions")).toEqual([ expect.objectContaining({ scope: "server", path: "host.listSessions" }), ]); diff --git a/nodejs/test/e2e/session_fs.e2e.test.ts b/nodejs/test/e2e/session_fs.e2e.test.ts index 61d15b9b26..81309ee5a8 100644 --- a/nodejs/test/e2e/session_fs.e2e.test.ts +++ b/nodejs/test/e2e/session_fs.e2e.test.ts @@ -6,7 +6,7 @@ import { SessionCompactionCompleteEvent } from "@github/copilot/sdk"; import { MemoryProvider, VirtualProvider } from "@platformatic/vfs"; import { createHash } from "crypto"; import { existsSync, mkdtempSync, realpathSync } from "fs"; -import { mkdir, readFile, rm, writeFile } from "fs/promises"; +import { mkdir, readFile, readdir, rm, writeFile } from "fs/promises"; import { createServer } from "http"; import { tmpdir } from "os"; import { join } from "path"; @@ -307,6 +307,91 @@ describe("Session Fs", async () => { }); }); +describe("Session Fs native plan edits", async () => { + const { createClient, workDir } = await createSdkTestContext(); + + it.each(["interactive", "plan"] as const)( + "keeps native edits and write failures in the provider in %s mode", + async (mode) => { + const statePath = join(workDir, `provider-state-${mode}`); + const planPath = join(statePath, "plan.md"); + const provider = new MemoryProvider(); + const writes: string[] = []; + let rejectWrites = false; + const client = createClient({ + mode: "empty", + sessionFs: { + initialCwd: workDir, + sessionStatePath: statePath, + conventions: process.platform === "win32" ? "windows" : "posix", + }, + }); + onTestFinished(() => client.stop()); + const session = await client.createSession({ + onPermissionRequest: approveAll, + availableTools: ["edit"], + createSessionFsProvider: (session) => { + const handler = createTestSessionFsHandler(session, provider); + return { + ...handler, + async writeFile(path, content) { + if (path === planPath) { + writes.push(content); + if (rejectWrites) { + throw new Error("provider write denied"); + } + } + return handler.writeFile(path, content); + }, + }; + }, + }); + await session.rpc.mode.set({ mode }); + await session.rpc.plan.update({ content: "# Provider plan\n" }); + expect(await session.rpc.plan.read()).toMatchObject({ + path: planPath, + content: "# Provider plan\n", + }); + + // A writable host parent makes an accidental host write succeed. + await mkdir(statePath, { recursive: true }); + expect(await readdir(statePath)).toEqual([]); + const edit = (old_str: string, new_str: string) => + session.rpc.tools.execute({ + name: "edit", + arguments: { path: planPath, old_str, new_str }, + }); + await expect(edit("Provider plan", "Native update")).resolves.toMatchObject({ + resultType: "success", + }); + expect((await session.rpc.plan.read()).content).toBe("# Native update\n"); + expect(writes).toEqual(["# Provider plan\n", "# Native update\n"]); + expect(await readdir(statePath)).toEqual([]); + + await writeFile(planPath, "host-only content\n"); + await expect(edit("Native update", "Second update")).resolves.toMatchObject({ + resultType: "success", + }); + expect((await session.rpc.plan.read()).content).toBe("# Second update\n"); + expect(await readFile(planPath, "utf8")).toBe("host-only content\n"); + + rejectWrites = true; + const failed = await edit("Second update", "Rejected update"); + expect(failed.resultType).toBe("failure"); + expect(failed.textResultForLlm).toContain("provider write denied"); + expect((await session.rpc.plan.read()).content).toBe("# Second update\n"); + expect(writes).toEqual([ + "# Provider plan\n", + "# Native update\n", + "# Second update\n", + "# Rejected update\n", + ]); + expect(await readFile(planPath, "utf8")).toBe("host-only content\n"); + expect(await readdir(statePath)).toEqual(["plan.md"]); + } + ); +}); + describe("Session Fs remembered approvals", async () => { const workingDirectory = "/workspace"; const otherDirectory = "/provider-dir"; diff --git a/nodejs/test/e2e/skill_provider.e2e.test.ts b/nodejs/test/e2e/skill_provider.e2e.test.ts index 82d584809c..e8f2560625 100644 --- a/nodejs/test/e2e/skill_provider.e2e.test.ts +++ b/nodejs/test/e2e/skill_provider.e2e.test.ts @@ -6,10 +6,11 @@ import { execFileSync } from "child_process"; import * as fs from "fs"; import * as path from "path"; import { fileURLToPath } from "url"; -import { describe, expect, it } from "vitest"; +import { describe, expect, it, onTestFinished } from "vitest"; import { approveAll, RuntimeConnection, + type SessionConfig, type SessionEvent, type SkillProvider, type SkillProviderDescriptor, @@ -50,7 +51,12 @@ function skill(name: string, description: string, markdown: string): ProvidedSki } describe("Skill providers", async () => { - const { copilotClient: client, workDir } = await createSdkTestContext(); + const { + copilotClient: client, + createClient, + openAiEndpoint, + workDir, + } = await createSdkTestContext(); it("should load provider skill lazily through skill tool", async () => { // Body-only content: the catalog descriptor supplies all of the metadata. @@ -175,6 +181,83 @@ describe("Skill providers", async () => { } }); + it("should preserve skill prompt bytes across cold resume with reordered discovery", async () => { + const directories = ["custom-b", "custom-a"].map((name) => { + const directory = path.join(workDir, name); + fs.mkdirSync(directory, { recursive: true }); + fs.writeFileSync( + path.join(directory, "SKILL.md"), + `---\nname: ${name}\ndescription: An ordering fixture.\n---\nOrdering fixture.\n` + ); + return directory; + }); + const provided = ["provider-c", "provider-a", "provider-b"].map((name) => + skill(name, "An ordering fixture.", "Ordering fixture.\n") + ); + const config = { + model: "claude-sonnet-5", + onPermissionRequest: approveAll, + availableTools: ["skill"], + enableConfigDiscovery: false, + includedBuiltinSkills: [], + skipCustomInstructions: true, + skipEmbeddingRetrieval: true, + } satisfies SessionConfig; + const first = createClient({ connection: RuntimeConnection.forStdio() }); + onTestFinished(() => first.stop()); + const session = await first.createSession({ + ...config, + skillProvider: new TestSkillProvider(provided), + skillDirectories: directories, + }); + const response = await session.sendAndWait({ + prompt: "Without using tools, reply with exactly SKILL_ORDER_INITIAL_OK.", + }); + // Validate the final assistant response arrived (guards against truncated captures) + expect(response?.data.content).toContain("SKILL_ORDER_INITIAL_OK"); + const beforeRequests = await openAiEndpoint.getRequests(); + const beforeBlocks = beforeRequests.flatMap( + (request) => + request.body.match(/\\n[\s\S]*?<\/available_skills>/g) ?? [] + ); + expect(beforeBlocks.length).toBeGreaterThan(0); + for (const block of beforeBlocks) { + for (const name of [ + ...provided.map((entry) => entry.descriptor.name), + "custom-a", + "custom-b", + ]) { + expect(block).toContain(`${name}`); + } + expect(block.indexOf("provider-c")).toBeLessThan( + block.indexOf("custom-a") + ); + } + await session.disconnect(); + expect(await first.stop()).toHaveLength(0); + + const second = createClient({ connection: RuntimeConnection.forStdio() }); + onTestFinished(() => second.stop()); + const resumed = await second.resumeSession(session.sessionId, { + ...config, + skillProvider: new TestSkillProvider([provided[2], provided[0], provided[1]]), + skillDirectories: [...directories].reverse(), + }); + const resumedResponse = await resumed.sendAndWait({ + prompt: "Without using tools, reply with exactly SKILL_ORDER_RESUMED_OK.", + }); + // Validate the final assistant response arrived (guards against truncated captures) + expect(resumedResponse?.data.content).toContain("SKILL_ORDER_RESUMED_OK"); + const afterBlocks = (await openAiEndpoint.getRequests()) + .slice(beforeRequests.length) + .flatMap( + (request) => + request.body.match(/\\n[\s\S]*?<\/available_skills>/g) ?? [] + ); + expect(afterBlocks).toEqual(beforeBlocks); + await resumed.disconnect(); + }); + it("should report provider read failure without leaking details", async () => { const secret = "PROVIDER_SECRET_7F3A9C"; const provider = new TestSkillProvider([ diff --git a/python/copilot/generated/rpc.py b/python/copilot/generated/rpc.py index 9a3ec258af..605a606bfd 100644 --- a/python/copilot/generated/rpc.py +++ b/python/copilot/generated/rpc.py @@ -6617,16 +6617,18 @@ class ManagedSettingsResolvedData: shape as `session.managedSettings.get`, excluding session-local injection. """ bypass_permissions_disabled: bool - """Whether enterprise policy disables bypass-permissions ("yolo") mode for this session. - Deny-wins across layers, and forced on when `failClosed` is true. + """Whether an explicit enterprise policy restriction disables bypass-permissions ("yolo") + mode for this session. Deny-wins across layers; an unresolved policy does not force this + on by itself. """ device_managed: bool """Whether an actual device MDM/plist/registry/file managed-settings layer was present""" fail_closed: bool - """Whether managed policy could not be determined (e.g. a failed server fetch) and the - session fell back to the fail-closed restriction. When true, restrictions such as - disabling bypass-permissions are enforced even though `settings` may be absent. + """Whether managed policy could not be determined (e.g. a failed server fetch) and + unresolved-policy safeguards remain active. This does not by itself disable + bypass-permissions; `bypassPermissionsDisabled` reports only an explicit policy + restriction. """ managed_keys: list[str] """The setting keys under enterprise management in the effective managed settings (e.g. @@ -8317,6 +8319,94 @@ def to_dict(self) -> dict: result["cursor"] = from_union([from_str, from_none], self.cursor) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class MCPRegistryCancelRequest: + """Registry search to abandon.""" + + request_id: int + """Request ID from `mcp.registry.allocateRequestId` that the search uses.""" + + @staticmethod + def from_dict(obj: Any) -> 'MCPRegistryCancelRequest': + assert isinstance(obj, dict) + request_id = from_int(obj.get("requestId")) + return MCPRegistryCancelRequest(request_id) + + def to_dict(self) -> dict: + result: dict = {} + result["requestId"] = from_int(self.request_id) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class MCPRegistryCancelResult: + """Whether the cancel reached a live search.""" + + canceled: bool + """True when the cancel stopped a running search. False for unknown or reclaimed IDs, + completed or canceled searches, and unused reservations. The cancel releases an unused + reservation. + """ + + @staticmethod + def from_dict(obj: Any) -> 'MCPRegistryCancelResult': + assert isinstance(obj, dict) + canceled = from_bool(obj.get("canceled")) + return MCPRegistryCancelResult(canceled) + + def to_dict(self) -> dict: + result: dict = {} + result["canceled"] = from_bool(self.canceled) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class MCPRegistryRequestIDResult: + """Request id naming a cancellable registry search.""" + + request_id: int + """Request ID for `mcp.registry.search` and `mcp.registry.cancel`. It serves one search. + Allocation can reclaim unused IDs at the 1,024-ID reservation limit. + """ + + @staticmethod + def from_dict(obj: Any) -> 'MCPRegistryRequestIDResult': + assert isinstance(obj, dict) + request_id = from_int(obj.get("requestId")) + return MCPRegistryRequestIDResult(request_id) + + def to_dict(self) -> dict: + result: dict = {} + result["requestId"] = from_int(self.request_id) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class MCPRegistrySearchResult: + """Servers selected from the registry response.""" + + servers: Any + """The server objects, carried opaquely. The runtime follows pages, keeps the newest entry + per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub + stars. Each server object remains unchanged because the registry owns that shape. + """ + + @staticmethod + def from_dict(obj: Any) -> 'MCPRegistrySearchResult': + assert isinstance(obj, dict) + servers = obj.get("servers") + return MCPRegistrySearchResult(servers) + + def to_dict(self) -> dict: + result: dict = {} + result["servers"] = self.servers + return result + class MCPServerConfigType(Enum): """Local transport type. Defaults to stdio when omitted. @@ -8501,6 +8591,38 @@ class MCPSetEnvValueModeDetails(Enum): DIRECT = "direct" INDIRECT = "indirect" +# Experimental: this type is part of an experimental API and may change or be removed. +class OptionsUpdateToolFilterPrecedence(Enum): + """Controls how availableTools (allowlist) and excludedTools (denylist) combine when both + are set. + """ + AVAILABLE = "available" + EXCLUDED = "excluded" + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class MCPShouldExcludeGitHubToolsResult: + """Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by + the request. + """ + exclude_gh_replaceable_tools: bool + """True only when both halves hold: the session's filters still reach the platform shell + tool, and the host actually has the `gh` those tools would be replaced by. Feed it + straight back as the `excludeGhReplaceableTools` build option. + """ + + @staticmethod + def from_dict(obj: Any) -> 'MCPShouldExcludeGitHubToolsResult': + assert isinstance(obj, dict) + exclude_gh_replaceable_tools = from_bool(obj.get("excludeGhReplaceableTools")) + return MCPShouldExcludeGitHubToolsResult(exclude_gh_replaceable_tools) + + def to_dict(self) -> dict: + result: dict = {} + result["excludeGhReplaceableTools"] = from_bool(self.exclude_gh_replaceable_tools) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class MCPStopServerRequest: @@ -9927,14 +10049,6 @@ class OptionsUpdateContextTier(Enum): DEFAULT = "default" LONG_CONTEXT = "long_context" -# Experimental: this type is part of an experimental API and may change or be removed. -class OptionsUpdateToolFilterPrecedence(Enum): - """Controls how availableTools (allowlist) and excludedTools (denylist) combine when both - are set. - """ - AVAILABLE = "available" - EXCLUDED = "excluded" - # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class PendingPermissionRequest: @@ -12714,6 +12828,34 @@ class SandboxConfigSource(Enum): USER_DISABLED = "user_disabled" USER_ENABLED = "user_enabled" +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SandboxCredentialSuggestion: + """A possible secret-bearing environment variable and optional locally suggested HTTPS + injection hosts. This is a draft for user review, not an active grant. + """ + name: str + """Environment variable name. The secret value is never returned.""" + + suggested_inject_hosts: list[str] + """HTTPS hostnames suggested by a local known-provider mapping. An empty list requires the + user to supply injection hosts before adding a masking entry. These suggestions do not + allow network access. + """ + + @staticmethod + def from_dict(obj: Any) -> 'SandboxCredentialSuggestion': + assert isinstance(obj, dict) + name = from_str(obj.get("name")) + suggested_inject_hosts = from_list(from_str, obj.get("suggestedInjectHosts")) + return SandboxCredentialSuggestion(name, suggested_inject_hosts) + + def to_dict(self) -> dict: + result: dict = {} + result["name"] = from_str(self.name) + result["suggestedInjectHosts"] = from_list(from_str, self.suggested_inject_hosts) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class SandboxDisableForSessionResult: @@ -26036,6 +26178,45 @@ def to_dict(self) -> dict: result["mode"] = to_enum(MCPSetEnvValueModeDetails, self.mode) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class MCPShouldExcludeGitHubToolsRequest: + """The session tool filters that decide whether the session still has a shell to run `gh` + with. + """ + available_tools: list[str] | None = None + """The session's tool allowlist, when it set one. Omitted means the session constrains + nothing this way. + """ + excluded_tools: list[str] | None = None + """The session's tool denylist, when it set one. Omitted means the session constrains + nothing this way. + """ + tool_filter_precedence: OptionsUpdateToolFilterPrecedence | None = None + """How the allowlist and denylist combine when both are set. Omitted means the default every + session gets, so a caller that never chose a precedence is answered as its sessions + behave. + """ + + @staticmethod + def from_dict(obj: Any) -> 'MCPShouldExcludeGitHubToolsRequest': + assert isinstance(obj, dict) + available_tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("availableTools")) + excluded_tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("excludedTools")) + tool_filter_precedence = from_union([from_none, OptionsUpdateToolFilterPrecedence], obj.get("toolFilterPrecedence")) + return MCPShouldExcludeGitHubToolsRequest(available_tools, excluded_tools, tool_filter_precedence) + + def to_dict(self) -> dict: + result: dict = {} + if self.available_tools is not None: + result["availableTools"] = from_union([lambda x: from_list(from_str, x), from_none], self.available_tools) + if self.excluded_tools is not None: + result["excludedTools"] = from_union([lambda x: from_list(from_str, x), from_none], self.excluded_tools) + if self.tool_filter_precedence is not None: + result["toolFilterPrecedence"] = from_union([from_none, lambda x: to_enum(OptionsUpdateToolFilterPrecedence, x)], self.tool_filter_precedence) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class ConnectorDiscoveryCatalogEntry: @@ -30003,6 +30184,28 @@ def to_dict(self) -> dict: result["proxy"] = from_union([lambda x: to_class(SandboxConfigUserPolicyNetworkProxy, x), from_none], self.proxy) return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SandboxCredentialSuggestionsResult: + """Possible unconfigured secrets in the sandbox shell environment, sorted by variable name, + with no secret values. + """ + suggestions: list[SandboxCredentialSuggestion] + """Candidates for user review. Empty when sandboxing is disabled or no unconfigured + candidates are present. + """ + + @staticmethod + def from_dict(obj: Any) -> 'SandboxCredentialSuggestionsResult': + assert isinstance(obj, dict) + suggestions = from_list(SandboxCredentialSuggestion.from_dict, obj.get("suggestions")) + return SandboxCredentialSuggestionsResult(suggestions) + + def to_dict(self) -> dict: + result: dict = {} + result["suggestions"] = from_list(lambda x: to_class(SandboxCredentialSuggestion, x), self.suggestions) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class SandboxHostSupport: @@ -41555,9 +41758,6 @@ class _GlobalStateLoadResult: recorded nothing yet, so a reader must treat an absent field as `not yet`, never as a negative answer. Stored credentials are deliberately absent from this shape. """ - app_install_nudge_responded: bool | None = None - """Whether the user has answered the prompt suggesting they install the desktop app.""" - app_tip_shown: bool | None = None """Whether the app tip has been shown.""" @@ -41620,7 +41820,6 @@ class _GlobalStateLoadResult: @staticmethod def from_dict(obj: Any) -> '_GlobalStateLoadResult': assert isinstance(obj, dict) - app_install_nudge_responded = from_union([from_bool, from_none], obj.get("appInstallNudgeResponded")) app_tip_shown = from_union([from_bool, from_none], obj.get("appTipShown")) asked_setup_terminals = from_union([lambda x: from_list(from_str, x), from_none], obj.get("askedSetupTerminals")) auto_feedback_last_prompted_at = from_union([from_str, from_none], obj.get("autoFeedbackLastPromptedAt")) @@ -41640,12 +41839,10 @@ def from_dict(obj: Any) -> '_GlobalStateLoadResult': staff_update_channel_migration_at = from_union([from_str, from_none], obj.get("staffUpdateChannelMigrationAt")) suppress_init_folders = from_union([lambda x: from_list(from_str, x), from_none], obj.get("suppressInitFolders")) trusted_folders = from_union([lambda x: from_list(from_str, x), from_none], obj.get("trustedFolders")) - return _GlobalStateLoadResult(app_install_nudge_responded, app_tip_shown, asked_setup_terminals, auto_feedback_last_prompted_at, first_launch_at, installed_plugins, last_logged_in_user, logged_in_users, reasoning_summaries_cleanup_done, recent_model_ids, sandbox_credential_proxy_ca_declined, sandbox_onboarding_shown, staff, staff_github, staff_log_level_migration_at, staff_microsoft, staff_model_reset_at, staff_update_channel_migration_at, suppress_init_folders, trusted_folders) + return _GlobalStateLoadResult(app_tip_shown, asked_setup_terminals, auto_feedback_last_prompted_at, first_launch_at, installed_plugins, last_logged_in_user, logged_in_users, reasoning_summaries_cleanup_done, recent_model_ids, sandbox_credential_proxy_ca_declined, sandbox_onboarding_shown, staff, staff_github, staff_log_level_migration_at, staff_microsoft, staff_model_reset_at, staff_update_channel_migration_at, suppress_init_folders, trusted_folders) def to_dict(self) -> dict: result: dict = {} - if self.app_install_nudge_responded is not None: - result["appInstallNudgeResponded"] = from_union([from_bool, from_none], self.app_install_nudge_responded) if self.app_tip_shown is not None: result["appTipShown"] = from_union([from_bool, from_none], self.app_tip_shown) if self.asked_setup_terminals is not None: @@ -44343,7 +44540,7 @@ def from_dict(obj: Any) -> 'SessionUpdateOptionsParams': skip_custom_instructions = from_union([from_bool, from_none], obj.get("skipCustomInstructions")) skip_embedding_retrieval = from_union([from_bool, from_none], obj.get("skipEmbeddingRetrieval")) suppress_custom_agent_prompt = from_union([from_bool, from_none], obj.get("suppressCustomAgentPrompt")) - tool_filter_precedence = from_union([OptionsUpdateToolFilterPrecedence, from_none], obj.get("toolFilterPrecedence")) + tool_filter_precedence = from_union([from_none, OptionsUpdateToolFilterPrecedence], obj.get("toolFilterPrecedence")) trajectory_file = from_union([from_str, from_none], obj.get("trajectoryFile")) verbosity = from_union([Verbosity, from_none], obj.get("verbosity")) working_directory = from_union([from_str, from_none], obj.get("workingDirectory")) @@ -44464,7 +44661,7 @@ def to_dict(self) -> dict: if self.suppress_custom_agent_prompt is not None: result["suppressCustomAgentPrompt"] = from_union([from_bool, from_none], self.suppress_custom_agent_prompt) if self.tool_filter_precedence is not None: - result["toolFilterPrecedence"] = from_union([lambda x: to_enum(OptionsUpdateToolFilterPrecedence, x), from_none], self.tool_filter_precedence) + result["toolFilterPrecedence"] = from_union([from_none, lambda x: to_enum(OptionsUpdateToolFilterPrecedence, x)], self.tool_filter_precedence) if self.trajectory_file is not None: result["trajectoryFile"] = from_union([from_str, from_none], self.trajectory_file) if self.verbosity is not None: @@ -46622,6 +46819,57 @@ def to_dict(self) -> dict: result["transport"] = self.transport return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class MCPRegistrySearchRequest: + """Registry search terms, the credential to search under, and the request id that makes the + search cancellable. + """ + auth_info: Any + """The credential the search runs under, carried opaquely. Hosts usually send + credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a + token, while `env` and `gh-cli` identities can use a token embedded in the request first. + """ + limit: int + """Maximum number of servers to return.""" + + request_id: int + """Request ID from `mcp.registry.allocateRequestId`. The search refuses unknown, reclaimed, + or canceled IDs and IDs that another search or request already uses. + """ + query: str | None = None + """Free-text query. Omitted or empty asks the registry for its top servers rather than + searching. A value that is not a string is refused. + """ + repository: str | None = None + """Repository used for the policy lookup, as `owner/name`. The policy selects the registry + URL and whether the user token goes to the registry. The registry receives this + repository only when the policy entry lists it as required context. A value that is not a + string is refused. + """ + + @staticmethod + def from_dict(obj: Any) -> 'MCPRegistrySearchRequest': + assert isinstance(obj, dict) + auth_info = obj.get("authInfo") + limit = from_int(obj.get("limit")) + request_id = from_int(obj.get("requestId")) + query = from_union([from_str, from_none], obj.get("query")) + repository = from_union([from_str, from_none], obj.get("repository")) + return MCPRegistrySearchRequest(auth_info, limit, request_id, query, repository) + + def to_dict(self) -> dict: + result: dict = {} + result["authInfo"] = self.auth_info + result["limit"] = from_int(self.limit) + result["requestId"] = from_int(self.request_id) + if self.query is not None: + result["query"] = from_union([from_str, from_none], self.query) + if self.repository is not None: + result["repository"] = from_union([from_str, from_none], self.repository) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class MCPServerConfig: @@ -50576,6 +50824,11 @@ class RPC: mcp_prompts_list_request: MCPPromptsListRequest mcp_prompts_list_result: MCPPromptsListResult mcp_register_external_client_request: MCPRegisterExternalClientRequest + mcp_registry_cancel_request: MCPRegistryCancelRequest + mcp_registry_cancel_result: MCPRegistryCancelResult + mcp_registry_request_id_result: MCPRegistryRequestIDResult + mcp_registry_search_request: MCPRegistrySearchRequest + mcp_registry_search_result: MCPRegistrySearchResult mcp_reload_config: MCPReloadConfig mcp_reload_with_config_request: MCPReloadWithConfigRequest mcp_remove_git_hub_result: MCPRemoveGitHubResult @@ -50621,6 +50874,8 @@ class RPC: mcp_set_env_value_mode_details: MCPSetEnvValueModeDetails mcp_set_env_value_mode_params: MCPSetEnvValueModeParams mcp_set_env_value_mode_result: MCPSetEnvValueModeResult + mcp_should_exclude_git_hub_tools_request: MCPShouldExcludeGitHubToolsRequest + mcp_should_exclude_git_hub_tools_result: MCPShouldExcludeGitHubToolsResult mcp_source_file: MCPSourceFile mcp_source_plugin: MCPSourcePlugin mcp_source_ref: MCPSourceRef @@ -50995,6 +51250,8 @@ class RPC: sandbox_config_user_policy_network_proxy: SandboxConfigUserPolicyNetworkProxy sandbox_config_user_policy_seatbelt: SandboxConfigUserPolicySeatbelt sandbox_credentials_config: SandboxCredentialsConfig + sandbox_credential_suggestion: SandboxCredentialSuggestion + sandbox_credential_suggestions_result: SandboxCredentialSuggestionsResult sandbox_disable_for_session_request: SandboxDisableForSessionRequest sandbox_disable_for_session_result: SandboxDisableForSessionResult sandbox_enforcement_status: SandboxEnforcementStatus @@ -52182,6 +52439,11 @@ def from_dict(obj: Any) -> 'RPC': mcp_prompts_list_request = MCPPromptsListRequest.from_dict(obj.get("McpPromptsListRequest")) mcp_prompts_list_result = MCPPromptsListResult.from_dict(obj.get("McpPromptsListResult")) mcp_register_external_client_request = MCPRegisterExternalClientRequest.from_dict(obj.get("McpRegisterExternalClientRequest")) + mcp_registry_cancel_request = MCPRegistryCancelRequest.from_dict(obj.get("McpRegistryCancelRequest")) + mcp_registry_cancel_result = MCPRegistryCancelResult.from_dict(obj.get("McpRegistryCancelResult")) + mcp_registry_request_id_result = MCPRegistryRequestIDResult.from_dict(obj.get("McpRegistryRequestIdResult")) + mcp_registry_search_request = MCPRegistrySearchRequest.from_dict(obj.get("McpRegistrySearchRequest")) + mcp_registry_search_result = MCPRegistrySearchResult.from_dict(obj.get("McpRegistrySearchResult")) mcp_reload_config = MCPReloadConfig.from_dict(obj.get("McpReloadConfig")) mcp_reload_with_config_request = MCPReloadWithConfigRequest.from_dict(obj.get("McpReloadWithConfigRequest")) mcp_remove_git_hub_result = MCPRemoveGitHubResult.from_dict(obj.get("McpRemoveGitHubResult")) @@ -52227,6 +52489,8 @@ def from_dict(obj: Any) -> 'RPC': mcp_set_env_value_mode_details = MCPSetEnvValueModeDetails(obj.get("McpSetEnvValueModeDetails")) mcp_set_env_value_mode_params = MCPSetEnvValueModeParams.from_dict(obj.get("McpSetEnvValueModeParams")) mcp_set_env_value_mode_result = MCPSetEnvValueModeResult.from_dict(obj.get("McpSetEnvValueModeResult")) + mcp_should_exclude_git_hub_tools_request = MCPShouldExcludeGitHubToolsRequest.from_dict(obj.get("McpShouldExcludeGitHubToolsRequest")) + mcp_should_exclude_git_hub_tools_result = MCPShouldExcludeGitHubToolsResult.from_dict(obj.get("McpShouldExcludeGitHubToolsResult")) mcp_source_file = MCPSourceFile.from_dict(obj.get("McpSourceFile")) mcp_source_plugin = MCPSourcePlugin.from_dict(obj.get("McpSourcePlugin")) mcp_source_ref = MCPSourceRef.from_dict(obj.get("McpSourceRef")) @@ -52601,6 +52865,8 @@ def from_dict(obj: Any) -> 'RPC': sandbox_config_user_policy_network_proxy = SandboxConfigUserPolicyNetworkProxy.from_dict(obj.get("SandboxConfigUserPolicyNetworkProxy")) sandbox_config_user_policy_seatbelt = SandboxConfigUserPolicySeatbelt.from_dict(obj.get("SandboxConfigUserPolicySeatbelt")) sandbox_credentials_config = SandboxCredentialsConfig.from_dict(obj.get("SandboxCredentialsConfig")) + sandbox_credential_suggestion = SandboxCredentialSuggestion.from_dict(obj.get("SandboxCredentialSuggestion")) + sandbox_credential_suggestions_result = SandboxCredentialSuggestionsResult.from_dict(obj.get("SandboxCredentialSuggestionsResult")) sandbox_disable_for_session_request = SandboxDisableForSessionRequest.from_dict(obj.get("SandboxDisableForSessionRequest")) sandbox_disable_for_session_result = SandboxDisableForSessionResult.from_dict(obj.get("SandboxDisableForSessionResult")) sandbox_enforcement_status = SandboxEnforcementStatus.from_dict(obj.get("SandboxEnforcementStatus")) @@ -53122,7 +53388,7 @@ def from_dict(obj: Any) -> 'RPC': subagent_settings = from_union([SubagentSettings.from_dict, from_none], obj.get("SubagentSettings")) task_progress = from_union([TaskProgress.from_dict, from_none], obj.get("TaskProgress")) workspace_summary = from_union([WorkspaceSummary.from_dict, from_none], obj.get("WorkspaceSummary")) - return RPC(abort_request, abort_result, accepted_enqueue_command_result, account_all_users, account_auth_info, account_get_all_users_result, account_get_current_auth_result, account_get_quota_request, account_get_quota_result, account_kind, account_login_request, account_login_result, account_logout_request, account_logout_result, account_quota_snapshot, accounts_enumerate_request, accounts_get_request, accounts_set_request, account_status, adaptive_thinking_support, agent_discovery_path, agent_discovery_path_list, agent_discovery_path_scope, agent_get_current_result, agent_info, agent_info_source, agent_list, agent_list_request, agent_registry_live_target_entry, agent_registry_live_target_entry_attention_kind, agent_registry_live_target_entry_kind, agent_registry_live_target_entry_last_terminal_event, agent_registry_live_target_entry_status, agent_registry_log_capture, agent_registry_log_capture_open_error_reason, agent_registry_spawn_error, agent_registry_spawn_permission_mode, agent_registry_spawn_registry_timeout, agent_registry_spawn_request, agent_registry_spawn_result, agent_registry_spawn_spawned, agent_registry_spawn_validation_error, agent_registry_spawn_validation_error_field, agent_registry_spawn_validation_error_reason, agent_reload_result, agents_custom_agent_initial_model_decision_params, agents_custom_agent_initial_model_decision_result, agents_discover_request, agent_select_request, agent_select_result, agent_set_prompt_request, agents_get_available_builtins_request, agents_get_available_builtins_result, agents_get_builtin_definition_request, agents_get_builtin_definition_result, agents_get_builtin_listing_definition_request, agents_get_builtin_listing_definition_result, agents_get_builtins_result, agents_get_discovery_paths_request, api_key_auth_info, auth_enumerate_query, auth_enumerate_value, auth_identity, auth_identity_metadata, auth_info, auth_info_type, auth_login_account, auth_login_advance_request, auth_login_begin_request, auth_login_begun, auth_login_cancel_request, auth_login_result_dto, auth_login_result_status, auth_login_step, auth_read_query, auth_read_value, auth_status_dto, auth_validation_error, auth_validation_errors, auth_write, auth_write_result, autopilot_objective_credit_limit, autopilot_objective_get_state_result, autopilot_objective_state, autopilot_objective_status, auto_tier_descriptor, auto_tier_metadata, auto_tier_status, builtin_agent_summary, built_in_model_catalog, built_in_model_catalog_entry, builtin_tool_descriptor, builtin_tool_format, builtin_tool_format_type, builtin_tool_input_schema, builtin_tool_input_schema_type, builtin_tool_safe_for_telemetry, builtin_tool_safe_telemetry_fields, cancel_user_requested_shell_command_result, canvas_action, canvas_action_invoke_request, canvas_action_invoke_result, canvas_close_request, canvas_host_context, canvas_host_context_capabilities, canvas_json_schema, canvas_list, canvas_list_open_result, canvas_open_request, canvas_provider_close_request, canvas_provider_invoke_action_request, canvas_provider_open_request, canvas_provider_open_result, canvas_provider_register_request, canvas_provider_unregister_request, canvas_session_context, capi_session_options, card_digest, card_digest_algorithm, card_digest_value, catalog_agent_plugin_candidate, catalog_agent_plugin_candidate_kind, catalog_agent_plugin_candidate_provenance, catalog_agent_plugin_compatibility_tag, catalog_agent_plugin_media_type, catalog_ai_skill_candidate, catalog_ai_skill_candidate_kind, catalog_ai_skill_candidate_provenance, catalog_ai_skill_installability, catalog_ai_skill_media_type, catalog_authentication_required_error, catalog_authentication_required_reason, catalog_candidate, catalog_candidate_kind, catalog_candidate_source, catalog_candidate_source_embedded, catalog_candidate_source_url, catalog_capability, catalog_capability_id, catalog_client_contract, catalog_contract_violation_error, catalog_contract_violation_reason, catalog_handle_rejected_error, catalog_handle_rejection_reason, catalog_handle_type, catalog_invalid_request_error, catalog_invalid_request_field, catalog_malformed_card_error, catalog_malformed_card_reason, catalog_mcp_server_candidate, catalog_mcp_server_candidate_kind, catalog_mcp_server_candidate_provenance, catalog_mcp_server_installability, catalog_media_type, catalog_negotiated_contract, catalog_negotiation_refused_error, catalog_negotiation_refused_reason, catalog_network_failure_error, catalog_network_failure_reason, catalog_not_installable_error, catalog_not_installable_reason, catalog_plugin_repository_source, catalog_policy_rejected_error, catalog_resource_identity, catalog_resource_version, catalog_search_page, catalog_search_pagination, catalog_search_request, catalog_search_result, catalog_search_succeeded, catalog_search_total_count_relation, catalog_selection_cancelled, catalog_selection_decision, catalog_selection_declined, catalog_selection_foreign, catalog_selection_invalid, catalog_selection_replayed, catalog_selection_request, catalog_selection_result, catalog_selection_selected, catalog_selection_stale, catalog_selection_timed_out, catalog_selection_wrong_kind, catalog_trust_eligibility, catalog_trust_provenance, catalog_trust_snapshot, catalog_trust_snapshot_absent, catalog_trust_snapshot_absent_status, catalog_trust_snapshot_current, catalog_trust_snapshot_current_status, catalog_trust_snapshot_downgraded, catalog_trust_snapshot_downgraded_status, catalog_trust_snapshot_malformed, catalog_trust_snapshot_malformed_status, catalog_trust_snapshot_revoked, catalog_trust_snapshot_revoked_status, catalog_trust_snapshot_schema_version, catalog_trust_snapshot_stale, catalog_trust_snapshot_stale_status, catalog_trust_snapshot_unsupported, catalog_trust_snapshot_unsupported_status, catalog_trust_source, catalog_trust_tier, catalog_unavailable_error, catalog_unavailable_reason, catalog_unavailable_transport_error, catalog_unavailable_transport_reason, catalog_unsafe_retrieval_error, catalog_unsafe_retrieval_reason, catalog_unsupported_kind_error, client_metadata, client_task_cancel_reason, client_task_cancel_request, client_task_cancel_result, command_list, commands_finalize_invocation_effect_request, commands_finalize_invocation_effect_result, commands_handle_pending_command_request, commands_handle_pending_command_result, commands_invocation_effect_outcome, commands_invocation_origin, commands_invoke_request, commands_list_request, commands_respond_to_queued_command_request, commands_respond_to_queued_command_result, completions_get_trigger_characters_result, completions_request_request, completions_request_result, configure_session_extensions_params, connect_client_info, connected_remote_session_metadata, connected_remote_session_metadata_kind, connected_remote_session_metadata_repository, connector_account_request, connector_authorization_requirement, connector_authorization_scope, connector_availability, connector_capabilities, connector_catalog_entry, connector_catalog_result, connector_catalog_status, connector_connect_request, connector_connect_result, connector_continue_request, connector_disconnect_result, connector_discovery_account, connector_discovery_account_list, connector_discovery_account_request, connector_discovery_auth_info, connector_discovery_availability, connector_discovery_capabilities, connector_discovery_catalog_entry, connector_discovery_catalog_result, connector_mcp_status, connector_reconcile_request, connector_runtime_status, connector_session_account, connector_status, connect_remote_session_params, connect_request, connect_result, content_exclusion_check_paths_request, content_exclusion_check_paths_result, content_exclusion_path_check, content_filter_mode, context_heaviest_message, copilot_api_token_auth_info, copilot_user_response, copilot_user_response_endpoints, copilot_user_response_quota_snapshots, copilot_user_response_quota_snapshots_chat, copilot_user_response_quota_snapshots_completions, copilot_user_response_quota_snapshots_premium_interactions, current_model, current_tool_metadata, customization_reload_outcome, customization_reload_status, customization_reload_subsystem, customizations_reload_result, debug_collect_logs_collected_entry, debug_collect_logs_destination, debug_collect_logs_entry, debug_collect_logs_entry_kind, debug_collect_logs_include, debug_collect_logs_redaction, debug_collect_logs_request, debug_collect_logs_result, debug_collect_logs_result_kind, debug_collect_logs_skipped_entry, debug_collect_logs_source, diagnostic_cursor_status, diagnostic_entry, diagnostic_log_level, diagnostics_configuration, diagnostics_configure_request, diagnostic_severity, diagnostic_source, diagnostic_sources_configuration, diagnostics_read_request, diagnostics_read_result, discovered_canvas, discovered_extension, discovered_extension_mode, discovered_extension_plugin, discovered_extensions, discovered_extensions_disable_request, discovered_extensions_enable_request, discovered_extension_source, discovered_hook, discovered_mcp_server, discovered_mcp_server_type, discovered_model, discovered_model_list, enqueue_command_params, enqueue_command_result, env_auth_info, environment_capabilities, environment_kind, environments_delete_request, environments_delete_result, environments_get_request, environments_get_result, environments_list_request, environments_list_result, event_log_read_request, event_log_release_interest_result, event_log_tail_result, event_log_types, events_agent_scope, events_cursor_status, events_read_direction, events_read_result, execute_command_params, execute_command_result, extension, extension_context_push_input, extension_launch_profile, extension_launch_provider_resolve_request, extension_launch_provider_resolve_result, extension_list, extensions_disable_request, extensions_enable_request, extension_source, extension_status, external_tool_result, external_tool_text_result_for_llm, external_tool_text_result_for_llm_binary_results_for_llm, external_tool_text_result_for_llm_binary_results_for_llm_type, external_tool_text_result_for_llm_content, external_tool_text_result_for_llm_content_audio, external_tool_text_result_for_llm_content_image, external_tool_text_result_for_llm_content_resource, external_tool_text_result_for_llm_content_resource_details, external_tool_text_result_for_llm_content_resource_link, external_tool_text_result_for_llm_content_resource_link_icon, external_tool_text_result_for_llm_content_resource_link_icon_theme, external_tool_text_result_for_llm_content_shell_exit, external_tool_text_result_for_llm_content_terminal, external_tool_text_result_for_llm_content_text, filter_mapping, fleet_start_request, fleet_start_result, folder_trust_add_params, folder_trust_check_params, folder_trust_check_result, gh_cli_auth_info, git_current_branch_remote_result, git_cwd_request, git_hub_environment, git_hub_owner_option, git_hub_owners_cancel_request, git_hub_owners_cancel_result, git_hub_owners_list_request, git_hub_owners_list_result, git_hub_owners_request_id_result, git_hub_repository_at_path_request, git_hub_repository_at_path_result, git_hub_repository_identity, git_hub_telemetry_client_info, git_hub_telemetry_event, git_hub_telemetry_notification, git_hub_token_acquire_reason, git_hub_token_acquire_request, git_hub_token_acquire_result, git_remote_repository, git_repos_from_remotes_request, git_repos_from_remotes_result, global_state_load_for_config_dir_request, global_state_load_result, global_state_write_key_request, handle_pending_tool_call_request, handle_pending_tool_call_result, history_abort_manual_compaction_result, history_cancel_background_compaction_result, history_clear_context_request, history_clear_context_result, history_compact_context_window, history_compact_request, history_compact_result, history_file_restore_skip_reason, history_list_rewind_points_result, history_preview_rewind_request, history_preview_rewind_result, history_rewind_change_type, history_rewind_file_preview, history_rewind_mode, history_rewind_outcome, history_rewind_point, history_rewind_request, history_rewind_result, history_rewind_unavailable_reason, history_skipped_file_restore, history_summarize_for_handoff_result, history_truncate_request, history_truncate_result, hmac_auth_info, hook_invoke_request, hook_invoke_response, hook_origin, hooks_discover_request, hooks_discover_result, hook_type, host_configuration, host_dispose_request, host_empty_result, host_environment_credentials, host_exited_notification, host_exit_reason, host_git_hub_environment_options, host_list_sessions_request, host_list_sessions_result, host_local_server_configuration, host_local_server_options, host_publish_session_request, host_publish_session_result, host_ready_request, host_register_session_request, host_session_create_callback, host_session_create_request, host_session_create_result, host_session_released_notification, host_session_release_request, host_session_summary, host_start_request, host_start_result, installation_catalogue_identity, installation_confirmation_request, installation_confirmation_response, installation_decision, installation_review, installed_plugin, installed_plugin_info, installed_plugin_source, installed_plugin_source_git_hub, installed_plugin_source_local, installed_plugin_source_url, instruction_discovery_path, instruction_discovery_path_kind, instruction_discovery_path_list, instruction_discovery_path_location, instructions_discover_request, instructions_get_discovery_paths_request, instructions_get_sources_result, instruction_source, instruction_source_location, instruction_source_type, interrupt_main_turn_request, interrupt_main_turn_result, json_schema_response_format, llm_inference_headers, llm_inference_http_request_chunk_request, llm_inference_http_request_chunk_result, llm_inference_http_request_start_request, llm_inference_http_request_start_result, llm_inference_http_request_start_transport, llm_inference_http_response_chunk_error, llm_inference_http_response_chunk_request, llm_inference_http_response_chunk_result, llm_inference_http_response_start_request, llm_inference_http_response_start_result, llm_inference_set_provider_result, local_session_metadata_value, logged_in_user, login_provider_kind, log_request, log_result, lsp_initialize_request, managed_mcp_server_config, managed_permission_evaluation, managed_permission_operation, managed_permission_operation_kind, managed_permissions_evaluate_request, managed_permissions_evaluate_result, managed_permission_verdict, managed_plugin_retry_entry, managed_plugin_retry_status, managed_setting_meta, managed_settings_channel, managed_settings_compose_layer, managed_settings_compose_request, managed_settings_compose_result, managed_settings_diagnostic, managed_settings_diagnostic_severity, managed_settings_layer, managed_settings_meta, managed_settings_read_result, managed_settings_resolved_data, managed_settings_resolve_request, managed_settings_resolve_result, managed_settings_schema_result, managed_settings_validate_request, managed_settings_validate_result, managed_settings_values, marketplace_add_result, marketplace_browse_result, marketplace_info, marketplace_list_result, marketplace_plugin_info, marketplace_refresh_entry, marketplace_refresh_result, marketplace_remove_result, mcp_allowed_server, mcp_apply_install_request, mcp_apply_uninstall_request, mcp_apps_call_tool_request, mcp_apps_diagnose_capability, mcp_apps_diagnose_request, mcp_apps_diagnose_result, mcp_apps_diagnose_server, mcp_apps_host_context, mcp_apps_host_context_details, mcp_apps_host_context_details_available_display_mode, mcp_apps_host_context_details_display_mode, mcp_apps_host_context_details_platform, mcp_apps_host_context_details_theme, mcp_apps_list_tools_request, mcp_apps_list_tools_result, mcp_apps_read_resource_request, mcp_apps_read_resource_result, mcp_apps_resource_content, mcp_apps_set_host_context_details, mcp_apps_set_host_context_details_available_display_mode, mcp_apps_set_host_context_details_display_mode, mcp_apps_set_host_context_details_platform, mcp_apps_set_host_context_details_theme, mcp_apps_set_host_context_request, mcp_cancel_sampling_execution_params, mcp_cancel_sampling_execution_result, mcp_config_add_request, mcp_config_disable_request, mcp_config_enable_request, mcp_config_list, mcp_config_remove_request, mcp_config_update_request, mcp_configured_server, mcp_configured_server_list, mcp_configured_server_state, mcp_configure_git_hub_request, mcp_configure_git_hub_result, mcp_diagnostic_details, mcp_diagnostic_direction, mcp_diagnostic_kind, mcp_diagnostic_source_configuration, mcp_disable_request, mcp_discover_request, mcp_discover_result, mcp_elicitation_form_mode, mcp_enable_request, mcp_execute_sampling_params, mcp_execute_sampling_request, mcp_execute_sampling_result, mcp_failed_server, mcp_filtered_server, mcp_headers_handle_pending_headers_refresh_request, mcp_headers_handle_pending_headers_refresh_request_request, mcp_headers_handle_pending_headers_refresh_request_result, mcp_host_state, mcp_installation_failure_reason, mcp_installation_input, mcp_installation_management_outcome, mcp_installation_management_result, mcp_installation_operation_request, mcp_installation_operation_status, mcp_installation_outcome, mcp_installation_remote_configuration, mcp_installation_result, mcp_installation_review, mcp_installation_secret, mcp_installation_secret_storage, mcp_installations_request, mcp_installation_state, mcp_installation_summary, mcp_install_plan, mcp_is_server_running_request, mcp_is_server_running_result, mcp_list_tools_request, mcp_list_tools_result, mcp_oauth_authentication_state_changed_request, mcp_oauth_cancel_login_request, mcp_oauth_cancel_login_result, mcp_oauth_complete_request, mcp_oauth_handle_pending_request, mcp_oauth_handle_pending_result, mcp_oauth_login_grant_type, mcp_oauth_login_request, mcp_oauth_login_result, mcp_oauth_pending_request_response, mcp_oauth_prepare_login_request, mcp_oauth_prepare_login_result, mcp_oauth_probe_needs_auth_reason, mcp_oauth_probe_request, mcp_oauth_probe_result, mcp_oauth_respond_request, mcp_oauth_respond_result, mcp_owned_oauth_login_status, mcp_plan_configuration_change, mcp_plan_configuration_operation, mcp_plan_enum_value_type, mcp_plan_install_planned, mcp_plan_install_request, mcp_plan_install_result, mcp_plan_install_source, mcp_plan_install_source_candidate, mcp_plan_install_source_candidate_kind, mcp_plan_install_source_card, mcp_plan_install_source_card_kind, mcp_plan_package_install_method, mcp_plan_package_transport, mcp_plan_policy_decision, mcp_plan_policy_result, mcp_plan_policy_source, mcp_plan_provenance, mcp_plan_remote_install_method, mcp_plan_remote_transport, mcp_plan_required_value, mcp_plan_required_value_enum, mcp_plan_required_value_enum_kind, mcp_plan_required_value_scalar, mcp_plan_required_value_scalar_kind, mcp_plan_resource_identity, mcp_plan_scalar_value_type, mcp_plan_scope, mcp_plan_secret_placeholder, mcp_plan_secret_reference, mcp_plan_target, mcp_plan_transport_choice, mcp_plan_transport_choice_package, mcp_plan_transport_choice_remote, mcp_plan_uninstall_request, mcp_plan_value_category, mcp_prepared_install, mcp_prepare_install_request, mcp_prompt, mcp_prompt_argument, mcp_prompt_icon, mcp_prompt_message, mcp_prompt_role, mcp_prompts_get_request, mcp_prompts_get_result, mcp_prompts_list_request, mcp_prompts_list_result, mcp_register_external_client_request, mcp_reload_config, mcp_reload_with_config_request, mcp_remove_git_hub_result, mcp_resource, mcp_resource_annotations, mcp_resource_content, mcp_resource_icon, mcp_resources_list_request, mcp_resources_list_result, mcp_resources_list_templates_request, mcp_resources_list_templates_result, mcp_resources_read_request, mcp_resources_read_result, mcp_resource_template, mcp_restart_server_request, mcp_safe_for_telemetry, mcp_safe_for_telemetry_fields, mcp_sampling_execution_action, mcp_sampling_execution_result, mcp_serializable_server_config, mcp_server, mcp_server_auth_config, mcp_server_auth_config_redirect_port, mcp_server_card_embedded, mcp_server_card_embedded_kind, mcp_server_card_media_type, mcp_server_card_reference, mcp_server_card_url, mcp_server_card_url_kind, mcp_server_config, mcp_server_config_defer_tools, mcp_server_config_http, mcp_server_config_http_oauth_grant_type, mcp_server_config_http_type, mcp_server_config_memory, mcp_server_config_memory_type, mcp_server_config_stdio, mcp_server_config_stdio_type, mcp_server_failure_info, mcp_server_list, mcp_server_needs_auth_info, mcp_server_ownership, mcp_set_env_value_mode_details, mcp_set_env_value_mode_params, mcp_set_env_value_mode_result, mcp_source_file, mcp_source_plugin, mcp_source_ref, mcp_start_server_request, mcp_start_servers_result, mcp_stop_server_request, mcp_task_metadata, mcp_tools, mcp_tool_ui, mcp_tool_ui_visibility, mcp_uninstall_plan, mcp_unregister_external_client_request, memory_configuration, metadata_context_attribution_result, metadata_context_heaviest_messages_request, metadata_context_heaviest_messages_result, metadata_context_info_request, metadata_context_info_result, metadata_is_processing_result, metadata_recompute_context_tokens_request, metadata_recompute_context_tokens_result, metadata_record_context_change_request, metadata_record_context_change_result, metadata_set_working_directory_request, metadata_set_working_directory_result, metadata_snapshot_current_mode, metadata_snapshot_remote_metadata, metadata_snapshot_remote_metadata_repository, metadata_snapshot_remote_metadata_task_type, metadata_update_client_metadata_request, model, model_apply_startup_overlay_request, model_artifact_details, model_billing, model_billing_promo, model_billing_token_prices, model_billing_token_prices_long_context, model_capabilities, model_capabilities_limits, model_capabilities_limits_vision, model_capabilities_override, model_capabilities_override_limits, model_capabilities_override_limits_vision, model_capabilities_override_supports, model_capabilities_supports, model_clear_startup_seed_request, model_clear_startup_seed_result, model_list, model_list_request, model_message, model_picker_category, model_picker_persistence_request, model_picker_price_category, model_picker_settings_context, model_policy, model_policy_state, model_provider_adapter_catalog, model_provider_adapter_descriptor, model_provider_adapter_operation_descriptor, model_provider_attribution, model_provider_automatic_discovery_mode, model_provider_automatic_discovery_policy, model_provider_configuration_disposition, model_provider_configuration_plan, model_provider_descriptor, model_provider_discover_request, model_provider_discover_result, model_provider_discovery_network_scope, model_provider_get_status_request, model_provider_instance, model_provider_instance_reference, model_provider_models_list_request, model_provider_operation_outcome, model_provider_operation_outcome_code, model_provider_prepare_configuration_request, model_provider_provenance, model_provider_provenance_source, model_provider_status, model_provider_warning, model_set_allowed_models_request, model_set_allowed_models_result, model_set_reasoning_effort_request, model_set_reasoning_effort_result, models_list_request, model_switch_auto_tier_request, model_switch_auto_tier_result, model_switch_auto_tier_status, model_switch_confirmation, model_switch_to_request, model_switch_to_result, model_warning_text, mode_set_request, mode_set_result, move_mcp_loading_to_background_result, named_provider_config, name_get_result, name_set_auto_request, name_set_auto_result, name_set_request, open_canvas_instance, options_update_additional_content_exclusion_policy, options_update_additional_content_exclusion_policy_rule, options_update_additional_content_exclusion_policy_rule_source, options_update_additional_content_exclusion_policy_scope, options_update_context_tier, options_update_env_value_mode, options_update_reasoning_summary, options_update_tool_filter_precedence, pending_external_tool_request, pending_external_tool_request_list, pending_permission_request, pending_permission_request_list, permission_decision, permission_decision_approved, permission_decision_approved_for_location, permission_decision_approved_for_session, permission_decision_approve_for_location, permission_decision_approve_for_location_approval, permission_decision_approve_for_location_approval_commands, permission_decision_approve_for_location_approval_custom_tool, permission_decision_approve_for_location_approval_extension_env_access, permission_decision_approve_for_location_approval_extension_management, permission_decision_approve_for_location_approval_extension_permission_access, permission_decision_approve_for_location_approval_mcp, permission_decision_approve_for_location_approval_mcp_sampling, permission_decision_approve_for_location_approval_memory, permission_decision_approve_for_location_approval_read, permission_decision_approve_for_location_approval_workflow, permission_decision_approve_for_location_approval_write, permission_decision_approve_for_session, permission_decision_approve_for_session_approval, permission_decision_approve_for_session_approval_commands, permission_decision_approve_for_session_approval_custom_tool, permission_decision_approve_for_session_approval_extension_env_access, permission_decision_approve_for_session_approval_extension_management, permission_decision_approve_for_session_approval_extension_permission_access, permission_decision_approve_for_session_approval_mcp, permission_decision_approve_for_session_approval_mcp_sampling, permission_decision_approve_for_session_approval_memory, permission_decision_approve_for_session_approval_read, permission_decision_approve_for_session_approval_workflow, permission_decision_approve_for_session_approval_write, permission_decision_approve_once, permission_decision_approve_permanently, permission_decision_approve_read_only_for_session, permission_decision_cancelled, permission_decision_context, permission_decision_denied_by_content_exclusion_policy, permission_decision_denied_by_permission_request_hook, permission_decision_denied_by_rules, permission_decision_denied_interactively_by_user, permission_decision_denied_no_approval_rule_and_could_not_request_from_user, permission_decision_outcome, permission_decision_reject, permission_decision_request, permission_decision_surface, permission_decision_user_not_available, permission_location_add_tool_approval_params, permission_location_apply_params, permission_location_apply_result, permission_location_resolve_params, permission_location_resolve_result, permission_location_type, permission_mode_source, permission_paths_add_params, permission_paths_allowed_check_params, permission_paths_allowed_check_result, permission_paths_config, permission_paths_list, permission_paths_update_primary_params, permission_paths_workspace_check_params, permission_paths_workspace_check_result, permission_prompt_shown_notification, permission_request_result, permission_response_capability, permission_rules_set, permissions_configure_additional_content_exclusion_policy, permissions_configure_additional_content_exclusion_policy_rule, permissions_configure_additional_content_exclusion_policy_rule_source, permissions_configure_additional_content_exclusion_policy_scope, permissions_configure_params, permissions_configure_result, permissions_folder_trust_add_trusted_result, permissions_get_mode_request, permissions_get_mode_result, permissions_locations_add_tool_approval_details, permissions_locations_add_tool_approval_details_commands, permissions_locations_add_tool_approval_details_custom_tool, permissions_locations_add_tool_approval_details_extension_env_access, permissions_locations_add_tool_approval_details_extension_management, permissions_locations_add_tool_approval_details_extension_permission_access, permissions_locations_add_tool_approval_details_mcp, permissions_locations_add_tool_approval_details_mcp_sampling, permissions_locations_add_tool_approval_details_memory, permissions_locations_add_tool_approval_details_read, permissions_locations_add_tool_approval_details_workflow, permissions_locations_add_tool_approval_details_write, permissions_locations_add_tool_approval_result, permissions_modify_rules_params, permissions_modify_rules_result, permissions_modify_rules_scope, permissions_notify_prompt_shown_result, permissions_paths_add_result, permissions_paths_list_request, permissions_paths_update_primary_result, permissions_pending_requests_request, permissions_reset_session_approvals_request, permissions_reset_session_approvals_result, permissions_set_approve_all_request, permissions_set_approve_all_result, permissions_set_approve_all_source, permissions_set_mode_request, permissions_set_mode_result, permissions_set_required_request, permissions_set_required_result, permissions_urls_set_unrestricted_mode_result, permission_urls_config, permission_urls_set_unrestricted_mode_params, ping_request, ping_result, plan_read_result, plan_read_sql_todos_result, plan_read_sql_todos_with_dependencies_result, plan_sql_todo_dependency, plan_sql_todos_row, plan_update_request, plugin, plugin_install_result, plugin_install_staging_mode, plugin_list, plugin_list_result, plugins_builtin_set_request, plugins_disable_request, plugins_enable_request, plugins_install_request, plugins_marketplaces_add_request, plugins_marketplaces_browse_request, plugins_marketplaces_refresh_request, plugins_marketplaces_remove_request, plugins_reload_request, plugins_uninstall_request, plugins_update_request, plugin_update_all_entry, plugin_update_all_result, plugin_update_result, protocol_append_mode, protocol_customize_mode, protocol_external_tool_defer, protocol_external_tool_definition, protocol_marker_section_override, protocol_replace_mode, protocol_section_override, protocol_static_section_action, protocol_static_section_override, protocol_system_message_append_config, protocol_system_message_config, protocol_system_message_customize_config, protocol_system_message_replace_config, provider_add_request, provider_add_result, provider_config, provider_config_azure, provider_config_model_provider, provider_config_transport, provider_config_type, provider_config_wire_api, provider_descriptor, provider_endpoint, provider_endpoint_transport, provider_endpoint_type, provider_endpoint_wire_api, provider_get_endpoint_request, provider_model_config, provider_session_token, provider_sync_request, provider_sync_result, provider_token_acquire_request, provider_token_acquire_result, provider_withdraw_request, provider_withdraw_result, push_attachment, push_attachment_blob, push_attachment_directory, push_attachment_file, push_attachment_file_line_range, push_attachment_git_hub_actions_job, push_attachment_git_hub_commit, push_attachment_git_hub_file, push_attachment_git_hub_file_diff, push_attachment_git_hub_file_diff_side, push_attachment_git_hub_reference, push_attachment_git_hub_reference_type, push_attachment_git_hub_release, push_attachment_git_hub_repository, push_attachment_git_hub_snippet, push_attachment_git_hub_tree_comparison, push_attachment_git_hub_tree_comparison_side, push_attachment_git_hub_url, push_attachment_selection, push_attachment_selection_details, push_attachment_selection_details_end, push_attachment_selection_details_start, push_git_hub_repo_ref, queue_append_steering_request, queue_begin_deferred_idle_drain_request, queue_begin_deferred_idle_drain_result, queue_consume_system_notifications_request, queued_command_handled, queued_command_not_handled, queued_command_result, queue_defer_session_idle_request, queue_duplicate_at_request, queue_duplicate_at_result, queue_enqueue_resume_pending_result, queue_finish_deferred_idle_drain_request, queue_finish_deferred_idle_drain_result, queue_has_pending_result, queue_insert_at_request, queue_insert_at_result, queue_insert_message, queue_move_item_request, queue_move_item_result, queue_pending_items, queue_pending_items_kind, queue_pending_items_result, queue_remove_at_request, queue_remove_at_result, queue_remove_most_recent_result, queue_send_now_request, queue_send_now_result, queue_set_drain_paused_request, queue_snapshot_result, queue_update_text_request, queue_update_text_result, queue_withdraw_message_request, queue_withdraw_message_result, quota_take_warnings_result, quota_warning_projection, register_event_interest_params, register_event_interest_result, release_event_interest_params, remote_control_config, remote_control_config_existing_mc_session, remote_control_status, remote_control_status_active, remote_control_status_connecting, remote_control_status_error, remote_control_status_off, remote_control_status_result, remote_control_stop_result, remote_control_transfer_result, remote_enable_request, remote_enable_result, remote_notify_steerable_changed_request, remote_notify_steerable_changed_result, remote_session_connection_result, remote_session_host_status, remote_session_metadata_repository, remote_session_metadata_task_type, remote_session_metadata_value, remote_session_mode, remote_session_repository, response_format, sandbox_config, sandbox_config_auth, sandbox_config_source, sandbox_config_user_policy, sandbox_config_user_policy_experimental, sandbox_config_user_policy_experimental_seatbelt, sandbox_config_user_policy_filesystem, sandbox_config_user_policy_network, sandbox_config_user_policy_network_proxy, sandbox_config_user_policy_seatbelt, sandbox_credentials_config, sandbox_disable_for_session_request, sandbox_disable_for_session_result, sandbox_enforcement_status, sandbox_grant_path_for_request_request, sandbox_grant_path_for_request_result, sandbox_host_capability, sandbox_host_capability_name, sandbox_host_support, sandbox_masked_env_var, sandbox_proxy_ca_create_result, sandbox_proxy_ca_request, sandbox_proxy_ca_state, sandbox_proxy_ca_status, sandbox_session_change, schedule_add_at_request, schedule_add_cron_request, schedule_add_request, schedule_add_result, schedule_add_self_paced_request, schedule_entry, schedule_has_self_paced_result, schedule_list, schedule_rearm_self_paced_request, schedule_stop_request, schedule_stop_result, secrets_add_filter_values_request, secrets_add_filter_values_result, send_agent_mode, send_attachments_to_message_params, send_message_item, send_messages_request, send_messages_result, send_mode, send_request, send_result, send_system_notification_request, server_agent_list, server_instruction_source_list, server_skill, server_skill_list, session_activity, session_agent_list_request, session_auth_login_request, session_auth_logout_user_request, session_auth_status, session_auth_switch_request, session_bulk_delete_result, session_cancel_all_background_agents_result, session_capability, session_commands_list_request, session_completion_item, session_connected_ide_info, session_context, session_context_host_type, session_enrich_metadata_result, session_fs_append_file_request, session_fs_error, session_fs_error_code, session_fs_exists_request, session_fs_exists_result, session_fs_mkdir_request, session_fs_readdir_request, session_fs_readdir_result, session_fs_readdir_with_types_entry, session_fs_readdir_with_types_entry_type, session_fs_readdir_with_types_request, session_fs_readdir_with_types_result, session_fs_read_file_bytes_request, session_fs_read_file_bytes_result, session_fs_read_file_request, session_fs_read_file_result, session_fs_rename_request, session_fs_rm_request, session_fs_set_provider_capabilities, session_fs_set_provider_conventions, session_fs_set_provider_request, session_fs_set_provider_result, session_fs_sqlite_exists_request, session_fs_sqlite_exists_result, session_fs_sqlite_query_request, session_fs_sqlite_query_result, session_fs_sqlite_query_type, session_fs_sqlite_transaction_error, session_fs_sqlite_transaction_error_class, session_fs_sqlite_transaction_request, session_fs_sqlite_transaction_result, session_fs_sqlite_transaction_statement, session_fs_stat_request, session_fs_stat_result, session_fs_write_file_bytes_request, session_fs_write_file_request, session_git_hub_auth_get_all_auth_available_result, session_git_hub_auth_logout_result, session_git_hub_auth_logout_user_result, session_history_compact_request, session_installed_plugin, session_installed_plugin_source, session_installed_plugin_source_git_hub, session_installed_plugin_source_local, session_installed_plugin_source_url, session_limit_prediction_baseline_data, session_limit_prediction_client_type, session_limit_prediction_details, session_limit_prediction_predict_request, session_limit_prediction_request, session_limit_prediction_result, session_limit_prediction_source, session_limit_prediction_tier, session_limit_prediction_tier_option, session_limit_prediction_unavailable_reason, session_list, session_list_entry, session_list_filter, session_load_deferred_repo_hooks_result, session_log_level, session_managed_permissions, session_managed_settings, session_mcp_apps_call_tool_result, session_mcp_oauth_cancel_login_request, session_mcp_oauth_cancel_login_result, session_mcp_oauth_prepare_login_request, session_mcp_oauth_prepare_login_result, session_mcp_set_connected_ide_info_params, session_metadata_snapshot, session_mode, session_model_clear_startup_seed_request, session_model_clear_startup_seed_result, session_model_list, session_model_list_request, session_model_price_category, session_open_options, session_open_options_additional_content_exclusion_policy, session_open_options_additional_content_exclusion_policy_rule, session_open_options_additional_content_exclusion_policy_rule_source, session_open_options_additional_content_exclusion_policy_scope, session_open_options_env_value_mode, session_open_options_reasoning_summary, session_open_params, session_open_result, session_plugins_disable_request, session_plugins_enable_request, session_plugins_install_request, session_plugins_marketplaces_refresh_request, session_plugins_reload_request, session_plugins_retry_managed_request, session_plugins_retry_managed_result, session_provider_get_endpoint_request, session_prune_result, session_quota_delegate_warning, session_quota_get_result, session_quota_plan_tier, session_quota_projection, session_quota_refresh_result, session_quota_snapshot, session_quota_take_warnings_result, sessions_bulk_delete_request, sessions_check_in_use_request, sessions_check_in_use_result, sessions_client_metadata_entry, sessions_close_request, sessions_close_result, sessions_create_workspace_request, sessions_create_workspace_result, sessions_delete_request, sessions_enrich_metadata_request, session_set_credentials_params, session_set_credentials_result, session_settings_built_in_tool_availability_snapshot, session_settings_evaluate_predicate_request, session_settings_evaluate_predicate_result, session_settings_job_snapshot, session_settings_model_snapshot, session_settings_online_evaluation_snapshot, session_settings_predicate_name, session_settings_repo_snapshot, session_settings_snapshot, session_settings_validation_snapshot, sessions_find_by_prefix_request, sessions_find_by_prefix_result, sessions_find_by_task_id_request, sessions_find_by_task_id_result, sessions_fork_request, sessions_fork_result, sessions_get_board_entry_count_request, sessions_get_board_entry_count_result, sessions_get_client_metadata_request, sessions_get_client_metadata_result, sessions_get_event_file_path_request, sessions_get_event_file_path_result, sessions_get_last_for_context_request, sessions_get_last_for_context_result, sessions_get_metadata_request, sessions_get_metadata_result, sessions_get_persisted_remote_steerable_request, sessions_get_persisted_remote_steerable_result, session_sizes, sessions_list_non_empty_session_ids_request, sessions_list_non_empty_session_ids_result, sessions_list_request, sessions_load_deferred_repo_hooks_request, sessions_load_workspace_request, sessions_load_workspace_result, sessions_open_attach, sessions_open_cloud, sessions_open_create, sessions_open_handoff, sessions_open_handoff_task_type, sessions_open_progress, sessions_open_progress_status, sessions_open_progress_step, sessions_open_remote, sessions_open_resume, sessions_open_resume_last, sessions_open_status, session_source, sessions_prune_old_request, sessions_read_persisted_events_request, sessions_release_lock_request, sessions_release_lock_result, sessions_reload_plugin_hooks_request, sessions_reload_plugin_hooks_result, sessions_save_request, sessions_save_result, sessions_set_additional_plugins_request, sessions_set_additional_plugins_result, sessions_set_remote_control_steering_request, sessions_start_remote_control_request, sessions_stop_remote_control_request, sessions_transfer_remote_control_request, sessions_update_workspace_fields_request, sessions_update_workspace_fields_result, session_telemetry_engagement, session_update_options_params, session_update_options_result, session_usage_set_code_changes_request, session_visibility_status, session_workflow_pause_at_checkpoint_result, session_working_directory_context, session_working_directory_context_host_type, session_working_directory_context_with_client, settable_auth_info, settable_token_auth_info, shell_cancel_user_requested_request, shell_credentials, shell_exec_request, shell_exec_result, shell_execute_user_requested_request, shell_init_profile, shell_init_script, shell_init_script_shell, shell_kill_request, shell_kill_result, shell_kill_signal, shell_options, shutdown_request, skill, skill_apply_install_request, skill_apply_uninstall_request, skill_discovery_path, skill_discovery_path_list, skill_discovery_scope, skill_installation_failure_reason, skill_installation_file_review, skill_installation_location, skill_installation_management_outcome, skill_installation_management_result, skill_installation_operation_request, skill_installation_operation_status, skill_installation_outcome, skill_installation_ownership_state, skill_installation_result, skill_installation_review, skill_installation_scope, skill_installation_session_state, skill_installation_source, skill_installations_request, skill_installation_summary, skill_install_plan, skill_list, skill_plan_install_request, skill_plan_uninstall_request, skill_provider_descriptor, skill_provider_list_request, skill_provider_list_result, skill_provider_read_request, skill_provider_read_result, skills_config_set_disabled_skills_request, skills_config_set_skill_disabled_request, skills_disable_request, skills_discover_request, skills_enable_request, skill_set_enabled_request, skills_get_discovery_paths_request, skills_get_invoked_result, skills_invoked_skill, skills_load_diagnostics, skill_uninstall_plan, slash_command_add_timeline_entry_result, slash_command_agent_prompt_result, slash_command_completed_result, slash_command_info, slash_command_input, slash_command_input_choice, slash_command_input_completion, slash_command_invocation_result, slash_command_kind, slash_command_model_picker_dialog, slash_command_select_subcommand_option, slash_command_select_subcommand_result, slash_command_set_model_result, slash_command_set_plan_model_result, slash_command_show_dialog_result, slash_command_text_result, slash_command_timeline_entry, subagent_settings_entry, subagent_settings_entry_context_tier, system_message_block, task_agent_info, task_agent_progress, task_client_active_status, task_client_execution_mode, task_client_info, task_client_owner, task_client_owner_kind, task_client_owner_presence, task_client_progress, task_client_status, task_client_type, task_client_update, task_complete_data, task_completion_decision, task_execution_mode, task_info, task_kind, task_list, task_progress_line, tasks_cancel_request, tasks_cancel_result, tasks_get_current_promotable_result, tasks_get_progress_request, tasks_get_progress_result, task_shell_info, task_shell_info_attachment_mode, task_shell_progress, tasks_promote_current_to_background_result, tasks_promote_to_background_request, tasks_promote_to_background_result, tasks_refresh_result, tasks_register_request, tasks_register_result, tasks_remove_request, tasks_remove_result, tasks_send_message_request, tasks_send_message_result, tasks_start_agent_request, tasks_start_agent_result, task_status, tasks_update_request, tasks_update_result, tasks_wait_for_pending_result, telemetry_set_feature_overrides_request, token_auth_info, token_provider_auth_info, tool, tool_list, tool_result, tool_result_expanded, tool_result_new_message, tool_result_type, tools_execute_request, tools_get_builtin_descriptors_request, tools_get_builtin_descriptors_result, tools_get_current_metadata_result, tools_initialize_and_validate_result, tools_list_pending_requests_request, tools_list_request, tools_set_request, tools_set_result, tools_shell_descriptor_config, tools_task_complete_event_data_request, tools_update_subagent_settings_result, ui_auto_mode_switch_response, ui_elicitation_array_any_of_field, ui_elicitation_array_any_of_field_items, ui_elicitation_array_any_of_field_items_any_of, ui_elicitation_array_enum_field, ui_elicitation_array_enum_field_items, ui_elicitation_field_value, ui_elicitation_request, ui_elicitation_response, ui_elicitation_response_action, ui_elicitation_response_content, ui_elicitation_result, ui_elicitation_schema, ui_elicitation_schema_property, ui_elicitation_schema_property_boolean, ui_elicitation_schema_property_number, ui_elicitation_schema_property_number_type, ui_elicitation_schema_property_string, ui_elicitation_schema_property_string_format, ui_elicitation_string_enum_field, ui_elicitation_string_one_of_field, ui_elicitation_string_one_of_field_one_of, ui_ephemeral_query_request, ui_ephemeral_query_result, ui_exit_plan_mode_action, ui_exit_plan_mode_response, ui_handle_pending_auto_mode_switch_request, ui_handle_pending_elicitation_request, ui_handle_pending_exit_plan_mode_request, ui_handle_pending_result, ui_handle_pending_sampling_request, ui_handle_pending_sampling_response, ui_handle_pending_session_limits_exhausted_request, ui_handle_pending_user_input_request, ui_register_direct_auto_mode_switch_handler_result, ui_session_limits_exhausted_response, ui_session_limits_exhausted_response_action, ui_unregister_direct_auto_mode_switch_handler_request, ui_unregister_direct_auto_mode_switch_handler_result, ui_user_input_response, unsupported_enqueue_command_result, update_subagent_settings_request, usage_get_metrics_result, usage_set_code_changes_request, user_auth_info, user_requested_shell_command_result, user_setting_metadata, user_settings_get_result, user_settings_set_request, visibility_get_result, visibility_set_request, visibility_set_result, workflow_abort_request, workflow_ack_result, workflow_agent_options, workflow_agent_request, workflow_agent_result, workflow_agent_summary, workflow_cancel_request, workflow_current_phase, workflow_declared_limits, workflow_durable_operation, workflow_execute_request, workflow_execute_result, workflow_get_run_progress_request, workflow_get_run_request, workflow_journal_get_request, workflow_journal_get_result, workflow_journal_put_request, workflow_list_runs_request, workflow_list_runs_result, workflow_log_line, workflow_log_line_kind, workflow_log_request, workflow_pause_checkpoint_action, workflow_pause_checkpoint_request, workflow_pause_checkpoint_result, workflow_pause_info, workflow_pause_request, workflow_phase_observation, workflow_phase_status, workflow_progress_line, workflow_progress_page, workflow_resume_request, workflow_resume_result, workflow_run_consumed, workflow_run_detail, workflow_run_failure, workflow_run_failure_kind, workflow_run_limits, workflow_run_options, workflow_run_request, workflow_run_result, workflow_run_status, workflow_run_summary, workflow_run_terminal, workflow_tool_resume_request, workflow_tool_run_options, workflow_tool_run_request, workspace_diff_contents, workspace_diff_file_change, workspace_diff_file_change_type, workspace_diff_mode, workspace_diff_result, workspaces_add_summary_request, workspaces_add_summary_result, workspaces_autopilot_objective_exists_result, workspaces_checkpoints, workspaces_create_directory_request, workspaces_create_file_request, workspaces_delete_autopilot_objective_result, workspaces_diff_request, workspaces_ensure_request, workspaces_get_workspace_result, workspaces_list_checkpoints_result, workspaces_list_files_result, workspaces_read_autopilot_objective_result, workspaces_read_checkpoint_request, workspaces_read_checkpoint_result, workspaces_read_file_request, workspaces_read_file_result, workspaces_remove_path_request, workspaces_rename_path_request, workspaces_save_large_paste_request, workspaces_save_large_paste_result, workspaces_stat_file_request, workspaces_stat_file_result, workspaces_truncate_summaries_request, workspace_summary_host_type, workspaces_update_metadata_request, workspaces_workspace_details_host_type, workspaces_write_autopilot_objective_request, workspaces_write_autopilot_objective_result, connector_session_account_result, session_auth_info_result, session_context_attribution, session_context_info, subagent_settings, task_progress, workspace_summary) + return RPC(abort_request, abort_result, accepted_enqueue_command_result, account_all_users, account_auth_info, account_get_all_users_result, account_get_current_auth_result, account_get_quota_request, account_get_quota_result, account_kind, account_login_request, account_login_result, account_logout_request, account_logout_result, account_quota_snapshot, accounts_enumerate_request, accounts_get_request, accounts_set_request, account_status, adaptive_thinking_support, agent_discovery_path, agent_discovery_path_list, agent_discovery_path_scope, agent_get_current_result, agent_info, agent_info_source, agent_list, agent_list_request, agent_registry_live_target_entry, agent_registry_live_target_entry_attention_kind, agent_registry_live_target_entry_kind, agent_registry_live_target_entry_last_terminal_event, agent_registry_live_target_entry_status, agent_registry_log_capture, agent_registry_log_capture_open_error_reason, agent_registry_spawn_error, agent_registry_spawn_permission_mode, agent_registry_spawn_registry_timeout, agent_registry_spawn_request, agent_registry_spawn_result, agent_registry_spawn_spawned, agent_registry_spawn_validation_error, agent_registry_spawn_validation_error_field, agent_registry_spawn_validation_error_reason, agent_reload_result, agents_custom_agent_initial_model_decision_params, agents_custom_agent_initial_model_decision_result, agents_discover_request, agent_select_request, agent_select_result, agent_set_prompt_request, agents_get_available_builtins_request, agents_get_available_builtins_result, agents_get_builtin_definition_request, agents_get_builtin_definition_result, agents_get_builtin_listing_definition_request, agents_get_builtin_listing_definition_result, agents_get_builtins_result, agents_get_discovery_paths_request, api_key_auth_info, auth_enumerate_query, auth_enumerate_value, auth_identity, auth_identity_metadata, auth_info, auth_info_type, auth_login_account, auth_login_advance_request, auth_login_begin_request, auth_login_begun, auth_login_cancel_request, auth_login_result_dto, auth_login_result_status, auth_login_step, auth_read_query, auth_read_value, auth_status_dto, auth_validation_error, auth_validation_errors, auth_write, auth_write_result, autopilot_objective_credit_limit, autopilot_objective_get_state_result, autopilot_objective_state, autopilot_objective_status, auto_tier_descriptor, auto_tier_metadata, auto_tier_status, builtin_agent_summary, built_in_model_catalog, built_in_model_catalog_entry, builtin_tool_descriptor, builtin_tool_format, builtin_tool_format_type, builtin_tool_input_schema, builtin_tool_input_schema_type, builtin_tool_safe_for_telemetry, builtin_tool_safe_telemetry_fields, cancel_user_requested_shell_command_result, canvas_action, canvas_action_invoke_request, canvas_action_invoke_result, canvas_close_request, canvas_host_context, canvas_host_context_capabilities, canvas_json_schema, canvas_list, canvas_list_open_result, canvas_open_request, canvas_provider_close_request, canvas_provider_invoke_action_request, canvas_provider_open_request, canvas_provider_open_result, canvas_provider_register_request, canvas_provider_unregister_request, canvas_session_context, capi_session_options, card_digest, card_digest_algorithm, card_digest_value, catalog_agent_plugin_candidate, catalog_agent_plugin_candidate_kind, catalog_agent_plugin_candidate_provenance, catalog_agent_plugin_compatibility_tag, catalog_agent_plugin_media_type, catalog_ai_skill_candidate, catalog_ai_skill_candidate_kind, catalog_ai_skill_candidate_provenance, catalog_ai_skill_installability, catalog_ai_skill_media_type, catalog_authentication_required_error, catalog_authentication_required_reason, catalog_candidate, catalog_candidate_kind, catalog_candidate_source, catalog_candidate_source_embedded, catalog_candidate_source_url, catalog_capability, catalog_capability_id, catalog_client_contract, catalog_contract_violation_error, catalog_contract_violation_reason, catalog_handle_rejected_error, catalog_handle_rejection_reason, catalog_handle_type, catalog_invalid_request_error, catalog_invalid_request_field, catalog_malformed_card_error, catalog_malformed_card_reason, catalog_mcp_server_candidate, catalog_mcp_server_candidate_kind, catalog_mcp_server_candidate_provenance, catalog_mcp_server_installability, catalog_media_type, catalog_negotiated_contract, catalog_negotiation_refused_error, catalog_negotiation_refused_reason, catalog_network_failure_error, catalog_network_failure_reason, catalog_not_installable_error, catalog_not_installable_reason, catalog_plugin_repository_source, catalog_policy_rejected_error, catalog_resource_identity, catalog_resource_version, catalog_search_page, catalog_search_pagination, catalog_search_request, catalog_search_result, catalog_search_succeeded, catalog_search_total_count_relation, catalog_selection_cancelled, catalog_selection_decision, catalog_selection_declined, catalog_selection_foreign, catalog_selection_invalid, catalog_selection_replayed, catalog_selection_request, catalog_selection_result, catalog_selection_selected, catalog_selection_stale, catalog_selection_timed_out, catalog_selection_wrong_kind, catalog_trust_eligibility, catalog_trust_provenance, catalog_trust_snapshot, catalog_trust_snapshot_absent, catalog_trust_snapshot_absent_status, catalog_trust_snapshot_current, catalog_trust_snapshot_current_status, catalog_trust_snapshot_downgraded, catalog_trust_snapshot_downgraded_status, catalog_trust_snapshot_malformed, catalog_trust_snapshot_malformed_status, catalog_trust_snapshot_revoked, catalog_trust_snapshot_revoked_status, catalog_trust_snapshot_schema_version, catalog_trust_snapshot_stale, catalog_trust_snapshot_stale_status, catalog_trust_snapshot_unsupported, catalog_trust_snapshot_unsupported_status, catalog_trust_source, catalog_trust_tier, catalog_unavailable_error, catalog_unavailable_reason, catalog_unavailable_transport_error, catalog_unavailable_transport_reason, catalog_unsafe_retrieval_error, catalog_unsafe_retrieval_reason, catalog_unsupported_kind_error, client_metadata, client_task_cancel_reason, client_task_cancel_request, client_task_cancel_result, command_list, commands_finalize_invocation_effect_request, commands_finalize_invocation_effect_result, commands_handle_pending_command_request, commands_handle_pending_command_result, commands_invocation_effect_outcome, commands_invocation_origin, commands_invoke_request, commands_list_request, commands_respond_to_queued_command_request, commands_respond_to_queued_command_result, completions_get_trigger_characters_result, completions_request_request, completions_request_result, configure_session_extensions_params, connect_client_info, connected_remote_session_metadata, connected_remote_session_metadata_kind, connected_remote_session_metadata_repository, connector_account_request, connector_authorization_requirement, connector_authorization_scope, connector_availability, connector_capabilities, connector_catalog_entry, connector_catalog_result, connector_catalog_status, connector_connect_request, connector_connect_result, connector_continue_request, connector_disconnect_result, connector_discovery_account, connector_discovery_account_list, connector_discovery_account_request, connector_discovery_auth_info, connector_discovery_availability, connector_discovery_capabilities, connector_discovery_catalog_entry, connector_discovery_catalog_result, connector_mcp_status, connector_reconcile_request, connector_runtime_status, connector_session_account, connector_status, connect_remote_session_params, connect_request, connect_result, content_exclusion_check_paths_request, content_exclusion_check_paths_result, content_exclusion_path_check, content_filter_mode, context_heaviest_message, copilot_api_token_auth_info, copilot_user_response, copilot_user_response_endpoints, copilot_user_response_quota_snapshots, copilot_user_response_quota_snapshots_chat, copilot_user_response_quota_snapshots_completions, copilot_user_response_quota_snapshots_premium_interactions, current_model, current_tool_metadata, customization_reload_outcome, customization_reload_status, customization_reload_subsystem, customizations_reload_result, debug_collect_logs_collected_entry, debug_collect_logs_destination, debug_collect_logs_entry, debug_collect_logs_entry_kind, debug_collect_logs_include, debug_collect_logs_redaction, debug_collect_logs_request, debug_collect_logs_result, debug_collect_logs_result_kind, debug_collect_logs_skipped_entry, debug_collect_logs_source, diagnostic_cursor_status, diagnostic_entry, diagnostic_log_level, diagnostics_configuration, diagnostics_configure_request, diagnostic_severity, diagnostic_source, diagnostic_sources_configuration, diagnostics_read_request, diagnostics_read_result, discovered_canvas, discovered_extension, discovered_extension_mode, discovered_extension_plugin, discovered_extensions, discovered_extensions_disable_request, discovered_extensions_enable_request, discovered_extension_source, discovered_hook, discovered_mcp_server, discovered_mcp_server_type, discovered_model, discovered_model_list, enqueue_command_params, enqueue_command_result, env_auth_info, environment_capabilities, environment_kind, environments_delete_request, environments_delete_result, environments_get_request, environments_get_result, environments_list_request, environments_list_result, event_log_read_request, event_log_release_interest_result, event_log_tail_result, event_log_types, events_agent_scope, events_cursor_status, events_read_direction, events_read_result, execute_command_params, execute_command_result, extension, extension_context_push_input, extension_launch_profile, extension_launch_provider_resolve_request, extension_launch_provider_resolve_result, extension_list, extensions_disable_request, extensions_enable_request, extension_source, extension_status, external_tool_result, external_tool_text_result_for_llm, external_tool_text_result_for_llm_binary_results_for_llm, external_tool_text_result_for_llm_binary_results_for_llm_type, external_tool_text_result_for_llm_content, external_tool_text_result_for_llm_content_audio, external_tool_text_result_for_llm_content_image, external_tool_text_result_for_llm_content_resource, external_tool_text_result_for_llm_content_resource_details, external_tool_text_result_for_llm_content_resource_link, external_tool_text_result_for_llm_content_resource_link_icon, external_tool_text_result_for_llm_content_resource_link_icon_theme, external_tool_text_result_for_llm_content_shell_exit, external_tool_text_result_for_llm_content_terminal, external_tool_text_result_for_llm_content_text, filter_mapping, fleet_start_request, fleet_start_result, folder_trust_add_params, folder_trust_check_params, folder_trust_check_result, gh_cli_auth_info, git_current_branch_remote_result, git_cwd_request, git_hub_environment, git_hub_owner_option, git_hub_owners_cancel_request, git_hub_owners_cancel_result, git_hub_owners_list_request, git_hub_owners_list_result, git_hub_owners_request_id_result, git_hub_repository_at_path_request, git_hub_repository_at_path_result, git_hub_repository_identity, git_hub_telemetry_client_info, git_hub_telemetry_event, git_hub_telemetry_notification, git_hub_token_acquire_reason, git_hub_token_acquire_request, git_hub_token_acquire_result, git_remote_repository, git_repos_from_remotes_request, git_repos_from_remotes_result, global_state_load_for_config_dir_request, global_state_load_result, global_state_write_key_request, handle_pending_tool_call_request, handle_pending_tool_call_result, history_abort_manual_compaction_result, history_cancel_background_compaction_result, history_clear_context_request, history_clear_context_result, history_compact_context_window, history_compact_request, history_compact_result, history_file_restore_skip_reason, history_list_rewind_points_result, history_preview_rewind_request, history_preview_rewind_result, history_rewind_change_type, history_rewind_file_preview, history_rewind_mode, history_rewind_outcome, history_rewind_point, history_rewind_request, history_rewind_result, history_rewind_unavailable_reason, history_skipped_file_restore, history_summarize_for_handoff_result, history_truncate_request, history_truncate_result, hmac_auth_info, hook_invoke_request, hook_invoke_response, hook_origin, hooks_discover_request, hooks_discover_result, hook_type, host_configuration, host_dispose_request, host_empty_result, host_environment_credentials, host_exited_notification, host_exit_reason, host_git_hub_environment_options, host_list_sessions_request, host_list_sessions_result, host_local_server_configuration, host_local_server_options, host_publish_session_request, host_publish_session_result, host_ready_request, host_register_session_request, host_session_create_callback, host_session_create_request, host_session_create_result, host_session_released_notification, host_session_release_request, host_session_summary, host_start_request, host_start_result, installation_catalogue_identity, installation_confirmation_request, installation_confirmation_response, installation_decision, installation_review, installed_plugin, installed_plugin_info, installed_plugin_source, installed_plugin_source_git_hub, installed_plugin_source_local, installed_plugin_source_url, instruction_discovery_path, instruction_discovery_path_kind, instruction_discovery_path_list, instruction_discovery_path_location, instructions_discover_request, instructions_get_discovery_paths_request, instructions_get_sources_result, instruction_source, instruction_source_location, instruction_source_type, interrupt_main_turn_request, interrupt_main_turn_result, json_schema_response_format, llm_inference_headers, llm_inference_http_request_chunk_request, llm_inference_http_request_chunk_result, llm_inference_http_request_start_request, llm_inference_http_request_start_result, llm_inference_http_request_start_transport, llm_inference_http_response_chunk_error, llm_inference_http_response_chunk_request, llm_inference_http_response_chunk_result, llm_inference_http_response_start_request, llm_inference_http_response_start_result, llm_inference_set_provider_result, local_session_metadata_value, logged_in_user, login_provider_kind, log_request, log_result, lsp_initialize_request, managed_mcp_server_config, managed_permission_evaluation, managed_permission_operation, managed_permission_operation_kind, managed_permissions_evaluate_request, managed_permissions_evaluate_result, managed_permission_verdict, managed_plugin_retry_entry, managed_plugin_retry_status, managed_setting_meta, managed_settings_channel, managed_settings_compose_layer, managed_settings_compose_request, managed_settings_compose_result, managed_settings_diagnostic, managed_settings_diagnostic_severity, managed_settings_layer, managed_settings_meta, managed_settings_read_result, managed_settings_resolved_data, managed_settings_resolve_request, managed_settings_resolve_result, managed_settings_schema_result, managed_settings_validate_request, managed_settings_validate_result, managed_settings_values, marketplace_add_result, marketplace_browse_result, marketplace_info, marketplace_list_result, marketplace_plugin_info, marketplace_refresh_entry, marketplace_refresh_result, marketplace_remove_result, mcp_allowed_server, mcp_apply_install_request, mcp_apply_uninstall_request, mcp_apps_call_tool_request, mcp_apps_diagnose_capability, mcp_apps_diagnose_request, mcp_apps_diagnose_result, mcp_apps_diagnose_server, mcp_apps_host_context, mcp_apps_host_context_details, mcp_apps_host_context_details_available_display_mode, mcp_apps_host_context_details_display_mode, mcp_apps_host_context_details_platform, mcp_apps_host_context_details_theme, mcp_apps_list_tools_request, mcp_apps_list_tools_result, mcp_apps_read_resource_request, mcp_apps_read_resource_result, mcp_apps_resource_content, mcp_apps_set_host_context_details, mcp_apps_set_host_context_details_available_display_mode, mcp_apps_set_host_context_details_display_mode, mcp_apps_set_host_context_details_platform, mcp_apps_set_host_context_details_theme, mcp_apps_set_host_context_request, mcp_cancel_sampling_execution_params, mcp_cancel_sampling_execution_result, mcp_config_add_request, mcp_config_disable_request, mcp_config_enable_request, mcp_config_list, mcp_config_remove_request, mcp_config_update_request, mcp_configured_server, mcp_configured_server_list, mcp_configured_server_state, mcp_configure_git_hub_request, mcp_configure_git_hub_result, mcp_diagnostic_details, mcp_diagnostic_direction, mcp_diagnostic_kind, mcp_diagnostic_source_configuration, mcp_disable_request, mcp_discover_request, mcp_discover_result, mcp_elicitation_form_mode, mcp_enable_request, mcp_execute_sampling_params, mcp_execute_sampling_request, mcp_execute_sampling_result, mcp_failed_server, mcp_filtered_server, mcp_headers_handle_pending_headers_refresh_request, mcp_headers_handle_pending_headers_refresh_request_request, mcp_headers_handle_pending_headers_refresh_request_result, mcp_host_state, mcp_installation_failure_reason, mcp_installation_input, mcp_installation_management_outcome, mcp_installation_management_result, mcp_installation_operation_request, mcp_installation_operation_status, mcp_installation_outcome, mcp_installation_remote_configuration, mcp_installation_result, mcp_installation_review, mcp_installation_secret, mcp_installation_secret_storage, mcp_installations_request, mcp_installation_state, mcp_installation_summary, mcp_install_plan, mcp_is_server_running_request, mcp_is_server_running_result, mcp_list_tools_request, mcp_list_tools_result, mcp_oauth_authentication_state_changed_request, mcp_oauth_cancel_login_request, mcp_oauth_cancel_login_result, mcp_oauth_complete_request, mcp_oauth_handle_pending_request, mcp_oauth_handle_pending_result, mcp_oauth_login_grant_type, mcp_oauth_login_request, mcp_oauth_login_result, mcp_oauth_pending_request_response, mcp_oauth_prepare_login_request, mcp_oauth_prepare_login_result, mcp_oauth_probe_needs_auth_reason, mcp_oauth_probe_request, mcp_oauth_probe_result, mcp_oauth_respond_request, mcp_oauth_respond_result, mcp_owned_oauth_login_status, mcp_plan_configuration_change, mcp_plan_configuration_operation, mcp_plan_enum_value_type, mcp_plan_install_planned, mcp_plan_install_request, mcp_plan_install_result, mcp_plan_install_source, mcp_plan_install_source_candidate, mcp_plan_install_source_candidate_kind, mcp_plan_install_source_card, mcp_plan_install_source_card_kind, mcp_plan_package_install_method, mcp_plan_package_transport, mcp_plan_policy_decision, mcp_plan_policy_result, mcp_plan_policy_source, mcp_plan_provenance, mcp_plan_remote_install_method, mcp_plan_remote_transport, mcp_plan_required_value, mcp_plan_required_value_enum, mcp_plan_required_value_enum_kind, mcp_plan_required_value_scalar, mcp_plan_required_value_scalar_kind, mcp_plan_resource_identity, mcp_plan_scalar_value_type, mcp_plan_scope, mcp_plan_secret_placeholder, mcp_plan_secret_reference, mcp_plan_target, mcp_plan_transport_choice, mcp_plan_transport_choice_package, mcp_plan_transport_choice_remote, mcp_plan_uninstall_request, mcp_plan_value_category, mcp_prepared_install, mcp_prepare_install_request, mcp_prompt, mcp_prompt_argument, mcp_prompt_icon, mcp_prompt_message, mcp_prompt_role, mcp_prompts_get_request, mcp_prompts_get_result, mcp_prompts_list_request, mcp_prompts_list_result, mcp_register_external_client_request, mcp_registry_cancel_request, mcp_registry_cancel_result, mcp_registry_request_id_result, mcp_registry_search_request, mcp_registry_search_result, mcp_reload_config, mcp_reload_with_config_request, mcp_remove_git_hub_result, mcp_resource, mcp_resource_annotations, mcp_resource_content, mcp_resource_icon, mcp_resources_list_request, mcp_resources_list_result, mcp_resources_list_templates_request, mcp_resources_list_templates_result, mcp_resources_read_request, mcp_resources_read_result, mcp_resource_template, mcp_restart_server_request, mcp_safe_for_telemetry, mcp_safe_for_telemetry_fields, mcp_sampling_execution_action, mcp_sampling_execution_result, mcp_serializable_server_config, mcp_server, mcp_server_auth_config, mcp_server_auth_config_redirect_port, mcp_server_card_embedded, mcp_server_card_embedded_kind, mcp_server_card_media_type, mcp_server_card_reference, mcp_server_card_url, mcp_server_card_url_kind, mcp_server_config, mcp_server_config_defer_tools, mcp_server_config_http, mcp_server_config_http_oauth_grant_type, mcp_server_config_http_type, mcp_server_config_memory, mcp_server_config_memory_type, mcp_server_config_stdio, mcp_server_config_stdio_type, mcp_server_failure_info, mcp_server_list, mcp_server_needs_auth_info, mcp_server_ownership, mcp_set_env_value_mode_details, mcp_set_env_value_mode_params, mcp_set_env_value_mode_result, mcp_should_exclude_git_hub_tools_request, mcp_should_exclude_git_hub_tools_result, mcp_source_file, mcp_source_plugin, mcp_source_ref, mcp_start_server_request, mcp_start_servers_result, mcp_stop_server_request, mcp_task_metadata, mcp_tools, mcp_tool_ui, mcp_tool_ui_visibility, mcp_uninstall_plan, mcp_unregister_external_client_request, memory_configuration, metadata_context_attribution_result, metadata_context_heaviest_messages_request, metadata_context_heaviest_messages_result, metadata_context_info_request, metadata_context_info_result, metadata_is_processing_result, metadata_recompute_context_tokens_request, metadata_recompute_context_tokens_result, metadata_record_context_change_request, metadata_record_context_change_result, metadata_set_working_directory_request, metadata_set_working_directory_result, metadata_snapshot_current_mode, metadata_snapshot_remote_metadata, metadata_snapshot_remote_metadata_repository, metadata_snapshot_remote_metadata_task_type, metadata_update_client_metadata_request, model, model_apply_startup_overlay_request, model_artifact_details, model_billing, model_billing_promo, model_billing_token_prices, model_billing_token_prices_long_context, model_capabilities, model_capabilities_limits, model_capabilities_limits_vision, model_capabilities_override, model_capabilities_override_limits, model_capabilities_override_limits_vision, model_capabilities_override_supports, model_capabilities_supports, model_clear_startup_seed_request, model_clear_startup_seed_result, model_list, model_list_request, model_message, model_picker_category, model_picker_persistence_request, model_picker_price_category, model_picker_settings_context, model_policy, model_policy_state, model_provider_adapter_catalog, model_provider_adapter_descriptor, model_provider_adapter_operation_descriptor, model_provider_attribution, model_provider_automatic_discovery_mode, model_provider_automatic_discovery_policy, model_provider_configuration_disposition, model_provider_configuration_plan, model_provider_descriptor, model_provider_discover_request, model_provider_discover_result, model_provider_discovery_network_scope, model_provider_get_status_request, model_provider_instance, model_provider_instance_reference, model_provider_models_list_request, model_provider_operation_outcome, model_provider_operation_outcome_code, model_provider_prepare_configuration_request, model_provider_provenance, model_provider_provenance_source, model_provider_status, model_provider_warning, model_set_allowed_models_request, model_set_allowed_models_result, model_set_reasoning_effort_request, model_set_reasoning_effort_result, models_list_request, model_switch_auto_tier_request, model_switch_auto_tier_result, model_switch_auto_tier_status, model_switch_confirmation, model_switch_to_request, model_switch_to_result, model_warning_text, mode_set_request, mode_set_result, move_mcp_loading_to_background_result, named_provider_config, name_get_result, name_set_auto_request, name_set_auto_result, name_set_request, open_canvas_instance, options_update_additional_content_exclusion_policy, options_update_additional_content_exclusion_policy_rule, options_update_additional_content_exclusion_policy_rule_source, options_update_additional_content_exclusion_policy_scope, options_update_context_tier, options_update_env_value_mode, options_update_reasoning_summary, options_update_tool_filter_precedence, pending_external_tool_request, pending_external_tool_request_list, pending_permission_request, pending_permission_request_list, permission_decision, permission_decision_approved, permission_decision_approved_for_location, permission_decision_approved_for_session, permission_decision_approve_for_location, permission_decision_approve_for_location_approval, permission_decision_approve_for_location_approval_commands, permission_decision_approve_for_location_approval_custom_tool, permission_decision_approve_for_location_approval_extension_env_access, permission_decision_approve_for_location_approval_extension_management, permission_decision_approve_for_location_approval_extension_permission_access, permission_decision_approve_for_location_approval_mcp, permission_decision_approve_for_location_approval_mcp_sampling, permission_decision_approve_for_location_approval_memory, permission_decision_approve_for_location_approval_read, permission_decision_approve_for_location_approval_workflow, permission_decision_approve_for_location_approval_write, permission_decision_approve_for_session, permission_decision_approve_for_session_approval, permission_decision_approve_for_session_approval_commands, permission_decision_approve_for_session_approval_custom_tool, permission_decision_approve_for_session_approval_extension_env_access, permission_decision_approve_for_session_approval_extension_management, permission_decision_approve_for_session_approval_extension_permission_access, permission_decision_approve_for_session_approval_mcp, permission_decision_approve_for_session_approval_mcp_sampling, permission_decision_approve_for_session_approval_memory, permission_decision_approve_for_session_approval_read, permission_decision_approve_for_session_approval_workflow, permission_decision_approve_for_session_approval_write, permission_decision_approve_once, permission_decision_approve_permanently, permission_decision_approve_read_only_for_session, permission_decision_cancelled, permission_decision_context, permission_decision_denied_by_content_exclusion_policy, permission_decision_denied_by_permission_request_hook, permission_decision_denied_by_rules, permission_decision_denied_interactively_by_user, permission_decision_denied_no_approval_rule_and_could_not_request_from_user, permission_decision_outcome, permission_decision_reject, permission_decision_request, permission_decision_surface, permission_decision_user_not_available, permission_location_add_tool_approval_params, permission_location_apply_params, permission_location_apply_result, permission_location_resolve_params, permission_location_resolve_result, permission_location_type, permission_mode_source, permission_paths_add_params, permission_paths_allowed_check_params, permission_paths_allowed_check_result, permission_paths_config, permission_paths_list, permission_paths_update_primary_params, permission_paths_workspace_check_params, permission_paths_workspace_check_result, permission_prompt_shown_notification, permission_request_result, permission_response_capability, permission_rules_set, permissions_configure_additional_content_exclusion_policy, permissions_configure_additional_content_exclusion_policy_rule, permissions_configure_additional_content_exclusion_policy_rule_source, permissions_configure_additional_content_exclusion_policy_scope, permissions_configure_params, permissions_configure_result, permissions_folder_trust_add_trusted_result, permissions_get_mode_request, permissions_get_mode_result, permissions_locations_add_tool_approval_details, permissions_locations_add_tool_approval_details_commands, permissions_locations_add_tool_approval_details_custom_tool, permissions_locations_add_tool_approval_details_extension_env_access, permissions_locations_add_tool_approval_details_extension_management, permissions_locations_add_tool_approval_details_extension_permission_access, permissions_locations_add_tool_approval_details_mcp, permissions_locations_add_tool_approval_details_mcp_sampling, permissions_locations_add_tool_approval_details_memory, permissions_locations_add_tool_approval_details_read, permissions_locations_add_tool_approval_details_workflow, permissions_locations_add_tool_approval_details_write, permissions_locations_add_tool_approval_result, permissions_modify_rules_params, permissions_modify_rules_result, permissions_modify_rules_scope, permissions_notify_prompt_shown_result, permissions_paths_add_result, permissions_paths_list_request, permissions_paths_update_primary_result, permissions_pending_requests_request, permissions_reset_session_approvals_request, permissions_reset_session_approvals_result, permissions_set_approve_all_request, permissions_set_approve_all_result, permissions_set_approve_all_source, permissions_set_mode_request, permissions_set_mode_result, permissions_set_required_request, permissions_set_required_result, permissions_urls_set_unrestricted_mode_result, permission_urls_config, permission_urls_set_unrestricted_mode_params, ping_request, ping_result, plan_read_result, plan_read_sql_todos_result, plan_read_sql_todos_with_dependencies_result, plan_sql_todo_dependency, plan_sql_todos_row, plan_update_request, plugin, plugin_install_result, plugin_install_staging_mode, plugin_list, plugin_list_result, plugins_builtin_set_request, plugins_disable_request, plugins_enable_request, plugins_install_request, plugins_marketplaces_add_request, plugins_marketplaces_browse_request, plugins_marketplaces_refresh_request, plugins_marketplaces_remove_request, plugins_reload_request, plugins_uninstall_request, plugins_update_request, plugin_update_all_entry, plugin_update_all_result, plugin_update_result, protocol_append_mode, protocol_customize_mode, protocol_external_tool_defer, protocol_external_tool_definition, protocol_marker_section_override, protocol_replace_mode, protocol_section_override, protocol_static_section_action, protocol_static_section_override, protocol_system_message_append_config, protocol_system_message_config, protocol_system_message_customize_config, protocol_system_message_replace_config, provider_add_request, provider_add_result, provider_config, provider_config_azure, provider_config_model_provider, provider_config_transport, provider_config_type, provider_config_wire_api, provider_descriptor, provider_endpoint, provider_endpoint_transport, provider_endpoint_type, provider_endpoint_wire_api, provider_get_endpoint_request, provider_model_config, provider_session_token, provider_sync_request, provider_sync_result, provider_token_acquire_request, provider_token_acquire_result, provider_withdraw_request, provider_withdraw_result, push_attachment, push_attachment_blob, push_attachment_directory, push_attachment_file, push_attachment_file_line_range, push_attachment_git_hub_actions_job, push_attachment_git_hub_commit, push_attachment_git_hub_file, push_attachment_git_hub_file_diff, push_attachment_git_hub_file_diff_side, push_attachment_git_hub_reference, push_attachment_git_hub_reference_type, push_attachment_git_hub_release, push_attachment_git_hub_repository, push_attachment_git_hub_snippet, push_attachment_git_hub_tree_comparison, push_attachment_git_hub_tree_comparison_side, push_attachment_git_hub_url, push_attachment_selection, push_attachment_selection_details, push_attachment_selection_details_end, push_attachment_selection_details_start, push_git_hub_repo_ref, queue_append_steering_request, queue_begin_deferred_idle_drain_request, queue_begin_deferred_idle_drain_result, queue_consume_system_notifications_request, queued_command_handled, queued_command_not_handled, queued_command_result, queue_defer_session_idle_request, queue_duplicate_at_request, queue_duplicate_at_result, queue_enqueue_resume_pending_result, queue_finish_deferred_idle_drain_request, queue_finish_deferred_idle_drain_result, queue_has_pending_result, queue_insert_at_request, queue_insert_at_result, queue_insert_message, queue_move_item_request, queue_move_item_result, queue_pending_items, queue_pending_items_kind, queue_pending_items_result, queue_remove_at_request, queue_remove_at_result, queue_remove_most_recent_result, queue_send_now_request, queue_send_now_result, queue_set_drain_paused_request, queue_snapshot_result, queue_update_text_request, queue_update_text_result, queue_withdraw_message_request, queue_withdraw_message_result, quota_take_warnings_result, quota_warning_projection, register_event_interest_params, register_event_interest_result, release_event_interest_params, remote_control_config, remote_control_config_existing_mc_session, remote_control_status, remote_control_status_active, remote_control_status_connecting, remote_control_status_error, remote_control_status_off, remote_control_status_result, remote_control_stop_result, remote_control_transfer_result, remote_enable_request, remote_enable_result, remote_notify_steerable_changed_request, remote_notify_steerable_changed_result, remote_session_connection_result, remote_session_host_status, remote_session_metadata_repository, remote_session_metadata_task_type, remote_session_metadata_value, remote_session_mode, remote_session_repository, response_format, sandbox_config, sandbox_config_auth, sandbox_config_source, sandbox_config_user_policy, sandbox_config_user_policy_experimental, sandbox_config_user_policy_experimental_seatbelt, sandbox_config_user_policy_filesystem, sandbox_config_user_policy_network, sandbox_config_user_policy_network_proxy, sandbox_config_user_policy_seatbelt, sandbox_credentials_config, sandbox_credential_suggestion, sandbox_credential_suggestions_result, sandbox_disable_for_session_request, sandbox_disable_for_session_result, sandbox_enforcement_status, sandbox_grant_path_for_request_request, sandbox_grant_path_for_request_result, sandbox_host_capability, sandbox_host_capability_name, sandbox_host_support, sandbox_masked_env_var, sandbox_proxy_ca_create_result, sandbox_proxy_ca_request, sandbox_proxy_ca_state, sandbox_proxy_ca_status, sandbox_session_change, schedule_add_at_request, schedule_add_cron_request, schedule_add_request, schedule_add_result, schedule_add_self_paced_request, schedule_entry, schedule_has_self_paced_result, schedule_list, schedule_rearm_self_paced_request, schedule_stop_request, schedule_stop_result, secrets_add_filter_values_request, secrets_add_filter_values_result, send_agent_mode, send_attachments_to_message_params, send_message_item, send_messages_request, send_messages_result, send_mode, send_request, send_result, send_system_notification_request, server_agent_list, server_instruction_source_list, server_skill, server_skill_list, session_activity, session_agent_list_request, session_auth_login_request, session_auth_logout_user_request, session_auth_status, session_auth_switch_request, session_bulk_delete_result, session_cancel_all_background_agents_result, session_capability, session_commands_list_request, session_completion_item, session_connected_ide_info, session_context, session_context_host_type, session_enrich_metadata_result, session_fs_append_file_request, session_fs_error, session_fs_error_code, session_fs_exists_request, session_fs_exists_result, session_fs_mkdir_request, session_fs_readdir_request, session_fs_readdir_result, session_fs_readdir_with_types_entry, session_fs_readdir_with_types_entry_type, session_fs_readdir_with_types_request, session_fs_readdir_with_types_result, session_fs_read_file_bytes_request, session_fs_read_file_bytes_result, session_fs_read_file_request, session_fs_read_file_result, session_fs_rename_request, session_fs_rm_request, session_fs_set_provider_capabilities, session_fs_set_provider_conventions, session_fs_set_provider_request, session_fs_set_provider_result, session_fs_sqlite_exists_request, session_fs_sqlite_exists_result, session_fs_sqlite_query_request, session_fs_sqlite_query_result, session_fs_sqlite_query_type, session_fs_sqlite_transaction_error, session_fs_sqlite_transaction_error_class, session_fs_sqlite_transaction_request, session_fs_sqlite_transaction_result, session_fs_sqlite_transaction_statement, session_fs_stat_request, session_fs_stat_result, session_fs_write_file_bytes_request, session_fs_write_file_request, session_git_hub_auth_get_all_auth_available_result, session_git_hub_auth_logout_result, session_git_hub_auth_logout_user_result, session_history_compact_request, session_installed_plugin, session_installed_plugin_source, session_installed_plugin_source_git_hub, session_installed_plugin_source_local, session_installed_plugin_source_url, session_limit_prediction_baseline_data, session_limit_prediction_client_type, session_limit_prediction_details, session_limit_prediction_predict_request, session_limit_prediction_request, session_limit_prediction_result, session_limit_prediction_source, session_limit_prediction_tier, session_limit_prediction_tier_option, session_limit_prediction_unavailable_reason, session_list, session_list_entry, session_list_filter, session_load_deferred_repo_hooks_result, session_log_level, session_managed_permissions, session_managed_settings, session_mcp_apps_call_tool_result, session_mcp_oauth_cancel_login_request, session_mcp_oauth_cancel_login_result, session_mcp_oauth_prepare_login_request, session_mcp_oauth_prepare_login_result, session_mcp_set_connected_ide_info_params, session_metadata_snapshot, session_mode, session_model_clear_startup_seed_request, session_model_clear_startup_seed_result, session_model_list, session_model_list_request, session_model_price_category, session_open_options, session_open_options_additional_content_exclusion_policy, session_open_options_additional_content_exclusion_policy_rule, session_open_options_additional_content_exclusion_policy_rule_source, session_open_options_additional_content_exclusion_policy_scope, session_open_options_env_value_mode, session_open_options_reasoning_summary, session_open_params, session_open_result, session_plugins_disable_request, session_plugins_enable_request, session_plugins_install_request, session_plugins_marketplaces_refresh_request, session_plugins_reload_request, session_plugins_retry_managed_request, session_plugins_retry_managed_result, session_provider_get_endpoint_request, session_prune_result, session_quota_delegate_warning, session_quota_get_result, session_quota_plan_tier, session_quota_projection, session_quota_refresh_result, session_quota_snapshot, session_quota_take_warnings_result, sessions_bulk_delete_request, sessions_check_in_use_request, sessions_check_in_use_result, sessions_client_metadata_entry, sessions_close_request, sessions_close_result, sessions_create_workspace_request, sessions_create_workspace_result, sessions_delete_request, sessions_enrich_metadata_request, session_set_credentials_params, session_set_credentials_result, session_settings_built_in_tool_availability_snapshot, session_settings_evaluate_predicate_request, session_settings_evaluate_predicate_result, session_settings_job_snapshot, session_settings_model_snapshot, session_settings_online_evaluation_snapshot, session_settings_predicate_name, session_settings_repo_snapshot, session_settings_snapshot, session_settings_validation_snapshot, sessions_find_by_prefix_request, sessions_find_by_prefix_result, sessions_find_by_task_id_request, sessions_find_by_task_id_result, sessions_fork_request, sessions_fork_result, sessions_get_board_entry_count_request, sessions_get_board_entry_count_result, sessions_get_client_metadata_request, sessions_get_client_metadata_result, sessions_get_event_file_path_request, sessions_get_event_file_path_result, sessions_get_last_for_context_request, sessions_get_last_for_context_result, sessions_get_metadata_request, sessions_get_metadata_result, sessions_get_persisted_remote_steerable_request, sessions_get_persisted_remote_steerable_result, session_sizes, sessions_list_non_empty_session_ids_request, sessions_list_non_empty_session_ids_result, sessions_list_request, sessions_load_deferred_repo_hooks_request, sessions_load_workspace_request, sessions_load_workspace_result, sessions_open_attach, sessions_open_cloud, sessions_open_create, sessions_open_handoff, sessions_open_handoff_task_type, sessions_open_progress, sessions_open_progress_status, sessions_open_progress_step, sessions_open_remote, sessions_open_resume, sessions_open_resume_last, sessions_open_status, session_source, sessions_prune_old_request, sessions_read_persisted_events_request, sessions_release_lock_request, sessions_release_lock_result, sessions_reload_plugin_hooks_request, sessions_reload_plugin_hooks_result, sessions_save_request, sessions_save_result, sessions_set_additional_plugins_request, sessions_set_additional_plugins_result, sessions_set_remote_control_steering_request, sessions_start_remote_control_request, sessions_stop_remote_control_request, sessions_transfer_remote_control_request, sessions_update_workspace_fields_request, sessions_update_workspace_fields_result, session_telemetry_engagement, session_update_options_params, session_update_options_result, session_usage_set_code_changes_request, session_visibility_status, session_workflow_pause_at_checkpoint_result, session_working_directory_context, session_working_directory_context_host_type, session_working_directory_context_with_client, settable_auth_info, settable_token_auth_info, shell_cancel_user_requested_request, shell_credentials, shell_exec_request, shell_exec_result, shell_execute_user_requested_request, shell_init_profile, shell_init_script, shell_init_script_shell, shell_kill_request, shell_kill_result, shell_kill_signal, shell_options, shutdown_request, skill, skill_apply_install_request, skill_apply_uninstall_request, skill_discovery_path, skill_discovery_path_list, skill_discovery_scope, skill_installation_failure_reason, skill_installation_file_review, skill_installation_location, skill_installation_management_outcome, skill_installation_management_result, skill_installation_operation_request, skill_installation_operation_status, skill_installation_outcome, skill_installation_ownership_state, skill_installation_result, skill_installation_review, skill_installation_scope, skill_installation_session_state, skill_installation_source, skill_installations_request, skill_installation_summary, skill_install_plan, skill_list, skill_plan_install_request, skill_plan_uninstall_request, skill_provider_descriptor, skill_provider_list_request, skill_provider_list_result, skill_provider_read_request, skill_provider_read_result, skills_config_set_disabled_skills_request, skills_config_set_skill_disabled_request, skills_disable_request, skills_discover_request, skills_enable_request, skill_set_enabled_request, skills_get_discovery_paths_request, skills_get_invoked_result, skills_invoked_skill, skills_load_diagnostics, skill_uninstall_plan, slash_command_add_timeline_entry_result, slash_command_agent_prompt_result, slash_command_completed_result, slash_command_info, slash_command_input, slash_command_input_choice, slash_command_input_completion, slash_command_invocation_result, slash_command_kind, slash_command_model_picker_dialog, slash_command_select_subcommand_option, slash_command_select_subcommand_result, slash_command_set_model_result, slash_command_set_plan_model_result, slash_command_show_dialog_result, slash_command_text_result, slash_command_timeline_entry, subagent_settings_entry, subagent_settings_entry_context_tier, system_message_block, task_agent_info, task_agent_progress, task_client_active_status, task_client_execution_mode, task_client_info, task_client_owner, task_client_owner_kind, task_client_owner_presence, task_client_progress, task_client_status, task_client_type, task_client_update, task_complete_data, task_completion_decision, task_execution_mode, task_info, task_kind, task_list, task_progress_line, tasks_cancel_request, tasks_cancel_result, tasks_get_current_promotable_result, tasks_get_progress_request, tasks_get_progress_result, task_shell_info, task_shell_info_attachment_mode, task_shell_progress, tasks_promote_current_to_background_result, tasks_promote_to_background_request, tasks_promote_to_background_result, tasks_refresh_result, tasks_register_request, tasks_register_result, tasks_remove_request, tasks_remove_result, tasks_send_message_request, tasks_send_message_result, tasks_start_agent_request, tasks_start_agent_result, task_status, tasks_update_request, tasks_update_result, tasks_wait_for_pending_result, telemetry_set_feature_overrides_request, token_auth_info, token_provider_auth_info, tool, tool_list, tool_result, tool_result_expanded, tool_result_new_message, tool_result_type, tools_execute_request, tools_get_builtin_descriptors_request, tools_get_builtin_descriptors_result, tools_get_current_metadata_result, tools_initialize_and_validate_result, tools_list_pending_requests_request, tools_list_request, tools_set_request, tools_set_result, tools_shell_descriptor_config, tools_task_complete_event_data_request, tools_update_subagent_settings_result, ui_auto_mode_switch_response, ui_elicitation_array_any_of_field, ui_elicitation_array_any_of_field_items, ui_elicitation_array_any_of_field_items_any_of, ui_elicitation_array_enum_field, ui_elicitation_array_enum_field_items, ui_elicitation_field_value, ui_elicitation_request, ui_elicitation_response, ui_elicitation_response_action, ui_elicitation_response_content, ui_elicitation_result, ui_elicitation_schema, ui_elicitation_schema_property, ui_elicitation_schema_property_boolean, ui_elicitation_schema_property_number, ui_elicitation_schema_property_number_type, ui_elicitation_schema_property_string, ui_elicitation_schema_property_string_format, ui_elicitation_string_enum_field, ui_elicitation_string_one_of_field, ui_elicitation_string_one_of_field_one_of, ui_ephemeral_query_request, ui_ephemeral_query_result, ui_exit_plan_mode_action, ui_exit_plan_mode_response, ui_handle_pending_auto_mode_switch_request, ui_handle_pending_elicitation_request, ui_handle_pending_exit_plan_mode_request, ui_handle_pending_result, ui_handle_pending_sampling_request, ui_handle_pending_sampling_response, ui_handle_pending_session_limits_exhausted_request, ui_handle_pending_user_input_request, ui_register_direct_auto_mode_switch_handler_result, ui_session_limits_exhausted_response, ui_session_limits_exhausted_response_action, ui_unregister_direct_auto_mode_switch_handler_request, ui_unregister_direct_auto_mode_switch_handler_result, ui_user_input_response, unsupported_enqueue_command_result, update_subagent_settings_request, usage_get_metrics_result, usage_set_code_changes_request, user_auth_info, user_requested_shell_command_result, user_setting_metadata, user_settings_get_result, user_settings_set_request, visibility_get_result, visibility_set_request, visibility_set_result, workflow_abort_request, workflow_ack_result, workflow_agent_options, workflow_agent_request, workflow_agent_result, workflow_agent_summary, workflow_cancel_request, workflow_current_phase, workflow_declared_limits, workflow_durable_operation, workflow_execute_request, workflow_execute_result, workflow_get_run_progress_request, workflow_get_run_request, workflow_journal_get_request, workflow_journal_get_result, workflow_journal_put_request, workflow_list_runs_request, workflow_list_runs_result, workflow_log_line, workflow_log_line_kind, workflow_log_request, workflow_pause_checkpoint_action, workflow_pause_checkpoint_request, workflow_pause_checkpoint_result, workflow_pause_info, workflow_pause_request, workflow_phase_observation, workflow_phase_status, workflow_progress_line, workflow_progress_page, workflow_resume_request, workflow_resume_result, workflow_run_consumed, workflow_run_detail, workflow_run_failure, workflow_run_failure_kind, workflow_run_limits, workflow_run_options, workflow_run_request, workflow_run_result, workflow_run_status, workflow_run_summary, workflow_run_terminal, workflow_tool_resume_request, workflow_tool_run_options, workflow_tool_run_request, workspace_diff_contents, workspace_diff_file_change, workspace_diff_file_change_type, workspace_diff_mode, workspace_diff_result, workspaces_add_summary_request, workspaces_add_summary_result, workspaces_autopilot_objective_exists_result, workspaces_checkpoints, workspaces_create_directory_request, workspaces_create_file_request, workspaces_delete_autopilot_objective_result, workspaces_diff_request, workspaces_ensure_request, workspaces_get_workspace_result, workspaces_list_checkpoints_result, workspaces_list_files_result, workspaces_read_autopilot_objective_result, workspaces_read_checkpoint_request, workspaces_read_checkpoint_result, workspaces_read_file_request, workspaces_read_file_result, workspaces_remove_path_request, workspaces_rename_path_request, workspaces_save_large_paste_request, workspaces_save_large_paste_result, workspaces_stat_file_request, workspaces_stat_file_result, workspaces_truncate_summaries_request, workspace_summary_host_type, workspaces_update_metadata_request, workspaces_workspace_details_host_type, workspaces_write_autopilot_objective_request, workspaces_write_autopilot_objective_result, connector_session_account_result, session_auth_info_result, session_context_attribution, session_context_info, subagent_settings, task_progress, workspace_summary) def to_dict(self) -> dict: result: dict = {} @@ -53788,6 +54054,11 @@ def to_dict(self) -> dict: result["McpPromptsListRequest"] = to_class(MCPPromptsListRequest, self.mcp_prompts_list_request) result["McpPromptsListResult"] = to_class(MCPPromptsListResult, self.mcp_prompts_list_result) result["McpRegisterExternalClientRequest"] = to_class(MCPRegisterExternalClientRequest, self.mcp_register_external_client_request) + result["McpRegistryCancelRequest"] = to_class(MCPRegistryCancelRequest, self.mcp_registry_cancel_request) + result["McpRegistryCancelResult"] = to_class(MCPRegistryCancelResult, self.mcp_registry_cancel_result) + result["McpRegistryRequestIdResult"] = to_class(MCPRegistryRequestIDResult, self.mcp_registry_request_id_result) + result["McpRegistrySearchRequest"] = to_class(MCPRegistrySearchRequest, self.mcp_registry_search_request) + result["McpRegistrySearchResult"] = to_class(MCPRegistrySearchResult, self.mcp_registry_search_result) result["McpReloadConfig"] = to_class(MCPReloadConfig, self.mcp_reload_config) result["McpReloadWithConfigRequest"] = to_class(MCPReloadWithConfigRequest, self.mcp_reload_with_config_request) result["McpRemoveGitHubResult"] = to_class(MCPRemoveGitHubResult, self.mcp_remove_git_hub_result) @@ -53833,6 +54104,8 @@ def to_dict(self) -> dict: result["McpSetEnvValueModeDetails"] = to_enum(MCPSetEnvValueModeDetails, self.mcp_set_env_value_mode_details) result["McpSetEnvValueModeParams"] = to_class(MCPSetEnvValueModeParams, self.mcp_set_env_value_mode_params) result["McpSetEnvValueModeResult"] = to_class(MCPSetEnvValueModeResult, self.mcp_set_env_value_mode_result) + result["McpShouldExcludeGitHubToolsRequest"] = to_class(MCPShouldExcludeGitHubToolsRequest, self.mcp_should_exclude_git_hub_tools_request) + result["McpShouldExcludeGitHubToolsResult"] = to_class(MCPShouldExcludeGitHubToolsResult, self.mcp_should_exclude_git_hub_tools_result) result["McpSourceFile"] = to_class(MCPSourceFile, self.mcp_source_file) result["McpSourcePlugin"] = to_class(MCPSourcePlugin, self.mcp_source_plugin) result["McpSourceRef"] = to_class(MCPSourceRef, self.mcp_source_ref) @@ -54207,6 +54480,8 @@ def to_dict(self) -> dict: result["SandboxConfigUserPolicyNetworkProxy"] = to_class(SandboxConfigUserPolicyNetworkProxy, self.sandbox_config_user_policy_network_proxy) result["SandboxConfigUserPolicySeatbelt"] = to_class(SandboxConfigUserPolicySeatbelt, self.sandbox_config_user_policy_seatbelt) result["SandboxCredentialsConfig"] = to_class(SandboxCredentialsConfig, self.sandbox_credentials_config) + result["SandboxCredentialSuggestion"] = to_class(SandboxCredentialSuggestion, self.sandbox_credential_suggestion) + result["SandboxCredentialSuggestionsResult"] = to_class(SandboxCredentialSuggestionsResult, self.sandbox_credential_suggestions_result) result["SandboxDisableForSessionRequest"] = to_class(SandboxDisableForSessionRequest, self.sandbox_disable_for_session_request) result["SandboxDisableForSessionResult"] = to_class(SandboxDisableForSessionResult, self.sandbox_disable_for_session_result) result["SandboxEnforcementStatus"] = to_class(SandboxEnforcementStatus, self.sandbox_enforcement_status) @@ -56100,6 +56375,38 @@ async def _ready(self, params: HostReadyRequest, *, timeout: float | None = None return HostEmptyResult.from_dict(await self._client.request("host.ready", params_dict, **_timeout_kwargs(timeout))) +# Experimental: this API group is experimental and may change or be removed. +class _InternalServerMcpRegistryApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def _allocate_request_id(self, *, timeout: float | None = None) -> MCPRegistryRequestIDResult: + "Allocates an ID for one cancellable MCP registry search. The ID exists before the search starts, so callers can cancel before it starts. The networking stack supplies the cancellation namespace. The runtime retains at most 1,024 unused IDs. At capacity, another allocation can reclaim an unused ID. Active searches retain their IDs until they finish.\n\nReturns:\n Request id naming a cancellable registry search.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + return MCPRegistryRequestIDResult.from_dict(await self._client.request("mcp.registry.allocateRequestId", {}, **_timeout_kwargs(timeout))) + + async def _search(self, params: MCPRegistrySearchRequest, *, timeout: float | None = None) -> MCPRegistrySearchResult: + "Searches the MCP registry the supplied credential may read, resolving the registry endpoint from policy first. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. The runtime follows registry pages, keeps the newest entry per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub stars. Each server object is carried opaquely.\n\nArgs:\n params: Registry search terms, the credential to search under, and the request id that makes the search cancellable.\n\nReturns:\n Servers selected from the registry response.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return MCPRegistrySearchResult.from_dict(await self._client.request("mcp.registry.search", params_dict, **_timeout_kwargs(timeout))) + + async def _cancel(self, params: MCPRegistryCancelRequest, *, timeout: float | None = None) -> MCPRegistryCancelResult: + "Abandons the registry search that uses the given request ID. It acts only on IDs from `mcp.registry.allocateRequestId`, so it never cancels another component's request. Answers `canceled: true` when it stops a running search. Answers `canceled: false` for unknown or reclaimed IDs, completed or canceled searches, and unused reservations. It releases an unused reservation, so a later search with that ID is refused.\n\nArgs:\n params: Registry search to abandon.\n\nReturns:\n Whether the cancel reached a live search.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return MCPRegistryCancelResult.from_dict(await self._client.request("mcp.registry.cancel", params_dict, **_timeout_kwargs(timeout))) + + +# Experimental: this API group is experimental and may change or be removed. +class _InternalServerMcpApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + self.registry = _InternalServerMcpRegistryApi(client) + + async def _should_exclude_git_hub_tools(self, params: MCPShouldExcludeGitHubToolsRequest, *, timeout: float | None = None) -> MCPShouldExcludeGitHubToolsResult: + "Reports whether the gh-replaceable GitHub MCP tools may be clipped for a session, which a host feeds back as the `excludeGhReplaceableTools` build option. The tools are redundant only when the session can reach a shell *and* the host has the `gh` that would replace them, so both halves are decided here. The shell half runs the platform shell tool through the runtime's own tool-filter matcher, so entry forms like `builtin:bash` and `builtin:*` behave exactly as they do when a session builds its tool catalog. The host half probes for `gh`, and is skipped entirely when the filters already rule the shell out. Host presence alone is not enough: a session restricted to, say, `view` would otherwise lose the built-in issue-read fallback while having no shell to replace it with. The answer describes the host the runtime runs on, so it is never forwarded to a remote engine.\n\nArgs:\n params: The session tool filters that decide whether the session still has a shell to run `gh` with.\n\nReturns:\n Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by the request.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return MCPShouldExcludeGitHubToolsResult.from_dict(await self._client.request("mcp.shouldExcludeGitHubTools", params_dict, **_timeout_kwargs(timeout))) + + # Experimental: this API group is experimental and may change or be removed. class _InternalServerAgentsApi: def __init__(self, client: "JsonRpcClient"): @@ -56145,7 +56452,7 @@ async def _load_for_config_dir(self, params: _GlobalStateLoadForConfigDirRequest return _GlobalStateLoadResult.from_dict(await self._client.request("globalState.loadForConfigDir", params_dict, **_timeout_kwargs(timeout))) async def _write_key(self, params: _GlobalStateWriteKeyRequest, *, timeout: float | None = None) -> None: - "Records one top-level key in the host's machine-wide state, the counterpart to `globalState.load`. A host calls this to remember that it has shown an onboarding step, asked a one-off question, or completed a migration, so the next run can skip it. Only the named key is replaced and the rest of the document is preserved, which lets two writers record different flags without overwriting each other; passing no value removes the key instead. Only the keys a host records itself are writable: `appInstallNudgeResponded`, `appTipShown`, `askedSetupTerminals`, `autoFeedbackLastPromptedAt`, `firstLaunchAt`, `recentModelIds`, `sandboxCredentialProxyCaDeclined` and `sandboxOnboardingShown`. Every other key is refused, including `installedPlugins`, the stored credentials, `trustedFolders`, the staff flags and the signed-in accounts. Plugin enablement must use the plugin APIs, which apply repository and managed-policy checks.\n\nArgs:\n params: A single top-level key to record in the host's machine-wide state. The write replaces only that key and leaves the rest of the document untouched, so two writers recording different one-off flags do not overwrite each other. The stored credential keys cannot be written through this method.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + "Records one top-level key in the host's machine-wide state, the counterpart to `globalState.load`. A host calls this to remember that it has shown an onboarding step, asked a one-off question, or completed a migration, so the next run can skip it. Only the named key is replaced and the rest of the document is preserved, which lets two writers record different flags without overwriting each other; passing no value removes the key instead. Only the keys a host records itself are writable: `appTipShown`, `askedSetupTerminals`, `autoFeedbackLastPromptedAt`, `firstLaunchAt`, `recentModelIds`, `sandboxCredentialProxyCaDeclined` and `sandboxOnboardingShown`. Every other key is refused, including `installedPlugins`, the stored credentials, `trustedFolders`, the staff flags and the signed-in accounts. Plugin enablement must use the plugin APIs, which apply repository and managed-policy checks.\n\nArgs:\n params: A single top-level key to record in the host's machine-wide state. The write replaces only that key and leaves the rest of the document untouched, so two writers recording different one-off flags do not overwrite each other. The stored credential keys cannot be written through this method.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." params_dict = {k: v for k, v in params.to_dict().items() if v is not None} await self._client.request("globalState.writeKey", params_dict, **_timeout_kwargs(timeout)) @@ -56263,6 +56570,7 @@ class _InternalServerRpc: def __init__(self, client: "JsonRpcClient"): self._client = client self.host = _InternalServerHostApi(client) + self.mcp = _InternalServerMcpApi(client) self.agents = _InternalServerAgentsApi(client) self.global_state = _InternalServerGlobalStateApi(client) self.git_hub_repository = _InternalServerGitHubRepositoryApi(client) @@ -56329,6 +56637,10 @@ async def get_enforcement_status(self, *, timeout: float | None = None) -> Sandb "Returns whether managed policy requires sandbox enforcement and whether an enforcement failure has permanently blocked the session.\n\nReturns:\n Managed sandbox enforcement state for a session." return SandboxEnforcementStatus.from_dict(await self._client.request("session.sandbox.getEnforcementStatus", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + async def get_credential_suggestions(self, *, timeout: float | None = None) -> SandboxCredentialSuggestionsResult: + "Lists possible secret-bearing environment variables available to new sandboxed shells that are not already covered by credential masking. Uses local name rules and known-provider host suggestions, never returns secret values, and changes no settings or network permissions. Returns no suggestions while the session is not sandboxed.\n\nReturns:\n Possible unconfigured secrets in the sandbox shell environment, sorted by variable name, with no secret values." + return SandboxCredentialSuggestionsResult.from_dict(await self._client.request("session.sandbox.getCredentialSuggestions", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + async def disable_for_session(self, params: SandboxDisableForSessionRequest, *, timeout: float | None = None) -> SandboxDisableForSessionResult: "Disables sandboxing for the remainder of the current session and approves the referenced pending sandbox-bypass permission request. The request is rejected unless the exact request is still pending and the effective sandbox policy permits bypass.\n\nArgs:\n params: Request to disable sandboxing for the current session while resolving an active sandbox-bypass permission prompt.\n\nReturns:\n Result of attempting to disable sandboxing for the current session." params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} @@ -59788,6 +60100,11 @@ async def handle_installations_confirm(params: dict) -> dict | None: "MCPPromptsListRequest", "MCPPromptsListResult", "MCPRegisterExternalClientRequest", + "MCPRegistryCancelRequest", + "MCPRegistryCancelResult", + "MCPRegistryRequestIDResult", + "MCPRegistrySearchRequest", + "MCPRegistrySearchResult", "MCPReloadConfig", "MCPReloadWithConfigRequest", "MCPRemoveGitHubResult", @@ -59832,6 +60149,8 @@ async def handle_installations_confirm(params: dict) -> dict | None: "MCPSetEnvValueModeDetails", "MCPSetEnvValueModeParams", "MCPSetEnvValueModeResult", + "MCPShouldExcludeGitHubToolsRequest", + "MCPShouldExcludeGitHubToolsResult", "MCPSourceFile", "MCPSourcePlugin", "MCPSourceRef", @@ -60347,6 +60666,8 @@ async def handle_installations_confirm(params: dict) -> dict | None: "SandboxConfigUserPolicyNetwork", "SandboxConfigUserPolicyNetworkProxy", "SandboxConfigUserPolicySeatbelt", + "SandboxCredentialSuggestion", + "SandboxCredentialSuggestionsResult", "SandboxCredentialsConfig", "SandboxDisableForSessionRequest", "SandboxDisableForSessionResult", diff --git a/rust/src/generated/api_types.rs b/rust/src/generated/api_types.rs index 10d4e963b1..577940cb1e 100644 --- a/rust/src/generated/api_types.rs +++ b/rust/src/generated/api_types.rs @@ -97,8 +97,16 @@ pub mod rpc_methods { pub const MCP_CONFIG_DISABLE: &str = "mcp.config.disable"; /// `mcp.config.reload` pub const MCP_CONFIG_RELOAD: &str = "mcp.config.reload"; + /// `mcp.registry.allocateRequestId` + pub const MCP_REGISTRY_ALLOCATEREQUESTID: &str = "mcp.registry.allocateRequestId"; + /// `mcp.registry.search` + pub const MCP_REGISTRY_SEARCH: &str = "mcp.registry.search"; + /// `mcp.registry.cancel` + pub const MCP_REGISTRY_CANCEL: &str = "mcp.registry.cancel"; /// `mcp.discover` pub const MCP_DISCOVER: &str = "mcp.discover"; + /// `mcp.shouldExcludeGitHubTools` + pub const MCP_SHOULDEXCLUDEGITHUBTOOLS: &str = "mcp.shouldExcludeGitHubTools"; /// `mcp.planInstall` pub const MCP_PLANINSTALL: &str = "mcp.planInstall"; /// `mcp.prepareInstall` @@ -349,6 +357,9 @@ pub mod rpc_methods { pub const SESSION_SENDMESSAGES: &str = "session.sendMessages"; /// `session.sandbox.getEnforcementStatus` pub const SESSION_SANDBOX_GETENFORCEMENTSTATUS: &str = "session.sandbox.getEnforcementStatus"; + /// `session.sandbox.getCredentialSuggestions` + pub const SESSION_SANDBOX_GETCREDENTIALSUGGESTIONS: &str = + "session.sandbox.getCredentialSuggestions"; /// `session.sandbox.disableForSession` pub const SESSION_SANDBOX_DISABLEFORSESSION: &str = "session.sandbox.disableForSession"; /// `session.sandbox.grantPathForRequest` @@ -8776,9 +8787,6 @@ pub(crate) struct LoggedInUser { #[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub(crate) struct GlobalStateLoadResult { - /// Whether the user has answered the prompt suggesting they install the desktop app. - #[serde(skip_serializing_if = "Option::is_none")] - pub app_install_nudge_responded: Option, /// Whether the app tip has been shown. #[serde(skip_serializing_if = "Option::is_none")] pub app_tip_shown: Option, @@ -11328,14 +11336,14 @@ pub struct ManagedSettingsMeta { #[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ManagedSettingsResolvedData { - /// Whether enterprise policy disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers, and forced on when `failClosed` is true. + /// Whether an explicit enterprise policy restriction disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers; an unresolved policy does not force this on by itself. pub bypass_permissions_disabled: bool, /// Whether a session-local permissions layer injected by the SDK host was present #[serde(skip_serializing_if = "Option::is_none")] pub client_managed: Option, /// Whether an actual device MDM/plist/registry/file managed-settings layer was present pub device_managed: bool, - /// Whether managed policy could not be determined (e.g. a failed server fetch) and the session fell back to the fail-closed restriction. When true, restrictions such as disabling bypass-permissions are enforced even though `settings` may be absent. + /// Whether managed policy could not be determined (e.g. a failed server fetch) and unresolved-policy safeguards remain active. This does not by itself disable bypass-permissions; `bypassPermissionsDisabled` reports only an explicit policy restriction. pub fail_closed: bool, /// The setting keys under enterprise management in the effective managed settings (e.g. `model`, `enabledPlugins`, `permissions`). Empty when no managed settings are in force. pub managed_keys: Vec, @@ -14026,6 +14034,91 @@ pub(crate) struct McpRegisterExternalClientRequest { pub(crate) transport: serde_json::Value, } +/// Registry search to abandon. +/// +///

+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct McpRegistryCancelRequest { + /// Request ID from `mcp.registry.allocateRequestId` that the search uses. + pub request_id: i64, +} + +/// Whether the cancel reached a live search. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct McpRegistryCancelResult { + /// True when the cancel stopped a running search. False for unknown or reclaimed IDs, completed or canceled searches, and unused reservations. The cancel releases an unused reservation. + pub canceled: bool, +} + +/// Request id naming a cancellable registry search. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct McpRegistryRequestIdResult { + /// Request ID for `mcp.registry.search` and `mcp.registry.cancel`. It serves one search. Allocation can reclaim unused IDs at the 1,024-ID reservation limit. + pub request_id: i64, +} + +/// Registry search terms, the credential to search under, and the request id that makes the search cancellable. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct McpRegistrySearchRequest { + /// The credential the search runs under, carried opaquely. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. + pub auth_info: serde_json::Value, + /// Maximum number of servers to return. + pub limit: i64, + /// Free-text query. Omitted or empty asks the registry for its top servers rather than searching. A value that is not a string is refused. + #[serde(skip_serializing_if = "Option::is_none")] + pub query: Option, + /// Repository used for the policy lookup, as `owner/name`. The policy selects the registry URL and whether the user token goes to the registry. The registry receives this repository only when the policy entry lists it as required context. A value that is not a string is refused. + #[serde(skip_serializing_if = "Option::is_none")] + pub repository: Option, + /// Request ID from `mcp.registry.allocateRequestId`. The search refuses unknown, reclaimed, or canceled IDs and IDs that another search or request already uses. + pub request_id: i64, +} + +/// Servers selected from the registry response. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct McpRegistrySearchResult { + /// The server objects, carried opaquely. The runtime follows pages, keeps the newest entry per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub stars. Each server object remains unchanged because the registry owns that shape. + pub servers: serde_json::Value, +} + /// In-process MCP reload configuration. /// ///
@@ -14846,6 +14939,43 @@ pub struct McpSetEnvValueModeResult { pub mode: McpSetEnvValueModeDetails, } +/// The session tool filters that decide whether the session still has a shell to run `gh` with. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct McpShouldExcludeGitHubToolsRequest { + /// The session's tool allowlist, when it set one. Omitted means the session constrains nothing this way. + #[serde(skip_serializing_if = "Option::is_none")] + pub available_tools: Option>, + /// The session's tool denylist, when it set one. Omitted means the session constrains nothing this way. + #[serde(skip_serializing_if = "Option::is_none")] + pub excluded_tools: Option>, + /// How the allowlist and denylist combine when both are set. Omitted means the default every session gets, so a caller that never chose a precedence is answered as its sessions behave. + #[serde(skip_serializing_if = "Option::is_none")] + pub tool_filter_precedence: Option, +} + +/// Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by the request. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct McpShouldExcludeGitHubToolsResult { + /// True only when both halves hold: the session's filters still reach the platform shell tool, and the host actually has the `gh` those tools would be replaced by. Feed it straight back as the `excludeGhReplaceableTools` build option. + pub exclude_gh_replaceable_tools: bool, +} + /// Server name and optional configuration for an individual MCP server start. Omit `config` for a config-free start-by-name of an already-configured server. /// ///
@@ -21225,6 +21355,38 @@ pub struct SandboxConfig { pub user_policy: Option, } +/// A possible secret-bearing environment variable and optional locally suggested HTTPS injection hosts. This is a draft for user review, not an active grant. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SandboxCredentialSuggestion { + /// Environment variable name. The secret value is never returned. + pub name: String, + /// HTTPS hostnames suggested by a local known-provider mapping. An empty list requires the user to supply injection hosts before adding a masking entry. These suggestions do not allow network access. + pub suggested_inject_hosts: Vec, +} + +/// Possible unconfigured secrets in the sandbox shell environment, sorted by variable name, with no secret values. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SandboxCredentialSuggestionsResult { + /// Candidates for user review. Empty when sandboxing is disabled or no unconfigured candidates are present. + pub suggestions: Vec, +} + /// Request to disable sandboxing for the current session while resolving an active sandbox-bypass permission prompt. /// ///
@@ -30584,6 +30746,21 @@ pub struct McpConfigListResult { pub servers: HashMap, } +/// Request id naming a cancellable registry search. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct McpRegistryAllocateRequestIdResult { + /// Request ID for `mcp.registry.search` and `mcp.registry.cancel`. It serves one search. Allocation can reclaim unused IDs at the 1,024-ID reservation limit. + pub request_id: i64, +} + /// Extensions discovered from persisted Copilot home state and their effective loading mode. Launch-scoped additional plugins are not included. /// ///
@@ -30860,9 +31037,6 @@ pub struct InstructionsGetDiscoveryPathsResult { #[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub(crate) struct GlobalStateLoadForConfigDirResult { - /// Whether the user has answered the prompt suggesting they install the desktop app. - #[serde(skip_serializing_if = "Option::is_none")] - pub app_install_nudge_responded: Option, /// Whether the app tip has been shown. #[serde(skip_serializing_if = "Option::is_none")] pub app_tip_shown: Option, @@ -31545,6 +31719,36 @@ pub struct SessionSandboxGetEnforcementStatusResult { pub required: bool, } +/// Identifies the target session. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SessionSandboxGetCredentialSuggestionsParams { + /// Target session identifier + pub session_id: SessionId, +} + +/// Possible unconfigured secrets in the sandbox shell environment, sorted by variable name, with no secret values. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SessionSandboxGetCredentialSuggestionsResult { + /// Candidates for user review. Empty when sandboxing is disabled or no unconfigured candidates are present. + pub suggestions: Vec, +} + /// Result of attempting to disable sandboxing for the current session. /// ///
@@ -34994,14 +35198,14 @@ pub struct SessionManagedSettingsGetParams { #[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct SessionManagedSettingsGetResult { - /// Whether enterprise policy disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers, and forced on when `failClosed` is true. + /// Whether an explicit enterprise policy restriction disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers; an unresolved policy does not force this on by itself. pub bypass_permissions_disabled: bool, /// Whether a session-local permissions layer injected by the SDK host was present #[serde(skip_serializing_if = "Option::is_none")] pub client_managed: Option, /// Whether an actual device MDM/plist/registry/file managed-settings layer was present pub device_managed: bool, - /// Whether managed policy could not be determined (e.g. a failed server fetch) and the session fell back to the fail-closed restriction. When true, restrictions such as disabling bypass-permissions are enforced even though `settings` may be absent. + /// Whether managed policy could not be determined (e.g. a failed server fetch) and unresolved-policy safeguards remain active. This does not by itself disable bypass-permissions; `bypassPermissionsDisabled` reports only an explicit policy restriction. pub fail_closed: bool, /// The setting keys under enterprise management in the effective managed settings (e.g. `model`, `enabledPlugins`, `permissions`). Empty when no managed settings are in force. pub managed_keys: Vec, @@ -43936,6 +44140,28 @@ pub enum McpSetEnvValueModeDetails { Unknown, } +/// Controls how availableTools (allowlist) and excludedTools (denylist) combine when both are set. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum OptionsUpdateToolFilterPrecedence { + /// If availableTools is set, it is the only constraint that applies (excludedTools is ignored). Preserves CLI / pre-existing client behavior. Default. + #[serde(rename = "available")] + Available, + /// A tool is enabled if and only if it matches the allowlist (or the allowlist is unset) AND it does not match the denylist. Makes 'all except X' expressible by combining the two lists. + #[serde(rename = "excluded")] + Excluded, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + /// Hosting platform type of the repository /// ///
@@ -44449,28 +44675,6 @@ pub enum OptionsUpdateReasoningSummary { Unknown, } -/// Controls how availableTools (allowlist) and excludedTools (denylist) combine when both are set. -/// -///
-/// -/// **Experimental.** This type is part of an experimental wire-protocol surface -/// and may change or be removed in future SDK or CLI releases. -/// -///
-#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] -pub enum OptionsUpdateToolFilterPrecedence { - /// If availableTools is set, it is the only constraint that applies (excludedTools is ignored). Preserves CLI / pre-existing client behavior. Default. - #[serde(rename = "available")] - Available, - /// A tool is enabled if and only if it matches the allowlist (or the allowlist is unset) AND it does not match the denylist. Makes 'all except X' expressible by combining the two lists. - #[serde(rename = "excluded")] - Excluded, - /// Unknown variant for forward compatibility. - #[default] - #[serde(other)] - Unknown, -} - /// Approve this single request only #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] pub enum PermissionDecisionApproveOnceKind { diff --git a/rust/src/generated/rpc.rs b/rust/src/generated/rpc.rs index 2af2f66e82..e2b69d3933 100644 --- a/rust/src/generated/rpc.rs +++ b/rust/src/generated/rpc.rs @@ -1452,7 +1452,7 @@ impl<'a> ClientRpcGlobalState<'a> { Ok(serde_json::from_value(_value)?) } - /// Records one top-level key in the host's machine-wide state, the counterpart to `globalState.load`. A host calls this to remember that it has shown an onboarding step, asked a one-off question, or completed a migration, so the next run can skip it. Only the named key is replaced and the rest of the document is preserved, which lets two writers record different flags without overwriting each other; passing no value removes the key instead. Only the keys a host records itself are writable: `appInstallNudgeResponded`, `appTipShown`, `askedSetupTerminals`, `autoFeedbackLastPromptedAt`, `firstLaunchAt`, `recentModelIds`, `sandboxCredentialProxyCaDeclined` and `sandboxOnboardingShown`. Every other key is refused, including `installedPlugins`, the stored credentials, `trustedFolders`, the staff flags and the signed-in accounts. Plugin enablement must use the plugin APIs, which apply repository and managed-policy checks. + /// Records one top-level key in the host's machine-wide state, the counterpart to `globalState.load`. A host calls this to remember that it has shown an onboarding step, asked a one-off question, or completed a migration, so the next run can skip it. Only the named key is replaced and the rest of the document is preserved, which lets two writers record different flags without overwriting each other; passing no value removes the key instead. Only the keys a host records itself are writable: `appTipShown`, `askedSetupTerminals`, `autoFeedbackLastPromptedAt`, `firstLaunchAt`, `recentModelIds`, `sandboxCredentialProxyCaDeclined` and `sandboxOnboardingShown`. Every other key is refused, including `installedPlugins`, the stored credentials, `trustedFolders`, the staff flags and the signed-in accounts. Plugin enablement must use the plugin APIs, which apply repository and managed-policy checks. /// /// Wire method: `globalState.writeKey`. /// @@ -2254,6 +2254,13 @@ impl<'a> ClientRpcMcp<'a> { } } + /// `mcp.registry.*` sub-namespace. + pub fn registry(&self) -> ClientRpcMcpRegistry<'a> { + ClientRpcMcpRegistry { + client: self.client, + } + } + /// Discovers MCP servers from user, workspace, plugin, and builtin sources. /// /// Wire method: `mcp.discover`. @@ -2282,6 +2289,37 @@ impl<'a> ClientRpcMcp<'a> { Ok(serde_json::from_value(_value)?) } + /// Reports whether the gh-replaceable GitHub MCP tools may be clipped for a session, which a host feeds back as the `excludeGhReplaceableTools` build option. The tools are redundant only when the session can reach a shell *and* the host has the `gh` that would replace them, so both halves are decided here. The shell half runs the platform shell tool through the runtime's own tool-filter matcher, so entry forms like `builtin:bash` and `builtin:*` behave exactly as they do when a session builds its tool catalog. The host half probes for `gh`, and is skipped entirely when the filters already rule the shell out. Host presence alone is not enough: a session restricted to, say, `view` would otherwise lose the built-in issue-read fallback while having no shell to replace it with. The answer describes the host the runtime runs on, so it is never forwarded to a remote engine. + /// + /// Wire method: `mcp.shouldExcludeGitHubTools`. + /// + /// # Parameters + /// + /// * `params` - The session tool filters that decide whether the session still has a shell to run `gh` with. + /// + /// # Returns + /// + /// Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by the request. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn should_exclude_git_hub_tools( + &self, + params: McpShouldExcludeGitHubToolsRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::MCP_SHOULDEXCLUDEGITHUBTOOLS, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + /// Requests a side-effect-free MCP install plan from a catalog candidate handle or a caller-supplied card. This host-implemented server method is available through SDK/TUI hosts; standalone and C-ABI runtimes whose host does not implement server-method dispatch return JSON-RPC MethodNotFound. A runtime with planning available returns a normalised plan and opaque single-use plan handle; a runtime without it returns the typed planning-unavailable result. A completed plan reports resource identity, provenance, eligible transport choices, the user-scope target, required typed values and secret placeholders, the policy result, the configuration changes installing would make, and whether a reload would be needed. Planning never writes configuration, stores a secret, or reloads MCP servers, so abandoning a plan needs no call and leaves nothing behind. /// /// Wire method: `mcp.planInstall`. @@ -2775,6 +2813,103 @@ impl<'a> ClientRpcMcpInstallations<'a> { } } +/// `mcp.registry.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcMcpRegistry<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcMcpRegistry<'a> { + /// Allocates an ID for one cancellable MCP registry search. The ID exists before the search starts, so callers can cancel before it starts. The networking stack supplies the cancellation namespace. The runtime retains at most 1,024 unused IDs. At capacity, another allocation can reclaim an unused ID. Active searches retain their IDs until they finish. + /// + /// Wire method: `mcp.registry.allocateRequestId`. + /// + /// # Returns + /// + /// Request id naming a cancellable registry search. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn allocate_request_id(&self) -> Result { + let wire_params = serde_json::json!({}); + let _value = self + .client + .call( + rpc_methods::MCP_REGISTRY_ALLOCATEREQUESTID, + Some(wire_params), + ) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Searches the MCP registry the supplied credential may read, resolving the registry endpoint from policy first. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. The runtime follows registry pages, keeps the newest entry per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub stars. Each server object is carried opaquely. + /// + /// Wire method: `mcp.registry.search`. + /// + /// # Parameters + /// + /// * `params` - Registry search terms, the credential to search under, and the request id that makes the search cancellable. + /// + /// # Returns + /// + /// Servers selected from the registry response. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn search( + &self, + params: McpRegistrySearchRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::MCP_REGISTRY_SEARCH, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Abandons the registry search that uses the given request ID. It acts only on IDs from `mcp.registry.allocateRequestId`, so it never cancels another component's request. Answers `canceled: true` when it stops a running search. Answers `canceled: false` for unknown or reclaimed IDs, completed or canceled searches, and unused reservations. It releases an unused reservation, so a later search with that ID is refused. + /// + /// Wire method: `mcp.registry.cancel`. + /// + /// # Parameters + /// + /// * `params` - Registry search to abandon. + /// + /// # Returns + /// + /// Whether the cancel reached a live search. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn cancel( + &self, + params: McpRegistryCancelRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::MCP_REGISTRY_CANCEL, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } +} + /// `models.*` RPCs. #[derive(Clone, Copy)] pub struct ClientRpcModels<'a> { @@ -13656,6 +13791,36 @@ impl<'a> SessionRpcSandbox<'a> { Ok(serde_json::from_value(_value)?) } + /// Lists possible secret-bearing environment variables available to new sandboxed shells that are not already covered by credential masking. Uses local name rules and known-provider host suggestions, never returns secret values, and changes no settings or network permissions. Returns no suggestions while the session is not sandboxed. + /// + /// Wire method: `session.sandbox.getCredentialSuggestions`. + /// + /// # Returns + /// + /// Possible unconfigured secrets in the sandbox shell environment, sorted by variable name, with no secret values. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn get_credential_suggestions( + &self, + ) -> Result { + let wire_params = serde_json::json!({ "sessionId": self.session.id() }); + let _value = self + .session + .client() + .call( + rpc_methods::SESSION_SANDBOX_GETCREDENTIALSUGGESTIONS, + Some(wire_params), + ) + .await?; + Ok(serde_json::from_value(_value)?) + } + /// Disables sandboxing for the remainder of the current session and approves the referenced pending sandbox-bypass permission request. The request is rejected unless the exact request is still pending and the effective sandbox policy permits bypass. /// /// Wire method: `session.sandbox.disableForSession`. diff --git a/rust/src/generated/session_events.rs b/rust/src/generated/session_events.rs index 8d3f7a844a..8d0e4d9b65 100644 --- a/rust/src/generated/session_events.rs +++ b/rust/src/generated/session_events.rs @@ -8100,14 +8100,14 @@ pub struct ManagedPermissionsContext { #[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct SessionManagedSettingsResolvedData { - /// Whether enterprise policy disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers, and forced on when `failClosed` is true. + /// Whether an explicit enterprise policy restriction disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers; an unresolved policy does not force this on by itself. pub bypass_permissions_disabled: bool, /// Whether a session-local permissions layer injected by the SDK host was present #[serde(skip_serializing_if = "Option::is_none")] pub client_managed: Option, /// Whether an actual device MDM/plist/registry/file managed-settings layer was present pub device_managed: bool, - /// Whether managed policy could not be determined (e.g. a failed server fetch) and the session fell back to the fail-closed restriction. When true, restrictions such as disabling bypass-permissions are enforced even though `settings` may be absent. + /// Whether managed policy could not be determined (e.g. a failed server fetch) and unresolved-policy safeguards remain active. This does not by itself disable bypass-permissions; `bypassPermissionsDisabled` reports only an explicit policy restriction. pub fail_closed: bool, /// The setting keys under enterprise management in the effective managed settings (e.g. `model`, `enabledPlugins`, `permissions`). Empty when no managed settings are in force. pub managed_keys: Vec, diff --git a/test/snapshots/skill_provider/should_preserve_skill_prompt_bytes_across_cold_resume_with_reordered_discovery.yaml b/test/snapshots/skill_provider/should_preserve_skill_prompt_bytes_across_cold_resume_with_reordered_discovery.yaml new file mode 100644 index 0000000000..72910c73cd --- /dev/null +++ b/test/snapshots/skill_provider/should_preserve_skill_prompt_bytes_across_cold_resume_with_reordered_discovery.yaml @@ -0,0 +1,14 @@ +models: + - claude-sonnet-5 +conversations: + - messages: + - role: system + content: ${system} + - role: user + content: Without using tools, reply with exactly SKILL_ORDER_INITIAL_OK. + - role: assistant + content: SKILL_ORDER_INITIAL_OK + - role: user + content: Without using tools, reply with exactly SKILL_ORDER_RESUMED_OK. + - role: assistant + content: SKILL_ORDER_RESUMED_OK From 6be623b01b194a61466385e3f708639ec98ce8ac Mon Sep 17 00:00:00 2001 From: "copilot-cli-release-app[bot]" Date: Sat, 10 Oct 2026 02:20:03 +0000 Subject: [PATCH 6/9] Update SDK snapshot for Copilot CLI 1.0.96-2 --- nodejs/package.json | 2 +- nodejs/src/cliVersion.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nodejs/package.json b/nodejs/package.json index a0d1e8e5dd..4e68a1b0eb 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -5,7 +5,7 @@ "url": "https://github.com/github/copilot-sdk.git" }, "version": "0.0.0-dev", - "copilotCliVersion": "1.0.96-1", + "copilotCliVersion": "1.0.96-2", "description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC", "main": "./dist/cjs/index.js", "types": "./dist/index.d.ts", diff --git a/nodejs/src/cliVersion.ts b/nodejs/src/cliVersion.ts index 196f9326fb..884f2a267e 100644 --- a/nodejs/src/cliVersion.ts +++ b/nodejs/src/cliVersion.ts @@ -1,3 +1,3 @@ -export const COPILOT_CLI_VERSION = "1.0.96-1"; +export const COPILOT_CLI_VERSION = "1.0.96-2"; export const COPILOT_CLI_USE_NPM_PACKAGE = false; From a72e9dda2b1269e6d684bdb7a1de43f5c0c539df Mon Sep 17 00:00:00 2001 From: "copilot-cli-release-app[bot]" Date: Mon, 12 Oct 2026 20:56:33 +0000 Subject: [PATCH 7/9] Update SDK snapshot for Copilot CLI 1.0.97-0 --- .../workflows/block-remove-before-merge.yml | 1 - .github/workflows/sdk-dotnet.yml | 27 +- .github/workflows/sdk-go.yml | 9 +- .github/workflows/sdk-java.yml | 6 - .github/workflows/sdk-nodejs.yml | 5 - .github/workflows/sdk-python.yml | 5 - .github/workflows/sdk-runtime-artifact.yml | 13 +- .github/workflows/sdk-rust.yml | 8 +- .github/workflows/sdk.yml | 45 +- BUILD.bazel | 5 + CONTRIBUTING.md | 10 +- docs/features/custom-agents.md | 2 + docs/features/customization-locations.md | 55 + docs/features/hooks.md | 49 + docs/features/mcp.md | 2 +- dotnet/src/Client.cs | 10 + dotnet/src/Generated/Rpc.cs | 2360 +++++++++++++---- dotnet/src/Generated/SessionEvents.cs | 50 +- dotnet/src/Types.cs | 59 +- dotnet/test/E2E/ClientOptionsE2ETests.cs | 3 + dotnet/test/E2E/PendingWorkResumeE2ETests.cs | 57 +- dotnet/test/E2E/PermissionE2ETests.cs | 69 +- dotnet/test/E2E/SessionE2ETests.cs | 49 +- dotnet/test/Harness/E2ETestBase.cs | 2 +- dotnet/test/Harness/E2ETestContext.cs | 2 +- ...nLifetimeTests.CustomizationDirectories.cs | 157 ++ dotnet/test/Unit/E2ETestFixtureTests.cs | 23 + dotnet/test/Unit/RuntimeWrapperTests.cs | 3 +- go/client.go | 5 + go/client_test.go | 32 + go/customization_directories_test.go | 116 + go/internal/e2e/client_options_e2e_test.go | 2 + go/internal/jsonrpc2/jsonrpc2.go | 23 +- go/internal/jsonrpc2/jsonrpc2_test.go | 135 + go/rpc/repo_settings_test.go | 54 + go/rpc/settings_presence_test.go | 107 + go/rpc/zrpc.go | 1488 ++++++++++- go/rpc/zrpc_encoding.go | 6 + go/rpc/zsession_encoding.go | 4 + go/rpc/zsession_events.go | 16 +- go/types.go | 82 +- go/zsession_events.go | 1 + java/README.md | 13 + java/scripts/codegen/java.ts | 28 +- java/sdk/pom.xml | 4 +- ...ompactionCompleteCompactionTokensUsed.java | 2 + .../generated/PermissionRecoveryData.java | 4 + .../generated/PermissionRequestedEvent.java | 4 + .../copilot/generated/RemediationAction.java | 4 +- .../copilot/generated/SessionErrorEvent.java | 6 +- .../SessionPermissionRecoveryEvent.java | 4 + .../rpc/AccountDescribeAuthInfoParams.java | 30 + .../rpc/AccountDescribeAuthInfoResult.java | 29 + .../rpc/AccountGetGistSupportParams.java | 30 + .../rpc/AccountGetGistSupportResult.java | 31 + .../rpc/AccountGetTokenEnvVarResult.java | 27 + .../generated/rpc/AccountGetWebUrlParams.java | 32 + .../generated/rpc/AccountGetWebUrlResult.java | 27 + .../copilot/generated/rpc/AgentInfo.java | 4 +- .../generated/rpc/AgentsDiscoverRequest.java | 107 + .../rpc/AgentsGetDiscoveryPathsRequest.java | 107 + .../rpc/FeatureFlagAvailability.java | 49 + .../generated/rpc/FeatureFlagMetadata.java | 37 + .../rpc/FeatureFlagsMetadataResult.java | 28 + .../rpc/FeatureFlagsResolveParams.java | 47 + .../generated/rpc/GitHubOwnersListParams.java | 1 + .../generated/rpc/HooksDiscoverRequest.java | 107 + ...InstructionsDiscoverRepoSourcesParams.java | 41 + .../rpc/InstructionsDiscoverRequest.java | 107 + .../InstructionsGetDiscoveryPathsRequest.java | 107 + .../rpc/InstructionsInitPromptResult.java | 27 + .../rpc/ManagedSettingsValidateParams.java | 1 + .../rpc/McpListBuiltinServerNamesResult.java | 32 + .../rpc/McpRegistrySearchParams.java | 1 + .../generated/rpc/PermissionRecoveryData.java | 4 + .../generated/rpc/RemediationAction.java | 4 +- .../rpc/RepoSettingsReadRawParams.java | 32 + .../rpc/RepoSettingsReadRawResult.java | 29 + .../rpc/RepoSettingsWriteAllParams.java | 35 + .../rpc/RepoSettingsWriteKeyParams.java | 38 + .../generated/rpc/ServerAccountApi.java | 44 + .../generated/rpc/ServerAgentsApi.java | 27 + .../generated/rpc/ServerFeatureFlagsApi.java | 52 + .../copilot/generated/rpc/ServerHooksApi.java | 14 + .../rpc/ServerInstructionSourceList.java | 28 + .../generated/rpc/ServerInstructionsApi.java | 60 + .../copilot/generated/rpc/ServerMcpApi.java | 11 + .../copilot/generated/rpc/ServerRepoApi.java | 32 + .../generated/rpc/ServerRepoSettingsApi.java | 62 + .../copilot/generated/rpc/ServerRpc.java | 12 +- .../generated/rpc/ServerSkillsApi.java | 14 + .../generated/rpc/ServerUserSettingsApi.java | 110 + .../SessionCanvasProviderRegisterParams.java | 1 + .../rpc/SessionMcpExecuteSamplingParams.java | 1 + .../generated/rpc/SessionModelApi.java | 16 + ...ssionModelGetReasoningSummariesParams.java | 44 + ...ssionModelGetReasoningSummariesResult.java | 44 + .../generated/rpc/SessionOpenOptions.java | 10 +- .../rpc/SessionOptionsUpdateParams.java | 12 +- ...QueueConsumeSystemNotificationsParams.java | 1 + .../rpc/SessionToolsExecuteParams.java | 1 + ...ssionToolsTaskCompleteEventDataParams.java | 1 + .../rpc/SessionWorkflowJournalPutParams.java | 1 + .../rpc/SessionWorkflowRunFromToolParams.java | 1 + .../rpc/SessionWorkflowRunParams.java | 1 + .../generated/rpc/SettingsEditOperation.java | 43 + .../generated/rpc/SettingsEditResult.java | 31 + .../generated/rpc/SettingsEditStatus.java | 41 + .../generated/rpc/SkillsDiscoverParams.java | 2 +- .../rpc/SkillsGetDiscoveryPathsRequest.java | 131 + .../rpc/UserSettingsApplyTopKeyParams.java | 39 + .../rpc/UserSettingsApplyTopKeyResult.java | 32 + .../UserSettingsDiagnoseProblemsParams.java | 31 + .../generated/rpc/UserSettingsEditParams.java | 37 + .../rpc/UserSettingsGetPathsParams.java | 30 + .../rpc/UserSettingsGetPathsResult.java | 31 + .../rpc/UserSettingsGovernanceKeysResult.java | 32 + .../rpc/UserSettingsLoadForEditResult.java | 29 + .../rpc/UserSettingsNormalizeParams.java | 31 + .../rpc/UserSettingsNormalizeResult.java | 27 + .../generated/rpc/UserSettingsProblem.java | 37 + .../rpc/UserSettingsProblemLocation.java | 31 + .../rpc/UserSettingsProblemSource.java | 36 + .../rpc/UserSettingsProblemsResult.java | 28 + .../generated/rpc/UserSettingsSetParams.java | 1 + .../rpc/UserSettingsUpdateParams.java | 37 + .../rpc/UserSettingsUpdateResult.java | 27 + .../rpc/UserSettingsValidateParams.java | 34 + .../rpc/UserSettingsValidateResult.java | 30 + .../rpc/UserSettingsValidationIssue.java | 30 + .../rpc/UserSettingsWriteAllParams.java | 31 + .../generated/rpc/WorkflowExecuteParams.java | 1 + .../com/github/copilot/CliServerManager.java | 65 +- .../com/github/copilot/CopilotClient.java | 3 + .../github/copilot/SessionRequestBuilder.java | 5 + .../com/github/copilot/rpc/AgentInfo.java | 28 + .../copilot/rpc/CreateSessionRequest.java | 44 + .../github/copilot/rpc/CustomAgentConfig.java | 24 + .../copilot/rpc/ResumeSessionConfig.java | 74 +- .../copilot/rpc/ResumeSessionRequest.java | 31 + .../com/github/copilot/rpc/SessionConfig.java | 100 +- .../com/github/copilot/AgentInfoTest.java | 20 + .../java/com/github/copilot/AutoTierIT.java | 12 +- .../github/copilot/CliServerManagerTest.java | 173 +- .../github/copilot/ClientOptionsE2ETest.java | 5 +- .../com/github/copilot/E2ETestContext.java | 2 +- .../github/copilot/E2ETestContextTest.java | 25 + .../copilot/RpcHandlerDispatcherTest.java | 4 + .../com/github/copilot/RpcWrappersTest.java | 80 + .../copilot/SessionEventHandlingTest.java | 4 +- .../copilot/SessionRequestBuilderTest.java | 67 + .../rpc/GeneratedRpcRecordsCoverageTest.java | 17 +- nodejs/README.md | 37 + nodejs/examples/internal-feature-flags.ts | 95 + nodejs/examples/internal-user-settings.ts | 29 + nodejs/package-lock.json | 780 ++---- nodejs/package.json | 5 +- nodejs/samples/package-lock.json | 1226 ++++++--- nodejs/src/cliVersion.ts | 2 +- nodejs/src/client.ts | 5 + nodejs/src/generated/rpc.ts | 1313 ++++++++- nodejs/src/generated/session-events.ts | 34 +- nodejs/src/index.ts | 7 +- nodejs/src/types.ts | 51 +- nodejs/test/account-facts-projection.test.ts | 45 + nodejs/test/csharp-codegen.test.ts | 15 + nodejs/test/customization-directories.test.ts | 100 + .../test/e2e/agent_scoped_hooks.e2e.test.ts | 69 + .../assisted_autopilot_permission.e2e.test.ts | 345 ++- nodejs/test/e2e/commands.e2e.test.ts | 81 +- nodejs/test/e2e/compaction.e2e.test.ts | 296 +++ .../e2e/copilot_request_handler.e2e.test.ts | 729 ++++- .../e2e/customization_directories.e2e.test.ts | 387 +++ .../test/e2e/disabled_mcp_servers.e2e.test.ts | 17 +- .../test/e2e/entra_identity_first.e2e.test.ts | 184 +- nodejs/test/e2e/harness/mcpTestServer.ts | 24 + nodejs/test/e2e/harness/sdkTestContext.ts | 27 +- nodejs/test/e2e/hydrafusion_max.e2e.test.ts | 246 +- nodejs/test/e2e/mcp_and_agents.e2e.test.ts | 79 +- .../mcp_remote_session_closure.e2e.test.ts | 51 +- .../test/e2e/mcp_scoped_sign_in.e2e.test.ts | 14 + .../test/e2e/pending_work_resume.e2e.test.ts | 30 +- nodejs/test/e2e/rpc_mcp_lifecycle.e2e.test.ts | 97 + nodejs/test/e2e/rpc_session_state.e2e.test.ts | 54 + nodejs/test/e2e/rpc_settings.e2e.test.ts | 138 + .../test/e2e/rpc_shell_and_fleet.e2e.test.ts | 51 +- .../test/e2e/rpc_surface_coverage.e2e.test.ts | 14 +- nodejs/test/e2e/sandbox_network.e2e.test.ts | 20 + nodejs/test/e2e/session_fs.e2e.test.ts | 129 +- nodejs/test/e2e/structured_output.e2e.test.ts | 48 +- .../e2e/subagent_prompt_resume.e2e.test.ts | 111 +- nodejs/test/e2e/telemetry.e2e.test.ts | 5 + .../e2e/telemetry_preparation.e2e.test.ts | 170 ++ .../e2e/tools_anthropic_updates.e2e.test.ts | 772 +++++- .../test/e2e/user_settings_edit.e2e.test.ts | 63 + nodejs/test/e2e/workflow.e2e.test.ts | 15 +- nodejs/test/java-codegen.test.ts | 90 +- nodejs/test/reasoning-summaries-types.test.ts | 19 + nodejs/test/rust-codegen.test.ts | 36 + nodejs/test/toolSet.test.ts | 21 + nodejs/tsconfig.test.json | 1 + nodejs/vitest.config.ts | 2 + python/copilot/client.py | 71 +- python/copilot/generated/rpc.py | 2192 +++++++++++++-- python/copilot/generated/session_events.py | 47 + python/copilot/session.py | 1 + python/e2e/test_client_options_e2e.py | 2 + python/test_customization_directories.py | 71 + rust/Cargo.toml | 4 +- rust/README.md | 6 + .../crates/BUILD.windows-sys-0.61.2.bazel | 4 +- rust/src/ahp_host.rs | 2 + rust/src/ahp_host/factory_tests.rs | 1 + rust/src/copilot_request_handler.rs | 29 +- rust/src/generated/api_types.rs | 1663 +++++++++++- rust/src/generated/rpc.rs | 938 ++++++- rust/src/generated/session_events.rs | 32 +- rust/src/process_tree.rs | 198 +- rust/src/process_tree/tests.rs | 318 +++ rust/src/tests.rs | 55 + rust/src/types.rs | 141 +- .../types/customization_directory_tests.rs | 88 + rust/src/types/tests.rs | 49 + rust/src/wire.rs | 10 + rust/tests/e2e/client_options.rs | 6 + .../client_options/windows_process_tree.rs | 252 ++ rust/tests/e2e/session_lifecycle.rs | 76 +- rust/tests/e2e/telemetry.rs | 21 +- rust/tests/fixtures/host_crash_fixture.rs | 11 +- rust/tests/http_request_body_test.rs | 614 +++++ scripts/ci/check-generated.test.mjs | 40 +- scripts/ci/run-dotnet-tests.sh | 5 + scripts/ci/run-dotnet-tests.test.mjs | 17 +- scripts/codegen/csharp.ts | 38 +- scripts/codegen/go.ts | 45 +- scripts/codegen/python.ts | 80 +- scripts/codegen/rust.ts | 8 +- scripts/corrections/package-lock.json | 532 ++-- scripts/corrections/package.json | 2 +- scripts/docs-validation/package-lock.json | 6 +- test/harness/package-lock.json | 534 ++-- test/harness/package.json | 7 +- test/harness/replayingCapiProxy.test.ts | 26 + test/harness/replayingCapiProxy.ts | 9 + test/harness/sdk-diagnostics.mjs | 179 +- test/harness/sdk-diagnostics.test.ts | 279 +- test/harness/sessionExpiryMcpServer.test.mjs | 108 +- test/harness/stdio-shutdown-runtime.cjs | 19 +- test/harness/test-mcp-server.mjs | 5 +- .../test-mcp-session-expiry-server.mjs | 29 +- ...andle_async_permission_handler_dotnet.yaml | 20 + ...ummaries_policy_for_the_current_model.yaml | 3 + 252 files changed, 22444 insertions(+), 3278 deletions(-) create mode 100644 docs/features/customization-locations.md create mode 100644 dotnet/test/Unit/ClientSessionLifetimeTests.CustomizationDirectories.cs create mode 100644 go/customization_directories_test.go create mode 100644 go/rpc/repo_settings_test.go create mode 100644 go/rpc/settings_presence_test.go create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountDescribeAuthInfoParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountDescribeAuthInfoResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetGistSupportParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetGistSupportResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetTokenEnvVarResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetWebUrlParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetWebUrlResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsDiscoverRequest.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetDiscoveryPathsRequest.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagAvailability.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagMetadata.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagsMetadataResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagsResolveParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/HooksDiscoverRequest.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsDiscoverRepoSourcesParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsDiscoverRequest.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsGetDiscoveryPathsRequest.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsInitPromptResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpListBuiltinServerNamesResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsReadRawParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsReadRawResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsWriteAllParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsWriteKeyParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerFeatureFlagsApi.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerInstructionSourceList.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRepoApi.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRepoSettingsApi.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetReasoningSummariesParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetReasoningSummariesResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SettingsEditOperation.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SettingsEditResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SettingsEditStatus.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillsGetDiscoveryPathsRequest.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsApplyTopKeyParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsApplyTopKeyResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsDiagnoseProblemsParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsEditParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetPathsParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetPathsResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGovernanceKeysResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadForEditResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsNormalizeParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsNormalizeResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblem.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblemLocation.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblemSource.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblemsResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsUpdateParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsUpdateResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsValidateParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsValidateResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsValidationIssue.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsWriteAllParams.java create mode 100644 nodejs/examples/internal-feature-flags.ts create mode 100644 nodejs/examples/internal-user-settings.ts create mode 100644 nodejs/test/account-facts-projection.test.ts create mode 100644 nodejs/test/customization-directories.test.ts create mode 100644 nodejs/test/e2e/agent_scoped_hooks.e2e.test.ts create mode 100644 nodejs/test/e2e/customization_directories.e2e.test.ts create mode 100644 nodejs/test/e2e/harness/mcpTestServer.ts create mode 100644 nodejs/test/e2e/rpc_settings.e2e.test.ts create mode 100644 nodejs/test/e2e/telemetry_preparation.e2e.test.ts create mode 100644 nodejs/test/e2e/user_settings_edit.e2e.test.ts create mode 100644 nodejs/test/reasoning-summaries-types.test.ts create mode 100644 python/test_customization_directories.py create mode 100644 rust/src/process_tree/tests.rs create mode 100644 rust/src/types/customization_directory_tests.rs create mode 100644 rust/tests/e2e/client_options/windows_process_tree.rs create mode 100644 rust/tests/http_request_body_test.rs create mode 100644 test/snapshots/permissions/should_handle_async_permission_handler_dotnet.yaml create mode 100644 test/snapshots/rpc_session_state/should_read_the_reasoning_summaries_policy_for_the_current_model.yaml diff --git a/.github/workflows/block-remove-before-merge.yml b/.github/workflows/block-remove-before-merge.yml index 443eea9f7c..0cd4a9824e 100644 --- a/.github/workflows/block-remove-before-merge.yml +++ b/.github/workflows/block-remove-before-merge.yml @@ -17,7 +17,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: fetch-depth: 2 - name: Check for remove-before-merge paths in PR diff --git a/.github/workflows/sdk-dotnet.yml b/.github/workflows/sdk-dotnet.yml index 14a4c3265b..5ebbe5c0c4 100644 --- a/.github/workflows/sdk-dotnet.yml +++ b/.github/workflows/sdk-dotnet.yml @@ -7,7 +7,6 @@ env: HUSKY: 0 POWERSHELL_UPDATECHECK: Off SDK_HOME: ${{ inputs.sdk-home }} - SETUP_NODE_TIMEOUT_MINUTES: 10 on: workflow_call: @@ -27,7 +26,6 @@ jobs: dotnet-linux-x64: name: ".NET (ubuntu-latest, CAPI)" if: inputs.platform == 'all' || inputs.platform == 'linux-x64' - timeout-minutes: 30 runs-on: ubuntu-latest defaults: run: @@ -38,7 +36,6 @@ jobs: DOTNET_TEST_RESULTS_DIRECTORY: TestResults/subprocess steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -102,7 +99,6 @@ jobs: name: ".NET (macos-26-xlarge-agent-runtime, default, CAPI)" if: inputs.platform == 'all' || inputs.platform == 'darwin-arm64' runs-on: macos-26-xlarge-agent-runtime - timeout-minutes: 30 defaults: run: shell: bash @@ -112,7 +108,6 @@ jobs: DOTNET_TEST_RESULTS_DIRECTORY: TestResults/subprocess steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -153,10 +148,19 @@ jobs: retention-days: 7 dotnet-win32-x64: - name: ".NET (windows-latest, default, CAPI)" + name: ".NET (windows-latest, ${{ matrix.framework }}, ${{ matrix.suite.name }}, CAPI)" if: inputs.platform == 'all' || inputs.platform == 'win32-x64' runs-on: windows-latest - timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + framework: [net8.0, net472] + # Complementary filters include every test, including newly added classes. + suite: + - name: e2e-s + filter: FullyQualifiedName~GitHub.Copilot.Test.E2E.S + - name: remaining + filter: FullyQualifiedName!~GitHub.Copilot.Test.E2E.S defaults: run: shell: bash @@ -164,10 +168,11 @@ jobs: env: COPILOT_SDK_E2E_BACKEND: capi DOTNET_TEST_RUNTIME: win-x64 + DOTNET_TEST_FRAMEWORK: ${{ matrix.framework }} + DOTNET_TEST_FILTER: ${{ matrix.suite.filter }} DOTNET_TEST_RESULTS_DIRECTORY: TestResults/subprocess steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -183,7 +188,7 @@ jobs: with: node-version: 22 - run: dotnet restore test/GitHub.Copilot.SDK.Test.csproj --runtime "$DOTNET_TEST_RUNTIME" -p:CopilotCliBinaryPath="$COPILOT_RUNTIME_BINARY_PATH" -p:CopilotSkipCliDownload=true - - run: dotnet build test/GitHub.Copilot.SDK.Test.csproj --no-restore --runtime "$DOTNET_TEST_RUNTIME" -p:CopilotCliBinaryPath="$COPILOT_RUNTIME_BINARY_PATH" -p:CopilotSkipCliDownload=true + - run: dotnet build test/GitHub.Copilot.SDK.Test.csproj --no-restore --framework "$DOTNET_TEST_FRAMEWORK" --runtime "$DOTNET_TEST_RUNTIME" -p:CopilotCliBinaryPath="$COPILOT_RUNTIME_BINARY_PATH" -p:CopilotSkipCliDownload=true - run: npm ci --ignore-scripts working-directory: ${{ inputs.sdk-home }}/test/harness - run: pwsh.exe -Command "Write-Host 'PowerShell ready'" @@ -203,7 +208,7 @@ jobs: - if: failure() uses: actions/upload-artifact@v7 with: - name: dotnet-test-diagnostics-windows-latest-default-capi-${{ github.run_attempt }} + name: dotnet-test-diagnostics-windows-latest-${{ matrix.framework }}-${{ matrix.suite.name }}-capi-${{ github.run_attempt }} path: ${{ inputs.sdk-home }}/dotnet/TestResults/ if-no-files-found: warn retention-days: 7 @@ -212,12 +217,10 @@ jobs: name: ".NET (Alpine x64, CAPI)" if: inputs.platform == 'all' || inputs.platform == 'linuxmusl-x64' runs-on: ubuntu-latest - timeout-minutes: 20 env: COPILOT_SDK_E2E_BACKEND: capi steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime diff --git a/.github/workflows/sdk-go.yml b/.github/workflows/sdk-go.yml index b5593f26b1..d07042076e 100644 --- a/.github/workflows/sdk-go.yml +++ b/.github/workflows/sdk-go.yml @@ -7,7 +7,6 @@ env: HUSKY: 0 POWERSHELL_UPDATECHECK: Off SDK_HOME: ${{ inputs.sdk-home }} - SETUP_NODE_TIMEOUT_MINUTES: 10 on: workflow_call: @@ -38,7 +37,6 @@ jobs: working-directory: ${{ inputs.sdk-home }}/go steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -68,7 +66,9 @@ jobs: - if: runner.os == 'Linux' run: go test ./... working-directory: ${{ inputs.sdk-home }}/go/samples - - run: npm ci --ignore-scripts + - run: | + npm ci --ignore-scripts + npm rebuild esbuild working-directory: ${{ inputs.sdk-home }}/test/harness - if: runner.os == 'Windows' run: pwsh.exe -Command "Write-Host 'PowerShell ready'" @@ -102,10 +102,8 @@ jobs: name: "Go (Alpine x64)" if: inputs.platform == 'all' || inputs.platform == 'linuxmusl-x64' runs-on: ubuntu-latest - timeout-minutes: 20 steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -125,6 +123,7 @@ jobs: apk add --no-cache build-base nodejs npm npm --prefix "$COPILOT_SDK_ROOT/nodejs" ci --ignore-scripts npm --prefix "$COPILOT_SDK_ROOT/test/harness" ci --ignore-scripts + npm --prefix "$COPILOT_SDK_ROOT/test/harness" rebuild esbuild export GITHUB_ENV=/tmp/copilot-sdk-runtime.env export COPILOT_RUNTIME_TARGET=linuxmusl-x64 diff --git a/.github/workflows/sdk-java.yml b/.github/workflows/sdk-java.yml index 011fef0898..28f9650925 100644 --- a/.github/workflows/sdk-java.yml +++ b/.github/workflows/sdk-java.yml @@ -6,7 +6,6 @@ env: HUSKY: 0 POWERSHELL_UPDATECHECK: Off SDK_HOME: ${{ inputs.sdk-home }} - SETUP_NODE_TIMEOUT_MINUTES: 10 on: workflow_call: @@ -43,7 +42,6 @@ jobs: working-directory: ${{ inputs.sdk-home }}/java steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -126,10 +124,8 @@ jobs: name: "Java (JDK 25, linuxmusl-x64)" if: inputs.platform == 'all' || inputs.platform == 'linuxmusl-x64' runs-on: ubuntu-latest - timeout-minutes: 30 steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -187,10 +183,8 @@ jobs: name: "Java (JDK 25, linuxmusl-arm64)" if: inputs.platform == 'all' || inputs.platform == 'linuxmusl-arm64' runs-on: ubuntu-24.04-arm - timeout-minutes: 30 steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime diff --git a/.github/workflows/sdk-nodejs.yml b/.github/workflows/sdk-nodejs.yml index db14685c13..d573049446 100644 --- a/.github/workflows/sdk-nodejs.yml +++ b/.github/workflows/sdk-nodejs.yml @@ -7,7 +7,6 @@ env: HUSKY: 0 POWERSHELL_UPDATECHECK: Off SDK_HOME: ${{ inputs.sdk-home }} - SETUP_NODE_TIMEOUT_MINUTES: 10 on: workflow_call: @@ -43,7 +42,6 @@ jobs: working-directory: ${{ inputs.sdk-home }}/nodejs steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -128,7 +126,6 @@ jobs: name: "Node.js (ubuntu-latest, ${{ matrix.backend }})" if: github.event_name != 'merge_group' && (inputs.platform == 'all' || inputs.platform == 'linux-x64') runs-on: ubuntu-latest - timeout-minutes: 30 strategy: fail-fast: false matrix: @@ -141,7 +138,6 @@ jobs: COPILOT_SDK_E2E_BACKEND: ${{ matrix.backend }} steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -170,7 +166,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime diff --git a/.github/workflows/sdk-python.yml b/.github/workflows/sdk-python.yml index df9cbab1a9..b2db80794b 100644 --- a/.github/workflows/sdk-python.yml +++ b/.github/workflows/sdk-python.yml @@ -7,7 +7,6 @@ env: HUSKY: 0 POWERSHELL_UPDATECHECK: Off SDK_HOME: ${{ inputs.sdk-home }} - SETUP_NODE_TIMEOUT_MINUTES: 10 on: workflow_call: @@ -32,7 +31,6 @@ jobs: matrix: os: ${{ fromJSON(inputs.platform == 'linux-x64' && '["ubuntu-latest"]' || inputs.platform == 'darwin-arm64' && '["macos-26-agent-runtime"]' || inputs.platform == 'win32-x64' && '["windows-latest"]' || '["ubuntu-latest","macos-26-agent-runtime","windows-latest"]') }} runs-on: ${{ matrix.os }} - timeout-minutes: 20 defaults: run: shell: bash @@ -41,7 +39,6 @@ jobs: PYTHONUTF8: 1 steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -105,10 +102,8 @@ jobs: name: "Python (Alpine x64)" if: inputs.platform == 'all' || inputs.platform == 'linuxmusl-x64' runs-on: ubuntu-latest - timeout-minutes: 20 steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime diff --git a/.github/workflows/sdk-runtime-artifact.yml b/.github/workflows/sdk-runtime-artifact.yml index 0481e945ae..51c226b429 100644 --- a/.github/workflows/sdk-runtime-artifact.yml +++ b/.github/workflows/sdk-runtime-artifact.yml @@ -11,7 +11,6 @@ env: GIT_HTTP_LOW_SPEED_LIMIT: 1000 GIT_HTTP_LOW_SPEED_TIME: 60 HUSKY: 0 - SETUP_NODE_TIMEOUT_MINUTES: 10 on: workflow_call: @@ -47,10 +46,6 @@ on: required: false default: "" type: string - timeout-minutes: - required: false - default: 90 - type: number permissions: contents: read @@ -63,7 +58,6 @@ jobs: cache-relay: if: inputs.runtime-source == 'checkout' runs-on: ubuntu-slim - timeout-minutes: 15 permissions: actions: read contents: read @@ -71,7 +65,7 @@ jobs: cache-hit: ${{ steps.cache.outputs.cache-hit }} steps: - uses: actions/checkout@v7 - timeout-minutes: 4 + timeout-minutes: 60 with: persist-credentials: false @@ -144,7 +138,6 @@ jobs: (inputs.runtime-source == 'published' || (needs.cache-relay.result == 'success' && needs.cache-relay.outputs.cache-hit != 'true')) runs-on: ${{ inputs.runtime-source == 'checkout' && inputs.os || 'ubuntu-latest' }} - timeout-minutes: ${{ inputs.timeout-minutes }} permissions: actions: read contents: read @@ -152,7 +145,7 @@ jobs: packages: read steps: - uses: actions/checkout@v7 - timeout-minutes: 4 + timeout-minutes: 60 with: persist-credentials: false @@ -197,7 +190,7 @@ jobs: - if: inputs.runtime-source == 'checkout' && steps.cache.outputs.cache-hit != 'true' uses: ./.github/actions/setup-node - timeout-minutes: ${{ fromJSON(env.SETUP_NODE_TIMEOUT_MINUTES) }} + timeout-minutes: 60 - name: Capture verified addon source identity if: inputs.runtime-source == 'checkout' && steps.cache.outputs.cache-hit != 'true' diff --git a/.github/workflows/sdk-rust.yml b/.github/workflows/sdk-rust.yml index 04500c3489..902ae8ed11 100644 --- a/.github/workflows/sdk-rust.yml +++ b/.github/workflows/sdk-rust.yml @@ -7,7 +7,6 @@ env: HUSKY: 0 POWERSHELL_UPDATECHECK: Off SDK_HOME: ${{ inputs.sdk-home }} - SETUP_NODE_TIMEOUT_MINUTES: 10 on: workflow_call: @@ -27,7 +26,6 @@ jobs: rust: name: "Rust (${{ matrix.os }})" if: contains(fromJSON('["all","linux-x64","darwin-arm64","win32-x64"]'), inputs.platform) - timeout-minutes: 60 strategy: fail-fast: false matrix: @@ -40,9 +38,11 @@ jobs: env: CARGO_TERM_COLOR: always RUST_BACKTRACE: 1 + # Preserve source-line backtraces without full variable/type debug information. + CARGO_PROFILE_DEV_DEBUG: line-tables-only + CARGO_PROFILE_TEST_DEBUG: line-tables-only steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime @@ -128,10 +128,8 @@ jobs: name: "Rust (Alpine x64)" if: inputs.platform == 'all' || inputs.platform == 'linuxmusl-x64' runs-on: ubuntu-latest - timeout-minutes: 60 steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false - uses: ./.github/actions/download-sdk-runtime diff --git a/.github/workflows/sdk.yml b/.github/workflows/sdk.yml index 602d02b027..852163ec93 100644 --- a/.github/workflows/sdk.yml +++ b/.github/workflows/sdk.yml @@ -9,7 +9,6 @@ env: COPILOT_BAZEL_ANG_PR_SAMPLED_MODE: ${{ vars.COPILOT_BAZEL_ANG_PR_SAMPLED_MODE }} HUSKY: 0 POWERSHELL_UPDATECHECK: Off - SETUP_NODE_TIMEOUT_MINUTES: 10 on: pull_request: @@ -42,7 +41,6 @@ jobs: id: checkout if: github.event_name == 'pull_request' continue-on-error: true - timeout-minutes: 4 with: # Include the synthetic merge commit's base parent without fetching # repository history. @@ -177,9 +175,14 @@ jobs: sdk-home: ${{ steps.detect.outputs.sdk-home }} steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false + sparse-checkout: | + /src/sdk/package.json + /script/sea-build.ts + /package.json + /nodejs/package.json + sparse-checkout-cone-mode: false - id: detect run: | if [[ -f src/sdk/package.json && -f script/sea-build.ts ]]; then @@ -202,7 +205,6 @@ jobs: needs: detect-layout if: github.event_name != 'merge_group' && needs.detect-layout.outputs.runtime-source == 'checkout' runs-on: ubuntu-latest-xl - timeout-minutes: 60 concurrency: group: windows-x64-addons-release-windows-e2e-no-icf-${{ github.sha }} queue: max @@ -212,7 +214,6 @@ jobs: packages: read steps: - uses: actions/checkout@v7 - timeout-minutes: 4 with: persist-credentials: false @@ -242,7 +243,7 @@ jobs: - uses: ./.github/actions/setup-node if: steps.cache.outputs.cache-hit != 'true' - timeout-minutes: ${{ fromJSON(env.SETUP_NODE_TIMEOUT_MINUTES) }} + timeout-minutes: 60 - uses: ./.github/actions/setup-bazel if: steps.cache.outputs.cache-hit != 'true' with: @@ -352,7 +353,6 @@ jobs: artifact: Linux-X64-gnu bazel-config: e2e-no-lto shared-cli-build-compatible: true - timeout-minutes: 60 secrets: inherit build-runtime-linuxmusl-x64: @@ -372,7 +372,6 @@ jobs: target: linuxmusl-x64 artifact: Linux-X64-musl bazel-config: e2e-no-lto - timeout-minutes: 60 secrets: inherit build-runtime-linuxmusl-arm64: @@ -392,7 +391,6 @@ jobs: target: linuxmusl-arm64 artifact: Linux-ARM64-musl bazel-config: e2e-no-lto - timeout-minutes: 60 secrets: inherit build-runtime-darwin-arm64: @@ -414,7 +412,6 @@ jobs: bazel-config: e2e-no-lto use-bazel-addons-on-darwin: true shared-cli-build-compatible: true - timeout-minutes: 60 secrets: inherit build-runtime-win32-x64: @@ -436,7 +433,6 @@ jobs: bazel-config: windows-e2e-no-icf shared-cli-build-compatible: true prebuilt-addons-artifact: ${{ needs.detect-layout.outputs.runtime-source == 'checkout' && 'sdk-bazel-cross-addons-win32-x64-release' || '' }} - timeout-minutes: 60 secrets: inherit sdk-linux-x64: @@ -528,13 +524,34 @@ jobs: id-token: write steps: - uses: actions/checkout@v7 - timeout-minutes: 10 with: persist-credentials: false - fetch-depth: 0 + fetch-depth: ${{ github.event_name == 'pull_request' && 2 || 1 }} + - name: Fetch generation comparison baseline + if: needs.detect-layout.outputs.runtime-source == 'checkout' && (github.event_name == 'merge_group' || github.event_name == 'push') + env: + BASELINE_SHA: ${{ github.event.merge_group.base_sha || github.event.before }} + CHECKOUT_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + if [[ "$GITHUB_EVENT_NAME" == "push" && "$BASELINE_SHA" =~ ^0+$ ]]; then + echo "New branch push has no generation baseline; checking all projections." + exit 0 + fi + if [[ ! "$BASELINE_SHA" =~ ^[0-9a-fA-F]{40}$ ]]; then + echo "::error::Missing or invalid SDK generation baseline SHA." + exit 1 + fi + if git cat-file -e "$BASELINE_SHA^{commit}" 2>/dev/null; then + exit 0 + fi + auth_header="$(printf 'x-access-token:%s' "$CHECKOUT_TOKEN" | base64 | tr -d '\n')" + GIT_CONFIG_COUNT=1 \ + GIT_CONFIG_KEY_0=http.https://github.com/.extraheader \ + GIT_CONFIG_VALUE_0="AUTHORIZATION: basic $auth_header" \ + git fetch --no-tags --depth=1 origin "$BASELINE_SHA" - if: needs.detect-layout.outputs.runtime-source == 'checkout' uses: ./.github/actions/setup-node - timeout-minutes: ${{ fromJSON(env.SETUP_NODE_TIMEOUT_MINUTES) }} with: install-deps: "false" - if: needs.detect-layout.outputs.runtime-source == 'checkout' diff --git a/BUILD.bazel b/BUILD.bazel index 4fa953fbf5..b9465c7090 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,3 +1,8 @@ +exports_files( + ["test/harness/sdk-diagnostics.mjs"], + visibility = ["//src/runtime-bin:__pkg__"], +) + SHARED_CODEGEN_INPUTS = [ "nodejs/scripts/releaseArtifacts.ts", "nodejs/src/cliVersion.ts", diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 74519107b4..6513793b66 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -356,11 +356,11 @@ For TypeScript SDK E2Es, use the existing `nodejs/test/e2e/harness/sdkTestContext.ts` fixture. In the runtime repository, also follow the `e2e-test-author` skill's SDK section. -All six SDKs run full subprocess coverage followed by a short in-process -smoke step on the same runner on Linux/glibc x64, macOS ARM64, Windows x64, -and Linux/musl x64. Smoke still runs if the subprocess tests fail, and either -failure fails the job. Java uses JDK 25 on all four platforms, plus a -Linux/glibc JDK 17 compatibility job using precompiled classes. +All SDKs run full subprocess coverage and in-process smoke on Linux/glibc +x64, macOS ARM64, Windows x64, and Linux/musl x64. Windows .NET uses complementary +jobs per framework. Smoke also runs after subprocess failures; either failure +fails the job. Java uses JDK 25 on these platforms, +plus a Linux/glibc JDK 17 compatibility job using precompiled classes. Merge groups retain the reduced Linux TypeScript CAPI subprocess coverage. The `sdk-typescript` required rollup checks only the Linux CAPI job, including diff --git a/docs/features/custom-agents.md b/docs/features/custom-agents.md index 9e2f597688..965582a01b 100644 --- a/docs/features/custom-agents.md +++ b/docs/features/custom-agents.md @@ -25,6 +25,8 @@ flowchart TD ## Defining custom agents +To discover Markdown definitions from versioned packages or vendored folders, use `agentDirectories` or [repository customization locations](./customization-locations.md). + Pass `customAgents` when creating a session. Each agent needs at minimum a `name` and `prompt`.
diff --git a/docs/features/customization-locations.md b/docs/features/customization-locations.md new file mode 100644 index 0000000000..703c5d5066 --- /dev/null +++ b/docs/features/customization-locations.md @@ -0,0 +1,55 @@ + + +# Customization discovery locations + +GitHub Copilot can discover versioned skills, agents, instructions, and file hooks directly from package installations, submodules, and vendored directories. You don't need to copy them into conventional directories. + +## Repository settings + +Declare checkout-relative directories in `.github/copilot/settings.json`: + +```json +{ + "skillDirectories": ["node_modules/@example/team/skills"], + "agentDirectories": ["vendor/team/agents"], + "instructionDirectories": ["vendor/team/instructions"], + "hookDirectories": ["vendor/team/hooks"] +} +``` + +Each list adds discovery locations for its own customization type. Conventional locations continue to work. A key in `.github/copilot/settings.local.json` replaces only that repository list; an empty list removes its repository contribution. Omitted keys inherit the checked-in list. Repository lists don't replace SDK inputs or existing user skill directories. + +Repository paths must be nonempty, literal directories within the declaring checkout. Absolute paths, home or environment-variable expansion, globs, and escapes outside the checkout are rejected. Links and junctions are allowed only when their resolved roots and discovered descendants remain inside the checkout. A missing directory is reported and can be discovered after installation and an explicit customization reload. Copilot doesn't install packages or watch these directories. + +File content from repository-defined discovery locations is read through a validated, opened file handle. Retargeting a link outside the checkout between discovery and invocation doesn't authorize reading its new target. + +Repository locations require trust covering the declaring checkout root and remain subject to each customization type's existing discovery switches, disabled entries, and managed policy. Persisted trust for only a subdirectory doesn't authorize its parent checkout's settings. Listing a location doesn't enable a disabled customization type or grant filesystem access. + +In the CLI, remembered folder trust refreshes repository customizations in the current session, even if model catalog initialization failed. `/skills reload` also rechecks persisted trust and repository discovery settings. + +## SDK inputs + +Session creation, resume, and option updates accept the same four lists. TypeScript and Java use `skillDirectories`, `agentDirectories`, `instructionDirectories`, and `hookDirectories`. Python and Rust use snake case; Go and .NET use Pascal case. + +SDK directories can be outside the checkout. Leading and trailing whitespace is trimmed, and blank entries are ignored. Relative SDK paths resolve once against the request's effective working directory when supplied. Changing the working directory doesn't move retained SDK roots. Supplying a new relative list uses the new effective working directory. An empty list clears only the explicit SDK contribution; omission or `null` leaves it unchanged during an update. + +If adopting a `hookDirectories` replacement fails or is canceled before the new hook service takes ownership, the previous directory option and live hook service remain in place. Overlapping failed updates restore the retained value rather than another failed update's directories. A failed update doesn't roll back a newer accepted update. + +Explicit agent and file-hook directories don't require ambient configuration discovery. `enableFileHooks` controls repository-origin hooks, including conventional `.github/hooks`, but not explicit SDK hook directories or callback `hooks`. Managed restrictions and hook disables still apply. + +Directory inputs are discovery configuration, not general filesystem grants. They don't widen `additionalDirectories`. Existing file-hook sandbox rules remain in effect. + +Loading active local skills adds read-only grants for their contributing SDK skill directories under the runtime's skill-resource policy. Empty, ignored, and disabled skill sources don't add those grants. Repository-defined skill directories don't add them. + +## File formats and precedence + +| Type | Discovered content | +| --- | --- | +| Skills | A direct `SKILL.md` bundle or recursively discovered topmost bundles | +| Agents | Existing Markdown agent definitions | +| Repository instructions | Recursive `*.instructions.md` files, with existing frontmatter and `applyTo` matching | +| Hooks | Existing hook JSON configurations | + +Repository instruction directories don't import package `AGENTS.md` hierarchies or `.claude/rules`. Existing SDK instruction-directory formats remain supported. Each subsystem preserves its existing source precedence. Overlapping hook file references are deduplicated; distinct authored actions aren't collapsed because their commands happen to match. + +File-backed command hooks receive `COPILOT_HOOK_DIR`, the directory containing their configuration file. Use it to locate adjacent scripts and resources. Hook working-directory semantics don't change: they remain anchored to the consuming workspace. `COPILOT_HOOK_DIR` is an execution environment variable, not JSON template expansion; `COPILOT_PLUGIN_ROOT` retains its separate plugin-root behavior. Inline hooks and SDK callbacks don't gain a fabricated configuration directory. diff --git a/docs/features/hooks.md b/docs/features/hooks.md index a3cfc0f503..b0cd89d6e9 100644 --- a/docs/features/hooks.md +++ b/docs/features/hooks.md @@ -35,6 +35,55 @@ All hooks are **optional**—register only the ones you need. Returning `null` ( ## Registering hooks +Callback `hooks` remain separate from file-backed `hookDirectories`. For packaged hook configurations and adjacent resources, see [customization discovery locations](./customization-locations.md). + +### Agent-scoped declarative hooks + +Custom agents can declare a `hooks` event map in `.agent.md` frontmatter or in +the SDK's custom-agent configuration. These are declarative command or HTTP +actions, not SDK callback functions. They run only while that agent is selected, +in addition to applicable session, user, repository, plugin, and managed-policy +hooks. Changing or clearing the selected agent changes the scoped hooks for the +next invocation without changing other sessions or concurrent subagents. + +```yaml +--- +name: formatter +description: Formats changed files +hooks: + PostToolUse: + - type: command + command: ./scripts/format-changed-files.sh + windows: ./scripts/format-changed-files.ps1 +--- +Format the files you change. +``` + +Both runtime event names such as `postToolUse` and supported VS Code aliases +such as `PostToolUse` are accepted. `command` supplies the fallback shell command; +`windows`, `linux`, and `osx` override it on the corresponding platform. Hook +commands are relative to the executing session's repository root, unless they +set an explicit working directory. Hook payloads and decisions follow the +runtime's existing hook contracts. + +When a local agent runs as a subagent, its scoped `Stop` (`agentStop`) actions +run at `SubagentStop` instead of ordinary turn stop. An explicit `SubagentStop` +action on that agent still observes its own children. Stop callbacks receive +`stop_hook_active: true` after a prior block. After eight consecutive scoped +Stop continuations, the runtime ignores further scoped blocks and accepts the +child's final response unless a parent lifecycle hook still blocks completion. + +Repository and inherited-agent hooks require workspace admission. Agent +discovery or selection does not itself grant trust. Existing hook-disable +settings, enterprise restrictions, sandbox permissions, and timeouts also apply +to scoped actions. SDK-provided agents cannot claim managed-plugin privileges. +Remote or organization-hosted agent definitions do not execute scoped hooks, +and scoped Stop dispatch is supported for local runtime subagents, not external +AHP participants. + +Unsupported event names are reported before event selection. Action preparation +errors affect only their declared event; shared and managed-policy hooks still run. + Pass a `hooks` object when you create (or resume) a session. Every example below follows this pattern.
diff --git a/docs/features/mcp.md b/docs/features/mcp.md index 4be11f2452..1c93c82710 100644 --- a/docs/features/mcp.md +++ b/docs/features/mcp.md @@ -57,7 +57,7 @@ Inventory retries concurrent graph replacement a bounded number of times and returns an error if it cannot obtain a consistent snapshot. It never omits `live` to hide a graph race. -An explicit `startServer` or `restartServer` resolves and initializes only the +A name-only `startServer` or `restartServer` resolves and initializes only the requested server after a cold session resume without first calling `list`. This includes user and plugin configurations and the built-in GitHub server configured through `githubMcpToolConfig`. It does not start other configured diff --git a/dotnet/src/Client.cs b/dotnet/src/Client.cs index ad75548f77..77df3cba7f 100644 --- a/dotnet/src/Client.cs +++ b/dotnet/src/Client.cs @@ -1262,6 +1262,7 @@ public async Task CreateSessionAsync(SessionConfig config, Cance var request = new CreateSessionRequest( config.Model, localSessionId, + config.Name, config.ClientName, config.ReasoningEffort, config.ReasoningSummary, @@ -1321,6 +1322,8 @@ public async Task CreateSessionAsync(SessionConfig config, Cance Cloud: config.Cloud, RefreshCustomInstructions: config.RefreshCustomInstructions, InstructionDirectories: config.InstructionDirectories, + AgentDirectories: config.AgentDirectories, + HookDirectories: config.HookDirectories, PluginDirectories: config.PluginDirectories, DisabledMcpServers: config.DisabledMcpServers, LargeOutput: config.LargeOutput, @@ -1594,6 +1597,8 @@ public async Task ResumeSessionAsync(string sessionId, ResumeSes RemoteSession: config.RemoteSession, ContinuePendingWork: config.ContinuePendingWork, InstructionDirectories: config.InstructionDirectories, + AgentDirectories: config.AgentDirectories, + HookDirectories: config.HookDirectories, PluginDirectories: config.PluginDirectories, DisabledMcpServers: config.DisabledMcpServers, LargeOutput: config.LargeOutput, @@ -3224,6 +3229,7 @@ public static string Escape(string arg) internal record CreateSessionRequest( string? Model, string? SessionId, + string? Name, string? ClientName, string? ReasoningEffort, ReasoningSummary? ReasoningSummary, @@ -3283,6 +3289,8 @@ internal record CreateSessionRequest( CloudSessionOptions? Cloud = null, bool? RefreshCustomInstructions = null, IList? InstructionDirectories = null, + IList? AgentDirectories = null, + IList? HookDirectories = null, IList? PluginDirectories = null, [property: JsonPropertyName("disabledMcpServers")] IList? DisabledMcpServers = null, LargeToolOutputConfig? LargeOutput = null, @@ -3406,6 +3414,8 @@ internal record ResumeSessionRequest( RemoteSessionMode? RemoteSession = null, bool? ContinuePendingWork = null, IList? InstructionDirectories = null, + IList? AgentDirectories = null, + IList? HookDirectories = null, IList? PluginDirectories = null, [property: JsonPropertyName("disabledMcpServers")] IList? DisabledMcpServers = null, LargeToolOutputConfig? LargeOutput = null, diff --git a/dotnet/src/Generated/Rpc.cs b/dotnet/src/Generated/Rpc.cs index a9b486d94c..b3c4714dbf 100644 --- a/dotnet/src/Generated/Rpc.cs +++ b/dotnet/src/Generated/Rpc.cs @@ -597,12 +597,16 @@ public sealed class HooksDiscoverResult /// Optional project paths and host-exclusion behavior for server-scoped hook discovery. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HooksDiscoverRequest +public sealed class HooksDiscoverRequest { /// When true, omit host-owned user and plugin hook rows and their diagnostics. Managed-policy hooks and trusted repository hooks remain visible, and host disabledHooks still contribute to each remaining row's effective enabled state. This filters sources rather than simulating a host with no settings. [JsonPropertyName("excludeHostHooks")] public bool? ExcludeHostHooks { get; set; } + /// Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without ambient discovery or repository file-hook enablement, subject to managed/hook disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + [JsonPropertyName("hookDirectories")] + public IList? HookDirectories { get; set; } + /// Optional project directory paths whose trusted repository and project-expanded plugin hooks should be discovered. When omitted or empty, user, managed-policy, and globally enabled installed or explicit plugin hooks are returned without project expansion. [JsonPropertyName("projectPaths")] public IList? ProjectPaths { get; set; } @@ -2004,6 +2008,116 @@ internal sealed class AccountLogoutRequest public string? SelectionId { get; set; } } +/// The wording the runtime uses for an authentication identity. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AccountDescribeAuthInfoResult +{ + /// One-line description of the identity, suitable after a verb such as "Switched to". + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; + + /// Sign-in banner announcing the authenticated user. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; +} + +/// Credential-free authentication identity safe to expose to hosts and user interfaces. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class AuthIdentity +{ + /// Snapshot of the authenticated user's Copilot subscription info, if known. + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } + + /// Name of the environment variable that supplied the credential, when applicable. + [JsonPropertyName("envVar")] + public string? EnvVar { get; set; } + + /// Authentication host. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; + + /// Authenticated login, when available. + [JsonPropertyName("login")] + public string? Login { get; set; } + + /// Opaque SDK GitHub credential registration backing this identity. Routing metadata only; never a credential. + [JsonPropertyName("registrationId")] + public string? RegistrationId { get; set; } + + /// Authentication type. + [JsonPropertyName("type")] + public AuthInfoType Type { get; set; } +} + +/// The authentication identity whose shared wording should be rendered. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AccountDescribeAuthInfoRequest +{ + /// Identity to describe. + [JsonPropertyName("identity")] + public AuthIdentity Identity { get => field ??= new(); set; } +} + +/// Whether the identity can create gists, and why not when it cannot. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AccountGetGistSupportResult +{ + /// Machine-readable reason category when unsupported. + [JsonPropertyName("kind")] + public string? Kind { get; set; } + + /// Human-readable explanation to show where the gist action would have been. + [JsonPropertyName("reason")] + public string? Reason { get; set; } + + /// True when the identity can create gists. + [JsonPropertyName("supported")] + public bool Supported { get; set; } +} + +/// The authentication identity whose gist support should be reported. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AccountGetGistSupportRequest +{ + /// Identity to evaluate. + [JsonPropertyName("identity")] + public AuthIdentity Identity { get => field ??= new(); set; } +} + +/// An absolute URL on the identity's GitHub host. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AccountGetWebUrlResult +{ + /// Absolute URL for the requested path. + [JsonPropertyName("url")] + public string Url { get; set; } = string.Empty; +} + +/// A path to resolve against the GitHub host an identity is signed in to. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AccountGetWebUrlRequest +{ + /// Identity whose host the path resolves against. Omit to resolve against the public github.com host. + [JsonPropertyName("identity")] + public AuthIdentity? Identity { get; set; } + + /// Host-relative path, without a leading slash, for example `settings/copilot/features`. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; +} + +/// The environment variable supplying a classic personal access token, when one is set. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AccountGetTokenEnvVarResult +{ + /// Variable name, for example `GH_TOKEN`. Absent when no classic token is present in the environment. + [JsonPropertyName("name")] + public string? Name { get; set; } +} + /// Confirmation that the secret values were registered. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] public sealed class SecretsAddFilterValuesResult @@ -2149,6 +2263,15 @@ internal sealed class McpDiscoverRequest public string? WorkingDirectory { get; set; } } +/// Names of the MCP servers the runtime supplies itself. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpListBuiltinServerNamesResult +{ + /// Every built-in server name. A host disabling the built-ins wholesale suppresses exactly this set. + [JsonPropertyName("names")] + public IList Names { get => field ??= []; set; } +} + /// Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by the request. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] internal sealed class McpShouldExcludeGitHubToolsResult @@ -4300,6 +4423,166 @@ internal sealed class DiscoveredExtensionsDisableRequest public IList Ids { get => field ??= []; set; } } +/// The prompt the init command runs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class InstructionsInitPromptResult +{ + /// Prompt text authoring repository instructions. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; +} + +/// Loaded instruction source for a session, including path, content, category, location, applicability, and optional description. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class InstructionSource +{ + /// Glob pattern(s) from frontmatter — when set, this instruction applies only to matching files. + [JsonPropertyName("applyTo")] + public IList? ApplyTo { get; set; } + + /// Raw content of the instruction file. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; + + /// When true, this source starts disabled and must be toggled on by the user. + [JsonPropertyName("defaultDisabled")] + public bool? DefaultDisabled { get; set; } + + /// Short description (body after frontmatter) for use in instruction tables. + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Unique identifier for this source (used for toggling). + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + /// Human-readable label. + [JsonPropertyName("label")] + public string Label { get; set; } = string.Empty; + + /// Where this source lives — used for UI grouping. + [JsonPropertyName("location")] + public InstructionSourceLocation Location { get; set; } + + /// The project path this source was discovered from. Only set by sessionless discovery for repository, working-directory, and project-scoped plugin sources, where it disambiguates sources across multiple workspace roots. The session-scoped getSources leaves it unset. + [JsonPropertyName("projectPath")] + public string? ProjectPath { get; set; } + + /// File path relative to repo or absolute for home. + [JsonPropertyName("sourcePath")] + public string SourcePath { get; set; } = string.Empty; + + /// Category of instruction source — used for merge logic. + [JsonPropertyName("type")] + public InstructionSourceType Type { get; set; } +} + +/// Instruction sources discovered across user, repository, and plugin sources. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerInstructionSourceList +{ + /// All discovered instruction sources. + [JsonPropertyName("sources")] + public IList Sources { get => field ??= []; set; } +} + +/// Optional project paths to include in instruction discovery. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class InstructionsDiscoverRequest +{ + /// When true, omit the host's instruction sources (user/home-level files and plugin rules), leaving only repository and working-directory sources. For multitenant deployments. + [JsonPropertyName("excludeHostInstructions")] + public bool? ExcludeHostInstructions { get; set; } + + /// Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without ambient discovery, subject to instruction/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + [JsonPropertyName("instructionDirectories")] + public IList? InstructionDirectories { get; set; } + + /// Optional list of project directory paths to scan for repository/working-directory instruction sources. When omitted or empty, only user-level and plugin instruction sources are returned (no project scan). + [JsonPropertyName("projectPaths")] + public IList? ProjectPaths { get; set; } +} + +/// Explicit discovery arguments for one location, supplied by the caller rather than derived from a session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class InstructionsDiscoverRepoSourcesRequest +{ + /// Extra directories to scan alongside instruction directories configured in the runtime environment. + [JsonPropertyName("additionalDirs")] + public IList? AdditionalDirs { get; set; } + + /// Copilot configuration directory for user-level sources. An omitted or empty value uses the server's configuration home. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } + + /// Working directory whose instruction sources should also be included. Omission adds no separate working-directory scope. + [JsonPropertyName("cwdPath")] + public string? CwdPath { get; set; } + + /// When true, also discover instruction files nested below the location. + [JsonPropertyName("enableChildInstructions")] + public bool? EnableChildInstructions { get; set; } + + /// When true, include the sources a command-line host reads. Hosts that are not the CLI omit it. + [JsonPropertyName("isCli")] + public bool? IsCli { get; set; } + + /// Repository location to discover. An empty string selects no repository scope; cwdPath can still supply working-directory sources. + [JsonPropertyName("location")] + public string Location { get; set; } = string.Empty; +} + +/// Canonical file or directory where custom instructions can be discovered or created, with location, kind, preference, and project path. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class InstructionDiscoveryPath +{ + /// Whether the target is a single file or a directory of instruction files. + [JsonPropertyName("kind")] + public InstructionDiscoveryPathKind Kind { get; set; } + + /// Which tier this target belongs to. + [JsonPropertyName("location")] + public InstructionDiscoveryPathLocation Location { get; set; } + + /// Absolute path of the file or directory (may not exist on disk yet). + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// Whether this is the canonical target to create new instructions in its tier. At most one entry per tier is preferred. + [JsonPropertyName("preferredForCreation")] + public bool PreferredForCreation { get; set; } + + /// The input project path this target was derived from (only for repository targets). + [JsonPropertyName("projectPath")] + public string? ProjectPath { get; set; } +} + +/// Canonical files and directories where custom instructions can be created so the runtime will recognize them. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class InstructionDiscoveryPathList +{ + /// Canonical instruction create/discovery files and directories, in priority order. + [JsonPropertyName("paths")] + public IList Paths { get => field ??= []; set; } +} + +/// Optional project paths to include when enumerating instruction discovery targets. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class InstructionsGetDiscoveryPathsRequest +{ + /// When true, omit the host's user-level instruction targets, leaving only repository targets. For multitenant deployments (mirrors `discover`'s `excludeHostInstructions`). + [JsonPropertyName("excludeHostInstructions")] + public bool? ExcludeHostInstructions { get; set; } + + /// Explicit discovery-only instruction roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + [JsonPropertyName("instructionDirectories")] + public IList? InstructionDirectories { get; set; } + + /// Optional list of project directory paths. When omitted or empty, only the user-level targets are returned. + [JsonPropertyName("projectPaths")] + public IList? ProjectPaths { get; set; } +} + /// Skill installation management result with the honoured contract, or a typed refusal. /// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] @@ -5309,7 +5592,7 @@ internal sealed class SkillsDiscoverRequest [JsonPropertyName("projectPaths")] public IList? ProjectPaths { get; set; } - /// Optional list of additional skill directory paths to include. + /// Explicit discovery-only skill roots, not filesystem grants. Available without ambient discovery, subject to skill/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. [JsonPropertyName("skillDirectories")] public IList? SkillDirectories { get; set; } } @@ -5346,7 +5629,7 @@ public sealed class SkillDiscoveryPathList /// Optional project paths to enumerate. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillsGetDiscoveryPathsRequest +public sealed class SkillsGetDiscoveryPathsRequest { /// When true, omit the host's personal and custom skill directories, leaving only project directories. For multitenant deployments. [JsonPropertyName("excludeHostSkills")] @@ -5359,6 +5642,10 @@ internal sealed class SkillsGetDiscoveryPathsRequest /// Optional list of project directory paths. When omitted or empty, only personal and custom directories are returned. [JsonPropertyName("projectPaths")] public IList? ProjectPaths { get; set; } + + /// Explicit discovery-only skill roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + [JsonPropertyName("skillDirectories")] + public IList? SkillDirectories { get; set; } } /// Inventory request under an explicitly selected existing session. @@ -6793,6 +7080,10 @@ public sealed class AgentInfo [JsonPropertyName("displayName")] public string DisplayName { get; set; } = string.Empty; + /// Declarative hook actions keyed by event name, executed only while this agent is active. + [JsonPropertyName("hooks")] + public IDictionary>? Hooks { get; set; } + /// Stable identifier for selection. For most agents this is the same as `name`; for plugin/builtin agents it may differ. Always populated; defaults to `name` when no distinct id was assigned. [JsonPropertyName("id")] public string Id { get; set; } = string.Empty; @@ -6858,8 +7149,12 @@ public sealed class ServerAgentList /// Optional project paths to include in agent discovery. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AgentsDiscoverRequest +public sealed class AgentsDiscoverRequest { + /// Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without ambient discovery, subject to managed/source disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + [JsonPropertyName("agentDirectories")] + public IList? AgentDirectories { get; set; } + /// When true, omit the host's agents (the user-level agent directory and all plugin agents), leaving only project and remote agents. For multitenant deployments. [JsonPropertyName("excludeHostAgents")] public bool? ExcludeHostAgents { get; set; } @@ -6901,8 +7196,12 @@ public sealed class AgentDiscoveryPathList /// Optional project paths to include when enumerating agent discovery directories. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AgentsGetDiscoveryPathsRequest +public sealed class AgentsGetDiscoveryPathsRequest { + /// Explicit discovery-only agent roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + [JsonPropertyName("agentDirectories")] + public IList? AgentDirectories { get; set; } + /// When true, omit the host's user-level agent directory, leaving only project directories. For multitenant deployments (mirrors `discover`'s `excludeHostAgents`). [JsonPropertyName("excludeHostAgents")] public bool? ExcludeHostAgents { get; set; } @@ -7034,120 +7333,6 @@ internal sealed class AgentsCustomAgentInitialModelDecisionParams public string AvailableModelsJson { get; set; } = string.Empty; } -/// Loaded instruction source for a session, including path, content, category, location, applicability, and optional description. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class InstructionSource -{ - /// Glob pattern(s) from frontmatter — when set, this instruction applies only to matching files. - [JsonPropertyName("applyTo")] - public IList? ApplyTo { get; set; } - - /// Raw content of the instruction file. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; - - /// When true, this source starts disabled and must be toggled on by the user. - [JsonPropertyName("defaultDisabled")] - public bool? DefaultDisabled { get; set; } - - /// Short description (body after frontmatter) for use in instruction tables. - [JsonPropertyName("description")] - public string? Description { get; set; } - - /// Unique identifier for this source (used for toggling). - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - - /// Human-readable label. - [JsonPropertyName("label")] - public string Label { get; set; } = string.Empty; - - /// Where this source lives — used for UI grouping. - [JsonPropertyName("location")] - public InstructionSourceLocation Location { get; set; } - - /// The project path this source was discovered from. Only set by sessionless discovery for repository, working-directory, and project-scoped plugin sources, where it disambiguates sources across multiple workspace roots. The session-scoped getSources leaves it unset. - [JsonPropertyName("projectPath")] - public string? ProjectPath { get; set; } - - /// File path relative to repo or absolute for home. - [JsonPropertyName("sourcePath")] - public string SourcePath { get; set; } = string.Empty; - - /// Category of instruction source — used for merge logic. - [JsonPropertyName("type")] - public InstructionSourceType Type { get; set; } -} - -/// Instruction sources discovered across user, repository, and plugin sources. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerInstructionSourceList -{ - /// All discovered instruction sources. - [JsonPropertyName("sources")] - public IList Sources { get => field ??= []; set; } -} - -/// Optional project paths to include in instruction discovery. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class InstructionsDiscoverRequest -{ - /// When true, omit the host's instruction sources (user/home-level files and plugin rules), leaving only repository and working-directory sources. For multitenant deployments. - [JsonPropertyName("excludeHostInstructions")] - public bool? ExcludeHostInstructions { get; set; } - - /// Optional list of project directory paths to scan for repository/working-directory instruction sources. When omitted or empty, only user-level and plugin instruction sources are returned (no project scan). - [JsonPropertyName("projectPaths")] - public IList? ProjectPaths { get; set; } -} - -/// Canonical file or directory where custom instructions can be discovered or created, with location, kind, preference, and project path. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class InstructionDiscoveryPath -{ - /// Whether the target is a single file or a directory of instruction files. - [JsonPropertyName("kind")] - public InstructionDiscoveryPathKind Kind { get; set; } - - /// Which tier this target belongs to. - [JsonPropertyName("location")] - public InstructionDiscoveryPathLocation Location { get; set; } - - /// Absolute path of the file or directory (may not exist on disk yet). - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; - - /// Whether this is the canonical target to create new instructions in its tier. At most one entry per tier is preferred. - [JsonPropertyName("preferredForCreation")] - public bool PreferredForCreation { get; set; } - - /// The input project path this target was derived from (only for repository targets). - [JsonPropertyName("projectPath")] - public string? ProjectPath { get; set; } -} - -/// Canonical files and directories where custom instructions can be created so the runtime will recognize them. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class InstructionDiscoveryPathList -{ - /// Canonical instruction create/discovery files and directories, in priority order. - [JsonPropertyName("paths")] - public IList Paths { get => field ??= []; set; } -} - -/// Optional project paths to include when enumerating instruction discovery targets. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class InstructionsGetDiscoveryPathsRequest -{ - /// When true, omit the host's user-level instruction targets, leaving only repository targets. For multitenant deployments (mirrors `discover`'s `excludeHostInstructions`). - [JsonPropertyName("excludeHostInstructions")] - public bool? ExcludeHostInstructions { get; set; } - - /// Optional list of project directory paths. When omitted or empty, only the user-level targets are returned. - [JsonPropertyName("projectPaths")] - public IList? ProjectPaths { get; set; } -} - /// Installed plugin record from global state, with marketplace, version, install time, enabled state, cache path, and source. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] public sealed class InstalledPlugin @@ -7427,6 +7612,32 @@ public sealed class UserSettingsGetResult public IDictionary Settings { get => field ??= new Dictionary(); set; } } +/// On-disk locations of the settings files this runtime reads. A path is reported whether or not the file exists. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsGetPathsResult +{ + /// The repository's local, untracked settings file, or null when no repository root was supplied. + [JsonPropertyName("repoLocalSettings")] + public string? RepoLocalSettings { get; set; } + + /// The repository's checked-in settings file, or null when no repository root was supplied. + [JsonPropertyName("repoSettings")] + public string? RepoSettings { get; set; } + + /// The user settings file: `settings.json` under the resolved Copilot home. This is the file `user.settings.get`, `user.settings.load`, and `user.settings.set` read and write. + [JsonPropertyName("userSettings")] + public string UserSettings { get; set; } = string.Empty; +} + +/// Selects which settings file paths to resolve. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsGetPathsRequest +{ + /// Absolute path of a repository root. Supply it to also resolve that repository's two settings file paths; omit it to resolve only the user path. + [JsonPropertyName("repoRoot")] + public string? RepoRoot { get; set; } +} + /// Partial user settings to write to settings.json. Each top-level key is written individually, replacing the existing value; a key whose value is null is removed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] internal sealed class UserSettingsSetRequest @@ -7436,6 +7647,444 @@ internal sealed class UserSettingsSetRequest public JsonElement Settings { get; set; } } +/// Top-level user-setting keys grouped by who may govern them. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsGovernanceKeysResult +{ + /// Top-level keys a repository may override through a Claude-compatible repository config. + [JsonPropertyName("claudeRepo")] + public IList ClaudeRepo { get => field ??= []; set; } + + /// Top-level keys an enterprise policy may fix through managed settings. + [JsonPropertyName("managed")] + public IList Managed { get => field ??= []; set; } + + /// Top-level keys a repository may override through `.github/copilot/settings.json` or `.github/copilot/settings.local.json`. + [JsonPropertyName("repo")] + public IList Repo { get => field ??= []; set; } +} + +/// Outcome of an atomic user or repository settings edit. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SettingsEditResult +{ + /// Changed, unchanged or invalid existing file. Rejected input, validation failures and I/O errors remain RPC errors. + [JsonPropertyName("status")] + public SettingsEditStatus Status { get; set; } +} + +/// One atomic edit of a canonical setting in settings.json. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsEditRequest +{ + /// Nonempty canonical path segments of the setting to edit, starting with its top-level key. + [JsonPropertyName("canonicalPath")] + public IList CanonicalPath { get => field ??= []; set; } + + /// Configuration directory to edit. Omitted or empty resolves the server's own home, as in `user.settings.loadForConfigDir`. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } + + /// Set a scalar, add or remove a string list item, or remove the setting. The handler rejects a missing or incompatible value. + [JsonPropertyName("operation")] + public SettingsEditOperation Operation { get; set; } + + /// Required boolean, string or number for set, required string for add-item and remove-item, and forbidden for remove. The runtime rejects all other JSON values. + [JsonPropertyName("value")] + public JsonElement? Value { get; set; } +} + +/// Settings object with canonical key names. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsNormalizeResult +{ + /// The same settings with every legacy or snake_case key renamed to its canonical spelling. + [JsonPropertyName("settings")] + public JsonElement Settings { get; set; } +} + +/// Settings object whose key names should be canonicalized. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsNormalizeRequest +{ + /// Free-form settings object, possibly using legacy or snake_case key names. + [JsonPropertyName("settings")] + public JsonElement Settings { get; set; } +} + +/// The settings layer a problem was found in. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class UserSettingsProblemLocation +{ + /// Absolute path of the file backing this layer. + [JsonPropertyName("filePath")] + public string FilePath { get; set; } = string.Empty; + + /// Which layer this is: `user`, `repo`, or `local`. + [JsonPropertyName("kind")] + public string Kind { get; set; } = string.Empty; + + /// The caller-supplied display label for the layer. + [JsonPropertyName("label")] + public string Label { get; set; } = string.Empty; +} + +/// One setting that will not take effect, and why. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class UserSettingsProblem +{ + /// Coarse grouping for the problem, for a caller that presents problems in sections. + [JsonPropertyName("category")] + public string Category { get; set; } = string.Empty; + + /// Why the setting will not take effect. Never contains the setting's value, which may be a token or another secret. + [JsonPropertyName("explanation")] + public string Explanation { get; set; } = string.Empty; + + /// Stable identifier for this problem within the reported set, so a caller can track a selection across refreshes. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + /// What is wrong in machine-readable form, for a caller that wants to branch rather than display. + [JsonPropertyName("kind")] + public string Kind { get; set; } = string.Empty; + + /// The offending key as written in the file, when the problem is attributable to a single key. Absent when the whole file is at fault. + [JsonPropertyName("rawKey")] + public string? RawKey { get; set; } + + /// The settings layer the problem was found in. + [JsonPropertyName("source")] + public UserSettingsProblemLocation Source { get => field ??= new(); set; } +} + +/// The settings that will not take effect across the given layers. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsProblemsResult +{ + /// Each setting that will not take effect, and why. Empty when every layer is healthy. + [JsonPropertyName("problems")] + public IList? Problems { get; set; } +} + +/// One already-loaded settings layer to diagnose. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class UserSettingsProblemSource +{ + /// The layer's settings exactly as loaded, unnormalized. Empty when the file is missing or failed to parse. + [JsonPropertyName("config")] + public IDictionary? Config { get; set; } + + /// Absolute path of the file backing this layer. + [JsonPropertyName("filePath")] + public string FilePath { get; set; } = string.Empty; + + /// True when the file itself failed to parse, so its keys could not be read at all. + [JsonPropertyName("invalid")] + public bool? Invalid { get; set; } + + /// Which layer this is: `user`, `repo`, or `local`. + [JsonPropertyName("kind")] + public string Kind { get; set; } = string.Empty; + + /// Caller-chosen display label for the layer, echoed back on each problem so a caller can group by layer without re-deriving its own naming. + [JsonPropertyName("label")] + public string Label { get; set; } = string.Empty; +} + +/// The settings layers to diagnose. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsProblemsRequest +{ + /// Layers to diagnose, in the precedence order the caller applies them. + [JsonPropertyName("sources")] + public IList? Sources { get; set; } +} + +/// One problem found while validating a setting value. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class UserSettingsValidationIssue +{ + /// Human-readable description of the problem. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; + + /// Where in the settings tree the problem sits, as object keys and array indices. The first element is the top-level key; a whole-value problem is reported as that single key. + [JsonPropertyName("path")] + public IList Path { get => field ??= []; set; } +} + +/// Outcome of validating and writing one top-level setting subtree. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsApplyTopKeyResult +{ + /// Why the write failed, present only when `status` is `write-error`. + [JsonPropertyName("error")] + public string? Error { get; set; } + + /// Problems found, present only when `status` is `validation-error`. + [JsonPropertyName("issues")] + public IList? Issues { get; set; } + + /// `ok` when the value was written, `validation-error` when it was rejected before any write, `write-error` when validation passed but the write failed. + [JsonPropertyName("status")] + public string Status { get; set; } = string.Empty; +} + +/// A single top-level setting subtree to validate and write. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsApplyTopKeyRequest +{ + /// Canonical path of the setting the caller is editing. Currently informational only. + [JsonPropertyName("canonicalPath")] + public IList CanonicalPath { get => field ??= []; set; } + + /// Records that the user chose an update channel explicitly, so the one-time staff channel migration stops reapplying. Honored only for the `autoUpdatesChannel` key. + [JsonPropertyName("completeStaffUpdateChannelMigration")] + public bool? CompleteStaffUpdateChannelMigration { get; set; } + + /// True to remove the top-level key instead of writing it. + [JsonPropertyName("delete")] + public bool? Delete { get; set; } + + /// Top-level setting name to write. + [JsonPropertyName("topKey")] + public string TopKey { get; set; } = string.Empty; + + /// Value to write for the whole top-level key. Omitted when `delete` is true. Explicit null is preserved and validated as null. + [JsonPropertyName("value")] + public JsonElement? Value { get; set; } +} + +/// The whole content to store in the user settings file. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsWriteAllRequest +{ + /// The settings object to store. It replaces the file's entire content, so a key absent here is removed. + [JsonPropertyName("settings")] + public JsonElement Settings { get; set; } +} + +/// The stored value of the user setting after the merge. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsUpdateResult +{ + /// The key's stored value after the write: the merged object when both the stored value and the supplied value are objects, otherwise the supplied value. + [JsonPropertyName("value")] + public JsonElement Value { get; set; } +} + +/// Names the user setting to merge into, and the partial object to merge. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsUpdateRequest +{ + /// Copilot configuration directory to write the settings document in, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to use the directory the server resolved for itself. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } + + /// Top-level user-setting key to merge into, such as `extensions`. + [JsonPropertyName("key")] + public string Key { get; set; } = string.Empty; + + /// Single-component name for the settings document at `<configDir>/settings/<subDir>.json`; path separators, `.` and `..` are rejected. Omit it, or pass an empty string, to use the main settings document. + [JsonPropertyName("subDir")] + public string? SubDir { get; set; } + + /// Value to store for `key`. When both the stored value and this value are objects, their fields are shallow-merged and fields this object does not name are preserved. Otherwise this value replaces the stored value. + [JsonPropertyName("value")] + public JsonElement Value { get; set; } +} + +/// Contents of settings.json as stored, for a caller about to rewrite it. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsLoadForEditResult +{ + /// Parsed contents, present only when `status` is `ok`. + [JsonPropertyName("settings")] + public JsonElement? Settings { get; set; } + + /// `ok` when the file parsed, `missing` when there is no file yet, `invalid` when the file exists but will not parse. + [JsonPropertyName("status")] + public string Status { get; set; } = string.Empty; +} + +/// Outcome of validating one top-level setting subtree. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsValidateResult +{ + /// Problems found, empty when `ok` is true. + [JsonPropertyName("issues")] + public IList? Issues { get; set; } + + /// True when the subtree is valid. + [JsonPropertyName("ok")] + public bool Ok { get; set; } +} + +/// A single top-level setting subtree to validate. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsValidateRequest +{ + /// True to validate a removal of this key. The current settings file is not read. + [JsonPropertyName("delete")] + public bool? Delete { get; set; } + + /// Top-level setting name to validate. + [JsonPropertyName("topKey")] + public string TopKey { get; set; } = string.Empty; + + /// Value to validate. Omitted when `delete` is true. + [JsonPropertyName("value")] + public JsonElement? Value { get; set; } +} + +/// The declared shape of one feature flag, independent of any caller population. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class FeatureFlagMetadata +{ + /// The population the flag is declared for before any environment or user-settings override is applied. + [JsonPropertyName("availability")] + public FeatureFlagAvailability Availability { get; set; } + + /// Whether the flag participates in the CAPI sanity suite. + [JsonPropertyName("capiSanity")] + public bool CapiSanity { get; set; } + + /// Text shown to a user choosing whether to turn the flag on in experimental mode. Absent when the flag is not user-facing. + [JsonPropertyName("experimentalDescription")] + public string? ExperimentalDescription { get; set; } + + /// The online-experiment (ExP) flag this maps to, when the flag is assigned by an experiment rather than declared statically. + [JsonPropertyName("expFlag")] + public string? ExpFlag { get; set; } + + /// Environment variable that overrides this flag's experiment assignment locally in the experiment service, not in `featureFlags.resolve`. Present exactly when `expFlag` is, and derived from it, so a caller reads a local override without reproducing the naming rule. + [JsonPropertyName("expFlagEnvVar")] + public string? ExpFlagEnvVar { get; set; } + + /// The flag's name, matching the key it is listed under. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; +} + +/// Every feature flag this runtime declares, with the shape each one was declared with. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class FeatureFlagsMetadataResult +{ + /// Declared feature flags keyed by flag name. + [JsonPropertyName("flags")] + public IDictionary Flags { get => field ??= new Dictionary(); set; } +} + +/// Caller population and overrides for static feature-flag resolution, independent of experiment assignments and active runtime state. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class FeatureFlagsResolveRequest +{ + /// Resolve against this already-computed flag set rather than each flag's declared availability. Keyed by flag name. + [JsonPropertyName("baseFlags")] + public IDictionary? BaseFlags { get; set; } + + /// User settings to apply, including `enabledFeatureFlags`, legacy `feature_flags.enabled`, and supported convenience settings. + [JsonPropertyName("config")] + public JsonElement? Config { get; set; } + + /// Environment for direct feature-flag overrides and `COPILOT_CLI_ENABLED_FEATURE_FLAGS`. Does not apply `COPILOT_EXP_*` experiment assignments. Defaults to this runtime process's own environment. + [JsonPropertyName("environment")] + public IDictionary? Environment { get; set; } + + /// Flags forced to a value after every other layer, keyed by flag name. + [JsonPropertyName("flagOverrides")] + public IDictionary? FlagOverrides { get; set; } + + /// Whether the caller is in an experimental population. + [JsonPropertyName("isExperimental")] + public bool IsExperimental { get; set; } + + /// Whether the caller is GitHub or Microsoft staff. + [JsonPropertyName("isStaff")] + public bool IsStaff { get; set; } + + /// GitHub-staff membership. Omit when it was never recorded: a legacy staff account then counts as both staff populations and keeps every staff feature. + [JsonPropertyName("isStaffGithub")] + public bool? IsStaffGitHub { get; set; } + + /// Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. + [JsonPropertyName("isStaffMicrosoft")] + public bool? IsStaffMicrosoft { get; set; } + + /// Whether the caller belongs to the team population used by feature availability. + [JsonPropertyName("isTeam")] + public bool IsTeam { get; set; } +} + +/// Parsed repository settings without normalization or layering. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class RepoSettingsReadRawResult +{ + /// Stored JSON values after the existing JSONC parser and prototype-safety checks. Empty when the file is missing, blank, or invalid. + [JsonPropertyName("config")] + public JsonElement Config { get; set; } + + /// True when the file exists but did not parse, so `config` is empty for that reason rather than because nothing is set. + [JsonPropertyName("invalid")] + public bool Invalid { get; set; } +} + +/// Which repository settings file to read. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class RepoSettingsReadRawRequest +{ + /// Absolute path of the repository root. + [JsonPropertyName("repoRoot")] + public string RepoRoot { get; set; } = string.Empty; + + /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + [JsonPropertyName("scope")] + public string Scope { get; set; } = string.Empty; +} + +/// One key to write or remove in a repository settings file. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class RepoSettingsWriteKeyRequest +{ + /// True to remove the key instead of writing it. + [JsonPropertyName("delete")] + public bool? Delete { get; set; } + + /// Canonical top-level key permitted by the repository settings allowlist. + [JsonPropertyName("key")] + public string Key { get; set; } = string.Empty; + + /// Absolute path of the repository root. + [JsonPropertyName("repoRoot")] + public string RepoRoot { get; set; } = string.Empty; + + /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + [JsonPropertyName("scope")] + public string Scope { get; set; } = string.Empty; + + /// Value to validate and write. Required unless delete is true; a null value is validated, not treated as deletion. + [JsonPropertyName("value")] + public JsonElement? Value { get; set; } +} + +/// The complete set of repository-overridable settings to store. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class RepoSettingsWriteAllRequest +{ + /// Absolute path of the repository root. + [JsonPropertyName("repoRoot")] + public string RepoRoot { get; set; } = string.Empty; + + /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + [JsonPropertyName("scope")] + public string Scope { get; set; } = string.Empty; + + /// Object of allowed settings to store. Missing allowlisted keys are removed. Other input keys are ignored, while unknown stored keys are preserved. + [JsonPropertyName("settings")] + public JsonElement Settings { get; set; } +} + /// Owner, name, and host of a GitHub repository, as resolved from a git remote URL. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] public sealed class GitHubRepositoryIdentity @@ -11500,35 +12149,6 @@ internal sealed class SessionSetCredentialsParams public string SessionId { get; set; } = string.Empty; } -/// Credential-free authentication identity safe to expose to hosts and user interfaces. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AuthIdentity -{ - /// Snapshot of the authenticated user's Copilot subscription info, if known. - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } - - /// Name of the environment variable that supplied the credential, when applicable. - [JsonPropertyName("envVar")] - public string? EnvVar { get; set; } - - /// Authentication host. - [JsonPropertyName("host")] - public string Host { get; set; } = string.Empty; - - /// Authenticated login, when available. - [JsonPropertyName("login")] - public string? Login { get; set; } - - /// Opaque SDK GitHub credential registration backing this identity. Routing metadata only; never a credential. - [JsonPropertyName("registrationId")] - public string? RegistrationId { get; set; } - - /// Authentication type. - [JsonPropertyName("type")] - public AuthInfoType Type { get; set; } -} - /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] internal sealed class SessionGitHubAuthGetCurrentAuthInfoRequest @@ -14210,6 +14830,60 @@ internal sealed class ModelSetReasoningEffortRequest public string SessionId { get; set; } = string.Empty; } +/// Reasoning-summaries presentation policy for the session's current model. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ModelGetReasoningSummariesResult +{ + /// Whether the supplied `persistedShowReasoning` setting only restates the model default. This reports a redundancy, not a standing instruction to delete the setting: it stays true for as long as the setting and the model default agree, including for a user who later chose that value deliberately. It exists for a one-time migration of a legacy setting written before the model default made it redundant, so a host that acts on it owns the cleanup and must gate it behind its own persisted `done` marker, delete only a setting whose value still matches the one it read, and never repeat the deletion on a later launch. Under an off-by-default reasoning-summaries experiment an explicit `showReasoning: true` opt-in also reads as redundant on a summary-producing model, so an ungated host would keep deleting that opt-in and hide summaries again on every launch. + [JsonPropertyName("clearRedundantSetting")] + public bool ClearRedundantSetting { get; set; } + + /// Whether the session's reasoning-summaries experiment assignment has settled. False means this read does not wait for a pending assignment and reports the experiment-derived fields conservatively: `showHiddenHint` is false and `visibility` falls back to `persistedShowReasoning`, or is omitted when none was supplied. A host that wants the assigned answer re-reads until this is true. + [JsonPropertyName("experimentSettled")] + public bool ExperimentSettled { get; set; } + + /// Whether the selected model shows reasoning summaries by default. + [JsonPropertyName("modelDefaultShowsSummaries")] + public bool ModelDefaultShowsSummaries { get; set; } + + /// False until the session has a model catalog and a selected model. This read never resolves the catalog itself, and the runtime emits no readiness notification, so repeating this call alone leaves `ready` false indefinitely on a session that has neither listed models nor run a turn. `session.model.list` is the prerequisite and the signal: it resolves and caches the catalog for the session, so a successful return means the next read is ready. The exception is a session that resolves models without a Copilot catalog, that is a BYOK registry or an alternate provider: `session.model.list` returns an empty list without caching a catalog, so `ready` stays false and this policy is unavailable there. While false, every model-policy field is false and `visibility` is omitted; `experimentSettled` is independent of readiness and still reports the assignment state. + [JsonPropertyName("ready")] + public bool Ready { get; set; } + + /// Whether turns on this session produce reasoning summaries, honouring an explicit session reasoning-summary override. + [JsonPropertyName("sessionShowsSummaries")] + public bool SessionShowsSummaries { get; set; } + + /// Whether to show the hint that reasoning summaries are hidden. Always false while `experimentSettled` is false. + [JsonPropertyName("showHiddenHint")] + public bool ShowHiddenHint { get; set; } + + /// Whether the selected model emits reasoning headers. + [JsonPropertyName("showReasoningHeaders")] + public bool ShowReasoningHeaders { get; set; } + + /// Default reasoning visibility, and only meaningful once `ready` is true: false when the session produces no summaries, else the persisted setting, else the experiment's default. While `ready` is true it is omitted only when all three are unavailable, that is when the session produces summaries, no `persistedShowReasoning` was supplied, and `experimentSettled` is false. While `ready` is false there is no model policy to report and this field is always omitted, so an absent value alone does not imply a pending experiment. + [JsonPropertyName("visibility")] + public bool? Visibility { get; set; } +} + +/// Host presentation state the reasoning-summaries policy depends on. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ModelGetReasoningSummariesRequest +{ + /// The host's persisted `showReasoning` user setting, omitted when unset. + [JsonPropertyName("persistedShowReasoning")] + public bool? PersistedShowReasoning { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Whether the host is currently showing reasoning summaries. Defaults to false. + [JsonPropertyName("summariesVisible")] + public bool? SummariesVisible { get; set; } +} + /// Availability of a server-advertised routing preference. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] public sealed class AutoTierStatus @@ -20118,6 +20792,10 @@ internal sealed class SessionUpdateOptionsParams [JsonPropertyName("agentContext")] public string? AgentContext { get; set; } + /// Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + [JsonPropertyName("agentDirectories")] + public IList? AgentDirectories { get; set; } + /// Whether to include instructions from every MCP server in the system prompt instead of only allowlisted servers. [JsonPropertyName("allowAllMcpServerInstructions")] public bool? AllowAllMcpServerInstructions { get; set; } @@ -20166,7 +20844,7 @@ internal sealed class SessionUpdateOptionsParams [JsonPropertyName("disabledSkills")] public IList? DisabledSkills { get; set; } - /// Whether to enable loading of `.github/hooks/` filesystem hooks. Separate from the SDK callback hook mechanism. + /// Whether to enable repository-origin file hooks from `.github/hooks/` and trusted repository-configured roots. Does not control explicit hookDirectories or SDK callback hooks. [JsonPropertyName("enableFileHooks")] public bool? EnableFileHooks { get; set; } @@ -20190,7 +20868,7 @@ internal sealed class SessionUpdateOptionsParams [JsonPropertyName("enableSessionStore")] public bool? EnableSessionStore { get; set; } - /// Whether skill loading is enabled. Explicit false disables every source, including a bound SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless an SDK skill provider is registered. + /// Whether skill loading is enabled. Explicit false disables every source, including explicit SDK roots and a bound SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless explicit SDK skill roots or an SDK skill provider are supplied. [JsonPropertyName("enableSkills")] public bool? EnableSkills { get; set; } @@ -20222,6 +20900,10 @@ internal sealed class SessionUpdateOptionsParams [JsonPropertyName("featureFlags")] public IDictionary? FeatureFlags { get; set; } + /// Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without enableConfigDiscovery or enableFileHooks, which controls repository-origin hooks only; hook/managed disables still apply. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + [JsonPropertyName("hookDirectories")] + public IList? HookDirectories { get; set; } + /// Skill scan directories and descendants excluded from discovery. Supports `~`-relative paths. [JsonPropertyName("ignoredSkillsLocations")] public IList? IgnoredSkillsLocations { get; set; } @@ -20238,6 +20920,10 @@ internal sealed class SessionUpdateOptionsParams [JsonPropertyName("installedPlugins")] public IList? InstalledPlugins { get; set; } + /// Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without enableConfigDiscovery, subject to instruction/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + [JsonPropertyName("instructionDirectories")] + public IList? InstructionDirectories { get; set; } + /// Stable integration identifier used for analytics and rate-limit attribution. [JsonPropertyName("integrationId")] public string? IntegrationId { get; set; } @@ -20329,7 +21015,7 @@ internal sealed class SessionUpdateOptionsParams [JsonPropertyName("shellProcessFlags")] public IList? ShellProcessFlags { get; set; } - /// Additional directories to search for skills. + /// Explicit discovery-only skill roots, not filesystem grants. Available without enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. [JsonPropertyName("skillDirectories")] public IList? SkillDirectories { get; set; } @@ -28810,6 +29496,90 @@ public override void Write(Utf8JsonWriter writer, SandboxProxyCaState value, Jso } +/// Authentication type. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct AuthInfoType : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public AuthInfoType(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// Authentication provided by a GitHub App HMAC credential. + public static AuthInfoType Hmac { get; } = new("hmac"); + + /// Authentication resolved from environment-provided credentials. + public static AuthInfoType Env { get; } = new("env"); + + /// Authentication from an interactive user sign-in. + public static AuthInfoType User { get; } = new("user"); + + /// Authentication from a selected provider-owned account, without a GitHub credential. + public static AuthInfoType Account { get; } = new("account"); + + /// Authentication delegated to the GitHub CLI. + public static AuthInfoType GhCli { get; } = new("gh-cli"); + + /// Authentication from an API key credential. + public static AuthInfoType ApiKey { get; } = new("api-key"); + + /// Authentication from a GitHub token. + public static AuthInfoType Token { get; } = new("token"); + + /// Authentication from an SDK GitHub token callback. + public static AuthInfoType TokenProvider { get; } = new("token-provider"); + + /// Authentication from a Copilot API token. + public static AuthInfoType CopilotApiToken { get; } = new("copilot-api-token"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(AuthInfoType left, AuthInfoType right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(AuthInfoType left, AuthInfoType right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is AuthInfoType other && Equals(other); + + /// + public bool Equals(AuthInfoType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override AuthInfoType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, AuthInfoType value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(AuthInfoType)); + } + } +} + + /// Server transport type: stdio, http, sse (deprecated), or memory. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] @@ -31336,6 +32106,285 @@ public override void Write(Utf8JsonWriter writer, DiscoveredExtensionMode value, } +/// Where this source lives — used for UI grouping. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct InstructionSourceLocation : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public InstructionSourceLocation(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// Instructions live in user-level configuration. + public static InstructionSourceLocation User { get; } = new("user"); + + /// Instructions live in repository-level configuration. + public static InstructionSourceLocation Repository { get; } = new("repository"); + + /// Instructions live under the current working directory. + public static InstructionSourceLocation WorkingDirectory { get; } = new("working-directory"); + + /// Instructions live in plugin-provided configuration. + public static InstructionSourceLocation Plugin { get; } = new("plugin"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(InstructionSourceLocation left, InstructionSourceLocation right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(InstructionSourceLocation left, InstructionSourceLocation right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is InstructionSourceLocation other && Equals(other); + + /// + public bool Equals(InstructionSourceLocation other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override InstructionSourceLocation Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, InstructionSourceLocation value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(InstructionSourceLocation)); + } + } +} + + +/// Category of instruction source — used for merge logic. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct InstructionSourceType : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public InstructionSourceType(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// Instructions loaded from the user's home configuration. + public static InstructionSourceType Home { get; } = new("home"); + + /// Instructions loaded from repository-scoped files. + public static InstructionSourceType Repo { get; } = new("repo"); + + /// Instructions loaded from model-specific files. + public static InstructionSourceType Model { get; } = new("model"); + + /// Instructions loaded from VS Code instruction files. + public static InstructionSourceType Vscode { get; } = new("vscode"); + + /// Instructions discovered from nested agent files. + public static InstructionSourceType NestedAgents { get; } = new("nested-agents"); + + /// Instructions inherited from child instruction files. + public static InstructionSourceType ChildInstructions { get; } = new("child-instructions"); + + /// Instructions supplied by an installed plugin. + public static InstructionSourceType Plugin { get; } = new("plugin"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(InstructionSourceType left, InstructionSourceType right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(InstructionSourceType left, InstructionSourceType right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is InstructionSourceType other && Equals(other); + + /// + public bool Equals(InstructionSourceType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override InstructionSourceType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, InstructionSourceType value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(InstructionSourceType)); + } + } +} + + +/// Whether the target is a single file or a directory of instruction files. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct InstructionDiscoveryPathKind : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public InstructionDiscoveryPathKind(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// The target is a single instruction file. + public static InstructionDiscoveryPathKind File { get; } = new("file"); + + /// The target is a directory that holds instruction files. + public static InstructionDiscoveryPathKind Directory { get; } = new("directory"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(InstructionDiscoveryPathKind left, InstructionDiscoveryPathKind right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(InstructionDiscoveryPathKind left, InstructionDiscoveryPathKind right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is InstructionDiscoveryPathKind other && Equals(other); + + /// + public bool Equals(InstructionDiscoveryPathKind other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override InstructionDiscoveryPathKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, InstructionDiscoveryPathKind value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(InstructionDiscoveryPathKind)); + } + } +} + + +/// Which tier this target belongs to. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct InstructionDiscoveryPathLocation : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public InstructionDiscoveryPathLocation(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// Instructions live in user-level configuration. + public static InstructionDiscoveryPathLocation User { get; } = new("user"); + + /// Instructions live in repository-level configuration. + public static InstructionDiscoveryPathLocation Repository { get; } = new("repository"); + + /// Instructions live under the current working directory. + public static InstructionDiscoveryPathLocation WorkingDirectory { get; } = new("working-directory"); + + /// Instructions live in plugin-provided configuration. + public static InstructionDiscoveryPathLocation Plugin { get; } = new("plugin"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(InstructionDiscoveryPathLocation left, InstructionDiscoveryPathLocation right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(InstructionDiscoveryPathLocation left, InstructionDiscoveryPathLocation right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is InstructionDiscoveryPathLocation other && Equals(other); + + /// + public bool Equals(InstructionDiscoveryPathLocation other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override InstructionDiscoveryPathLocation Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, InstructionDiscoveryPathLocation value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(InstructionDiscoveryPathLocation)); + } + } +} + + /// Defines the allowed values. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] @@ -32464,49 +33513,40 @@ public override void Write(Utf8JsonWriter writer, AgentDiscoveryPathScope value, } -/// Where this source lives — used for UI grouping. +/// Optional completion hint for the input (e.g. 'directory' for filesystem path completion). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct InstructionSourceLocation : IEquatable +public readonly struct SlashCommandInputCompletion : IEquatable { private readonly string? _value; - /// Initializes a new instance of the struct. - /// The value to associate with this . + /// Initializes a new instance of the struct. + /// The value to associate with this . [JsonConstructor] - public InstructionSourceLocation(string value) + public SlashCommandInputCompletion(string value) { ArgumentException.ThrowIfNullOrWhiteSpace(value); _value = value; } - /// Gets the value associated with this . + /// Gets the value associated with this . public string Value => _value ?? string.Empty; - /// Instructions live in user-level configuration. - public static InstructionSourceLocation User { get; } = new("user"); - - /// Instructions live in repository-level configuration. - public static InstructionSourceLocation Repository { get; } = new("repository"); - - /// Instructions live under the current working directory. - public static InstructionSourceLocation WorkingDirectory { get; } = new("working-directory"); - - /// Instructions live in plugin-provided configuration. - public static InstructionSourceLocation Plugin { get; } = new("plugin"); + /// Input should complete filesystem directories. + public static SlashCommandInputCompletion Directory { get; } = new("directory"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(InstructionSourceLocation left, InstructionSourceLocation right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SlashCommandInputCompletion left, SlashCommandInputCompletion right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(InstructionSourceLocation left, InstructionSourceLocation right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SlashCommandInputCompletion left, SlashCommandInputCompletion right) => !(left == right); /// - public override bool Equals(object? obj) => obj is InstructionSourceLocation other && Equals(other); + public override bool Equals(object? obj) => obj is SlashCommandInputCompletion other && Equals(other); /// - public bool Equals(InstructionSourceLocation other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(SlashCommandInputCompletion other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -32514,77 +33554,65 @@ public InstructionSourceLocation(string value) /// public override string ToString() => Value; - /// Provides a for serializing instances. + /// Provides a for serializing instances. [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + public sealed class Converter : JsonConverter { /// - public override InstructionSourceLocation Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override SlashCommandInputCompletion Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, InstructionSourceLocation value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, SlashCommandInputCompletion value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(InstructionSourceLocation)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SlashCommandInputCompletion)); } } } -/// Category of instruction source — used for merge logic. +/// Coarse command category for grouping and behavior: runtime built-in, skill-backed command, or SDK/client-owned command. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct InstructionSourceType : IEquatable +public readonly struct SlashCommandKind : IEquatable { private readonly string? _value; - /// Initializes a new instance of the struct. - /// The value to associate with this . + /// Initializes a new instance of the struct. + /// The value to associate with this . [JsonConstructor] - public InstructionSourceType(string value) + public SlashCommandKind(string value) { ArgumentException.ThrowIfNullOrWhiteSpace(value); _value = value; } - /// Gets the value associated with this . + /// Gets the value associated with this . public string Value => _value ?? string.Empty; - /// Instructions loaded from the user's home configuration. - public static InstructionSourceType Home { get; } = new("home"); - - /// Instructions loaded from repository-scoped files. - public static InstructionSourceType Repo { get; } = new("repo"); - - /// Instructions loaded from model-specific files. - public static InstructionSourceType Model { get; } = new("model"); - - /// Instructions loaded from VS Code instruction files. - public static InstructionSourceType Vscode { get; } = new("vscode"); - - /// Instructions discovered from nested agent files. - public static InstructionSourceType NestedAgents { get; } = new("nested-agents"); + /// Command implemented by the runtime. + public static SlashCommandKind Builtin { get; } = new("builtin"); - /// Instructions inherited from child instruction files. - public static InstructionSourceType ChildInstructions { get; } = new("child-instructions"); + /// Command backed by a skill. + public static SlashCommandKind Skill { get; } = new("skill"); - /// Instructions supplied by an installed plugin. - public static InstructionSourceType Plugin { get; } = new("plugin"); + /// Command registered by an SDK client or extension. + public static SlashCommandKind Client { get; } = new("client"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(InstructionSourceType left, InstructionSourceType right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SlashCommandKind left, SlashCommandKind right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(InstructionSourceType left, InstructionSourceType right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SlashCommandKind left, SlashCommandKind right) => !(left == right); /// - public override bool Equals(object? obj) => obj is InstructionSourceType other && Equals(other); + public override bool Equals(object? obj) => obj is SlashCommandKind other && Equals(other); /// - public bool Equals(InstructionSourceType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(SlashCommandKind other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -32592,62 +33620,65 @@ public InstructionSourceType(string value) /// public override string ToString() => Value; - /// Provides a for serializing instances. + /// Provides a for serializing instances. [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + public sealed class Converter : JsonConverter { /// - public override InstructionSourceType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override SlashCommandKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, InstructionSourceType value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, SlashCommandKind value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(InstructionSourceType)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SlashCommandKind)); } } } -/// Whether the target is a single file or a directory of instruction files. +/// Whether one atomic settings edit changed a file. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct InstructionDiscoveryPathKind : IEquatable +public readonly struct SettingsEditStatus : IEquatable { private readonly string? _value; - /// Initializes a new instance of the struct. - /// The value to associate with this . + /// Initializes a new instance of the struct. + /// The value to associate with this . [JsonConstructor] - public InstructionDiscoveryPathKind(string value) + public SettingsEditStatus(string value) { ArgumentException.ThrowIfNullOrWhiteSpace(value); _value = value; } - /// Gets the value associated with this . + /// Gets the value associated with this . public string Value => _value ?? string.Empty; - /// The target is a single instruction file. - public static InstructionDiscoveryPathKind File { get; } = new("file"); + /// The edit changed the setting and was stored. + public static SettingsEditStatus Changed { get; } = new("changed"); - /// The target is a directory that holds instruction files. - public static InstructionDiscoveryPathKind Directory { get; } = new("directory"); + /// The setting already had the requested state. + public static SettingsEditStatus Unchanged { get; } = new("unchanged"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(InstructionDiscoveryPathKind left, InstructionDiscoveryPathKind right) => left.Equals(right); + /// The existing settings file could not be edited safely; nothing was written. + public static SettingsEditStatus Invalid { get; } = new("invalid"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(InstructionDiscoveryPathKind left, InstructionDiscoveryPathKind right) => !(left == right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SettingsEditStatus left, SettingsEditStatus right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SettingsEditStatus left, SettingsEditStatus right) => !(left == right); /// - public override bool Equals(object? obj) => obj is InstructionDiscoveryPathKind other && Equals(other); + public override bool Equals(object? obj) => obj is SettingsEditStatus other && Equals(other); /// - public bool Equals(InstructionDiscoveryPathKind other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(SettingsEditStatus other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -32655,68 +33686,68 @@ public InstructionDiscoveryPathKind(string value) /// public override string ToString() => Value; - /// Provides a for serializing instances. + /// Provides a for serializing instances. [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + public sealed class Converter : JsonConverter { /// - public override InstructionDiscoveryPathKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override SettingsEditStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, InstructionDiscoveryPathKind value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, SettingsEditStatus value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(InstructionDiscoveryPathKind)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SettingsEditStatus)); } } } -/// Which tier this target belongs to. +/// One atomic settings mutation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct InstructionDiscoveryPathLocation : IEquatable +public readonly struct SettingsEditOperation : IEquatable { private readonly string? _value; - /// Initializes a new instance of the struct. - /// The value to associate with this . + /// Initializes a new instance of the struct. + /// The value to associate with this . [JsonConstructor] - public InstructionDiscoveryPathLocation(string value) + public SettingsEditOperation(string value) { ArgumentException.ThrowIfNullOrWhiteSpace(value); _value = value; } - /// Gets the value associated with this . + /// Gets the value associated with this . public string Value => _value ?? string.Empty; - /// Instructions live in user-level configuration. - public static InstructionDiscoveryPathLocation User { get; } = new("user"); + /// Set one scalar value. + public static SettingsEditOperation Set { get; } = new("set"); - /// Instructions live in repository-level configuration. - public static InstructionDiscoveryPathLocation Repository { get; } = new("repository"); + /// Add one string to a list, unless present. + public static SettingsEditOperation AddItem { get; } = new("add-item"); - /// Instructions live under the current working directory. - public static InstructionDiscoveryPathLocation WorkingDirectory { get; } = new("working-directory"); + /// Remove one string from a list, unless absent. + public static SettingsEditOperation RemoveItem { get; } = new("remove-item"); - /// Instructions live in plugin-provided configuration. - public static InstructionDiscoveryPathLocation Plugin { get; } = new("plugin"); + /// Remove the setting without supplying a value. + public static SettingsEditOperation Remove { get; } = new("remove"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(InstructionDiscoveryPathLocation left, InstructionDiscoveryPathLocation right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SettingsEditOperation left, SettingsEditOperation right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(InstructionDiscoveryPathLocation left, InstructionDiscoveryPathLocation right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SettingsEditOperation left, SettingsEditOperation right) => !(left == right); /// - public override bool Equals(object? obj) => obj is InstructionDiscoveryPathLocation other && Equals(other); + public override bool Equals(object? obj) => obj is SettingsEditOperation other && Equals(other); /// - public bool Equals(InstructionDiscoveryPathLocation other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(SettingsEditOperation other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -32724,125 +33755,83 @@ public InstructionDiscoveryPathLocation(string value) /// public override string ToString() => Value; - /// Provides a for serializing instances. + /// Provides a for serializing instances. [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + public sealed class Converter : JsonConverter { /// - public override InstructionDiscoveryPathLocation Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override SettingsEditOperation Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, InstructionDiscoveryPathLocation value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, SettingsEditOperation value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(InstructionDiscoveryPathLocation)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SettingsEditOperation)); } } } -/// Optional completion hint for the input (e.g. 'directory' for filesystem path completion). +/// The population a feature flag is declared for, before overrides. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct SlashCommandInputCompletion : IEquatable +public readonly struct FeatureFlagAvailability : IEquatable { private readonly string? _value; - /// Initializes a new instance of the struct. - /// The value to associate with this . + /// Initializes a new instance of the struct. + /// The value to associate with this . [JsonConstructor] - public SlashCommandInputCompletion(string value) + public FeatureFlagAvailability(string value) { ArgumentException.ThrowIfNullOrWhiteSpace(value); _value = value; } - /// Gets the value associated with this . + /// Gets the value associated with this . public string Value => _value ?? string.Empty; - /// Input should complete filesystem directories. - public static SlashCommandInputCompletion Directory { get; } = new("directory"); + /// Enabled for everyone, before any override. + public static FeatureFlagAvailability On { get; } = new("on"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SlashCommandInputCompletion left, SlashCommandInputCompletion right) => left.Equals(right); + /// Enabled only for accounts on the owning team. + public static FeatureFlagAvailability Team { get; } = new("team"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SlashCommandInputCompletion left, SlashCommandInputCompletion right) => !(left == right); + /// Enabled only for staff accounts that have also opted into experimental features. + public static FeatureFlagAvailability StaffAndExperimental { get; } = new("staff-and-experimental"); - /// - public override bool Equals(object? obj) => obj is SlashCommandInputCompletion other && Equals(other); + /// Enabled for staff accounts and for accounts that opted into experimental features. + public static FeatureFlagAvailability StaffOrExperimental { get; } = new("staff-or-experimental"); - /// - public bool Equals(SlashCommandInputCompletion other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + /// Enabled for any staff account, GitHub or Microsoft. + public static FeatureFlagAvailability Staff { get; } = new("staff"); - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + /// Enabled for GitHub staff accounts only. + public static FeatureFlagAvailability StaffGitHub { get; } = new("staff-github"); - /// - public override string ToString() => Value; + /// Enabled for Microsoft staff accounts only. + public static FeatureFlagAvailability StaffMicrosoft { get; } = new("staff-microsoft"); - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter - { - /// - public override SlashCommandInputCompletion Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } + /// Enabled only for accounts that opted into experimental features. + public static FeatureFlagAvailability Experimental { get; } = new("experimental"); - /// - public override void Write(Utf8JsonWriter writer, SlashCommandInputCompletion value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SlashCommandInputCompletion)); - } - } -} + /// Disabled for everyone, before any override. + public static FeatureFlagAvailability Off { get; } = new("off"); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(FeatureFlagAvailability left, FeatureFlagAvailability right) => left.Equals(right); -/// Coarse command category for grouping and behavior: runtime built-in, skill-backed command, or SDK/client-owned command. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct SlashCommandKind : IEquatable -{ - private readonly string? _value; - - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public SlashCommandKind(string value) - { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; - } - - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// Command implemented by the runtime. - public static SlashCommandKind Builtin { get; } = new("builtin"); - - /// Command backed by a skill. - public static SlashCommandKind Skill { get; } = new("skill"); - - /// Command registered by an SDK client or extension. - public static SlashCommandKind Client { get; } = new("client"); - - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SlashCommandKind left, SlashCommandKind right) => left.Equals(right); - - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SlashCommandKind left, SlashCommandKind right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(FeatureFlagAvailability left, FeatureFlagAvailability right) => !(left == right); /// - public override bool Equals(object? obj) => obj is SlashCommandKind other && Equals(other); + public override bool Equals(object? obj) => obj is FeatureFlagAvailability other && Equals(other); /// - public bool Equals(SlashCommandKind other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(FeatureFlagAvailability other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -32850,20 +33839,20 @@ public SlashCommandKind(string value) /// public override string ToString() => Value; - /// Provides a for serializing instances. + /// Provides a for serializing instances. [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + public sealed class Converter : JsonConverter { /// - public override SlashCommandKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override FeatureFlagAvailability Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, SlashCommandKind value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, FeatureFlagAvailability value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SlashCommandKind)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(FeatureFlagAvailability)); } } } @@ -34462,90 +35451,6 @@ public override void Write(Utf8JsonWriter writer, ConnectorDiscoveryAvailability } -/// Authentication type. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct AuthInfoType : IEquatable -{ - private readonly string? _value; - - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public AuthInfoType(string value) - { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; - } - - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// Authentication provided by a GitHub App HMAC credential. - public static AuthInfoType Hmac { get; } = new("hmac"); - - /// Authentication resolved from environment-provided credentials. - public static AuthInfoType Env { get; } = new("env"); - - /// Authentication from an interactive user sign-in. - public static AuthInfoType User { get; } = new("user"); - - /// Authentication from a selected provider-owned account, without a GitHub credential. - public static AuthInfoType Account { get; } = new("account"); - - /// Authentication delegated to the GitHub CLI. - public static AuthInfoType GhCli { get; } = new("gh-cli"); - - /// Authentication from an API key credential. - public static AuthInfoType ApiKey { get; } = new("api-key"); - - /// Authentication from a GitHub token. - public static AuthInfoType Token { get; } = new("token"); - - /// Authentication from an SDK GitHub token callback. - public static AuthInfoType TokenProvider { get; } = new("token-provider"); - - /// Authentication from a Copilot API token. - public static AuthInfoType CopilotApiToken { get; } = new("copilot-api-token"); - - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(AuthInfoType left, AuthInfoType right) => left.Equals(right); - - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(AuthInfoType left, AuthInfoType right) => !(left == right); - - /// - public override bool Equals(object? obj) => obj is AuthInfoType other && Equals(other); - - /// - public bool Equals(AuthInfoType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - - /// - public override string ToString() => Value; - - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter - { - /// - public override AuthInfoType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } - - /// - public override void Write(Utf8JsonWriter writer, AuthInfoType value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(AuthInfoType)); - } - } -} - - /// Authoritative service connection state for one Connector. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] @@ -43783,6 +44688,12 @@ public async Task RegisterExtensionLaunchProviderAsync(CancellationToken cancell Interlocked.CompareExchange(ref field, new(_rpc), null) ?? field; + /// Instructions APIs. + public ServerInstructionsApi Instructions => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + /// Skills APIs. public ServerSkillsApi Skills => field ?? @@ -43807,12 +44718,6 @@ public async Task RegisterExtensionLaunchProviderAsync(CancellationToken cancell Interlocked.CompareExchange(ref field, new(_rpc), null) ?? field; - /// Instructions APIs. - public ServerInstructionsApi Instructions => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; - /// GlobalState APIs. public ServerGlobalStateApi GlobalState => field ?? @@ -43831,6 +44736,18 @@ public async Task RegisterExtensionLaunchProviderAsync(CancellationToken cancell Interlocked.CompareExchange(ref field, new(_rpc), null) ?? field; + /// FeatureFlags APIs. + public ServerFeatureFlagsApi FeatureFlags => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Repo APIs. + public ServerRepoApi Repo => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + /// GitHubRepository APIs. public ServerGitHubRepositoryApi GitHubRepository => field ?? @@ -44097,6 +45014,16 @@ public async Task DiscoverAsync(IList? projectPaths var request = new HooksDiscoverRequest { ProjectPaths = projectPaths, ExcludeHostHooks = excludeHostHooks }; return await CopilotClient.InvokeRpcAsync(_rpc, "hooks.discover", [request], cancellationToken); } + + /// Discovers hook actions enabled under server-side discovery settings from user, repository, plugin, and managed-policy sources. + /// Optional project paths and host-exclusion behavior for server-scoped hook discovery. + /// The to monitor for cancellation requests. The default is . + /// Server-discovered hook actions and partial-load diagnostics from user, repository, plugin, and managed-policy sources. Concrete sessions may include additional session-specific hook sources. + public async Task DiscoverAsync(HooksDiscoverRequest request, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(request); + return await CopilotClient.InvokeRpcAsync(_rpc, "hooks.discover", [request], cancellationToken); + } } /// Provides server-scoped Models APIs. @@ -44301,6 +45228,51 @@ public async Task LogoutAsync(string? selectionId = null, A var request = new AccountLogoutRequest { SelectionId = selectionId, AuthInfo = authInfo }; return await CopilotClient.InvokeRpcAsync(_rpc, "account.logout", [request], cancellationToken); } + + /// Renders the sign-in banner and the one-line account description the runtime uses for an authentication identity. The runtime words these in several places for its own callers, so a host that announces a sign-in or an account switch should render them from here rather than composing its own, which would let the two spellings drift apart. + /// Identity to describe. + /// The to monitor for cancellation requests. The default is . + /// The wording the runtime uses for an authentication identity. + internal async Task DescribeAuthInfoAsync(AuthIdentity identity, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(identity); + + var request = new AccountDescribeAuthInfoRequest { Identity = identity }; + return await CopilotClient.InvokeRpcAsync(_rpc, "account.describeAuthInfo", [request], cancellationToken); + } + + /// Reports whether the supplied identity can create gists. Gists are unavailable on GitHub Enterprise Cloud with data residency, and to Enterprise Managed Users on github.com, so a host that offers gist actions should hide or disable them when this reports no support. + /// Identity to evaluate. + /// The to monitor for cancellation requests. The default is . + /// Whether the identity can create gists, and why not when it cannot. + internal async Task GetGistSupportAsync(AuthIdentity identity, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(identity); + + var request = new AccountGetGistSupportRequest { Identity = identity }; + return await CopilotClient.InvokeRpcAsync(_rpc, "account.getGistSupport", [request], cancellationToken); + } + + /// Resolves a path on the identity's GitHub host into an absolute URL, so a host can link to settings or documentation on the enterprise instance the user is signed in to rather than to github.com. Falls back to the public host when no identity is supplied. + /// Host-relative path, without a leading slash, for example `settings/copilot/features`. + /// Identity whose host the path resolves against. Omit to resolve against the public github.com host. + /// The to monitor for cancellation requests. The default is . + /// An absolute URL on the identity's GitHub host. + internal async Task GetWebUrlAsync(string path, AuthIdentity? identity = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(path); + + var request = new AccountGetWebUrlRequest { Path = path, Identity = identity }; + return await CopilotClient.InvokeRpcAsync(_rpc, "account.getWebUrl", [request], cancellationToken); + } + + /// Names the environment variable supplying a classic personal access token, if one is set. A classic token cannot be upgraded in place, so a host that finds one should tell the user which variable to unset rather than starting an interactive sign-in that the variable would override. + /// The to monitor for cancellation requests. The default is . + /// The environment variable supplying a classic personal access token, when one is set. + internal async Task GetTokenEnvVarAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "account.getTokenEnvVar", [], cancellationToken); + } } /// Provides server-scoped Secrets APIs. @@ -44349,6 +45321,14 @@ public async Task DiscoverAsync(string? workingDirectory = nu return await CopilotClient.InvokeRpcAsync(_rpc, "mcp.discover", [request], cancellationToken); } + /// Lists the MCP servers the runtime supplies itself, so a host that disables the built-ins wholesale suppresses exactly the set the runtime would otherwise add. The names are fixed for a build and depend on no configuration, session or account. + /// The to monitor for cancellation requests. The default is . + /// Names of the MCP servers the runtime supplies itself. + internal async Task ListBuiltinServerNamesAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "mcp.listBuiltinServerNames", [], cancellationToken); + } + /// Reports whether the gh-replaceable GitHub MCP tools may be clipped for a session, which a host feeds back as the `excludeGhReplaceableTools` build option. The tools are redundant only when the session can reach a shell *and* the host has the `gh` that would replace them, so both halves are decided here. The shell half runs the platform shell tool through the runtime's own tool-filter matcher, so entry forms like `builtin:bash` and `builtin:*` behave exactly as they do when a session builds its tool catalog. The host half probes for `gh`, and is skipped entirely when the filters already rule the shell out. Host presence alone is not enough: a session restricted to, say, `view` would otherwise lose the built-in issue-read fallback while having no shell to replace it with. The answer describes the host the runtime runs on, so it is never forwarded to a remote engine. /// The session's tool allowlist, when it set one. Omitted means the session constrains nothing this way. /// The session's tool denylist, when it set one. Omitted means the session constrains nothing this way. @@ -44509,12 +45489,11 @@ public async Task ListAsync(CancellationToken cancellationToken = /// Unique name for the MCP server. /// MCP server configuration (stdio process or remote HTTP/SSE). /// The to monitor for cancellation requests. The default is . - public async Task AddAsync(string name, object config, CancellationToken cancellationToken = default) + public async Task AddAsync(string name, object? config, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(name); - ArgumentNullException.ThrowIfNull(config); - var request = new McpConfigAddRequest { Name = name, Config = CopilotClient.ToJsonElementForWire(config)!.Value }; + var request = new McpConfigAddRequest { Name = name, Config = CopilotClient.ToJsonElementForWire(config) ?? JsonElement.Parse("null") }; await CopilotClient.InvokeRpcAsync(_rpc, "mcp.config.add", [request], cancellationToken); } @@ -44522,12 +45501,11 @@ public async Task AddAsync(string name, object config, CancellationToken cancell /// Name of the MCP server to update. /// MCP server configuration (stdio process or remote HTTP/SSE). /// The to monitor for cancellation requests. The default is . - public async Task UpdateAsync(string name, object config, CancellationToken cancellationToken = default) + public async Task UpdateAsync(string name, object? config, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(name); - ArgumentNullException.ThrowIfNull(config); - var request = new McpConfigUpdateRequest { Name = name, Config = CopilotClient.ToJsonElementForWire(config)!.Value }; + var request = new McpConfigUpdateRequest { Name = name, Config = CopilotClient.ToJsonElementForWire(config) ?? JsonElement.Parse("null") }; await CopilotClient.InvokeRpcAsync(_rpc, "mcp.config.update", [request], cancellationToken); } @@ -44600,11 +45578,9 @@ internal async Task AllocateRequestIdAsync(Cancellat /// Repository used for the policy lookup, as `owner/name`. The policy selects the registry URL and whether the user token goes to the registry. The registry receives this repository only when the policy entry lists it as required context. A value that is not a string is refused. /// The to monitor for cancellation requests. The default is . /// Servers selected from the registry response. - internal async Task SearchAsync(long requestId, object authInfo, long limit, string? query = null, string? repository = null, CancellationToken cancellationToken = default) + internal async Task SearchAsync(long requestId, object? authInfo, long limit, string? query = null, string? repository = null, CancellationToken cancellationToken = default) { - ArgumentNullException.ThrowIfNull(authInfo); - - var request = new McpRegistrySearchRequest { RequestId = requestId, AuthInfo = CopilotClient.ToJsonElementForWire(authInfo)!.Value, Limit = limit, Query = query, Repository = repository }; + var request = new McpRegistrySearchRequest { RequestId = requestId, AuthInfo = CopilotClient.ToJsonElementForWire(authInfo) ?? JsonElement.Parse("null"), Limit = limit, Query = query, Repository = repository }; return await CopilotClient.InvokeRpcAsync(_rpc, "mcp.registry.search", [request], cancellationToken); } @@ -44729,6 +45705,92 @@ public async Task DisableAsync(IList ids, CancellationToken cancellation } } +/// Provides server-scoped Instructions APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerInstructionsApi +{ + private readonly JsonRpc _rpc; + + internal ServerInstructionsApi(JsonRpc rpc) + { + _rpc = rpc; + } + + /// Returns the prompt the `init` command runs to author repository instructions. A host offering its own initialize action sends this text so the instructions it produces match the ones the CLI produces. The text is fixed for a build and depends on no configuration, session or repository. + /// The to monitor for cancellation requests. The default is . + /// The prompt the init command runs. + internal async Task GetInitPromptAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "instructions.getInitPrompt", [], cancellationToken); + } + + /// Discovers instruction sources across user, repository, and plugin sources. + /// Optional list of project directory paths to scan for repository/working-directory instruction sources. When omitted or empty, only user-level and plugin instruction sources are returned (no project scan). + /// When true, omit the host's instruction sources (user/home-level files and plugin rules), leaving only repository and working-directory sources. For multitenant deployments. + /// The to monitor for cancellation requests. The default is . + /// Instruction sources discovered across user, repository, and plugin sources. + public async Task DiscoverAsync(IList? projectPaths = null, bool? excludeHostInstructions = null, CancellationToken cancellationToken = default) + { + var request = new InstructionsDiscoverRequest { ProjectPaths = projectPaths, ExcludeHostInstructions = excludeHostInstructions }; + return await CopilotClient.InvokeRpcAsync(_rpc, "instructions.discover", [request], cancellationToken); + } + + /// Discovers instruction sources across user, repository, and plugin sources. + /// Optional project paths to include in instruction discovery. + /// The to monitor for cancellation requests. The default is . + /// Instruction sources discovered across user, repository, and plugin sources. + public async Task DiscoverAsync(InstructionsDiscoverRequest request, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(request); + return await CopilotClient.InvokeRpcAsync(_rpc, "instructions.discover", [request], cancellationToken); + } + + /// Discovers the instruction sources for one caller-named location and returns them in the order the runtime applies them. `discover` answers for a set of project paths and derives the rest of its scope itself; this one instead takes every argument from the caller — the extra directories to scan and whether to descend into nested instruction files — and honors them as given. It also includes instruction directories from trusted repository settings, matching native repository discovery. Use it when the caller knows its own scope and no session exists to derive that scope from, such as a host reporting how many instruction files a directory contributes before any session starts. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. + /// Repository location to discover. An empty string selects no repository scope; cwdPath can still supply working-directory sources. + /// When true, include the sources a command-line host reads. Hosts that are not the CLI omit it. + /// Working directory whose instruction sources should also be included. Omission adds no separate working-directory scope. + /// Copilot configuration directory for user-level sources. An omitted or empty value uses the server's configuration home. + /// Extra directories to scan alongside instruction directories configured in the runtime environment. + /// When true, also discover instruction files nested below the location. + /// The to monitor for cancellation requests. The default is . + /// Instruction sources discovered across user, repository, and plugin sources. + internal async Task DiscoverRepoSourcesAsync(string location, bool? isCli = null, string? cwdPath = null, string? configDir = null, IList? additionalDirs = null, bool? enableChildInstructions = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(location); + + var request = new InstructionsDiscoverRepoSourcesRequest { Location = location, IsCli = isCli, CwdPath = cwdPath, ConfigDir = configDir, AdditionalDirs = additionalDirs, EnableChildInstructions = enableChildInstructions }; + return await CopilotClient.InvokeRpcAsync(_rpc, "instructions.discoverRepoSources", [request], cancellationToken); + } + + /// Returns the canonical files and directories where a client may create custom instructions that the runtime will recognize, including ones that do not exist yet. Repository targets become active once created. + /// Optional list of project directory paths. When omitted or empty, only the user-level targets are returned. + /// When true, omit the host's user-level instruction targets, leaving only repository targets. For multitenant deployments (mirrors `discover`'s `excludeHostInstructions`). + /// The to monitor for cancellation requests. The default is . + /// Canonical files and directories where custom instructions can be created so the runtime will recognize them. + public async Task GetDiscoveryPathsAsync(IList? projectPaths = null, bool? excludeHostInstructions = null, CancellationToken cancellationToken = default) + { + var request = new InstructionsGetDiscoveryPathsRequest { ProjectPaths = projectPaths, ExcludeHostInstructions = excludeHostInstructions }; + return await CopilotClient.InvokeRpcAsync(_rpc, "instructions.getDiscoveryPaths", [request], cancellationToken); + } + + /// Returns the canonical files and directories where a client may create custom instructions that the runtime will recognize, including ones that do not exist yet. Repository targets become active once created. + /// Optional project paths to include when enumerating instruction discovery targets. + /// The to monitor for cancellation requests. The default is . + /// Canonical files and directories where custom instructions can be created so the runtime will recognize them. + public async Task GetDiscoveryPathsAsync(InstructionsGetDiscoveryPathsRequest request, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(request); + return await CopilotClient.InvokeRpcAsync(_rpc, "instructions.getDiscoveryPaths", [request], cancellationToken); + } + + /// Drops the runtime's in-memory cache of discovered custom instructions so the next discovery reads them from disk again. A host calls this after it changes instruction files, or after it trusts a folder whose instructions an earlier discovery skipped, so that a session started afterwards sees the current files instead of a cached earlier answer. The call performs no I/O of its own and removes nothing from disk; it only invalidates, so the cost lands on the next discovery. Returns once the cache is clear, which is what lets a caller order a session start after it. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. + /// The to monitor for cancellation requests. The default is . + internal async Task ClearCacheAsync(CancellationToken cancellationToken = default) + { + await CopilotClient.InvokeRpcAsync(_rpc, "instructions.clearCache", [], cancellationToken); + } +} + /// Provides server-scoped Skills APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] public sealed class ServerSkillsApi @@ -44806,7 +45868,7 @@ public async Task ApplyUninstallAsync(CatalogClientCont /// Discovers skills across global and project sources. /// Optional list of project directory paths to scan for project-scoped skills. - /// Optional list of additional skill directory paths to include. + /// Explicit discovery-only skill roots, not filesystem grants. Available without ambient discovery, subject to skill/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. /// Optional skill scan paths to exclude from discovery. /// When true, omit skills from the host's global sources (personal, custom, plugin, and built-in), returning only project-scoped skills. For multitenant deployments. /// The to monitor for cancellation requests. The default is . @@ -44829,6 +45891,16 @@ public async Task GetDiscoveryPathsAsync(IList? return await CopilotClient.InvokeRpcAsync(_rpc, "skills.getDiscoveryPaths", [request], cancellationToken); } + /// Returns the canonical directories where a client may create skills that the runtime will recognize, including ones that do not exist yet. Project directories become active once created. + /// Optional project paths to enumerate. + /// The to monitor for cancellation requests. The default is . + /// Canonical locations where skills can be created so the runtime will recognize them. + public async Task GetDiscoveryPathsAsync(SkillsGetDiscoveryPathsRequest request, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(request); + return await CopilotClient.InvokeRpcAsync(_rpc, "skills.getDiscoveryPaths", [request], cancellationToken); + } + /// Installations APIs. public ServerSkillsInstallationsApi Installations => field ?? @@ -45234,6 +46306,16 @@ public async Task DiscoverAsync(IList? projectPaths = n return await CopilotClient.InvokeRpcAsync(_rpc, "agents.discover", [request], cancellationToken); } + /// Discovers custom agents across user, project, plugin, and remote sources. + /// Optional project paths to include in agent discovery. + /// The to monitor for cancellation requests. The default is . + /// Agents discovered across user, project, plugin, and remote sources. + public async Task DiscoverAsync(AgentsDiscoverRequest request, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(request); + return await CopilotClient.InvokeRpcAsync(_rpc, "agents.discover", [request], cancellationToken); + } + /// Returns the canonical directories where a client may create custom agents that the runtime will recognize, including ones that do not exist yet. Project directories become active once created. /// Optional list of project directory paths. When omitted or empty, only the user-level directory is returned. /// When true, omit the host's user-level agent directory, leaving only project directories. For multitenant deployments (mirrors `discover`'s `excludeHostAgents`). @@ -45245,6 +46327,16 @@ public async Task GetDiscoveryPathsAsync(IList? return await CopilotClient.InvokeRpcAsync(_rpc, "agents.getDiscoveryPaths", [request], cancellationToken); } + /// Returns the canonical directories where a client may create custom agents that the runtime will recognize, including ones that do not exist yet. Project directories become active once created. + /// Optional project paths to include when enumerating agent discovery directories. + /// The to monitor for cancellation requests. The default is . + /// Canonical locations where custom agents can be created so the runtime will recognize them. + public async Task GetDiscoveryPathsAsync(AgentsGetDiscoveryPathsRequest request, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(request); + return await CopilotClient.InvokeRpcAsync(_rpc, "agents.getDiscoveryPaths", [request], cancellationToken); + } + /// Lists the agents this runtime ships, by name. A consumer separating shipped agents from ones the user or a plugin authored should compare against these names rather than against `AgentInfo.source`: an authored agent may carry the `builtin` source while not being one of these, and the runtime treats the two as separate questions. `disableableNames` is the subset a user may turn off, which a client needs to decide whether to offer a toggle. `yamlBasedNames` is the subset backed by a shipped YAML definition, which a client needs before asking the runtime to load one. /// The to monitor for cancellation requests. The default is . /// The agents this runtime ships, named so a consumer can tell them apart from authored ones. @@ -45304,40 +46396,6 @@ internal async Task CustomAgentInit } } -/// Provides server-scoped Instructions APIs. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerInstructionsApi -{ - private readonly JsonRpc _rpc; - - internal ServerInstructionsApi(JsonRpc rpc) - { - _rpc = rpc; - } - - /// Discovers instruction sources across user, repository, and plugin sources. - /// Optional list of project directory paths to scan for repository/working-directory instruction sources. When omitted or empty, only user-level and plugin instruction sources are returned (no project scan). - /// When true, omit the host's instruction sources (user/home-level files and plugin rules), leaving only repository and working-directory sources. For multitenant deployments. - /// The to monitor for cancellation requests. The default is . - /// Instruction sources discovered across user, repository, and plugin sources. - public async Task DiscoverAsync(IList? projectPaths = null, bool? excludeHostInstructions = null, CancellationToken cancellationToken = default) - { - var request = new InstructionsDiscoverRequest { ProjectPaths = projectPaths, ExcludeHostInstructions = excludeHostInstructions }; - return await CopilotClient.InvokeRpcAsync(_rpc, "instructions.discover", [request], cancellationToken); - } - - /// Returns the canonical files and directories where a client may create custom instructions that the runtime will recognize, including ones that do not exist yet. Repository targets become active once created. - /// Optional list of project directory paths. When omitted or empty, only the user-level targets are returned. - /// When true, omit the host's user-level instruction targets, leaving only repository targets. For multitenant deployments (mirrors `discover`'s `excludeHostInstructions`). - /// The to monitor for cancellation requests. The default is . - /// Canonical files and directories where custom instructions can be created so the runtime will recognize them. - public async Task GetDiscoveryPathsAsync(IList? projectPaths = null, bool? excludeHostInstructions = null, CancellationToken cancellationToken = default) - { - var request = new InstructionsGetDiscoveryPathsRequest { ProjectPaths = projectPaths, ExcludeHostInstructions = excludeHostInstructions }; - return await CopilotClient.InvokeRpcAsync(_rpc, "instructions.getDiscoveryPaths", [request], cancellationToken); - } -} - /// Provides server-scoped GlobalState APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] public sealed class ServerGlobalStateApi @@ -45438,16 +46496,247 @@ public async Task GetAsync(CancellationToken cancellation return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.get", [], cancellationToken); } + /// Resolves the on-disk locations of the settings files this runtime reads, so a consumer can show or open them. The user path is the same file `user.settings.get`, `user.settings.load`, and `user.settings.set` operate on. Supply `repoRoot` to also resolve that repository's checked-in and local settings paths. A path is reported whether or not the file exists. + /// Absolute path of a repository root. Supply it to also resolve that repository's two settings file paths; omit it to resolve only the user path. + /// The to monitor for cancellation requests. The default is . + /// On-disk locations of the settings files this runtime reads. A path is reported whether or not the file exists. + internal async Task GetPathsAsync(string? repoRoot = null, CancellationToken cancellationToken = default) + { + var request = new UserSettingsGetPathsRequest { RepoRoot = repoRoot }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.getPaths", [request], cancellationToken); + } + /// Writes one or more user settings to settings.json, replacing each provided top-level key. A key whose value is null is removed. /// Partial user settings to write, as a free-form object keyed by setting name. /// The to monitor for cancellation requests. The default is . - public async Task SetAsync(object settings, CancellationToken cancellationToken = default) + public async Task SetAsync(object? settings, CancellationToken cancellationToken = default) { - ArgumentNullException.ThrowIfNull(settings); - - var request = new UserSettingsSetRequest { Settings = CopilotClient.ToJsonElementForWire(settings)!.Value }; + var request = new UserSettingsSetRequest { Settings = CopilotClient.ToJsonElementForWire(settings) ?? JsonElement.Parse("null") }; await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.set", [request], cancellationToken); } + + /// Lists the top-level user-setting keys by who is allowed to govern them: `repo` keys a repository may override through `.github/copilot/settings.json`, `claudeRepo` keys a repository may override through a Claude-compatible config, and `managed` keys an enterprise policy may fix. The lists are static for a given runtime build and fail closed: a key absent from a list cannot be governed that way. + /// The to monitor for cancellation requests. The default is . + /// Top-level user-setting keys grouped by who may govern them. + internal async Task ListGovernanceKeysAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.listGovernanceKeys", [], cancellationToken); + } + + /// Atomically edits one canonical user setting inside its settings-file lock. Reads, canonicalizes touched aliases, applies the edit, validates the resulting top-level setting and writes before releasing the lock. An explicit autoUpdatesChannel set completes the staff migration in the same transaction. Only a malformed existing file returns `invalid`; refused keys, invalid values and I/O errors reject the call. + /// Nonempty canonical path segments of the setting to edit, starting with its top-level key. + /// Set a scalar, add or remove a string list item, or remove the setting. The handler rejects a missing or incompatible value. + /// Configuration directory to edit. Omitted or empty resolves the server's own home, as in `user.settings.loadForConfigDir`. + /// Required boolean, string or number for set, required string for add-item and remove-item, and forbidden for remove. The runtime rejects all other JSON values. + /// The to monitor for cancellation requests. The default is . + /// Outcome of an atomic user or repository settings edit. + internal async Task EditAsync(IList canonicalPath, SettingsEditOperation operation, string? configDir = null, object? value = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(canonicalPath); + + var request = new UserSettingsEditRequest { CanonicalPath = canonicalPath, Operation = operation, ConfigDir = configDir, Value = CopilotClient.ToJsonElementForWire(value) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.edit", [request], cancellationToken); + } + + /// Rewrites legacy and snake_case setting names in a settings object to their canonical spelling. A caller editing settings.json must normalize before writing: a legacy key left in place survives the write, is re-normalized on the next load, and silently shadows the canonical value the write just stored. + /// Free-form settings object, possibly using legacy or snake_case key names. + /// The to monitor for cancellation requests. The default is . + /// Settings object with canonical key names. + internal async Task NormalizeAsync(object? settings, CancellationToken cancellationToken = default) + { + var request = new UserSettingsNormalizeRequest { Settings = CopilotClient.ToJsonElementForWire(settings) ?? JsonElement.Parse("null") }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.normalize", [request], cancellationToken); + } + + /// Diagnoses a set of already-loaded settings layers, reporting each key that will not take effect and why. Settings load tolerantly so that one bad key does not stop a session from starting; this method surfaces what was dropped so a caller can report it instead of silently ignoring the user's intent. Takes the layers as given rather than reading them, so a caller can diagnose exactly the content it is showing, including unsaved edits. Never echoes a setting's value, because a value may be a token or another secret. Marked internal because it exists to carry a CLI call site off the native addon, not to serve a consumer-facing need; it becomes public once an SDK consumer needs to inspect settings health itself. + /// Layers to diagnose, in the precedence order the caller applies them. + /// The to monitor for cancellation requests. The default is . + /// The settings that will not take effect across the given layers. + internal async Task DiagnoseProblemsAsync(IList? sources = null, CancellationToken cancellationToken = default) + { + var request = new UserSettingsProblemsRequest { Sources = sources }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.diagnoseProblems", [request], cancellationToken); + } + + /// Validates one top-level setting subtree and writes just that key to settings.json as a single step. Doing both here closes the race a caller cannot close itself: between a separate preflight read and the write, the file may change. Rewriting only the touched key keeps legacy siblings out of settings.json. Answers a status rather than failing, so a validation problem and a write problem stay distinguishable. + /// Canonical path of the setting the caller is editing. Currently informational only. + /// Top-level setting name to write. + /// Value to write for the whole top-level key. Omitted when `delete` is true. Explicit null is preserved and validated as null. + /// True to remove the top-level key instead of writing it. + /// Records that the user chose an update channel explicitly, so the one-time staff channel migration stops reapplying. Honored only for the `autoUpdatesChannel` key. + /// The to monitor for cancellation requests. The default is . + /// Outcome of validating and writing one top-level setting subtree. + internal async Task ApplyTopKeyAsync(IList canonicalPath, string topKey, object? value = null, bool? delete = null, bool? completeStaffUpdateChannelMigration = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(canonicalPath); + ArgumentNullException.ThrowIfNull(topKey); + + var request = new UserSettingsApplyTopKeyRequest { CanonicalPath = canonicalPath, TopKey = topKey, Value = CopilotClient.ToJsonElementForWire(value), Delete = delete, CompleteStaffUpdateChannelMigration = completeStaffUpdateChannelMigration }; + var payload = JsonSerializer.SerializeToNode(request, RpcJsonContext.Default.UserSettingsApplyTopKeyRequest)!.AsObject(); + if (request.Delete != true && request.Value is null) payload["value"] = null; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.applyTopKey", [payload], cancellationToken); + } + + /// Replaces the user settings file's entire content in one write. A key absent from `settings` is removed, which is what distinguishes this from `user.settings.set`: that one merges, so it can never clear a key the caller has dropped. For a caller saving the result of a raw edit, a merge would silently resurrect every key the user deleted. Records the same one-time mutation marks a per-key write records, so a setting the user has now chosen explicitly stops being migrated for them. + /// The settings object to store. It replaces the file's entire content, so a key absent here is removed. + /// The to monitor for cancellation requests. The default is . + internal async Task WriteAllAsync(object? settings, CancellationToken cancellationToken = default) + { + var request = new UserSettingsWriteAllRequest { Settings = CopilotClient.ToJsonElementForWire(settings) ?? JsonElement.Parse("null") }; + await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.writeAll", [request], cancellationToken); + } + + /// Merges a partial object into one top-level user setting, re-reading the stored value inside this runtime process's settings.json write lock so that concurrent writers in this process to different sub-fields of the same key do not clobber each other. Unlike `user.settings.set`, which replaces a key's whole value with what the caller last read, this keeps sub-fields the caller did not name when both the stored value and supplied value are objects; otherwise the supplied value replaces the stored value. Use it whenever two independent surfaces own different sub-fields of one setting. Returns the key's stored value after the write, in `value`. + /// Top-level user-setting key to merge into, such as `extensions`. + /// Value to store for `key`. When both the stored value and this value are objects, their fields are shallow-merged and fields this object does not name are preserved. Otherwise this value replaces the stored value. + /// Copilot configuration directory to write the settings document in, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to use the directory the server resolved for itself. + /// Single-component name for the settings document at `<configDir>/settings/<subDir>.json`; path separators, `.` and `..` are rejected. Omit it, or pass an empty string, to use the main settings document. + /// The to monitor for cancellation requests. The default is . + /// The stored value of the user setting after the merge. + internal async Task UpdateAsync(string key, object? value, string? configDir = null, string? subDir = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(key); + + var request = new UserSettingsUpdateRequest { Key = key, Value = CopilotClient.ToJsonElementForWire(value) ?? JsonElement.Parse("null"), ConfigDir = configDir, SubDir = subDir }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.update", [request], cancellationToken); + } + + /// Reads settings.json as stored for a caller that is about to edit it. Unlike `user.settings.get`, this returns file values rather than per-key metadata and defaults. Reports `missing` for an absent file and `invalid` when the existing file will not parse. Retired config.json and extensionless files are not read. + /// The to monitor for cancellation requests. The default is . + /// Contents of settings.json as stored, for a caller about to rewrite it. + internal async Task LoadForEditAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.loadForEdit", [], cancellationToken); + } + + /// Validates one top-level setting subtree without writing it, reporting each problem with the path it applies to. Scoped to a single top-level key on purpose: validating the whole file would reject an edit whenever an unrelated pre-existing field is malformed, locking the user out of the very tool that could fix it. + /// Top-level setting name to validate. + /// Value to validate. Omitted when `delete` is true. + /// True to validate a removal of this key. The current settings file is not read. + /// The to monitor for cancellation requests. The default is . + /// Outcome of validating one top-level setting subtree. + internal async Task ValidateAsync(string topKey, object? value = null, bool? delete = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(topKey); + + var request = new UserSettingsValidateRequest { TopKey = topKey, Value = CopilotClient.ToJsonElementForWire(value), Delete = delete }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.validate", [request], cancellationToken); + } +} + +/// Provides server-scoped FeatureFlags APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerFeatureFlagsApi +{ + private readonly JsonRpc _rpc; + + internal ServerFeatureFlagsApi(JsonRpc rpc) + { + _rpc = rpc; + } + + /// Lists every feature flag this runtime declares, with the population each one is declared for, its experimental description, and the online-experiment flag it maps to. This is the static catalog: it describes how each flag is defined, not whether it is on for anyone. Use `featureFlags.resolve` for static values with caller overrides, not active runtime values or experiment assignments. + /// The to monitor for cancellation requests. The default is . + /// Every feature flag this runtime declares, with the shape each one was declared with. + internal async Task ListMetadataAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "featureFlags.listMetadata", [], cancellationToken); + } + + /// Computes static feature flags from the supplied population and overrides without changing runtime state or verifying audience membership. Starts from declared availability, then applies direct feature-flag environment values, user settings, and explicit `flagOverrides`. It does not apply `COPILOT_EXP_*` experiment assignments, authenticated startup gates, or active runtime state. Settings include `enabledFeatureFlags`, the legacy `feature_flags.enabled` list, and supported convenience settings. Supply `baseFlags` to use an existing flag set instead of declared availability. Omit `isStaffGitHub` or `isStaffMicrosoft` when membership was never recorded: a legacy staff account then counts as both populations. + /// Whether the caller is GitHub or Microsoft staff. + /// Whether the caller is in an experimental population. + /// Whether the caller belongs to the team population used by feature availability. + /// GitHub-staff membership. Omit when it was never recorded: a legacy staff account then counts as both staff populations and keeps every staff feature. + /// Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. + /// Resolve against this already-computed flag set rather than each flag's declared availability. Keyed by flag name. + /// Environment for direct feature-flag overrides and `COPILOT_CLI_ENABLED_FEATURE_FLAGS`. Does not apply `COPILOT_EXP_*` experiment assignments. Defaults to this runtime process's own environment. + /// User settings to apply, including `enabledFeatureFlags`, legacy `feature_flags.enabled`, and supported convenience settings. + /// Flags forced to a value after every other layer, keyed by flag name. + /// The to monitor for cancellation requests. The default is . + /// The resolved feature flags, keyed by flag name. + internal async Task> ResolveAsync(bool isStaff, bool isExperimental, bool isTeam, bool? isStaffGithub = null, bool? isStaffMicrosoft = null, IDictionary? baseFlags = null, IDictionary? environment = null, object? config = null, IDictionary? flagOverrides = null, CancellationToken cancellationToken = default) + { + var request = new FeatureFlagsResolveRequest { IsStaff = isStaff, IsExperimental = isExperimental, IsTeam = isTeam, IsStaffGitHub = isStaffGithub, IsStaffMicrosoft = isStaffMicrosoft, BaseFlags = baseFlags, Environment = environment, Config = CopilotClient.ToJsonElementForWire(config), FlagOverrides = flagOverrides }; + return await CopilotClient.InvokeRpcAsync>(_rpc, "featureFlags.resolve", [request], cancellationToken); + } +} + +/// Provides server-scoped Repo APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerRepoApi +{ + private readonly JsonRpc _rpc; + + internal ServerRepoApi(JsonRpc rpc) + { + _rpc = rpc; + } + + /// Settings APIs. + public ServerRepoSettingsApi Settings => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; +} + +/// Provides server-scoped RepoSettings APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerRepoSettingsApi +{ + private readonly JsonRpc _rpc; + + internal ServerRepoSettingsApi(JsonRpc rpc) + { + _rpc = rpc; + } + + /// Reads one repository settings file without settings normalization or layering. The existing JSONC parser accepts comments and trailing commas and applies its prototype-safety rules. Missing or blank files return an empty valid config. Invalid files return an empty config with invalid=true; other read failures reject. + /// Absolute path of the repository root. + /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + /// The to monitor for cancellation requests. The default is . + /// Parsed repository settings without normalization or layering. + internal async Task ReadRawAsync(string repoRoot, string scope, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(repoRoot); + ArgumentNullException.ThrowIfNull(scope); + + var request = new RepoSettingsReadRawRequest { RepoRoot = repoRoot, Scope = scope }; + return await CopilotClient.InvokeRpcAsync(_rpc, "repo.settings.readRaw", [request], cancellationToken); + } + + /// Writes or removes one allowed top-level repository setting through the existing validator and file lock. Preserves unrelated stored keys. Invalid keys, values, existing documents, and I/O errors reject without replacing the file. Deletion requires delete=true; otherwise value must be present. + /// Absolute path of the repository root. + /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + /// Canonical top-level key permitted by the repository settings allowlist. + /// Value to validate and write. Required unless delete is true; a null value is validated, not treated as deletion. + /// True to remove the key instead of writing it. + /// The to monitor for cancellation requests. The default is . + internal async Task WriteKeyAsync(string repoRoot, string scope, string key, object? value = null, bool? delete = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(repoRoot); + ArgumentNullException.ThrowIfNull(scope); + ArgumentNullException.ThrowIfNull(key); + + var request = new RepoSettingsWriteKeyRequest { RepoRoot = repoRoot, Scope = scope, Key = key, Value = CopilotClient.ToJsonElementForWire(value), Delete = delete }; + var payload = JsonSerializer.SerializeToNode(request, RpcJsonContext.Default.RepoSettingsWriteKeyRequest)!.AsObject(); + if (request.Delete != true && request.Value is null) payload["value"] = null; + await CopilotClient.InvokeRpcAsync(_rpc, "repo.settings.writeKey", [payload], cancellationToken); + } + + /// Replaces the repository-overridable settings in one locked write. Allowed keys present in settings are validated and written; allowed keys absent from settings are removed. Other input keys are ignored, and unknown keys already stored in the file remain unchanged. Invalid values or an invalid existing file reject without a partial write. + /// Absolute path of the repository root. + /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + /// Object of allowed settings to store. Missing allowlisted keys are removed. Other input keys are ignored, while unknown stored keys are preserved. + /// The to monitor for cancellation requests. The default is . + internal async Task WriteAllAsync(string repoRoot, string scope, object? settings, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(repoRoot); + ArgumentNullException.ThrowIfNull(scope); + + var request = new RepoSettingsWriteAllRequest { RepoRoot = repoRoot, Scope = scope, Settings = CopilotClient.ToJsonElementForWire(settings) ?? JsonElement.Parse("null") }; + await CopilotClient.InvokeRpcAsync(_rpc, "repo.settings.writeAll", [request], cancellationToken); + } } /// Provides server-scoped GitHubRepository APIs. @@ -45498,11 +46787,9 @@ internal async Task NextRequestIdAsync(Cancellation /// The credential the listing runs under, carried opaquely because its shape is the host's own and the runtime only resolves a token and a GitHub host from it. No credential travels: this selects one the runtime already holds. /// The to monitor for cancellation requests. The default is . /// Outcome of an owner listing. Exactly one of `owners` and `message` is present, except that `throwError` reports a failure the caller is expected to raise rather than render. - internal async Task ListAsync(long requestId, object authInfo, CancellationToken cancellationToken = default) + internal async Task ListAsync(long requestId, object? authInfo, CancellationToken cancellationToken = default) { - ArgumentNullException.ThrowIfNull(authInfo); - - var request = new GitHubOwnersListRequest { RequestId = requestId, AuthInfo = CopilotClient.ToJsonElementForWire(authInfo)!.Value }; + var request = new GitHubOwnersListRequest { RequestId = requestId, AuthInfo = CopilotClient.ToJsonElementForWire(authInfo) ?? JsonElement.Parse("null") }; return await CopilotClient.InvokeRpcAsync(_rpc, "gitHubOwners.list", [request], cancellationToken); } @@ -45621,11 +46908,9 @@ public async Task SchemaAsync(CancellationToken can /// Channel the document is meant for (`device`, `server`, or `policyHelper`). Some keys are only honored in some channels; for example, a `policyHelper` registration is ignored in policy-helper output. When omitted, no channel-specific checks run. /// The to monitor for cancellation requests. The default is . /// Result of validating a managed-settings document. - public async Task ValidateAsync(object content, string? layer = null, CancellationToken cancellationToken = default) + public async Task ValidateAsync(object? content, string? layer = null, CancellationToken cancellationToken = default) { - ArgumentNullException.ThrowIfNull(content); - - var request = new ManagedSettingsValidateRequest { Content = CopilotClient.ToJsonElementForWire(content)!.Value, Layer = layer }; + var request = new ManagedSettingsValidateRequest { Content = CopilotClient.ToJsonElementForWire(content) ?? JsonElement.Parse("null"), Layer = layer }; return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.validate", [request], cancellationToken); } @@ -47278,14 +48563,13 @@ internal CanvasProviderApi(CopilotSession session) /// Provider metadata supplied by the host. /// Canvas contributions supplied by the provider. /// The to monitor for cancellation requests. The default is . - internal async Task RegisterAsync(string connectionId, object info, IList canvases, CancellationToken cancellationToken = default) + internal async Task RegisterAsync(string connectionId, object? info, IList canvases, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(connectionId); - ArgumentNullException.ThrowIfNull(info); ArgumentNullException.ThrowIfNull(canvases); _session.ThrowIfDisposed(); - var request = new CanvasProviderRegisterRequest { SessionId = _session.SessionId, ConnectionId = connectionId, Info = CopilotClient.ToJsonElementForWire(info)!.Value, Canvases = canvases.Select(static v => CopilotClient.ToJsonElementForWire(v)!.Value).ToList() }; + var request = new CanvasProviderRegisterRequest { SessionId = _session.SessionId, ConnectionId = connectionId, Info = CopilotClient.ToJsonElementForWire(info) ?? JsonElement.Parse("null"), Canvases = canvases.Select(static v => CopilotClient.ToJsonElementForWire(v)!.Value).ToList() }; await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.canvas.provider.register", [request], cancellationToken); } @@ -47319,13 +48603,12 @@ internal WorkflowApi(CopilotSession session) /// Workflow invocation options. /// The to monitor for cancellation requests. The default is . /// Complete current or terminal workflow run envelope. - public async Task RunAsync(string name, object args, WorkflowRunOptions? options = null, CancellationToken cancellationToken = default) + public async Task RunAsync(string name, object? args, WorkflowRunOptions? options = null, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(name); - ArgumentNullException.ThrowIfNull(args); _session.ThrowIfDisposed(); - var request = new WorkflowRunRequest { SessionId = _session.SessionId, Name = name, Args = CopilotClient.ToJsonElementForWire(args)!.Value, Options = options }; + var request = new WorkflowRunRequest { SessionId = _session.SessionId, Name = name, Args = CopilotClient.ToJsonElementForWire(args) ?? JsonElement.Parse("null"), Options = options }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.workflow.run", [request], cancellationToken); } @@ -47352,13 +48635,12 @@ public async Task ResumeAsync(string runId, WorkflowRunLim /// Opaque identifier of the originating tool call. /// The to monitor for cancellation requests. The default is . /// Complete current or terminal workflow run envelope. - internal async Task RunFromToolAsync(string name, object args, WorkflowToolRunOptions? options = null, string? toolCallId = null, CancellationToken cancellationToken = default) + internal async Task RunFromToolAsync(string name, object? args, WorkflowToolRunOptions? options = null, string? toolCallId = null, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(name); - ArgumentNullException.ThrowIfNull(args); _session.ThrowIfDisposed(); - var request = new WorkflowToolRunRequest { SessionId = _session.SessionId, Name = name, Args = CopilotClient.ToJsonElementForWire(args)!.Value, Options = options, ToolCallId = toolCallId }; + var request = new WorkflowToolRunRequest { SessionId = _session.SessionId, Name = name, Args = CopilotClient.ToJsonElementForWire(args) ?? JsonElement.Parse("null"), Options = options, ToolCallId = toolCallId }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.workflow.runFromTool", [request], cancellationToken); } @@ -47554,15 +48836,14 @@ public async Task GetAsync(string runId, string execut /// JSON result to memoize. /// The to monitor for cancellation requests. The default is . /// Acknowledgement that a workflow request was accepted. - public async Task PutAsync(string runId, string executionToken, string key, object resultJson, CancellationToken cancellationToken = default) + public async Task PutAsync(string runId, string executionToken, string key, object? resultJson, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(runId); ArgumentNullException.ThrowIfNull(executionToken); ArgumentNullException.ThrowIfNull(key); - ArgumentNullException.ThrowIfNull(resultJson); _session.ThrowIfDisposed(); - var request = new WorkflowJournalPutRequest { SessionId = _session.SessionId, RunId = runId, ExecutionToken = executionToken, Key = key, ResultJson = CopilotClient.ToJsonElementForWire(resultJson)!.Value }; + var request = new WorkflowJournalPutRequest { SessionId = _session.SessionId, RunId = runId, ExecutionToken = executionToken, Key = key, ResultJson = CopilotClient.ToJsonElementForWire(resultJson) ?? JsonElement.Parse("null") }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.workflow.journal.put", [request], cancellationToken); } } @@ -47704,6 +48985,19 @@ public async Task SetReasoningEffortAsync(string return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.model.setReasoningEffort", [request], cancellationToken); } + /// Computes whether the session's current model shows reasoning summaries and how a host should present them: the default Ctrl+T visibility, reasoning headers, the hidden-summaries hint, and whether a persisted `showReasoning` setting is redundant. The runtime folds in the session's model catalog, selection and reasoning-summaries experiment assignment; the host supplies only its own persisted setting and current visibility. This method reads the session's resolved model catalog rather than resolving it, so call `session.model.list` first on a session that has not listed models or run a turn; until then the result is `ready: false`. A session that resolves models without a Copilot catalog, that is a BYOK registry or an alternate provider, never caches one and stays `ready: false`. + /// The host's persisted `showReasoning` user setting, omitted when unset. + /// Whether the host is currently showing reasoning summaries. Defaults to false. + /// The to monitor for cancellation requests. The default is . + /// Reasoning-summaries presentation policy for the session's current model. + public async Task GetReasoningSummariesAsync(bool? persistedShowReasoning = null, bool? summariesVisible = null, CancellationToken cancellationToken = default) + { + _session.ThrowIfDisposed(); + + var request = new ModelGetReasoningSummariesRequest { SessionId = _session.SessionId, PersistedShowReasoning = persistedShowReasoning, SummariesVisible = summariesVisible }; + return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.model.getReasoningSummaries", [request], cancellationToken); + } + /// Lists models available to this session using its own auth and integration context. Connected hosts (CLI TUI, GitHub App) should call this through the session client so remote sessions return the remote CLI's available models rather than the caller's. /// Optional listing options. /// The to monitor for cancellation requests. The default is . @@ -48792,15 +50086,14 @@ internal async Task ReloadWithConfigAsync(CancellationTok /// Raw MCP CreateMessageRequest params, as received in the `sampling.requested` event. Treated as opaque at the schema layer; the runtime converts the embedded MCP messages into the OpenAI chat-completion shape internally. /// The to monitor for cancellation requests. The default is . /// Outcome of an MCP sampling execution: success result, failure error, or cancellation. - public async Task ExecuteSamplingAsync(string requestId, string serverName, object mcpRequestId, McpExecuteSamplingRequest request, CancellationToken cancellationToken = default) + public async Task ExecuteSamplingAsync(string requestId, string serverName, object? mcpRequestId, McpExecuteSamplingRequest request, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(requestId); ArgumentNullException.ThrowIfNull(serverName); - ArgumentNullException.ThrowIfNull(mcpRequestId); ArgumentNullException.ThrowIfNull(request); _session.ThrowIfDisposed(); - var rpcRequest = new McpExecuteSamplingParams { SessionId = _session.SessionId, RequestId = requestId, ServerName = serverName, McpRequestId = CopilotClient.ToJsonElementForWire(mcpRequestId)!.Value, Request = request }; + var rpcRequest = new McpExecuteSamplingParams { SessionId = _session.SessionId, RequestId = requestId, ServerName = serverName, McpRequestId = CopilotClient.ToJsonElementForWire(mcpRequestId) ?? JsonElement.Parse("null"), Request = request }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.mcp.executeSampling", [rpcRequest], cancellationToken); } @@ -49911,7 +51204,10 @@ internal OptionsApi(CopilotSession session) /// Whether interactive shell sessions are logged. /// How env values are passed to MCP servers (`direct` inlines literal values; `indirect` resolves at launch). /// Whether to include instructions from every MCP server in the system prompt instead of only allowlisted servers. - /// Additional directories to search for skills. + /// Explicit discovery-only skill roots, not filesystem grants. Available without enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + /// Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + /// Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without enableConfigDiscovery, subject to instruction/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + /// Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without enableConfigDiscovery or enableFileHooks, which controls repository-origin hooks only; hook/managed disables still apply. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. /// Skill scan directories and descendants excluded from discovery. Supports `~`-relative paths. /// Built-in skill names to include in this session. When specified, only these runtime-bundled skills are available. Skills from other sources with the same name remain available. Set to null to remove the allowlist restriction. /// Skill IDs that should be excluded from this session. @@ -49938,19 +51234,19 @@ internal OptionsApi(CopilotSession session) /// Replaces the session's capability set with the given list. Use to enable or disable capabilities mid-session (e.g., remove `memory` for reproducible scripted runs). Omit the field to leave the existing capability set unchanged. /// Whether to skip embedding retrieval pipeline initialization and execution. /// Organization-level custom instructions to inject into the system prompt. - /// Whether to enable loading of `.github/hooks/` filesystem hooks. Separate from the SDK callback hook mechanism. + /// Whether to enable repository-origin file hooks from `.github/hooks/` and trusted repository-configured roots. Does not control explicit hookDirectories or SDK callback hooks. /// Whether to enable host git operations (context resolution, child repo scanning, git info in system prompt). /// Whether to enable cross-session store writes and reads. - /// Whether skill loading is enabled. Explicit false disables every source, including a bound SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless an SDK skill provider is registered. + /// Whether skill loading is enabled. Explicit false disables every source, including explicit SDK roots and a bound SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless explicit SDK skill roots or an SDK skill provider are supplied. /// Context tier for models with tiered pricing. The session uses this to derive effective `modelCapabilitiesOverrides` so compaction, truncation, token display, and request limits honor the selected tier. /// Optional session limits. Pass null to clear the session limits. /// The to monitor for cancellation requests. The default is . /// Indicates whether the session options patch was applied successfully. - public async Task UpdateAsync(string? model = null, ModelCapabilitiesOverride? modelCapabilitiesOverrides = null, string? reasoningEffort = null, OptionsUpdateReasoningSummary? reasoningSummary = null, Verbosity? verbosity = null, string? clientName = null, string? lspClientName = null, string? integrationId = null, IDictionary? featureFlags = null, bool? isExperimentalMode = null, ProviderConfig? provider = null, CapiSessionOptions? capi = null, string? workingDirectory = null, IList? availableTools = null, IList? excludedTools = null, IList? includedBuiltinAgents = null, IList? excludedBuiltinAgents = null, OptionsUpdateToolFilterPrecedence? toolFilterPrecedence = null, bool? enableScriptSafety = null, ShellOptions? shell = null, string? shellInitProfile = null, IList? shellProcessFlags = null, SandboxConfig? sandboxConfig = null, SandboxConfigSource? sandboxConfigSource = null, bool? logInteractiveShells = null, OptionsUpdateEnvValueMode? envValueMode = null, bool? allowAllMcpServerInstructions = null, IList? skillDirectories = null, IList? ignoredSkillsLocations = null, IList? includedBuiltinSkills = null, IList? disabledSkills = null, bool? enableOnDemandInstructionDiscovery = null, long? maxInlineBinaryBytes = null, IList? installedPlugins = null, bool? customAgentsLocalOnly = null, bool? suppressCustomAgentPrompt = null, bool? skipCustomInstructions = null, IList? disabledInstructionSources = null, bool? coauthorEnabled = null, string? trajectoryFile = null, bool? enableStreaming = null, string? copilotUrl = null, bool? askUserDisabled = null, bool? continueOnAutoMode = null, bool? runningInInteractiveMode = null, bool? enableReasoningSummaries = null, string? agentContext = null, string? eventsLogDirectory = null, bool? eventsLogIncludesSubagents = null, IList? additionalContentExclusionPolicies = null, bool? manageScheduleEnabled = null, IList? sessionCapabilities = null, bool? skipEmbeddingRetrieval = null, string? organizationCustomInstructions = null, bool? enableFileHooks = null, bool? enableHostGitOperations = null, bool? enableSessionStore = null, bool? enableSkills = null, OptionsUpdateContextTier? contextTier = null, SessionLimitsConfig? sessionLimits = null, CancellationToken cancellationToken = default) + public async Task UpdateAsync(string? model = null, ModelCapabilitiesOverride? modelCapabilitiesOverrides = null, string? reasoningEffort = null, OptionsUpdateReasoningSummary? reasoningSummary = null, Verbosity? verbosity = null, string? clientName = null, string? lspClientName = null, string? integrationId = null, IDictionary? featureFlags = null, bool? isExperimentalMode = null, ProviderConfig? provider = null, CapiSessionOptions? capi = null, string? workingDirectory = null, IList? availableTools = null, IList? excludedTools = null, IList? includedBuiltinAgents = null, IList? excludedBuiltinAgents = null, OptionsUpdateToolFilterPrecedence? toolFilterPrecedence = null, bool? enableScriptSafety = null, ShellOptions? shell = null, string? shellInitProfile = null, IList? shellProcessFlags = null, SandboxConfig? sandboxConfig = null, SandboxConfigSource? sandboxConfigSource = null, bool? logInteractiveShells = null, OptionsUpdateEnvValueMode? envValueMode = null, bool? allowAllMcpServerInstructions = null, IList? skillDirectories = null, IList? agentDirectories = null, IList? instructionDirectories = null, IList? hookDirectories = null, IList? ignoredSkillsLocations = null, IList? includedBuiltinSkills = null, IList? disabledSkills = null, bool? enableOnDemandInstructionDiscovery = null, long? maxInlineBinaryBytes = null, IList? installedPlugins = null, bool? customAgentsLocalOnly = null, bool? suppressCustomAgentPrompt = null, bool? skipCustomInstructions = null, IList? disabledInstructionSources = null, bool? coauthorEnabled = null, string? trajectoryFile = null, bool? enableStreaming = null, string? copilotUrl = null, bool? askUserDisabled = null, bool? continueOnAutoMode = null, bool? runningInInteractiveMode = null, bool? enableReasoningSummaries = null, string? agentContext = null, string? eventsLogDirectory = null, bool? eventsLogIncludesSubagents = null, IList? additionalContentExclusionPolicies = null, bool? manageScheduleEnabled = null, IList? sessionCapabilities = null, bool? skipEmbeddingRetrieval = null, string? organizationCustomInstructions = null, bool? enableFileHooks = null, bool? enableHostGitOperations = null, bool? enableSessionStore = null, bool? enableSkills = null, OptionsUpdateContextTier? contextTier = null, SessionLimitsConfig? sessionLimits = null, CancellationToken cancellationToken = default) { _session.ThrowIfDisposed(); - var request = new SessionUpdateOptionsParams { SessionId = _session.SessionId, Model = model, ModelCapabilitiesOverrides = modelCapabilitiesOverrides, ReasoningEffort = reasoningEffort, ReasoningSummary = reasoningSummary, Verbosity = verbosity, ClientName = clientName, LspClientName = lspClientName, IntegrationId = integrationId, FeatureFlags = featureFlags, IsExperimentalMode = isExperimentalMode, Provider = provider, Capi = capi, WorkingDirectory = workingDirectory, AvailableTools = availableTools, ExcludedTools = excludedTools, IncludedBuiltinAgents = includedBuiltinAgents, ExcludedBuiltinAgents = excludedBuiltinAgents, ToolFilterPrecedence = toolFilterPrecedence, EnableScriptSafety = enableScriptSafety, Shell = shell, ShellInitProfile = shellInitProfile, ShellProcessFlags = shellProcessFlags, SandboxConfig = sandboxConfig, SandboxConfigSource = sandboxConfigSource, LogInteractiveShells = logInteractiveShells, EnvValueMode = envValueMode, AllowAllMcpServerInstructions = allowAllMcpServerInstructions, SkillDirectories = skillDirectories, IgnoredSkillsLocations = ignoredSkillsLocations, IncludedBuiltinSkills = includedBuiltinSkills, DisabledSkills = disabledSkills, EnableOnDemandInstructionDiscovery = enableOnDemandInstructionDiscovery, MaxInlineBinaryBytes = maxInlineBinaryBytes, InstalledPlugins = installedPlugins, CustomAgentsLocalOnly = customAgentsLocalOnly, SuppressCustomAgentPrompt = suppressCustomAgentPrompt, SkipCustomInstructions = skipCustomInstructions, DisabledInstructionSources = disabledInstructionSources, CoauthorEnabled = coauthorEnabled, TrajectoryFile = trajectoryFile, EnableStreaming = enableStreaming, CopilotUrl = copilotUrl, AskUserDisabled = askUserDisabled, ContinueOnAutoMode = continueOnAutoMode, RunningInInteractiveMode = runningInInteractiveMode, EnableReasoningSummaries = enableReasoningSummaries, AgentContext = agentContext, EventsLogDirectory = eventsLogDirectory, EventsLogIncludesSubagents = eventsLogIncludesSubagents, AdditionalContentExclusionPolicies = additionalContentExclusionPolicies, ManageScheduleEnabled = manageScheduleEnabled, SessionCapabilities = sessionCapabilities, SkipEmbeddingRetrieval = skipEmbeddingRetrieval, OrganizationCustomInstructions = organizationCustomInstructions, EnableFileHooks = enableFileHooks, EnableHostGitOperations = enableHostGitOperations, EnableSessionStore = enableSessionStore, EnableSkills = enableSkills, ContextTier = contextTier, SessionLimits = sessionLimits }; + var request = new SessionUpdateOptionsParams { SessionId = _session.SessionId, Model = model, ModelCapabilitiesOverrides = modelCapabilitiesOverrides, ReasoningEffort = reasoningEffort, ReasoningSummary = reasoningSummary, Verbosity = verbosity, ClientName = clientName, LspClientName = lspClientName, IntegrationId = integrationId, FeatureFlags = featureFlags, IsExperimentalMode = isExperimentalMode, Provider = provider, Capi = capi, WorkingDirectory = workingDirectory, AvailableTools = availableTools, ExcludedTools = excludedTools, IncludedBuiltinAgents = includedBuiltinAgents, ExcludedBuiltinAgents = excludedBuiltinAgents, ToolFilterPrecedence = toolFilterPrecedence, EnableScriptSafety = enableScriptSafety, Shell = shell, ShellInitProfile = shellInitProfile, ShellProcessFlags = shellProcessFlags, SandboxConfig = sandboxConfig, SandboxConfigSource = sandboxConfigSource, LogInteractiveShells = logInteractiveShells, EnvValueMode = envValueMode, AllowAllMcpServerInstructions = allowAllMcpServerInstructions, SkillDirectories = skillDirectories, AgentDirectories = agentDirectories, InstructionDirectories = instructionDirectories, HookDirectories = hookDirectories, IgnoredSkillsLocations = ignoredSkillsLocations, IncludedBuiltinSkills = includedBuiltinSkills, DisabledSkills = disabledSkills, EnableOnDemandInstructionDiscovery = enableOnDemandInstructionDiscovery, MaxInlineBinaryBytes = maxInlineBinaryBytes, InstalledPlugins = installedPlugins, CustomAgentsLocalOnly = customAgentsLocalOnly, SuppressCustomAgentPrompt = suppressCustomAgentPrompt, SkipCustomInstructions = skipCustomInstructions, DisabledInstructionSources = disabledInstructionSources, CoauthorEnabled = coauthorEnabled, TrajectoryFile = trajectoryFile, EnableStreaming = enableStreaming, CopilotUrl = copilotUrl, AskUserDisabled = askUserDisabled, ContinueOnAutoMode = continueOnAutoMode, RunningInInteractiveMode = runningInInteractiveMode, EnableReasoningSummaries = enableReasoningSummaries, AgentContext = agentContext, EventsLogDirectory = eventsLogDirectory, EventsLogIncludesSubagents = eventsLogIncludesSubagents, AdditionalContentExclusionPolicies = additionalContentExclusionPolicies, ManageScheduleEnabled = manageScheduleEnabled, SessionCapabilities = sessionCapabilities, SkipEmbeddingRetrieval = skipEmbeddingRetrieval, OrganizationCustomInstructions = organizationCustomInstructions, EnableFileHooks = enableFileHooks, EnableHostGitOperations = enableHostGitOperations, EnableSessionStore = enableSessionStore, EnableSkills = enableSkills, ContextTier = contextTier, SessionLimits = sessionLimits }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.options.update", [request], cancellationToken); } } @@ -50078,13 +51374,12 @@ internal ToolsApi(CopilotSession session) /// Optional identifier used to correlate this invocation with its tool call. /// The to monitor for cancellation requests. The default is . /// Canonical result returned by a session tool. - public async Task ExecuteAsync(string name, object arguments, string? toolCallId = null, CancellationToken cancellationToken = default) + public async Task ExecuteAsync(string name, object? arguments, string? toolCallId = null, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(name); - ArgumentNullException.ThrowIfNull(arguments); _session.ThrowIfDisposed(); - var request = new ToolsExecuteRequest { SessionId = _session.SessionId, Name = name, Arguments = CopilotClient.ToJsonElementForWire(arguments)!.Value, ToolCallId = toolCallId }; + var request = new ToolsExecuteRequest { SessionId = _session.SessionId, Name = name, Arguments = CopilotClient.ToJsonElementForWire(arguments) ?? JsonElement.Parse("null"), ToolCallId = toolCallId }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.tools.execute", [request], cancellationToken); } @@ -50111,13 +51406,12 @@ public async Task GetBuiltinDescriptorsAsync(b /// Final expanded result returned by the task_complete tool. /// The to monitor for cancellation requests. The default is . /// Task completion notification with summary from the agent. - public async Task TaskCompleteEventDataAsync(object toolArgs, ToolResultExpanded finalResult, CancellationToken cancellationToken = default) + public async Task TaskCompleteEventDataAsync(object? toolArgs, ToolResultExpanded finalResult, CancellationToken cancellationToken = default) { - ArgumentNullException.ThrowIfNull(toolArgs); ArgumentNullException.ThrowIfNull(finalResult); _session.ThrowIfDisposed(); - var request = new ToolsTaskCompleteEventDataRequest { SessionId = _session.SessionId, ToolArgs = CopilotClient.ToJsonElementForWire(toolArgs)!.Value, FinalResult = finalResult }; + var request = new ToolsTaskCompleteEventDataRequest { SessionId = _session.SessionId, ToolArgs = CopilotClient.ToJsonElementForWire(toolArgs) ?? JsonElement.Parse("null"), FinalResult = finalResult }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.tools.taskCompleteEventData", [request], cancellationToken); } @@ -51535,12 +52829,11 @@ public async Task ClearAsync(CancellationToken cancellationToken = default) /// Opaque runtime-owned filter object. /// The to monitor for cancellation requests. The default is . /// Indicates whether a user-facing pending item was removed. - internal async Task ConsumeSystemNotificationsAsync(object filter, CancellationToken cancellationToken = default) + internal async Task ConsumeSystemNotificationsAsync(object? filter, CancellationToken cancellationToken = default) { - ArgumentNullException.ThrowIfNull(filter); _session.ThrowIfDisposed(); - var request = new QueueConsumeSystemNotificationsRequest { SessionId = _session.SessionId, Filter = CopilotClient.ToJsonElementForWire(filter)!.Value }; + var request = new QueueConsumeSystemNotificationsRequest { SessionId = _session.SessionId, Filter = CopilotClient.ToJsonElementForWire(filter) ?? JsonElement.Parse("null") }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.queue.consumeSystemNotifications", [request], cancellationToken); } @@ -52914,9 +54207,16 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(AbortRequest))] [JsonSerializable(typeof(AbortResult))] [JsonSerializable(typeof(AccountAllUsers))] +[JsonSerializable(typeof(AccountDescribeAuthInfoRequest))] +[JsonSerializable(typeof(AccountDescribeAuthInfoResult))] [JsonSerializable(typeof(AccountGetCurrentAuthResult))] +[JsonSerializable(typeof(AccountGetGistSupportRequest))] +[JsonSerializable(typeof(AccountGetGistSupportResult))] [JsonSerializable(typeof(AccountGetQuotaRequest))] [JsonSerializable(typeof(AccountGetQuotaResult))] +[JsonSerializable(typeof(AccountGetTokenEnvVarResult))] +[JsonSerializable(typeof(AccountGetWebUrlRequest))] +[JsonSerializable(typeof(AccountGetWebUrlResult))] [JsonSerializable(typeof(AccountLoginRequest))] [JsonSerializable(typeof(AccountLoginResult))] [JsonSerializable(typeof(AccountLogoutRequest))] @@ -53121,6 +54421,9 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(ExternalToolTextResultForLlmBinaryResultsForLlm))] [JsonSerializable(typeof(ExternalToolTextResultForLlmContent))] [JsonSerializable(typeof(ExternalToolTextResultForLlmContentResourceLinkIcon))] +[JsonSerializable(typeof(FeatureFlagMetadata))] +[JsonSerializable(typeof(FeatureFlagsMetadataResult))] +[JsonSerializable(typeof(FeatureFlagsResolveRequest))] [JsonSerializable(typeof(FleetStartRequest))] [JsonSerializable(typeof(FleetStartResult))] [JsonSerializable(typeof(FolderTrustAddParams))] @@ -53192,6 +54495,7 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(HostStartRequest))] [JsonSerializable(typeof(HostStartResult))] [JsonSerializable(typeof(IDictionary))] +[JsonSerializable(typeof(IDictionary))] [JsonSerializable(typeof(IDictionary))] [JsonSerializable(typeof(IList))] [JsonSerializable(typeof(IList))] @@ -53207,9 +54511,11 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(InstructionDiscoveryPath))] [JsonSerializable(typeof(InstructionDiscoveryPathList))] [JsonSerializable(typeof(InstructionSource))] +[JsonSerializable(typeof(InstructionsDiscoverRepoSourcesRequest))] [JsonSerializable(typeof(InstructionsDiscoverRequest))] [JsonSerializable(typeof(InstructionsGetDiscoveryPathsRequest))] [JsonSerializable(typeof(InstructionsGetSourcesResult))] +[JsonSerializable(typeof(InstructionsInitPromptResult))] [JsonSerializable(typeof(InterruptMainTurnRequest))] [JsonSerializable(typeof(InterruptMainTurnResult))] [JsonSerializable(typeof(JsonSchemaResponseFormat))] @@ -53318,6 +54624,7 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(McpInstallationsRequest))] [JsonSerializable(typeof(McpIsServerRunningRequest))] [JsonSerializable(typeof(McpIsServerRunningResult))] +[JsonSerializable(typeof(McpListBuiltinServerNamesResult))] [JsonSerializable(typeof(McpListToolsRequest))] [JsonSerializable(typeof(McpListToolsResult))] [JsonSerializable(typeof(McpOauthAuthenticationStateChangedRequest))] @@ -53437,6 +54744,8 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(ModelCapabilitiesOverrideLimitsVision))] [JsonSerializable(typeof(ModelCapabilitiesOverrideSupports))] [JsonSerializable(typeof(ModelCapabilitiesSupports))] +[JsonSerializable(typeof(ModelGetReasoningSummariesRequest))] +[JsonSerializable(typeof(ModelGetReasoningSummariesResult))] [JsonSerializable(typeof(ModelList))] [JsonSerializable(typeof(ModelMessage))] [JsonSerializable(typeof(ModelPickerPersistenceRequest))] @@ -53643,6 +54952,10 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(RemoteSessionConnectionResult))] [JsonSerializable(typeof(RemoteSessionMetadataRepository))] [JsonSerializable(typeof(RemoteSessionMetadataValue))] +[JsonSerializable(typeof(RepoSettingsReadRawRequest))] +[JsonSerializable(typeof(RepoSettingsReadRawResult))] +[JsonSerializable(typeof(RepoSettingsWriteAllRequest))] +[JsonSerializable(typeof(RepoSettingsWriteKeyRequest))] [JsonSerializable(typeof(ResponseFormat))] [JsonSerializable(typeof(SandboxConfig))] [JsonSerializable(typeof(SandboxConfigAuth))] @@ -53940,6 +55253,7 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(SessionsUpdateWorkspaceFieldsRequest))] [JsonSerializable(typeof(SessionsUpdateWorkspaceFieldsResult))] [JsonSerializable(typeof(SettableAuthInfo))] +[JsonSerializable(typeof(SettingsEditResult))] [JsonSerializable(typeof(ShellCancelUserRequestedRequest))] [JsonSerializable(typeof(ShellCredentials))] [JsonSerializable(typeof(ShellExecRequest))] @@ -54062,8 +55376,28 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(UpdateSubagentSettingsRequestSubagents))] [JsonSerializable(typeof(UserRequestedShellCommandResult))] [JsonSerializable(typeof(UserSettingMetadata))] +[JsonSerializable(typeof(UserSettingsApplyTopKeyRequest))] +[JsonSerializable(typeof(UserSettingsApplyTopKeyResult))] +[JsonSerializable(typeof(UserSettingsEditRequest))] +[JsonSerializable(typeof(UserSettingsGetPathsRequest))] +[JsonSerializable(typeof(UserSettingsGetPathsResult))] [JsonSerializable(typeof(UserSettingsGetResult))] +[JsonSerializable(typeof(UserSettingsGovernanceKeysResult))] +[JsonSerializable(typeof(UserSettingsLoadForEditResult))] +[JsonSerializable(typeof(UserSettingsNormalizeRequest))] +[JsonSerializable(typeof(UserSettingsNormalizeResult))] +[JsonSerializable(typeof(UserSettingsProblem))] +[JsonSerializable(typeof(UserSettingsProblemLocation))] +[JsonSerializable(typeof(UserSettingsProblemSource))] +[JsonSerializable(typeof(UserSettingsProblemsRequest))] +[JsonSerializable(typeof(UserSettingsProblemsResult))] [JsonSerializable(typeof(UserSettingsSetRequest))] +[JsonSerializable(typeof(UserSettingsUpdateRequest))] +[JsonSerializable(typeof(UserSettingsUpdateResult))] +[JsonSerializable(typeof(UserSettingsValidateRequest))] +[JsonSerializable(typeof(UserSettingsValidateResult))] +[JsonSerializable(typeof(UserSettingsValidationIssue))] +[JsonSerializable(typeof(UserSettingsWriteAllRequest))] [JsonSerializable(typeof(VisibilityGetResult))] [JsonSerializable(typeof(VisibilitySetRequest))] [JsonSerializable(typeof(VisibilitySetResult))] diff --git a/dotnet/src/Generated/SessionEvents.cs b/dotnet/src/Generated/SessionEvents.cs index 6d7d21e0f7..190624d478 100644 --- a/dotnet/src/Generated/SessionEvents.cs +++ b/dotnet/src/Generated/SessionEvents.cs @@ -3014,7 +3014,7 @@ public sealed partial class SessionErrorData [JsonPropertyName("errorCode")] public string? ErrorCode { get; set; } - /// Category of error (e.g., "authentication", "authorization", "quota", "rate_limit", "context_limit", "query"). + /// Category of error (e.g., "authentication", "authorization", "policy", "quota", "rate_limit", "context_limit", "query"). [JsonPropertyName("errorType")] public required string ErrorType { get; set; } @@ -3027,6 +3027,16 @@ public sealed partial class SessionErrorData [JsonPropertyName("providerCallId")] public string? ProviderCallId { get; set; } + /// Sanitized provider-defined error parameter preserved from a structured upstream error envelope, when available. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("providerErrorParam")] + public string? ProviderErrorParam { get; set; } + + /// Provider-defined error type preserved from a structured upstream error envelope, when available (for example, `invalid_request_error`). + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("providerErrorType")] + public string? ProviderErrorType { get; set; } + /// What the user must do to recover, when the runtime knows of an action. The `message` never names a client affordance, so a client that offers one — a slash command, a settings pane, a link — renders it from this value. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("remediation")] @@ -4296,6 +4306,16 @@ public sealed partial class SessionPermissionRecoveryData [JsonPropertyName("onBlocked")] public required PermissionRecoveryOnBlocked OnBlocked { get; set; } + /// Subagent identifier that owns this recovery episode when the request was delegated through a parent permission service. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("ownerAgentId")] + public string? OwnerAgentId { get; set; } + + /// Root or child execution-session identifier that owns this recovery episode; omitted for legacy snapshots. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("ownerSessionId")] + public string? OwnerSessionId { get; set; } + /// Controlled reason for the latest episode transition. [JsonPropertyName("reason")] public required PermissionRecoveryReason Reason { get; set; } @@ -6626,6 +6646,16 @@ public sealed partial class PermissionRequestedData [JsonPropertyName("agentMode")] public SessionMode? AgentMode { get; set; } + /// Delegated agent that owns permission recovery when the owner session multiplexes remote agents. Absent otherwise. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("ownerAgentId")] + public string? OwnerAgentId { get; set; } + + /// Execution session that owns permission recovery for this request. Absent on historical events. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("ownerSessionId")] + public string? OwnerSessionId { get; set; } + /// Permission mode captured when evaluation began. Absent on historical events. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("permissionMode")] @@ -8805,6 +8835,11 @@ public sealed partial class CompactionCompleteCompactionTokensUsed [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("provider")] public ModelProviderRef? Provider { get; set; } + + /// Number of model requests represented by this aggregated compaction usage. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("requestCount")] + public long? RequestCount { get; set; } } /// Original request-level and effective conversation reasoning effort for a provider history boundary; the historical type name is retained for compatibility. @@ -8881,6 +8916,16 @@ public sealed partial class PermissionRecoveryData [JsonPropertyName("onBlocked")] public required PermissionRecoveryOnBlocked OnBlocked { get; set; } + /// Subagent identifier that owns this recovery episode when the request was delegated through a parent permission service. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("ownerAgentId")] + public string? OwnerAgentId { get; set; } + + /// Root or child execution-session identifier that owns this recovery episode; omitted for legacy snapshots. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("ownerSessionId")] + public string? OwnerSessionId { get; set; } + /// Controlled reason for the latest episode transition. [JsonPropertyName("reason")] public required PermissionRecoveryReason Reason { get; set; } @@ -14443,6 +14488,9 @@ public RemediationAction(string value) /// Permit outbound network access in the sandbox policy. public static RemediationAction AllowSandboxOutbound { get; } = new("allow_sandbox_outbound"); + /// Discard conversation history back through the blocked request before continuing. + public static RemediationAction RewindConversation { get; } = new("rewind_conversation"); + /// Returns a value indicating whether two instances are equivalent. public static bool operator ==(RemediationAction left, RemediationAction right) => left.Equals(right); diff --git a/dotnet/src/Types.cs b/dotnet/src/Types.cs index c836a095dc..9a70de1fc3 100644 --- a/dotnet/src/Types.cs +++ b/dotnet/src/Types.cs @@ -3131,6 +3131,12 @@ public sealed class McpHttpServerConfig : McpServerConfig ///
public sealed class CustomAgentConfig { + /// + /// Declarative hook actions keyed by event name, active only for this agent. + /// + [JsonPropertyName("hooks")] + public IDictionary>>? Hooks { get; set; } + /// /// Unique name of the custom agent. /// @@ -3700,6 +3706,8 @@ protected SessionConfigBase(SessionConfigBase? other) CanvasHandler = other.CanvasHandler; #pragma warning restore GHCP001 SkillDirectories = other.SkillDirectories is not null ? [.. other.SkillDirectories] : null; + AgentDirectories = other.AgentDirectories is not null ? [.. other.AgentDirectories] : null; + HookDirectories = other.HookDirectories is not null ? [.. other.HookDirectories] : null; PluginDirectories = other.PluginDirectories is not null ? [.. other.PluginDirectories] : null; InstructionDirectories = other.InstructionDirectories is not null ? [.. other.InstructionDirectories] : null; SessionLimits = other.SessionLimits; @@ -3804,9 +3812,9 @@ protected SessionConfigBase(SessionConfigBase? other) public bool? EnableOnDemandInstructionDiscovery { get; set; } /// - /// When , enables loading of file-based hooks from - /// .github/hooks/. This is separate from , which - /// controls SDK hook callback registration. + /// When , enables repository-origin file hooks from + /// .github/hooks/ and trusted repository-configured roots. + /// Does not control explicit or callback . /// public bool? EnableFileHooks { get; set; } @@ -4095,9 +4103,34 @@ protected SessionConfigBase(SessionConfigBase? other) /// public string? Agent { get; set; } - /// Directories to load skills from. + /// Explicit discovery-only skill roots, not general filesystem grants. + /// + /// Available without , subject to skill/managed disables. + /// Relative paths resolve once when supplied against the request's effective + /// ; retained roots do not move when it changes. + /// Null and omission are equivalent; an empty list clears only the explicit SDK contribution. + /// public IList? SkillDirectories { get; set; } + /// Explicit discovery-only agent roots, separate from . + /// + /// No general filesystem grant. Available without , + /// subject to source/managed disables. Relative paths resolve once when supplied against + /// the request's effective ; retained roots do not move. + /// Null and omission are equivalent; an empty list clears only the explicit SDK contribution. + /// + public IList? AgentDirectories { get; set; } + + /// Explicit discovery-only file-hook roots, separate from callback . + /// + /// No general filesystem grant. Available without or + /// (repository-origin hooks only), subject to hook/managed disables. + /// Relative paths resolve once when supplied against the request's effective + /// ; retained roots do not move when it changes. + /// Null and omission are equivalent; an empty list clears only the explicit SDK contribution. + /// + public IList? HookDirectories { get; set; } + /// /// Local filesystem paths to Open Plugins-format directories /// (https://open-plugins.com/) to load for this session. @@ -4109,7 +4142,13 @@ protected SessionConfigBase(SessionConfigBase? other) /// public IList? PluginDirectories { get; set; } - /// Additional directories to search for custom instruction files. + /// Explicit discovery-only instruction roots using existing SDK formats. + /// + /// No general filesystem grant. Available without , + /// subject to instruction/managed disables. Relative paths resolve once when supplied + /// against the request's effective ; retained roots do not move. + /// Null and omission are equivalent; an empty list clears only the explicit SDK contribution. + /// public IList? InstructionDirectories { get; set; } /// List of skill names to disable. @@ -4340,6 +4379,7 @@ private SessionConfig(SessionConfig? other) : base(other) if (other is null) return; SessionId = other.SessionId; + Name = other.Name; Cloud = other.Cloud; RefreshCustomInstructions = other.RefreshCustomInstructions; } @@ -4347,6 +4387,15 @@ private SessionConfig(SessionConfig? other) : base(other) /// Optional session identifier; a new ID is generated if not provided. public string? SessionId { get; set; } + /// + /// Names the session at creation, as session.name.set would, and is validated the + /// same way: non-empty, no leading or trailing whitespace, at most 100 UTF-16 units, no + /// control characters, and no double quotes. A name also makes the session persist from + /// the start, so it can be listed and resumed without ever running a turn. + /// Local sessions only: cloud creation rejects it. + /// + public string? Name { get; set; } + /// /// Creates a remote session in the cloud instead of a local session. /// The optional repository is associated with the cloud session. diff --git a/dotnet/test/E2E/ClientOptionsE2ETests.cs b/dotnet/test/E2E/ClientOptionsE2ETests.cs index d15dccc457..2c3888011d 100644 --- a/dotnet/test/E2E/ClientOptionsE2ETests.cs +++ b/dotnet/test/E2E/ClientOptionsE2ETests.cs @@ -278,6 +278,7 @@ public async Task Should_Forward_Granular_Multitenancy_Fields_In_Create_Wire_Req var session = await Ctx.CreateSessionAsync(client, new SessionConfig { + Name = "named at create", SkipEmbeddingRetrieval = false, OrganizationCustomInstructions = "Follow org policy.", EnableOnDemandInstructionDiscovery = true, @@ -291,6 +292,7 @@ public async Task Should_Forward_Granular_Multitenancy_Fields_In_Create_Wire_Req using var capture = JsonDocument.Parse(await File.ReadAllTextAsync(capturePath)); var createRequest = GetCapturedRequestParams(capture.RootElement, "session.create"); + Assert.Equal("named at create", createRequest.GetProperty("name").GetString()); Assert.False(createRequest.GetProperty("skipEmbeddingRetrieval").GetBoolean()); Assert.Equal("Follow org policy.", createRequest.GetProperty("organizationCustomInstructions").GetString()); Assert.True(createRequest.GetProperty("enableOnDemandInstructionDiscovery").GetBoolean()); @@ -537,6 +539,7 @@ public async Task Should_Apply_Empty_Mode_Defaults_To_CreateSession_Wire_Request Assert.False(createRequest.GetProperty("enableSkills").GetBoolean()); Assert.True(createRequest.GetProperty("customAgentsLocalOnly").GetBoolean()); Assert.False(createRequest.TryGetProperty("organizationCustomInstructions", out _)); + Assert.False(createRequest.TryGetProperty("name", out _)); await session.DisposeAsync(); } diff --git a/dotnet/test/E2E/PendingWorkResumeE2ETests.cs b/dotnet/test/E2E/PendingWorkResumeE2ETests.cs index b2e3a19d26..f6b539fa9d 100644 --- a/dotnet/test/E2E/PendingWorkResumeE2ETests.cs +++ b/dotnet/test/E2E/PendingWorkResumeE2ETests.cs @@ -55,7 +55,7 @@ await session1.SendAsync(new MessageOptions var permissionEvent = await permissionRequested; Assert.IsType(initialRequest); - await suspendedClient.ForceStopAsync(); + await ForceStopAfterSessionLockObservedAsync(suspendedClient, sessionId); await using var resumedTcpClient = Ctx.CreateClient(options: new CopilotClientOptions { Connection = RuntimeConnection.ForUri(cliUrl, connectionToken: SharedToken) }); var session2 = await Ctx.ResumeSessionAsync(resumedTcpClient, sessionId, new ResumeSessionConfig @@ -70,6 +70,8 @@ await session1.SendAsync(new MessageOptions "resume_permission_tool") ], }); + var resumeEvent = await GetSingleResumeEventAsync(session2); + Assert.False(resumeEvent.Data.SessionWasActive); var permissionResult = await session2.Rpc.Permissions.HandlePendingPermissionRequestAsync( permissionEvent.Data.RequestId, @@ -172,6 +174,34 @@ public Task Should_Keep_Pending_External_Tool_Handleable_On_Cold_Resume_When_Con expectedSessionWasActive: false, expectedHandleResult: false); + private async Task ForceStopAfterSessionLockObservedAsync(CopilotClient suspendedClient, string sessionId) + { + await using var lockObserver = Ctx.CreateClient(options: new CopilotClientOptions + { + Connection = RuntimeConnection.ForStdio(), + }); + await lockObserver.StartAsync(); + await TestHelper.WaitForConditionAsync( + async () => + { + var result = await lockObserver.Rpc.Sessions.CheckInUseAsync([sessionId]); + return result.InUse.Contains(sessionId); + }, + timeout: PendingWorkTimeout, + timeoutMessage: $"Timed out waiting for session '{sessionId}' to acquire its lock."); + + await suspendedClient.ForceStopAsync(); + + await TestHelper.WaitForConditionAsync( + async () => + { + var result = await lockObserver.Rpc.Sessions.CheckInUseAsync([sessionId]); + return !result.InUse.Contains(sessionId); + }, + timeout: PendingWorkTimeout, + timeoutMessage: $"Timed out waiting for session '{sessionId}' to release its lock."); + } + private async Task AssertPendingExternalToolHandleableOnResumeAsync( bool disconnectOriginalClient, bool expectedSessionWasActive, @@ -213,30 +243,7 @@ await session1.SendAsync(new MessageOptions if (disconnectOriginalClient) { - await using var lockObserver = Ctx.CreateClient(options: new CopilotClientOptions - { - Connection = RuntimeConnection.ForStdio(), - }); - await lockObserver.StartAsync(); - await TestHelper.WaitForConditionAsync( - async () => - { - var result = await lockObserver.Rpc.Sessions.CheckInUseAsync([sessionId]); - return result.InUse.Contains(sessionId); - }, - timeout: PendingWorkTimeout, - timeoutMessage: $"Timed out waiting for session '{sessionId}' to acquire its lock."); - - await suspendedClient.ForceStopAsync(); - - await TestHelper.WaitForConditionAsync( - async () => - { - var result = await lockObserver.Rpc.Sessions.CheckInUseAsync([sessionId]); - return !result.InUse.Contains(sessionId); - }, - timeout: PendingWorkTimeout, - timeoutMessage: $"Timed out waiting for session '{sessionId}' to release its lock."); + await ForceStopAfterSessionLockObservedAsync(suspendedClient, sessionId); } await using var resumedClient = Ctx.CreateClient(options: new CopilotClientOptions { Connection = RuntimeConnection.ForUri(cliUrl, connectionToken: SharedToken) }); diff --git a/dotnet/test/E2E/PermissionE2ETests.cs b/dotnet/test/E2E/PermissionE2ETests.cs index 78e792c2c2..77b0e588ff 100644 --- a/dotnet/test/E2E/PermissionE2ETests.cs +++ b/dotnet/test/E2E/PermissionE2ETests.cs @@ -5,6 +5,7 @@ using GitHub.Copilot.Rpc; using GitHub.Copilot.Test.Harness; using Microsoft.Extensions.AI; +using Microsoft.Extensions.Logging; using System.Text.Json; using System.Text.Json.Serialization; using Xunit; @@ -173,23 +174,64 @@ internal static async Task AssertApproveAllPermissionHandlerAsync(CopilotSession [Fact] public async Task Should_Handle_Async_Permission_Handler() { + await Ctx.ConfigureForTestAsync("permissions", "Should_Handle_Async_Permission_Handler_Dotnet"); + + const string toolName = "async_permission_echo"; + const string expectedResult = "DOTNET_ASYNC_PERMISSION_RESULT"; var permissionRequestReceived = false; - var session = await CreateSessionAsync(new SessionConfig + var toolCalls = 0; + string? permissionToolCallId = null; + CopilotSession? session = null; + session = await CreateSessionAsync(new SessionConfig { + Tools = + [ + AIFunctionFactory.Create( + Echo, + toolName, + "Returns the result for the asynchronous permission test.", + serializerOptions: PermissionJsonContext.Default.Options), + ], + AvailableTools = [toolName], OnPermissionRequest = async (request, invocation) => { - permissionRequestReceived = true; + var customToolRequest = Assert.IsType(request); + Assert.Equal(toolName, customToolRequest.ToolName); + Assert.Equal(session!.SessionId, invocation.SessionId); + Assert.False(string.IsNullOrWhiteSpace(customToolRequest.ToolCallId)); + permissionToolCallId = customToolRequest.ToolCallId; await Task.Yield(); + permissionRequestReceived = true; return PermissionDecision.ApproveOnce(); } }); - await TestHelper.SendAndGetFinalAssistantMessageAsync(session, new MessageOptions + ToolExecutionCompleteEvent? toolCompleted = null; + using var subscription = session.On(evt => + { + if (evt.Data.ToolCallId == permissionToolCallId) + { + toolCompleted = evt; + } + }); + var message = await TestHelper.SendAndGetFinalAssistantMessageAsync(session, new MessageOptions { - Prompt = "Run 'echo test' and tell me what happens" + Prompt = "Call async_permission_echo once and reply with only its returned text." }); Assert.True(permissionRequestReceived, "Permission request should have been received"); + Assert.Equal(1, toolCalls); + Assert.NotNull(toolCompleted); + Assert.True(toolCompleted.Data.Success); + Assert.Equal(expectedResult, toolCompleted.Data.Result?.Content); + Assert.Contains(expectedResult, message.Data.Content); + + string Echo() + { + Assert.True(permissionRequestReceived, "The yielding permission handler must finish before the tool runs."); + Interlocked.Increment(ref toolCalls); + return expectedResult; + } } [Fact] @@ -330,6 +372,7 @@ public async Task Should_Receive_ToolCallId_In_Permission_Requests() [Fact] public async Task Should_Wait_For_Slow_Permission_Handler() + => await WithSdkDiagnosticsAsync(async () => { var handlerEntered = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var releaseHandler = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -388,7 +431,21 @@ void AddLifecycleEvent(string phase, string? toolCallId) releaseHandler.SetResult(); - var message = await sendTask; + AssistantMessageEvent? message; + try + { + message = await sendTask; + } + catch (TimeoutException) + { + lock (lifecycleLock) + { + Logger.LogWarning( + "Slow-permission timeout lifecycle: {Lifecycle}", + string.Join(", ", lifecycle.Select(evt => $"{evt.Phase}:{evt.ToolCallId}"))); + } + throw; + } var persistedEvents = await WaitForPersistedEventsAsync( session, events => @@ -424,7 +481,7 @@ void AddLifecycleEvent(string phase, string? toolCallId) // The tool should have actually run after permission was granted Assert.Contains("slow_handler_test", message?.Data.Content ?? string.Empty); - } + }); [Fact] public async Task Should_Handle_Concurrent_Permission_Requests_From_Parallel_Tools() diff --git a/dotnet/test/E2E/SessionE2ETests.cs b/dotnet/test/E2E/SessionE2ETests.cs index 377bb0147d..c3b9e7bdd9 100644 --- a/dotnet/test/E2E/SessionE2ETests.cs +++ b/dotnet/test/E2E/SessionE2ETests.cs @@ -478,14 +478,20 @@ public async Task Should_Receive_Session_Events() public async Task Send_Returns_Immediately_While_Events_Stream_In_Background() => await WithSdkDiagnosticsAsync(async () => { - var session = await CreateSessionAsync(new SessionConfig + // Reuse a custom-tool capture instead of depending on a native shell completing within its wait. + await Ctx.ConfigureForTestAsync( + "pending_work_resume", "should_continue_pending_external_tool_request_after_resume", replayOnly: true); + var toolStarted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var releaseTool = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + await using var session = await CreateSessionAsync(new SessionConfig { + Tools = [AIFunctionFactory.Create(BlockingTool, "resume_external_tool")], OnPermissionRequest = PermissionHandler.ApproveAll, }); var events = new ConcurrentQueue(); AssistantMessageEvent? message = null; - session.On(evt => + using var subscription = session.On(evt => { events.Enqueue(evt.Type); if (evt is AssistantMessageEvent assistantMessage) @@ -495,18 +501,35 @@ public async Task Send_Returns_Immediately_While_Events_Stream_In_Background() }); var idle = TestHelper.GetNextEventOfTypeAsync(session); - // Use a slow command so we can verify SendAsync() returns before completion - await session.SendAsync(new MessageOptions { Prompt = "Run 'sleep 2 && echo done'" }); - - // SendAsync() should return before turn completes (no session.idle yet) - Assert.DoesNotContain("session.idle", events); - - // Wait for turn to complete - await idle; + try + { + var send = session.SendAsync(new MessageOptions + { + Prompt = "Use resume_external_tool with value 'beta', then reply with the result.", + }); + Assert.Equal("beta", await toolStarted.Task.WaitAsync(TimeSpan.FromSeconds(60))); + await send.WaitAsync(TimeSpan.FromSeconds(60)); + Assert.DoesNotContain("session.idle", events); + Assert.False(idle.IsCompleted); + + releaseTool.TrySetResult("EXTERNAL_RESUMED_BETA"); + await idle; + + Assert.Contains("EXTERNAL_RESUMED_BETA", message?.Data.Content ?? string.Empty); + Assert.Contains("session.idle", events); + Assert.Contains("assistant.message", events); + } + finally + { + releaseTool.TrySetResult("EXTERNAL_RESUMED_BETA"); + } - Assert.Contains("done", message?.Data.Content ?? string.Empty); - Assert.Contains("session.idle", events); - Assert.Contains("assistant.message", events); + [Description("Blocks until the test releases the active turn")] + async Task BlockingTool([Description("Value to return")] string value, CancellationToken cancellationToken) + { + toolStarted.TrySetResult(value); + return await releaseTool.Task.WaitAsync(Timeout.InfiniteTimeSpan, cancellationToken); + } }); [Fact] diff --git a/dotnet/test/Harness/E2ETestBase.cs b/dotnet/test/Harness/E2ETestBase.cs index 679fbb9c6b..008bbc8074 100644 --- a/dotnet/test/Harness/E2ETestBase.cs +++ b/dotnet/test/Harness/E2ETestBase.cs @@ -39,7 +39,7 @@ protected E2ETestBase( // Wire logger into the shared context so all clients created via Ctx.CreateClient get it. Ctx.Logger = Logger; - Ctx.DiagnosticsEnabled = snapshotCategory is "pending_work_resume" or "session"; + Ctx.DiagnosticsEnabled = snapshotCategory is "pending_work_resume" or "session" or "permissions"; } /// Logger that forwards warnings and above to xunit test output. diff --git a/dotnet/test/Harness/E2ETestContext.cs b/dotnet/test/Harness/E2ETestContext.cs index a5b76fbcd2..f35fe7a659 100644 --- a/dotnet/test/Harness/E2ETestContext.cs +++ b/dotnet/test/Harness/E2ETestContext.cs @@ -85,7 +85,7 @@ await proxy.ConfigureAsync( await proxy.SetCopilotUserByTokenAsync(DefaultGitHubToken, new CopilotUserConfig( Login: "e2e-test-user", CopilotPlan: "individual_pro", - Endpoints: new CopilotUserEndpoints(Api: context.ProxyUrl, Telemetry: "https://localhost:1/telemetry"), + Endpoints: new CopilotUserEndpoints(Api: context.ProxyUrl, Telemetry: context.ProxyUrl), AnalyticsTrackingId: "e2e-test-tracking-id", Id: 12345)); return context; diff --git a/dotnet/test/Unit/ClientSessionLifetimeTests.CustomizationDirectories.cs b/dotnet/test/Unit/ClientSessionLifetimeTests.CustomizationDirectories.cs new file mode 100644 index 0000000000..7e7aee511f --- /dev/null +++ b/dotnet/test/Unit/ClientSessionLifetimeTests.CustomizationDirectories.cs @@ -0,0 +1,157 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. + +#if NET8_0_OR_GREATER +using GitHub.Copilot.Rpc; +using Xunit; + +namespace GitHub.Copilot.Test.Unit; + +public sealed partial class ClientSessionLifetimeTests +{ + [Fact] + public async Task CustomizationDirectories_Preserve_Positional_Discovery_Calls() + { + await using var server = await FakeCopilotServer.StartAsync(); + server.ResponseFactory = _ => new Dictionary + { + ["agents"] = Array.Empty(), + ["hooks"] = Array.Empty(), + ["sources"] = Array.Empty(), + ["paths"] = Array.Empty() + }; + await using var client = new CopilotClient(new CopilotClientOptions + { + Connection = RuntimeConnection.ForUri(server.Url) + }); + IList projects = ["project-root"]; + await client.StartAsync(); + await client.Rpc.Agents.DiscoverAsync(projects, true, CancellationToken.None); + await client.Rpc.Agents.GetDiscoveryPathsAsync(projects, true, CancellationToken.None); + await client.Rpc.Hooks.DiscoverAsync(projects, true, CancellationToken.None); + await client.Rpc.Instructions.DiscoverAsync(projects, true, CancellationToken.None); + await client.Rpc.Instructions.GetDiscoveryPathsAsync(projects, true, CancellationToken.None); + await client.Rpc.Skills.GetDiscoveryPathsAsync(projects, ["ignored"], true, CancellationToken.None); + foreach (var method in new[] + { + "agents.discover", "agents.getDiscoveryPaths", "hooks.discover", + "instructions.discover", "instructions.getDiscoveryPaths", "skills.getDiscoveryPaths" + }) + { + var payload = Assert.Single(server.Requests, request => request.Method == method).Params; + Assert.Equal("project-root", Assert.Single(payload.GetProperty("projectPaths").EnumerateArray()).GetString()); + foreach (var key in new[] { "agentDirectories", "hookDirectories", "instructionDirectories", "skillDirectories" }) + { + Assert.False(payload.TryGetProperty(key, out _)); + } + } + await client.Rpc.Agents.DiscoverAsync(new AgentsDiscoverRequest + { + AgentDirectories = ["explicit-agent-root"] + }); + var explicitPayload = server.Requests.Last(request => request.Method == "agents.discover").Params; + Assert.Equal("explicit-agent-root", Assert.Single(explicitPayload.GetProperty("agentDirectories").EnumerateArray()).GetString()); + Assert.False(explicitPayload.TryGetProperty("projectPaths", out _)); + } + + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(2)] + public async Task CustomizationDirectories_Are_Preserved_On_Create_And_Resume(int kind) + { + IList? roots = kind switch + { + 0 => null, + 1 => [], + _ => ["relative-root", "other-root"] + }; + var directories = new Dictionary?> + { + ["skillDirectories"] = roots?.Select(root => root + "-skills").ToList(), + ["agentDirectories"] = roots?.Select(root => root + "-agents").ToList(), + ["instructionDirectories"] = roots?.Select(root => root + "-instructions").ToList(), + ["hookDirectories"] = roots?.Select(root => root + "-hooks").ToList() + }; + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions + { + Connection = RuntimeConnection.ForUri(server.Url) + }); + await using var created = await client.CreateSessionAsync(new SessionConfig + { + WorkingDirectory = "request-cwd", + EnableConfigDiscovery = false, + EnableFileHooks = false, + SkillDirectories = directories["skillDirectories"], + AgentDirectories = directories["agentDirectories"], + InstructionDirectories = directories["instructionDirectories"], + HookDirectories = directories["hookDirectories"] + }); + await using var resumed = await client.ResumeSessionAsync("resumed", new ResumeSessionConfig + { + WorkingDirectory = "resume-cwd", + EnableConfigDiscovery = false, + EnableFileHooks = false, + SkillDirectories = directories["skillDirectories"], + AgentDirectories = directories["agentDirectories"], + InstructionDirectories = directories["instructionDirectories"], + HookDirectories = directories["hookDirectories"] + }); + foreach (var method in new[] { "session.create", "session.resume" }) + { + var payload = Assert.Single(server.Requests, request => request.Method == method).Params; + foreach (var entry in directories) + { + if (entry.Value is null) + { + Assert.False(payload.TryGetProperty(entry.Key, out _)); + } + else + { + Assert.Equal(entry.Value, payload.GetProperty(entry.Key).EnumerateArray().Select(item => item.GetString())); + } + } + Assert.False(payload.GetProperty("enableConfigDiscovery").GetBoolean()); + Assert.False(payload.GetProperty("enableFileHooks").GetBoolean()); + Assert.False(payload.TryGetProperty("additionalDirectories", out _)); + Assert.False(payload.TryGetProperty("customAgents", out _)); + Assert.False(payload.TryGetProperty("hooks", out _)); + } + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void CustomizationDirectories_Clone_Owns_Its_Lists(bool resume) + { + SessionConfigBase original; + SessionConfigBase clone; + if (resume) + { + var config = new ResumeSessionConfig + { + AgentDirectories = ["agents"], + HookDirectories = ["hooks"] + }; + original = config; + clone = config.Clone(); + } + else + { + var config = new SessionConfig + { + AgentDirectories = ["agents"], + HookDirectories = ["hooks"] + }; + original = config; + clone = config.Clone(); + } + clone.AgentDirectories!.Add("clone-agents"); + clone.HookDirectories!.Add("clone-hooks"); + Assert.Equal("agents", Assert.Single(original.AgentDirectories!)); + Assert.Equal("hooks", Assert.Single(original.HookDirectories!)); + Assert.Collection(clone.AgentDirectories, item => Assert.Equal("agents", item), item => Assert.Equal("clone-agents", item)); + Assert.Collection(clone.HookDirectories, item => Assert.Equal("hooks", item), item => Assert.Equal("clone-hooks", item)); + } +} +#endif diff --git a/dotnet/test/Unit/E2ETestFixtureTests.cs b/dotnet/test/Unit/E2ETestFixtureTests.cs index 933b82c1fc..afbb87fd6f 100644 --- a/dotnet/test/Unit/E2ETestFixtureTests.cs +++ b/dotnet/test/Unit/E2ETestFixtureTests.cs @@ -4,7 +4,11 @@ using System.ComponentModel; using System.Diagnostics; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; using System.Reflection; +using System.Text.Json; using GitHub.Copilot.Test.E2E; using GitHub.Copilot.Test.Harness; using Xunit; @@ -13,6 +17,25 @@ namespace GitHub.Copilot.Test.Unit; public class E2ETestFixtureTests { + [Fact] + public async Task Default_Telemetry_Endpoint_Uses_The_Owned_Proxy() + { + await using var context = await E2ETestContext.CreateAsync(); + using var client = new HttpClient(); + using var userRequest = new HttpRequestMessage(HttpMethod.Get, context.ProxyUrl + "/copilot_internal/user"); + userRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.GetEnvironment()["GH_TOKEN"]); + using var userResponse = await client.SendAsync(userRequest); + Assert.Equal(HttpStatusCode.OK, userResponse.StatusCode); + using var user = JsonDocument.Parse(await userResponse.Content.ReadAsStringAsync()); + var telemetryEndpoint = user.RootElement.GetProperty("endpoints").GetProperty("telemetry").GetString(); + Assert.Equal(context.ProxyUrl, telemetryEndpoint); + using var content = new StringContent("{}\n"); + using var telemetryResponse = await client.PostAsync(telemetryEndpoint + "/telemetry", content); + Assert.Equal(HttpStatusCode.NoContent, telemetryResponse.StatusCode); + Assert.Equal(string.Empty, await telemetryResponse.Content.ReadAsStringAsync()); + Assert.Empty(await context.GetExchangesAsync()); + } + [Fact] public async Task Failed_Process_Launch_Reclaims_Context_Directories() { diff --git a/dotnet/test/Unit/RuntimeWrapperTests.cs b/dotnet/test/Unit/RuntimeWrapperTests.cs index e7c77ab92d..47bcba2ab6 100644 --- a/dotnet/test/Unit/RuntimeWrapperTests.cs +++ b/dotnet/test/Unit/RuntimeWrapperTests.cs @@ -93,7 +93,8 @@ public async Task Marked_Bundled_Explicit_Cli_Does_Not_Require_Runtime_Pair() var nativeDirectory = Path.Combine(baseDirectory, "runtimes", rid, "native"); Directory.CreateDirectory(nativeDirectory); var cliPath = Path.Combine(nativeDirectory, OperatingSystem.IsWindows() ? "copilot.exe" : "copilot"); - await File.WriteAllTextAsync(cliPath, "not an executable"); + // Nonempty invalid images can stall Windows process creation before it reports the launch error. + await File.WriteAllTextAsync(cliPath, string.Empty); await File.WriteAllTextAsync(Path.Combine(nativeDirectory, ".copilot-explicit-cli"), "explicit"); try diff --git a/go/client.go b/go/client.go index bc41bc4c44..2d77f82956 100644 --- a/go/client.go +++ b/go/client.go @@ -975,6 +975,8 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses req.DefaultAgent = config.DefaultAgent req.Agent = config.Agent req.SkillDirectories = config.SkillDirectories + req.AgentDirectories = config.AgentDirectories + req.HookDirectories = config.HookDirectories req.PluginDirectories = config.PluginDirectories req.InstructionDirectories = config.InstructionDirectories req.DisabledSkills = config.DisabledSkills @@ -1079,6 +1081,7 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses localSessionID = uuid.NewString() } req.SessionID = localSessionID + req.Name = config.Name // unregisterSession removes only the session created by this call and stops // its event consumer. The latter is essential on CreateSession error paths: @@ -1456,6 +1459,8 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string, req.DefaultAgent = config.DefaultAgent req.Agent = config.Agent req.SkillDirectories = config.SkillDirectories + req.AgentDirectories = config.AgentDirectories + req.HookDirectories = config.HookDirectories req.PluginDirectories = config.PluginDirectories req.InstructionDirectories = config.InstructionDirectories req.DisabledSkills = config.DisabledSkills diff --git a/go/client_test.go b/go/client_test.go index 2283385b33..289a8e4735 100644 --- a/go/client_test.go +++ b/go/client_test.go @@ -2312,6 +2312,38 @@ func TestCreateSessionRequest_ClientName(t *testing.T) { }) } +func TestCreateSessionRequest_Name(t *testing.T) { + t.Run("includes name in JSON when set", func(t *testing.T) { + req := createSessionRequest{Name: "named at create"} + data, err := json.Marshal(req) + if err != nil { + t.Fatalf("Failed to marshal: %v", err) + } + var m map[string]any + if err := json.Unmarshal(data, &m); err != nil { + t.Fatalf("Failed to unmarshal: %v", err) + } + if m["name"] != "named at create" { + t.Errorf("Expected name to be 'named at create', got %v", m["name"]) + } + }) + + t.Run("omits name from JSON when empty", func(t *testing.T) { + req := createSessionRequest{} + data, err := json.Marshal(req) + if err != nil { + t.Fatalf("Failed to marshal: %v", err) + } + var m map[string]any + if err := json.Unmarshal(data, &m); err != nil { + t.Fatalf("Failed to unmarshal: %v", err) + } + if _, ok := m["name"]; ok { + t.Error("Expected name to be omitted when empty") + } + }) +} + func TestResumeSessionRequest_ClientName(t *testing.T) { t.Run("includes clientName in JSON when set", func(t *testing.T) { req := resumeSessionRequest{SessionID: "s1", ClientName: "my-app"} diff --git a/go/customization_directories_test.go b/go/customization_directories_test.go new file mode 100644 index 0000000000..7e7a638868 --- /dev/null +++ b/go/customization_directories_test.go @@ -0,0 +1,116 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. + +package copilot + +import ( + "encoding/json" + "reflect" + "testing" + + "github.com/github/copilot-sdk/go/internal/jsonrpc2" + "github.com/github/copilot-sdk/go/rpc" +) + +func TestClient_CustomizationDirectoryAdapters(t *testing.T) { + for _, tt := range []struct { + name string + roots []string + }{ + {"omitted", nil}, + {"empty", []string{}}, + {"relative", []string{"relative-root", "other-root"}}, + } { + t.Run(tt.name, func(t *testing.T) { + directories := make(map[string][]string) + for key, suffix := range map[string]string{ + "skillDirectories": "skills", + "agentDirectories": "agents", + "instructionDirectories": "instructions", + "hookDirectories": "hooks", + } { + if tt.roots != nil { + directories[key] = make([]string, 0, len(tt.roots)) + for _, root := range tt.roots { + directories[key] = append(directories[key], root+"-"+suffix) + } + } + } + rpcClient, server, _ := newRuntimeShutdownRpcPair(t) + t.Cleanup(server.Stop) + t.Cleanup(rpcClient.Stop) + client := &Client{ + client: rpcClient, + RPC: rpc.NewServerRPC(rpcClient), + sessions: make(map[string]*Session), + } + requests := make(chan json.RawMessage, 2) + for _, method := range []string{"session.create", "session.resume"} { + server.SetRequestHandler(method, func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + requests <- append(json.RawMessage(nil), params...) + id := sessionIDFromParams(t, params) + response, err := json.Marshal(map[string]string{"sessionId": id}) + if err != nil { + return nil, &jsonrpc2.Error{Code: -32603, Message: err.Error()} + } + return response, nil + }) + } + _, err := client.CreateSession(t.Context(), &SessionConfig{ + WorkingDirectory: "request-cwd", + EnableConfigDiscovery: Bool(false), + EnableFileHooks: Bool(false), + SkillDirectories: directories["skillDirectories"], + AgentDirectories: directories["agentDirectories"], + InstructionDirectories: directories["instructionDirectories"], + HookDirectories: directories["hookDirectories"], + }) + if err != nil { + t.Fatal(err) + } + _, err = client.ResumeSessionWithOptions(t.Context(), "resumed", &ResumeSessionConfig{ + WorkingDirectory: "resume-cwd", + EnableConfigDiscovery: Bool(false), + EnableFileHooks: Bool(false), + SkillDirectories: directories["skillDirectories"], + AgentDirectories: directories["agentDirectories"], + InstructionDirectories: directories["instructionDirectories"], + HookDirectories: directories["hookDirectories"], + }) + if err != nil { + t.Fatal(err) + } + for range 2 { + var payload map[string]json.RawMessage + if err := json.Unmarshal(<-requests, &payload); err != nil { + t.Fatal(err) + } + for _, key := range []string{"skillDirectories", "agentDirectories", "instructionDirectories", "hookDirectories"} { + value, present := payload[key] + if tt.roots == nil { + if present { + t.Errorf("unexpected %s: %s", key, value) + } + } else { + var actual []string + if err := json.Unmarshal(value, &actual); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(actual, directories[key]) { + t.Errorf("%s = %#v, want %#v", key, actual, directories[key]) + } + } + } + for _, key := range []string{"enableConfigDiscovery", "enableFileHooks"} { + if string(payload[key]) != "false" { + t.Errorf("%s = %s, want false", key, payload[key]) + } + } + for _, key := range []string{"additionalDirectories", "customAgents", "hooks"} { + if _, present := payload[key]; present { + t.Errorf("unexpected %s in %s", key, payload[key]) + } + } + } + }) + } +} diff --git a/go/internal/e2e/client_options_e2e_test.go b/go/internal/e2e/client_options_e2e_test.go index 739f1a58da..49294ca052 100644 --- a/go/internal/e2e/client_options_e2e_test.go +++ b/go/internal/e2e/client_options_e2e_test.go @@ -412,6 +412,7 @@ func TestClientOptionsE2E(t *testing.T) { extensionSDKPath := filepath.Join(ctx.WorkDir, "extension-sdk") session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{ SessionID: sessionID, + Name: "go named at create", ClientName: "go-sdk-e2e-client", Model: "claude-sonnet-5", ReasoningEffort: "low", @@ -471,6 +472,7 @@ func TestClientOptionsE2E(t *testing.T) { } expectedValues := map[string]any{ "sessionId": sessionID, + "name": "go named at create", "clientName": "go-sdk-e2e-client", "model": "claude-sonnet-5", "reasoningEffort": "low", diff --git a/go/internal/jsonrpc2/jsonrpc2.go b/go/internal/jsonrpc2/jsonrpc2.go index d4898b6a9c..14566f7bea 100644 --- a/go/internal/jsonrpc2/jsonrpc2.go +++ b/go/internal/jsonrpc2/jsonrpc2.go @@ -329,11 +329,11 @@ func (c *Client) RequestWithInlineResponse(ctx context.Context, method string, p return response.Result, nil case <-c.processDone: if err := c.getProcessError(); err != nil { - return nil, err + return responseAfterShutdown(responseChan, err) } - return nil, fmt.Errorf("process exited unexpectedly") + return responseAfterShutdown(responseChan, fmt.Errorf("process exited unexpectedly")) case <-c.stopChan: - return nil, fmt.Errorf("client stopped") + return responseAfterShutdown(responseChan, fmt.Errorf("client stopped")) } } select { @@ -345,9 +345,22 @@ func (c *Client) RequestWithInlineResponse(ctx context.Context, method string, p } return response.Result, nil case <-c.connectionClosed: - return nil, fmt.Errorf("connection closed") + return responseAfterShutdown(responseChan, fmt.Errorf("connection closed")) case <-c.stopChan: - return nil, fmt.Errorf("client stopped") + return responseAfterShutdown(responseChan, fmt.Errorf("client stopped")) + } +} + +func responseAfterShutdown(responseChan <-chan *Response, shutdownErr error) (json.RawMessage, error) { + // Shutdown can win the outer select after the read loop has already admitted a reply. + select { + case response := <-responseChan: + if response.Error != nil { + return nil, response.Error + } + return response.Result, nil + default: + return nil, shutdownErr } } diff --git a/go/internal/jsonrpc2/jsonrpc2_test.go b/go/internal/jsonrpc2/jsonrpc2_test.go index 258992e101..0c42f185aa 100644 --- a/go/internal/jsonrpc2/jsonrpc2_test.go +++ b/go/internal/jsonrpc2/jsonrpc2_test.go @@ -3,7 +3,9 @@ package jsonrpc2 import ( "bytes" "context" + "encoding/json" "errors" + "fmt" "io" "sync" "testing" @@ -16,6 +18,10 @@ type writeCloser struct { func (w writeCloser) Close() error { return nil } +type writeFunc func([]byte) (int, error) + +func (w writeFunc) Write(data []byte) (int, error) { return w(data) } + func TestOnCloseCalledOnUnexpectedExit(t *testing.T) { stdinR, stdinW := io.Pipe() stdoutR, stdoutW := io.Pipe() @@ -110,6 +116,135 @@ func TestRequestReturnsWhenConnectionCloses(t *testing.T) { } } +func TestRequestUnacknowledgedShutdown(t *testing.T) { + for _, shutdown := range []string{"stop", "connection closed", "process exited", "process error"} { + t.Run(shutdown, func(t *testing.T) { + stdinR, stdinW := io.Pipe() + defer stdinR.Close() + defer stdinW.Close() + client := NewClient(stdinW, io.NopCloser(bytes.NewReader(nil))) + done := make(chan struct{}) + var processErr error + if shutdown == "process error" { + processErr = errors.New("CLI process exited: exit status 1") + } + if shutdown == "process exited" || shutdown == "process error" { + client.SetProcessDone(done, &processErr) + } + ctx, cancel := context.WithCancel(t.Context()) + finished := make(chan struct{}) + t.Cleanup(func() { + cancel() + stdinR.Close() + select { + case <-finished: + case <-time.After(time.Second): + t.Error("request did not finish during cleanup") + } + }) + result := make(chan error, 1) + go func() { + defer close(finished) + _, err := client.Request(ctx, "test.method", nil) + result <- err + }() + if _, err := newHeaderReader(stdinR).Read(); err != nil { + t.Fatalf("Read request failed: %v", err) + } + var expected string + switch shutdown { + case "stop": + close(client.stopChan) + expected = "client stopped" + case "connection closed": + close(client.connectionClosed) + expected = "connection closed" + case "process exited": + close(done) + expected = "process exited unexpectedly" + case "process error": + close(done) + expected = processErr.Error() + } + select { + case err := <-result: + if err == nil || err.Error() != expected { + t.Fatalf("unacknowledged request error = %v, want %s", err, expected) + } + case <-time.After(time.Second): + t.Fatal("unacknowledged request did not stop") + } + client.mu.Lock() + pending, callbacks := len(client.pendingRequests), len(client.pendingInlineCallbacks) + client.mu.Unlock() + if pending != 0 || callbacks != 0 { + t.Fatalf("request cleanup left %d pending requests and %d callbacks", pending, callbacks) + } + }) + } +} + +func TestRequestAdmittedResponseSurvivesShutdown(t *testing.T) { + for _, shutdown := range []string{"stop", "connection closed", "process exited", "process error"} { + t.Run(shutdown, func(t *testing.T) { + for _, rpcError := range []bool{false, true} { + for iteration := range 32 { + t.Run(fmt.Sprintf("RPC_error=%t/%d", rpcError, iteration), func(t *testing.T) { + expected := json.RawMessage(`{"messageId":"acknowledged-message"}`) + var expectedErr *Error + if rpcError { + expectedErr = &Error{Code: -32001, Message: "acknowledged failure", Data: json.RawMessage(`{"detail":"original"}`)} + } + done := make(chan struct{}) + var client *Client + writer := writeFunc(func(data []byte) (int, error) { + if bytes.HasPrefix(data, []byte("Content-Length:")) { + return len(data), nil + } + var request Request + if err := json.Unmarshal(data, &request); err != nil { + return 0, err + } + // Both outcomes are ready before Request reaches its response select. + client.handleResponse(&Response{ID: request.ID, Result: expected, Error: expectedErr}) + switch shutdown { + case "stop": + close(client.stopChan) + case "connection closed": + close(client.connectionClosed) + default: + close(done) + } + return len(data), nil + }) + client = NewClient(writeCloser{Writer: writer}, io.NopCloser(bytes.NewReader(nil))) + if shutdown == "process exited" || shutdown == "process error" { + var processErr error + if shutdown == "process error" { + processErr = errors.New("CLI process exited: exit status 1") + } + client.SetProcessDone(done, &processErr) + } + + result, err := client.Request(t.Context(), "test.method", nil) + + if expectedErr != nil { + if result != nil || err != expectedErr { + t.Fatalf("admitted error = (%s, %v), want original RPC error %v", result, err, expectedErr) + } + } else if err != nil || !bytes.Equal(result, expected) { + t.Fatalf("admitted response = (%s, %v), want (%s, nil)", result, err, expected) + } + if len(client.pendingRequests) != 0 || len(client.pendingInlineCallbacks) != 0 { + t.Fatal("completed request retained its pending response or callback") + } + }) + } + } + }) + } +} + // TestSetProcessDone_ErrorAvailableImmediately validates that getProcessError() // returns the correct error immediately after processDone is closed. // The current implementation stores a pointer to the process error diff --git a/go/rpc/repo_settings_test.go b/go/rpc/repo_settings_test.go new file mode 100644 index 0000000000..529daa40ff --- /dev/null +++ b/go/rpc/repo_settings_test.go @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. + +package rpc_test + +import ( + "encoding/json" + "fmt" + "reflect" + "testing" + + "github.com/github/copilot-sdk/go/rpc" +) + +func ExampleRepoSettingsReadRawResult() { + const input = `{"config":{"custom":{"items":[true,null,12.5]}},"invalid":false}` + var result rpc.RepoSettingsReadRawResult + if err := json.Unmarshal([]byte(input), &result); err != nil { + panic(err) + } + output, err := json.Marshal(result) + if err != nil { + panic(err) + } + fmt.Println(string(output)) + // Output: {"config":{"custom":{"items":[true,null,12.5]}},"invalid":false} +} + +func TestRawRepoSettingsPreserveUnknownJSON(t *testing.T) { + for _, input := range []string{ + `{"config":{"custom":{"items":[true,null,12.5],"text":"preserved"}},"invalid":false}`, + `{"config":{},"invalid":true}`, + } { + t.Run(input, func(t *testing.T) { + var decoded rpc.RepoSettingsReadRawResult + if err := json.Unmarshal([]byte(input), &decoded); err != nil { + t.Fatal(err) + } + output, err := json.Marshal(decoded) + if err != nil { + t.Fatal(err) + } + var expected, actual any + if err := json.Unmarshal([]byte(input), &expected); err != nil { + t.Fatal(err) + } + if err := json.Unmarshal(output, &actual); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("repository settings changed:\nactual: %s\nexpected: %s", output, input) + } + }) + } +} diff --git a/go/rpc/settings_presence_test.go b/go/rpc/settings_presence_test.go new file mode 100644 index 0000000000..86c562e194 --- /dev/null +++ b/go/rpc/settings_presence_test.go @@ -0,0 +1,107 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. + +package rpc + +import ( + "context" + "encoding/json" + "net" + "testing" + "time" + + "github.com/github/copilot-sdk/go/internal/jsonrpc2" +) + +func TestSettingsValuePresenceOnWire(t *testing.T) { + for _, method := range []string{"user.settings.applyTopKey", "repo.settings.writeKey", "user.settings.edit"} { + for _, test := range []struct { + name string + value any + present bool + delete bool + }{ + {name: "omitted"}, + {name: "explicit null", value: json.RawMessage("null"), present: true}, + {name: "value", value: "chosen", present: true}, + {name: "delete", delete: true}, + } { + t.Run(method+"/"+test.name, func(t *testing.T) { + clientConn, serverConn := net.Pipe() + defer clientConn.Close() + defer serverConn.Close() + client := jsonrpc2.NewClient(clientConn, clientConn) + server := jsonrpc2.NewClient(serverConn, serverConn) + requests := make(chan json.RawMessage, 1) + server.SetRequestHandler(method, func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) { + requests <- params + return json.RawMessage(`{}`), nil + }) + client.Start() + server.Start() + defer client.Stop() + defer server.Stop() + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + api := NewInternalServerRPC(client) + var err error + switch method { + case "user.settings.applyTopKey": + var value *any + if test.present { + value = &test.value + } + _, err = api.User.Settings().ApplyTopKey(ctx, &UserSettingsApplyTopKeyRequest{ + CanonicalPath: []string{"model"}, + TopKey: "model", + Value: value, + Delete: &test.delete, + }) + case "repo.settings.writeKey": + _, err = api.Repo.Settings().WriteKey(ctx, &RepoSettingsWriteKeyRequest{ + RepoRoot: t.TempDir(), + Scope: "repo", + Key: "model", + Value: test.value, + Delete: &test.delete, + }) + case "user.settings.edit": + operation := SettingsEditOperationSet + if test.delete { + operation = SettingsEditOperationRemove + } + _, err = api.User.Settings().Edit(ctx, &UserSettingsEditRequest{ + CanonicalPath: []string{"model"}, + Operation: operation, + Value: test.value, + }) + } + if err != nil { + t.Fatal(err) + } + select { + case raw := <-requests: + var fields map[string]json.RawMessage + if err := json.Unmarshal(raw, &fields); err != nil { + t.Fatal(err) + } + value, present := fields["value"] + wantPresent := test.present || (method == "user.settings.edit" && !test.delete) + if present != wantPresent { + t.Fatalf("value presence = %v, want %v; wire params: %s", present, wantPresent, raw) + } + if present { + expected, err := json.Marshal(test.value) + if err != nil { + t.Fatal(err) + } + if string(value) != string(expected) { + t.Fatalf("value = %s, want %s; wire params: %s", value, expected, raw) + } + } + case <-ctx.Done(): + t.Fatal(ctx.Err()) + } + }) + } + } +} diff --git a/go/rpc/zrpc.go b/go/rpc/zrpc.go index fd534106e1..fb0ba50714 100644 --- a/go/rpc/zrpc.go +++ b/go/rpc/zrpc.go @@ -39,6 +39,28 @@ type AccountAllUsers struct { Token *string `json:"token,omitempty"` } +// The authentication identity whose shared wording should be rendered. +// Experimental: AccountDescribeAuthInfoRequest is part of an experimental API and may +// change or be removed. +// Internal: AccountDescribeAuthInfoRequest is an internal SDK API and is not part of the +// public surface. +type AccountDescribeAuthInfoRequest struct { + // Identity to describe. + Identity AuthIdentity `json:"identity"` +} + +// The wording the runtime uses for an authentication identity. +// Experimental: AccountDescribeAuthInfoResult is part of an experimental API and may change +// or be removed. +// Internal: AccountDescribeAuthInfoResult is an internal SDK API and is not part of the +// public surface. +type AccountDescribeAuthInfoResult struct { + // One-line description of the identity, suitable after a verb such as "Switched to". + Description string `json:"description"` + // Sign-in banner announcing the authenticated user. + Message string `json:"message"` +} + // List of all authenticated users // Experimental: AccountGetAllUsersResult is part of an experimental API and may change or // be removed. @@ -54,6 +76,30 @@ type AccountGetCurrentAuthResult struct { AuthInfo AuthInfo `json:"authInfo,omitempty"` } +// The authentication identity whose gist support should be reported. +// Experimental: AccountGetGistSupportRequest is part of an experimental API and may change +// or be removed. +// Internal: AccountGetGistSupportRequest is an internal SDK API and is not part of the +// public surface. +type AccountGetGistSupportRequest struct { + // Identity to evaluate. + Identity AuthIdentity `json:"identity"` +} + +// Whether the identity can create gists, and why not when it cannot. +// Experimental: AccountGetGistSupportResult is part of an experimental API and may change +// or be removed. +// Internal: AccountGetGistSupportResult is an internal SDK API and is not part of the +// public surface. +type AccountGetGistSupportResult struct { + // Machine-readable reason category when unsupported. + Kind *string `json:"kind,omitempty"` + // Human-readable explanation to show where the gist action would have been. + Reason *string `json:"reason,omitempty"` + // True when the identity can create gists. + Supported bool `json:"supported"` +} + // Experimental: AccountGetQuotaRequest is part of an experimental API and may change or be // removed. type AccountGetQuotaRequest struct { @@ -73,6 +119,40 @@ type AccountGetQuotaResult struct { QuotaSnapshots map[string]AccountQuotaSnapshot `json:"quotaSnapshots"` } +// The environment variable supplying a classic personal access token, when one is set. +// Experimental: AccountGetTokenEnvVarResult is part of an experimental API and may change +// or be removed. +// Internal: AccountGetTokenEnvVarResult is an internal SDK API and is not part of the +// public surface. +type AccountGetTokenEnvVarResult struct { + // Variable name, for example `GH_TOKEN`. Absent when no classic token is present in the + // environment. + Name *string `json:"name,omitempty"` +} + +// A path to resolve against the GitHub host an identity is signed in to. +// Experimental: AccountGetWebURLRequest is part of an experimental API and may change or be +// removed. +// Internal: AccountGetWebURLRequest is an internal SDK API and is not part of the public +// surface. +type AccountGetWebURLRequest struct { + // Identity whose host the path resolves against. Omit to resolve against the public + // github.com host. + Identity *AuthIdentity `json:"identity,omitempty"` + // Host-relative path, without a leading slash, for example `settings/copilot/features`. + Path string `json:"path"` +} + +// An absolute URL on the identity's GitHub host. +// Experimental: AccountGetWebURLResult is part of an experimental API and may change or be +// removed. +// Internal: AccountGetWebURLResult is an internal SDK API and is not part of the public +// surface. +type AccountGetWebURLResult struct { + // Absolute URL for the requested path. + URL string `json:"url"` +} + // Credentials to validate and store. Omit login to resolve the authenticated user from the // token. // Experimental: AccountLoginRequest is part of an experimental API and may change or be @@ -226,6 +306,8 @@ type AgentInfo struct { DisableModelInvocation *bool `json:"disableModelInvocation,omitempty"` // Human-readable display name DisplayName string `json:"displayName"` + // Declarative hook actions keyed by event name, executed only while this agent is active. + Hooks map[string][]any `json:"hooks,omitzero"` // Stable identifier for selection. For most agents this is the same as `name`; for // plugin/builtin agents it may differ. Always populated; defaults to `name` when no // distinct id was assigned. @@ -506,6 +588,11 @@ type AgentsCustomAgentInitialModelDecisionResult struct { // Experimental: AgentsDiscoverRequest is part of an experimental API and may change or be // removed. type AgentsDiscoverRequest struct { + // Explicit discovery-only agent roots, separate from customAgents and filesystem grants. + // Available without ambient discovery, subject to managed/source disables. Relative paths + // resolve against the request's effective working directory when supplied. Null and + // omission are equivalent; an empty array contributes no explicit roots. + AgentDirectories []string `json:"agentDirectories,omitzero"` // When true, omit the host's agents (the user-level agent directory and all plugin agents), // leaving only project and remote agents. For multitenant deployments. ExcludeHostAgents *bool `json:"excludeHostAgents,omitempty"` @@ -639,6 +726,11 @@ type AgentsGetBuiltinsResult struct { // Experimental: AgentsGetDiscoveryPathsRequest is part of an experimental API and may // change or be removed. type AgentsGetDiscoveryPathsRequest struct { + // Explicit discovery-only agent roots to enumerate, including configured missing + // directories. Relative paths resolve against the request's effective working directory + // when supplied. These are not filesystem grants or preferred creation targets. Null and + // omission are equivalent. + AgentDirectories []string `json:"agentDirectories,omitzero"` // When true, omit the host's user-level agent directory, leaving only project directories. // For multitenant deployments (mirrors `discover`'s `excludeHostAgents`). ExcludeHostAgents *bool `json:"excludeHostAgents,omitempty"` @@ -4954,6 +5046,82 @@ type ExternalToolTextResultForLlmContentResourceLinkIcon struct { Theme *ExternalToolTextResultForLlmContentResourceLinkIconTheme `json:"theme,omitempty"` } +// The declared shape of one feature flag, independent of any caller population. +// Experimental: FeatureFlagMetadata is part of an experimental API and may change or be +// removed. +// Internal: FeatureFlagMetadata is an internal SDK API and is not part of the public +// surface. +type FeatureFlagMetadata struct { + // The population the flag is declared for before any environment or user-settings override + // is applied. + // Internal: Availability is part of the SDK's internal API surface and is not intended for + // external use. + Availability FeatureFlagAvailability `json:"availability"` + // Whether the flag participates in the CAPI sanity suite. + CapiSanity bool `json:"capiSanity"` + // Text shown to a user choosing whether to turn the flag on in experimental mode. Absent + // when the flag is not user-facing. + ExperimentalDescription *string `json:"experimentalDescription,omitempty"` + // The online-experiment (ExP) flag this maps to, when the flag is assigned by an experiment + // rather than declared statically. + ExpFlag *string `json:"expFlag,omitempty"` + // Environment variable that overrides this flag's experiment assignment locally in the + // experiment service, not in `featureFlags.resolve`. Present exactly when `expFlag` is, and + // derived from it, so a caller reads a local override without reproducing the naming rule. + ExpFlagEnvVar *string `json:"expFlagEnvVar,omitempty"` + // The flag's name, matching the key it is listed under. + Name string `json:"name"` +} + +// Every feature flag this runtime declares, with the shape each one was declared with. +// Experimental: FeatureFlagsMetadataResult is part of an experimental API and may change or +// be removed. +// Internal: FeatureFlagsMetadataResult is an internal SDK API and is not part of the public +// surface. +type FeatureFlagsMetadataResult struct { + // Declared feature flags keyed by flag name. + // Internal: Flags is part of the SDK's internal API surface and is not intended for + // external use. + Flags map[string]FeatureFlagMetadata `json:"flags"` +} + +// Caller population and overrides for static feature-flag resolution, independent of +// experiment assignments and active runtime state. +// Experimental: FeatureFlagsResolveRequest is part of an experimental API and may change or +// be removed. +// Internal: FeatureFlagsResolveRequest is an internal SDK API and is not part of the public +// surface. +type FeatureFlagsResolveRequest struct { + // Resolve against this already-computed flag set rather than each flag's declared + // availability. Keyed by flag name. + BaseFlags map[string]bool `json:"baseFlags,omitzero"` + // User settings to apply, including `enabledFeatureFlags`, legacy `feature_flags.enabled`, + // and supported convenience settings. + Config any `json:"config,omitempty"` + // Environment for direct feature-flag overrides and `COPILOT_CLI_ENABLED_FEATURE_FLAGS`. + // Does not apply `COPILOT_EXP_*` experiment assignments. Defaults to this runtime process's + // own environment. + Environment map[string]string `json:"environment,omitzero"` + // Flags forced to a value after every other layer, keyed by flag name. + FlagOverrides map[string]bool `json:"flagOverrides,omitzero"` + // Whether the caller is in an experimental population. + IsExperimental bool `json:"isExperimental"` + // Whether the caller is GitHub or Microsoft staff. + IsStaff bool `json:"isStaff"` + // GitHub-staff membership. Omit when it was never recorded: a legacy staff account then + // counts as both staff populations and keeps every staff feature. + IsStaffGitHub *bool `json:"isStaffGithub,omitempty"` + // Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. + IsStaffMicrosoft *bool `json:"isStaffMicrosoft,omitempty"` + // Whether the caller belongs to the team population used by feature availability. + IsTeam bool `json:"isTeam"` +} + +// The resolved feature flags, keyed by flag name. +// Experimental: FeatureFlagsResolveResult is part of an experimental API and may change or +// be removed. +type FeatureFlagsResolveResult map[string]bool + // Content filtering mode to apply to all tools, or a map of tool name to content filtering // mode. // Experimental: FilterMapping is part of an experimental API and may change or be removed. @@ -5145,6 +5313,8 @@ type GitHubOwnersListResult struct { // listing only. Long-abandoned unused ids can be released by later allocations. // Experimental: GitHubOwnersRequestIDResult is part of an experimental API and may change // or be removed. +// Internal: GitHubOwnersRequestIDResult is an internal SDK API and is not part of the +// public surface. type GitHubOwnersRequestIDResult struct { // Request id to pass to `gitHubOwners.list` and, to abandon it, `gitHubOwners.cancel`. RequestID int64 `json:"requestId"` @@ -5770,6 +5940,12 @@ type HooksDiscoverRequest struct { // still contribute to each remaining row's effective enabled state. This filters sources // rather than simulating a host with no settings. ExcludeHostHooks *bool `json:"excludeHostHooks,omitempty"` + // Explicit discovery-only file-hook roots, separate from callback hooks and filesystem + // grants. Available without ambient discovery or repository file-hook enablement, subject + // to managed/hook disables. Relative paths resolve against the request's effective working + // directory when supplied. Null and omission are equivalent; an empty array contributes no + // explicit roots. + HookDirectories []string `json:"hookDirectories,omitzero"` // Optional project directory paths whose trusted repository and project-expanded plugin // hooks should be discovered. When omitted or empty, user, managed-policy, and globally // enabled installed or explicit plugin hooks are returned without project expansion. @@ -6413,6 +6589,37 @@ type InstructionDiscoveryPathList struct { Paths []InstructionDiscoveryPath `json:"paths"` } +// Experimental: InstructionsClearCacheResult is part of an experimental API and may change +// or be removed. +type InstructionsClearCacheResult struct { +} + +// Explicit discovery arguments for one location, supplied by the caller rather than derived +// from a session. +// Experimental: InstructionsDiscoverRepoSourcesRequest is part of an experimental API and +// may change or be removed. +// Internal: InstructionsDiscoverRepoSourcesRequest is an internal SDK API and is not part +// of the public surface. +type InstructionsDiscoverRepoSourcesRequest struct { + // Extra directories to scan alongside instruction directories configured in the runtime + // environment. + AdditionalDirs []string `json:"additionalDirs,omitzero"` + // Copilot configuration directory for user-level sources. An omitted or empty value uses + // the server's configuration home. + ConfigDir *string `json:"configDir,omitempty"` + // Working directory whose instruction sources should also be included. Omission adds no + // separate working-directory scope. + CwdPath *string `json:"cwdPath,omitempty"` + // When true, also discover instruction files nested below the location. + EnableChildInstructions *bool `json:"enableChildInstructions,omitempty"` + // When true, include the sources a command-line host reads. Hosts that are not the CLI omit + // it. + IsCLI *bool `json:"isCli,omitempty"` + // Repository location to discover. An empty string selects no repository scope; cwdPath can + // still supply working-directory sources. + Location string `json:"location"` +} + // Optional project paths to include in instruction discovery. // Experimental: InstructionsDiscoverRequest is part of an experimental API and may change // or be removed. @@ -6420,6 +6627,11 @@ type InstructionsDiscoverRequest struct { // When true, omit the host's instruction sources (user/home-level files and plugin rules), // leaving only repository and working-directory sources. For multitenant deployments. ExcludeHostInstructions *bool `json:"excludeHostInstructions,omitempty"` + // Explicit discovery-only instruction roots using existing SDK instruction formats, not + // filesystem grants. Available without ambient discovery, subject to instruction/managed + // disables. Relative paths resolve against the request's effective working directory when + // supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + InstructionDirectories []string `json:"instructionDirectories,omitzero"` // Optional list of project directory paths to scan for repository/working-directory // instruction sources. When omitted or empty, only user-level and plugin instruction // sources are returned (no project scan). @@ -6433,6 +6645,11 @@ type InstructionsGetDiscoveryPathsRequest struct { // When true, omit the host's user-level instruction targets, leaving only repository // targets. For multitenant deployments (mirrors `discover`'s `excludeHostInstructions`). ExcludeHostInstructions *bool `json:"excludeHostInstructions,omitempty"` + // Explicit discovery-only instruction roots to enumerate, including configured missing + // directories. Relative paths resolve against the request's effective working directory + // when supplied. These are not filesystem grants or preferred creation targets. Null and + // omission are equivalent. + InstructionDirectories []string `json:"instructionDirectories,omitzero"` // Optional list of project directory paths. When omitted or empty, only the user-level // targets are returned. ProjectPaths []string `json:"projectPaths,omitzero"` @@ -6446,6 +6663,16 @@ type InstructionsGetSourcesResult struct { Sources []InstructionSource `json:"sources"` } +// The prompt the init command runs. +// Experimental: InstructionsInitPromptResult is part of an experimental API and may change +// or be removed. +// Internal: InstructionsInitPromptResult is an internal SDK API and is not part of the +// public surface. +type InstructionsInitPromptResult struct { + // Prompt text authoring repository instructions. + Prompt string `json:"prompt"` +} + // Loaded instruction source for a session, including path, content, category, location, // applicability, and optional description. // Experimental: InstructionSource is part of an experimental API and may change or be @@ -7579,6 +7806,8 @@ type MCPConfiguredServerState struct { // Credential-free authentication identity used to configure GitHub MCP. // Experimental: MCPConfigureGitHubRequest is part of an experimental API and may change or // be removed. +// Internal: MCPConfigureGitHubRequest is an internal SDK API and is not part of the public +// surface. type MCPConfigureGitHubRequest struct { // Opaque runtime auth info for GitHub MCP configuration. Marked internal: an in-process // runtime shape (configureGitHubMcp is a no-op over the wire). @@ -8387,6 +8616,17 @@ type MCPIsServerRunningResult struct { Running bool `json:"running"` } +// Names of the MCP servers the runtime supplies itself. +// Experimental: MCPListBuiltinServerNamesResult is part of an experimental API and may +// change or be removed. +// Internal: MCPListBuiltinServerNamesResult is an internal SDK API and is not part of the +// public surface. +type MCPListBuiltinServerNamesResult struct { + // Every built-in server name. A host disabling the built-ins wholesale suppresses exactly + // this set. + Names []string `json:"names"` +} + // Server name whose tool list should be returned. // Experimental: MCPListToolsRequest is part of an experimental API and may change or be // removed. @@ -9299,6 +9539,8 @@ type MCPPromptsListResult struct { // Registration parameters for an external MCP client. // Experimental: MCPRegisterExternalClientRequest is part of an experimental API and may // change or be removed. +// Internal: MCPRegisterExternalClientRequest is an internal SDK API and is not part of the +// public surface. type MCPRegisterExternalClientRequest struct { // In-process MCP Client instance. Marked internal: cannot be serialized across the JSON-RPC // boundary. @@ -9322,6 +9564,8 @@ type MCPRegisterExternalClientRequest struct { // Registry search to abandon. // Experimental: MCPRegistryCancelRequest is part of an experimental API and may change or // be removed. +// Internal: MCPRegistryCancelRequest is an internal SDK API and is not part of the public +// surface. type MCPRegistryCancelRequest struct { // Request ID from `mcp.registry.allocateRequestId` that the search uses. RequestID int64 `json:"requestId"` @@ -9330,6 +9574,8 @@ type MCPRegistryCancelRequest struct { // Whether the cancel reached a live search. // Experimental: MCPRegistryCancelResult is part of an experimental API and may change or be // removed. +// Internal: MCPRegistryCancelResult is an internal SDK API and is not part of the public +// surface. type MCPRegistryCancelResult struct { // True when the cancel stopped a running search. False for unknown or reclaimed IDs, // completed or canceled searches, and unused reservations. The cancel releases an unused @@ -9340,6 +9586,8 @@ type MCPRegistryCancelResult struct { // Request id naming a cancellable registry search. // Experimental: MCPRegistryRequestIDResult is part of an experimental API and may change or // be removed. +// Internal: MCPRegistryRequestIDResult is an internal SDK API and is not part of the public +// surface. type MCPRegistryRequestIDResult struct { // Request ID for `mcp.registry.search` and `mcp.registry.cancel`. It serves one search. // Allocation can reclaim unused IDs at the 1,024-ID reservation limit. @@ -9350,6 +9598,8 @@ type MCPRegistryRequestIDResult struct { // search cancellable. // Experimental: MCPRegistrySearchRequest is part of an experimental API and may change or // be removed. +// Internal: MCPRegistrySearchRequest is an internal SDK API and is not part of the public +// surface. type MCPRegistrySearchRequest struct { // The credential the search runs under, carried opaquely. Hosts usually send // credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a @@ -9373,6 +9623,8 @@ type MCPRegistrySearchRequest struct { // Servers selected from the registry response. // Experimental: MCPRegistrySearchResult is part of an experimental API and may change or be // removed. +// Internal: MCPRegistrySearchResult is an internal SDK API and is not part of the public +// surface. type MCPRegistrySearchResult struct { // The server objects, carried opaquely. The runtime follows pages, keeps the newest entry // per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub @@ -9382,6 +9634,7 @@ type MCPRegistrySearchResult struct { // In-process MCP reload configuration. // Experimental: MCPReloadConfig is part of an experimental API and may change or be removed. +// Internal: MCPReloadConfig is an internal SDK API and is not part of the public surface. type MCPReloadConfig struct { ActiveGitHubToken *string `json:"activeGitHubToken,omitempty"` // Server names the CLI enabled for this session via `--enable-mcp-server`. @@ -9402,6 +9655,8 @@ type MCPReloadConfig struct { // Opaque MCP reload configuration. // Experimental: MCPReloadWithConfigRequest is part of an experimental API and may change or // be removed. +// Internal: MCPReloadWithConfigRequest is an internal SDK API and is not part of the public +// surface. type MCPReloadWithConfigRequest struct { // Opaque runtime MCP reload configuration. Marked internal: an in-process runtime shape // (reloadMcpServers throws over the wire). @@ -9907,6 +10162,8 @@ func (MCPServerConfigHTTP) mcpServerConfig() {} // In-process MCP server configuration used by embedded SDK clients. // Experimental: MCPServerConfigMemory is part of an experimental API and may change or be // removed. +// Internal: MCPServerConfigMemory is an internal SDK API and is not part of the public +// surface. type MCPServerConfigMemory struct { // Configuration warnings recorded while loading the server. ConfigWarnings []string `json:"configWarnings,omitzero"` @@ -10031,6 +10288,8 @@ type MCPSetEnvValueModeResult struct { // with. // Experimental: MCPShouldExcludeGitHubToolsRequest is part of an experimental API and may // change or be removed. +// Internal: MCPShouldExcludeGitHubToolsRequest is an internal SDK API and is not part of +// the public surface. type MCPShouldExcludeGitHubToolsRequest struct { // The session's tool allowlist, when it set one. Omitted means the session constrains // nothing this way. @@ -10048,6 +10307,8 @@ type MCPShouldExcludeGitHubToolsRequest struct { // the request. // Experimental: MCPShouldExcludeGitHubToolsResult is part of an experimental API and may // change or be removed. +// Internal: MCPShouldExcludeGitHubToolsResult is an internal SDK API and is not part of the +// public surface. type MCPShouldExcludeGitHubToolsResult struct { // True only when both halves hold: the session's filters still reach the platform shell // tool, and the host actually has the `gh` those tools would be replaced by. Feed it @@ -10181,6 +10442,8 @@ type MCPUninstallPlan struct { // Server name identifying the external client to remove. // Experimental: MCPUnregisterExternalClientRequest is part of an experimental API and may // change or be removed. +// Internal: MCPUnregisterExternalClientRequest is an internal SDK API and is not part of +// the public surface. type MCPUnregisterExternalClientRequest struct { // Server name of the external client to unregister ServerName string `json:"serverName"` @@ -10721,6 +10984,68 @@ type ModelClearStartupSeedResult struct { Cleared bool `json:"cleared"` } +// Host presentation state the reasoning-summaries policy depends on. +// Experimental: ModelGetReasoningSummariesRequest is part of an experimental API and may +// change or be removed. +type ModelGetReasoningSummariesRequest struct { + // The host's persisted `showReasoning` user setting, omitted when unset. + PersistedShowReasoning *bool `json:"persistedShowReasoning,omitempty"` + // Whether the host is currently showing reasoning summaries. Defaults to false. + SummariesVisible *bool `json:"summariesVisible,omitempty"` +} + +// Reasoning-summaries presentation policy for the session's current model. +// Experimental: ModelGetReasoningSummariesResult is part of an experimental API and may +// change or be removed. +type ModelGetReasoningSummariesResult struct { + // Whether the supplied `persistedShowReasoning` setting only restates the model default. + // This reports a redundancy, not a standing instruction to delete the setting: it stays + // true for as long as the setting and the model default agree, including for a user who + // later chose that value deliberately. It exists for a one-time migration of a legacy + // setting written before the model default made it redundant, so a host that acts on it + // owns the cleanup and must gate it behind its own persisted `done` marker, delete only a + // setting whose value still matches the one it read, and never repeat the deletion on a + // later launch. Under an off-by-default reasoning-summaries experiment an explicit + // `showReasoning: true` opt-in also reads as redundant on a summary-producing model, so an + // ungated host would keep deleting that opt-in and hide summaries again on every launch. + ClearRedundantSetting bool `json:"clearRedundantSetting"` + // Whether the session's reasoning-summaries experiment assignment has settled. False means + // this read does not wait for a pending assignment and reports the experiment-derived + // fields conservatively: `showHiddenHint` is false and `visibility` falls back to + // `persistedShowReasoning`, or is omitted when none was supplied. A host that wants the + // assigned answer re-reads until this is true. + ExperimentSettled bool `json:"experimentSettled"` + // Whether the selected model shows reasoning summaries by default. + ModelDefaultShowsSummaries bool `json:"modelDefaultShowsSummaries"` + // False until the session has a model catalog and a selected model. This read never + // resolves the catalog itself, and the runtime emits no readiness notification, so + // repeating this call alone leaves `ready` false indefinitely on a session that has neither + // listed models nor run a turn. `session.model.list` is the prerequisite and the signal: it + // resolves and caches the catalog for the session, so a successful return means the next + // read is ready. The exception is a session that resolves models without a Copilot catalog, + // that is a BYOK registry or an alternate provider: `session.model.list` returns an empty + // list without caching a catalog, so `ready` stays false and this policy is unavailable + // there. While false, every model-policy field is false and `visibility` is omitted; + // `experimentSettled` is independent of readiness and still reports the assignment state. + Ready bool `json:"ready"` + // Whether turns on this session produce reasoning summaries, honouring an explicit session + // reasoning-summary override. + SessionShowsSummaries bool `json:"sessionShowsSummaries"` + // Whether to show the hint that reasoning summaries are hidden. Always false while + // `experimentSettled` is false. + ShowHiddenHint bool `json:"showHiddenHint"` + // Whether the selected model emits reasoning headers. + ShowReasoningHeaders bool `json:"showReasoningHeaders"` + // Default reasoning visibility, and only meaningful once `ready` is true: false when the + // session produces no summaries, else the persisted setting, else the experiment's default. + // While `ready` is true it is omitted only when all three are unavailable, that is when the + // session produces summaries, no `persistedShowReasoning` was supplied, and + // `experimentSettled` is false. While `ready` is false there is no model policy to report + // and this field is always omitted, so an absent value alone does not imply a pending + // experiment. + Visibility *bool `json:"visibility,omitempty"` +} + // List of Copilot models available to the resolved user, including capabilities and billing // metadata. // Experimental: ModelList is part of an experimental API and may change or be removed. @@ -12322,6 +12647,12 @@ type PermissionRecoveryData struct { // Policy selected from the current client's response capability; mode or client changes may // update it during recovery OnBlocked PermissionRecoveryOnBlocked `json:"onBlocked"` + // Subagent identifier that owns this recovery episode when the request was delegated + // through a parent permission service + OwnerAgentID *string `json:"ownerAgentId,omitempty"` + // Root or child execution-session identifier that owns this recovery episode; omitted for + // legacy snapshots + OwnerSessionID *string `json:"ownerSessionId,omitempty"` // Controlled reason for the latest episode transition Reason PermissionRecoveryReason `json:"reason"` // Current lifecycle state of the recovery episode @@ -14658,6 +14989,76 @@ type RemoteSessionRepository struct { Owner string `json:"owner"` } +// Which repository settings file to read. +// Experimental: RepoSettingsReadRawRequest is part of an experimental API and may change or +// be removed. +// Internal: RepoSettingsReadRawRequest is an internal SDK API and is not part of the public +// surface. +type RepoSettingsReadRawRequest struct { + // Absolute path of the repository root. + RepoRoot string `json:"repoRoot"` + // Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + Scope string `json:"scope"` +} + +// Parsed repository settings without normalization or layering. +// Experimental: RepoSettingsReadRawResult is part of an experimental API and may change or +// be removed. +// Internal: RepoSettingsReadRawResult is an internal SDK API and is not part of the public +// surface. +type RepoSettingsReadRawResult struct { + // Stored JSON values after the existing JSONC parser and prototype-safety checks. Empty + // when the file is missing, blank, or invalid. + Config any `json:"config"` + // True when the file exists but did not parse, so `config` is empty for that reason rather + // than because nothing is set. + Invalid bool `json:"invalid"` +} + +// The complete set of repository-overridable settings to store. +// Experimental: RepoSettingsWriteAllRequest is part of an experimental API and may change +// or be removed. +// Internal: RepoSettingsWriteAllRequest is an internal SDK API and is not part of the +// public surface. +type RepoSettingsWriteAllRequest struct { + // Absolute path of the repository root. + RepoRoot string `json:"repoRoot"` + // Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + Scope string `json:"scope"` + // Object of allowed settings to store. Missing allowlisted keys are removed. Other input + // keys are ignored, while unknown stored keys are preserved. + Settings any `json:"settings"` +} + +// Experimental: RepoSettingsWriteAllResult is part of an experimental API and may change or +// be removed. +type RepoSettingsWriteAllResult struct { +} + +// One key to write or remove in a repository settings file. +// Experimental: RepoSettingsWriteKeyRequest is part of an experimental API and may change +// or be removed. +// Internal: RepoSettingsWriteKeyRequest is an internal SDK API and is not part of the +// public surface. +type RepoSettingsWriteKeyRequest struct { + // True to remove the key instead of writing it. + Delete *bool `json:"delete,omitempty"` + // Canonical top-level key permitted by the repository settings allowlist. + Key string `json:"key"` + // Absolute path of the repository root. + RepoRoot string `json:"repoRoot"` + // Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + Scope string `json:"scope"` + // Value to validate and write. Required unless delete is true; a null value is validated, + // not treated as deletion. + Value any `json:"value,omitempty"` +} + +// Experimental: RepoSettingsWriteKeyResult is part of an experimental API and may change or +// be removed. +type RepoSettingsWriteKeyResult struct { +} + // Experimental: ResponseFormat is part of an experimental API and may change or be removed. type ResponseFormat struct { // JSON Schema and provider options for the turn's output. @@ -16765,6 +17166,12 @@ type SessionOpenOptions struct { AdditionalDirectories []string `json:"additionalDirectories,omitzero"` // Runtime context discriminator for agent filtering. AgentContext *string `json:"agentContext,omitempty"` + // Explicit discovery-only agent roots, separate from customAgents and filesystem grants. + // Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK + // paths resolve once when supplied against the request's effective workingDirectory; + // retained roots do not move on cwd changes. Null and omission are equivalent; [] clears + // only the explicit SDK contribution. + AgentDirectories []string `json:"agentDirectories,omitzero"` // Whether to include instructions from every MCP server in the system prompt instead of // only allowlisted servers. AllowAllMCPServerInstructions *bool `json:"allowAllMcpServerInstructions,omitempty"` @@ -16842,8 +17249,8 @@ type SessionOpenOptions struct { EnableOnDemandInstructionDiscovery *bool `json:"enableOnDemandInstructionDiscovery,omitempty"` // Whether shell-script safety heuristics are enabled. EnableScriptSafety *bool `json:"enableScriptSafety,omitempty"` - // Whether skill loading is enabled. When omitted, an SDK skill provider enables skills by - // default. + // Whether skill loading is enabled. When omitted, explicit SDK skill roots or an SDK skill + // provider enable skills independently of enableConfigDiscovery. EnableSkills *bool `json:"enableSkills,omitempty"` // Whether model responses stream as delta events. EnableStreaming *bool `json:"enableStreaming,omitempty"` @@ -16882,6 +17289,13 @@ type SessionOpenOptions struct { // Internal: HasSkillProvider is part of the SDK's internal API surface and is not intended // for external use. HasSkillProvider *bool `json:"hasSkillProvider,omitempty"` + // Explicit discovery-only file-hook roots, separate from callback hooks and filesystem + // grants. Available without enableConfigDiscovery or enableFileHooks, which controls + // repository-origin hooks only; hook/managed disables still apply. Relative SDK paths + // resolve once when supplied against the request's effective workingDirectory; retained + // roots do not move on cwd changes. Null and omission are equivalent; [] clears only the + // explicit SDK contribution. + HookDirectories []string `json:"hookDirectories,omitzero"` // Skill scan directories and descendants excluded from discovery. Supports `~`-relative // paths. IgnoredSkillsLocations []string `json:"ignoredSkillsLocations,omitzero"` @@ -16895,6 +17309,12 @@ type SessionOpenOptions struct { IncludedBuiltinSkills []string `json:"includedBuiltinSkills,omitzero"` // Installed plugins visible to the session. InstalledPlugins []InstalledPlugin `json:"installedPlugins,omitzero"` + // Explicit discovery-only instruction roots using existing SDK instruction formats, not + // filesystem grants. Available without enableConfigDiscovery, subject to + // instruction/managed disables. Relative SDK paths resolve once when supplied against the + // request's effective workingDirectory; retained roots do not move on cwd changes. Null and + // omission are equivalent; [] clears only the explicit SDK contribution. + InstructionDirectories []string `json:"instructionDirectories,omitzero"` // Stable integration identifier for analytics. IntegrationID *string `json:"integrationId,omitempty"` // Whether experimental behavior is enabled. @@ -16972,7 +17392,11 @@ type SessionOpenOptions struct { ShellInitProfile *string `json:"shellInitProfile,omitempty"` // PowerShell process flags applied to built-in and user-requested shell commands. ShellProcessFlags []string `json:"shellProcessFlags,omitzero"` - // Additional directories to search for skills. + // Explicit discovery-only skill roots, not filesystem grants. Available without + // enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once + // when supplied against the request's effective workingDirectory; retained roots do not + // move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK + // contribution. SkillDirectories []string `json:"skillDirectories,omitzero"` // Whether to skip custom instruction sources. SkipCustomInstructions *bool `json:"skipCustomInstructions,omitempty"` @@ -18322,6 +18746,12 @@ type SessionUpdateOptionsParams struct { AdditionalContentExclusionPolicies []OptionsUpdateAdditionalContentExclusionPolicy `json:"additionalContentExclusionPolicies,omitzero"` // Runtime context discriminator (e.g., `cli`, `actions`). AgentContext *string `json:"agentContext,omitempty"` + // Explicit discovery-only agent roots, separate from customAgents and filesystem grants. + // Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK + // paths resolve once when supplied against the request's effective workingDirectory; + // retained roots do not move on cwd changes. Null and omission are equivalent; [] clears + // only the explicit SDK contribution. + AgentDirectories []string `json:"agentDirectories,omitzero"` // Whether to include instructions from every MCP server in the system prompt instead of // only allowlisted servers. AllowAllMCPServerInstructions *bool `json:"allowAllMcpServerInstructions,omitempty"` @@ -18349,8 +18779,9 @@ type SessionUpdateOptionsParams struct { DisabledInstructionSources []string `json:"disabledInstructionSources,omitzero"` // Skill IDs that should be excluded from this session. DisabledSkills []string `json:"disabledSkills,omitzero"` - // Whether to enable loading of `.github/hooks/` filesystem hooks. Separate from the SDK - // callback hook mechanism. + // Whether to enable repository-origin file hooks from `.github/hooks/` and trusted + // repository-configured roots. Does not control explicit hookDirectories or SDK callback + // hooks. EnableFileHooks *bool `json:"enableFileHooks,omitempty"` // Whether to enable host git operations (context resolution, child repo scanning, git info // in system prompt). @@ -18365,9 +18796,10 @@ type SessionUpdateOptionsParams struct { EnableScriptSafety *bool `json:"enableScriptSafety,omitempty"` // Whether to enable cross-session store writes and reads. EnableSessionStore *bool `json:"enableSessionStore,omitempty"` - // Whether skill loading is enabled. Explicit false disables every source, including a bound - // SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, - // creation falls back to enableConfigDiscovery unless an SDK skill provider is registered. + // Whether skill loading is enabled. Explicit false disables every source, including + // explicit SDK roots and a bound SDK provider; changing the value invalidates the loaded + // skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless + // explicit SDK skill roots or an SDK skill provider are supplied. EnableSkills *bool `json:"enableSkills,omitempty"` // Whether to stream model responses. EnableStreaming *bool `json:"enableStreaming,omitempty"` @@ -18387,6 +18819,13 @@ type SessionUpdateOptionsParams struct { ExcludedTools []string `json:"excludedTools,omitzero"` // Map of feature-flag IDs to their boolean enabled state. FeatureFlags map[string]bool `json:"featureFlags,omitzero"` + // Explicit discovery-only file-hook roots, separate from callback hooks and filesystem + // grants. Available without enableConfigDiscovery or enableFileHooks, which controls + // repository-origin hooks only; hook/managed disables still apply. Relative SDK paths + // resolve once when supplied against the request's effective workingDirectory; retained + // roots do not move on cwd changes. Null and omission are equivalent; [] clears only the + // explicit SDK contribution. + HookDirectories []string `json:"hookDirectories,omitzero"` // Skill scan directories and descendants excluded from discovery. Supports `~`-relative // paths. IgnoredSkillsLocations []string `json:"ignoredSkillsLocations,omitzero"` @@ -18401,6 +18840,12 @@ type SessionUpdateOptionsParams struct { // Full set of installed plugins for the session. Replaces the existing list; the runtime // invalidates the skills cache only when the list materially changes. InstalledPlugins []SessionInstalledPlugin `json:"installedPlugins,omitzero"` + // Explicit discovery-only instruction roots using existing SDK instruction formats, not + // filesystem grants. Available without enableConfigDiscovery, subject to + // instruction/managed disables. Relative SDK paths resolve once when supplied against the + // request's effective workingDirectory; retained roots do not move on cwd changes. Null and + // omission are equivalent; [] clears only the explicit SDK contribution. + InstructionDirectories []string `json:"instructionDirectories,omitzero"` // Stable integration identifier used for analytics and rate-limit attribution. IntegrationID *string `json:"integrationId,omitempty"` // Whether experimental capabilities are enabled. @@ -18456,7 +18901,11 @@ type SessionUpdateOptionsParams struct { ShellInitProfile *string `json:"shellInitProfile,omitempty"` // PowerShell process flags applied to built-in and user-requested shell commands. ShellProcessFlags []string `json:"shellProcessFlags,omitzero"` - // Additional directories to search for skills. + // Explicit discovery-only skill roots, not filesystem grants. Available without + // enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once + // when supplied against the request's effective workingDirectory; retained roots do not + // move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK + // contribution. SkillDirectories []string `json:"skillDirectories,omitzero"` // Whether to skip loading custom instruction sources. SkipCustomInstructions *bool `json:"skipCustomInstructions,omitempty"` @@ -18647,6 +19096,18 @@ func (UserAuthInfo) settableAuthInfoType() SettableAuthInfoType { return SettableAuthInfoTypeUser } +// Outcome of an atomic user or repository settings edit. +// Experimental: SettingsEditResult is part of an experimental API and may change or be +// removed. +// Internal: SettingsEditResult is an internal SDK API and is not part of the public surface. +type SettingsEditResult struct { + // Changed, unchanged or invalid existing file. Rejected input, validation failures and I/O + // errors remain RPC errors. + // Internal: Status is part of the SDK's internal API surface and is not intended for + // external use. + Status SettingsEditStatus `json:"status"` +} + // User-requested shell execution cancellation handle. // Experimental: ShellCancelUserRequestedRequest is part of an experimental API and may // change or be removed. @@ -19600,7 +20061,10 @@ type SkillsDiscoverRequest struct { IgnoredSkillsLocations []string `json:"ignoredSkillsLocations,omitzero"` // Optional list of project directory paths to scan for project-scoped skills ProjectPaths []string `json:"projectPaths,omitzero"` - // Optional list of additional skill directory paths to include + // Explicit discovery-only skill roots, not filesystem grants. Available without ambient + // discovery, subject to skill/managed disables. Relative paths resolve against the + // request's effective working directory when supplied. Null and omission are equivalent; an + // empty array contributes no explicit roots. SkillDirectories []string `json:"skillDirectories,omitzero"` } @@ -19638,6 +20102,11 @@ type SkillsGetDiscoveryPathsRequest struct { // Optional list of project directory paths. When omitted or empty, only personal and custom // directories are returned. ProjectPaths []string `json:"projectPaths,omitzero"` + // Explicit discovery-only skill roots to enumerate, including configured missing + // directories. Relative paths resolve against the request's effective working directory + // when supplied. These are not filesystem grants or preferred creation targets. Null and + // omission are equivalent. + SkillDirectories []string `json:"skillDirectories,omitzero"` } // Skills invoked during this session, ordered by invocation time (most recent last). @@ -21516,6 +21985,82 @@ type UserSettingMetadata struct { Value any `json:"value"` } +// A single top-level setting subtree to validate and write. +// Experimental: UserSettingsApplyTopKeyRequest is part of an experimental API and may +// change or be removed. +type UserSettingsApplyTopKeyRequest struct { + // Canonical path of the setting the caller is editing. Currently informational only. + CanonicalPath []string `json:"canonicalPath"` + // Records that the user chose an update channel explicitly, so the one-time staff channel + // migration stops reapplying. Honored only for the `autoUpdatesChannel` key. + CompleteStaffUpdateChannelMigration *bool `json:"completeStaffUpdateChannelMigration,omitempty"` + // True to remove the top-level key instead of writing it. + Delete *bool `json:"delete,omitempty"` + // Top-level setting name to write. + TopKey string `json:"topKey"` + // Value to write for the whole top-level key. Omitted when `delete` is true. Explicit null + // is preserved and validated as null. + Value *any `json:"value,omitempty"` +} + +// Outcome of validating and writing one top-level setting subtree. +// Experimental: UserSettingsApplyTopKeyResult is part of an experimental API and may change +// or be removed. +type UserSettingsApplyTopKeyResult struct { + // Why the write failed, present only when `status` is `write-error`. + Error *string `json:"error,omitempty"` + // Problems found, present only when `status` is `validation-error`. + Issues []UserSettingsValidationIssue `json:"issues,omitzero"` + // `ok` when the value was written, `validation-error` when it was rejected before any + // write, `write-error` when validation passed but the write failed. + Status string `json:"status"` +} + +// One atomic edit of a canonical setting in settings.json. +// Experimental: UserSettingsEditRequest is part of an experimental API and may change or be +// removed. +// Internal: UserSettingsEditRequest is an internal SDK API and is not part of the public +// surface. +type UserSettingsEditRequest struct { + // Nonempty canonical path segments of the setting to edit, starting with its top-level key. + CanonicalPath []string `json:"canonicalPath"` + // Configuration directory to edit. Omitted or empty resolves the server's own home, as in + // `user.settings.loadForConfigDir`. + ConfigDir *string `json:"configDir,omitempty"` + // Set a scalar, add or remove a string list item, or remove the setting. The handler + // rejects a missing or incompatible value. + // Internal: Operation is part of the SDK's internal API surface and is not intended for + // external use. + Operation SettingsEditOperation `json:"operation"` + // Required boolean, string or number for set, required string for add-item and remove-item, + // and forbidden for remove. The runtime rejects all other JSON values. + Value any `json:"value,omitempty"` +} + +// Selects which settings file paths to resolve. +// Experimental: UserSettingsGetPathsRequest is part of an experimental API and may change +// or be removed. +type UserSettingsGetPathsRequest struct { + // Absolute path of a repository root. Supply it to also resolve that repository's two + // settings file paths; omit it to resolve only the user path. + RepoRoot *string `json:"repoRoot,omitempty"` +} + +// On-disk locations of the settings files this runtime reads. A path is reported whether or +// not the file exists. +// Experimental: UserSettingsGetPathsResult is part of an experimental API and may change or +// be removed. +type UserSettingsGetPathsResult struct { + // The repository's local, untracked settings file, or null when no repository root was + // supplied. + RepoLocalSettings *string `json:"repoLocalSettings,omitempty"` + // The repository's checked-in settings file, or null when no repository root was supplied. + RepoSettings *string `json:"repoSettings,omitempty"` + // The user settings file: `settings.json` under the resolved Copilot home. This is the file + // `user.settings.get`, `user.settings.load`, and `user.settings.set` read and write. + UserSettings string `json:"userSettings"` +} + // Per-key metadata for every known user setting in settings.json, including settings left // at their default. Excludes repository- and enterprise-managed overrides. // Experimental: UserSettingsGetResult is part of an experimental API and may change or be @@ -21526,6 +22071,114 @@ type UserSettingsGetResult struct { Settings map[string]UserSettingMetadata `json:"settings"` } +// Top-level user-setting keys grouped by who may govern them. +// Experimental: UserSettingsGovernanceKeysResult is part of an experimental API and may +// change or be removed. +type UserSettingsGovernanceKeysResult struct { + // Top-level keys a repository may override through a Claude-compatible repository config. + ClaudeRepo []string `json:"claudeRepo"` + // Top-level keys an enterprise policy may fix through managed settings. + Managed []string `json:"managed"` + // Top-level keys a repository may override through `.github/copilot/settings.json` or + // `.github/copilot/settings.local.json`. + Repo []string `json:"repo"` +} + +// Contents of settings.json as stored, for a caller about to rewrite it. +// Experimental: UserSettingsLoadForEditResult is part of an experimental API and may change +// or be removed. +type UserSettingsLoadForEditResult struct { + // Parsed contents, present only when `status` is `ok`. + Settings any `json:"settings,omitempty"` + // `ok` when the file parsed, `missing` when there is no file yet, `invalid` when the file + // exists but will not parse. + Status string `json:"status"` +} + +// Settings object whose key names should be canonicalized. +// Experimental: UserSettingsNormalizeRequest is part of an experimental API and may change +// or be removed. +type UserSettingsNormalizeRequest struct { + // Free-form settings object, possibly using legacy or snake_case key names. + Settings any `json:"settings"` +} + +// Settings object with canonical key names. +// Experimental: UserSettingsNormalizeResult is part of an experimental API and may change +// or be removed. +type UserSettingsNormalizeResult struct { + // The same settings with every legacy or snake_case key renamed to its canonical spelling. + Settings any `json:"settings"` +} + +// One setting that will not take effect, and why. +// Experimental: UserSettingsProblem is part of an experimental API and may change or be +// removed. +type UserSettingsProblem struct { + // Coarse grouping for the problem, for a caller that presents problems in sections. + Category string `json:"category"` + // Why the setting will not take effect. Never contains the setting's value, which may be a + // token or another secret. + Explanation string `json:"explanation"` + // Stable identifier for this problem within the reported set, so a caller can track a + // selection across refreshes. + ID string `json:"id"` + // What is wrong in machine-readable form, for a caller that wants to branch rather than + // display. + Kind string `json:"kind"` + // The offending key as written in the file, when the problem is attributable to a single + // key. Absent when the whole file is at fault. + RawKey *string `json:"rawKey,omitempty"` + // The settings layer the problem was found in. + Source UserSettingsProblemLocation `json:"source"` +} + +// The settings layer a problem was found in. +// Experimental: UserSettingsProblemLocation is part of an experimental API and may change +// or be removed. +type UserSettingsProblemLocation struct { + // Absolute path of the file backing this layer. + FilePath string `json:"filePath"` + // Which layer this is: `user`, `repo`, or `local`. + Kind string `json:"kind"` + // The caller-supplied display label for the layer. + Label string `json:"label"` +} + +// One already-loaded settings layer to diagnose. +// Experimental: UserSettingsProblemSource is part of an experimental API and may change or +// be removed. +type UserSettingsProblemSource struct { + // The layer's settings exactly as loaded, unnormalized. Empty when the file is missing or + // failed to parse. + Config map[string]any `json:"config,omitzero"` + // Absolute path of the file backing this layer. + FilePath string `json:"filePath"` + // True when the file itself failed to parse, so its keys could not be read at all. + Invalid *bool `json:"invalid,omitempty"` + // Which layer this is: `user`, `repo`, or `local`. + Kind string `json:"kind"` + // Caller-chosen display label for the layer, echoed back on each problem so a caller can + // group by layer without re-deriving its own naming. + Label string `json:"label"` +} + +// The settings layers to diagnose. +// Experimental: UserSettingsProblemsRequest is part of an experimental API and may change +// or be removed. +type UserSettingsProblemsRequest struct { + // Layers to diagnose, in the precedence order the caller applies them. + Sources []UserSettingsProblemSource `json:"sources,omitzero"` +} + +// The settings that will not take effect across the given layers. +// Experimental: UserSettingsProblemsResult is part of an experimental API and may change or +// be removed. +type UserSettingsProblemsResult struct { + // Each setting that will not take effect, and why. Empty when every layer is healthy. + Problems []UserSettingsProblem `json:"problems,omitzero"` +} + // Partial user settings to write to settings.json. Each top-level key is written // individually, replacing the existing value; a key whose value is null is removed. // Experimental: UserSettingsSetRequest is part of an experimental API and may change or be @@ -21540,6 +22193,86 @@ type UserSettingsSetRequest struct { type UserSettingsSetResult struct { } +// Names the user setting to merge into, and the partial object to merge. +// Experimental: UserSettingsUpdateRequest is part of an experimental API and may change or +// be removed. +// Internal: UserSettingsUpdateRequest is an internal SDK API and is not part of the public +// surface. +type UserSettingsUpdateRequest struct { + // Copilot configuration directory to write the settings document in, taking precedence over + // the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to + // use the directory the server resolved for itself. + ConfigDir *string `json:"configDir,omitempty"` + // Top-level user-setting key to merge into, such as `extensions`. + Key string `json:"key"` + // Single-component name for the settings document at `/settings/.json`; + // path separators, `.` and `..` are rejected. Omit it, or pass an empty string, to use the + // main settings document. + SubDir *string `json:"subDir,omitempty"` + // Value to store for `key`. When both the stored value and this value are objects, their + // fields are shallow-merged and fields this object does not name are preserved. Otherwise + // this value replaces the stored value. + Value any `json:"value"` +} + +// The stored value of the user setting after the merge. +// Experimental: UserSettingsUpdateResult is part of an experimental API and may change or +// be removed. +// Internal: UserSettingsUpdateResult is an internal SDK API and is not part of the public +// surface. +type UserSettingsUpdateResult struct { + // The key's stored value after the write: the merged object when both the stored value and + // the supplied value are objects, otherwise the supplied value. + Value any `json:"value"` +} + +// A single top-level setting subtree to validate. +// Experimental: UserSettingsValidateRequest is part of an experimental API and may change +// or be removed. +type UserSettingsValidateRequest struct { + // True to validate a removal of this key. The current settings file is not read. + Delete *bool `json:"delete,omitempty"` + // Top-level setting name to validate. + TopKey string `json:"topKey"` + // Value to validate. Omitted when `delete` is true. + Value any `json:"value,omitempty"` +} + +// Outcome of validating one top-level setting subtree. +// Experimental: UserSettingsValidateResult is part of an experimental API and may change or +// be removed. +type UserSettingsValidateResult struct { + // Problems found, empty when `ok` is true. + Issues []UserSettingsValidationIssue `json:"issues,omitzero"` + // True when the subtree is valid. + Ok bool `json:"ok"` +} + +// One problem found while validating a setting value. +// Experimental: UserSettingsValidationIssue is part of an experimental API and may change +// or be removed. +type UserSettingsValidationIssue struct { + // Human-readable description of the problem. + Message string `json:"message"` + // Where in the settings tree the problem sits, as object keys and array indices. The first + // element is the top-level key; a whole-value problem is reported as that single key. + Path []any `json:"path"` +} + +// The whole content to store in the user settings file. +// Experimental: UserSettingsWriteAllRequest is part of an experimental API and may change +// or be removed. +type UserSettingsWriteAllRequest struct { + // The settings object to store. It replaces the file's entire content, so a key absent here + // is removed. + Settings any `json:"settings"` +} + +// Experimental: UserSettingsWriteAllResult is part of an experimental API and may change or +// be removed. +type UserSettingsWriteAllResult struct { +} + // The approval to add as a session-scoped rule // Experimental: UserToolSessionApproval is part of an experimental API and may change or be // removed. @@ -24426,6 +25159,32 @@ const ( ExternalToolTextResultForLlmContentTypeText ExternalToolTextResultForLlmContentType = "text" ) +// The population a feature flag is declared for, before overrides. +// Experimental: FeatureFlagAvailability is part of an experimental API and may change or be +// removed. +type FeatureFlagAvailability string + +const ( + // Enabled only for accounts that opted into experimental features. + FeatureFlagAvailabilityExperimental FeatureFlagAvailability = "experimental" + // Disabled for everyone, before any override. + FeatureFlagAvailabilityOff FeatureFlagAvailability = "off" + // Enabled for everyone, before any override. + FeatureFlagAvailabilityOn FeatureFlagAvailability = "on" + // Enabled for any staff account, GitHub or Microsoft. + FeatureFlagAvailabilityStaff FeatureFlagAvailability = "staff" + // Enabled only for staff accounts that have also opted into experimental features. + FeatureFlagAvailabilityStaffAndExperimental FeatureFlagAvailability = "staff-and-experimental" + // Enabled for GitHub staff accounts only. + FeatureFlagAvailabilityStaffGitHub FeatureFlagAvailability = "staff-github" + // Enabled for Microsoft staff accounts only. + FeatureFlagAvailabilityStaffMicrosoft FeatureFlagAvailability = "staff-microsoft" + // Enabled for staff accounts and for accounts that opted into experimental features. + FeatureFlagAvailabilityStaffOrExperimental FeatureFlagAvailability = "staff-or-experimental" + // Enabled only for accounts on the owning team. + FeatureFlagAvailabilityTeam FeatureFlagAvailability = "team" +) + // Why the runtime is requesting a GitHub credential. // Experimental: GitHubTokenAcquireReason is part of an experimental API and may change or // be removed. @@ -26698,6 +27457,8 @@ const ( // Review or widen the sandbox policy. The blocked path or host is named by the accompanying // message or by the tool result the action arrived with. RemediationActionReviewSandboxPolicy RemediationAction = "review_sandbox_policy" + // Discard conversation history back through the blocked request before continuing. + RemediationActionRewindConversation RemediationAction = "rewind_conversation" // Inspect which account is currently authenticated before deciding what to change. RemediationActionShowAccount RemediationAction = "show_account" // Authenticate again with the Copilot backend. The current credential is absent, expired, @@ -27335,6 +28096,36 @@ const ( SettableAuthInfoTypeUser SettableAuthInfoType = "user" ) +// One atomic settings mutation. +// Experimental: SettingsEditOperation is part of an experimental API and may change or be +// removed. +type SettingsEditOperation string + +const ( + // Add one string to a list, unless present. + SettingsEditOperationAddItem SettingsEditOperation = "add-item" + // Remove the setting without supplying a value. + SettingsEditOperationRemove SettingsEditOperation = "remove" + // Remove one string from a list, unless absent. + SettingsEditOperationRemoveItem SettingsEditOperation = "remove-item" + // Set one scalar value. + SettingsEditOperationSet SettingsEditOperation = "set" +) + +// Whether one atomic settings edit changed a file. +// Experimental: SettingsEditStatus is part of an experimental API and may change or be +// removed. +type SettingsEditStatus string + +const ( + // The edit changed the setting and was stored. + SettingsEditStatusChanged SettingsEditStatus = "changed" + // The existing settings file could not be edited safely; nothing was written. + SettingsEditStatusInvalid SettingsEditStatus = "invalid" + // The setting already had the requested state. + SettingsEditStatusUnchanged SettingsEditStatus = "unchanged" +) + // Controls automatic non-interactive profile loading where supported. Explicit initScripts // are unaffected. // Experimental: ShellInitProfile is part of an experimental API and may change or be @@ -30960,6 +31751,105 @@ type internalServerAPI struct { client *jsonrpc2.Client } +// Experimental: InternalServerAccountAPI contains experimental APIs that may change or be +// removed. +type InternalServerAccountAPI internalServerAPI + +// DescribeAuthInfo renders the sign-in banner and the one-line account description the +// runtime uses for an authentication identity. The runtime words these in several places +// for its own callers, so a host that announces a sign-in or an account switch should +// render them from here rather than composing its own, which would let the two spellings +// drift apart. +// +// RPC method: account.describeAuthInfo. +// +// Parameters: The authentication identity whose shared wording should be rendered. +// +// Returns: The wording the runtime uses for an authentication identity. +// Internal: DescribeAuthInfo is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerAccountAPI) DescribeAuthInfo(ctx context.Context, params *AccountDescribeAuthInfoRequest) (*AccountDescribeAuthInfoResult, error) { + raw, err := a.client.Request(ctx, "account.describeAuthInfo", params) + if err != nil { + return nil, err + } + var result AccountDescribeAuthInfoResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetGistSupport reports whether the supplied identity can create gists. Gists are +// unavailable on GitHub Enterprise Cloud with data residency, and to Enterprise Managed +// Users on github.com, so a host that offers gist actions should hide or disable them when +// this reports no support. +// +// RPC method: account.getGistSupport. +// +// Parameters: The authentication identity whose gist support should be reported. +// +// Returns: Whether the identity can create gists, and why not when it cannot. +// Internal: GetGistSupport is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerAccountAPI) GetGistSupport(ctx context.Context, params *AccountGetGistSupportRequest) (*AccountGetGistSupportResult, error) { + raw, err := a.client.Request(ctx, "account.getGistSupport", params) + if err != nil { + return nil, err + } + var result AccountGetGistSupportResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetTokenEnvVar names the environment variable supplying a classic personal access token, +// if one is set. A classic token cannot be upgraded in place, so a host that finds one +// should tell the user which variable to unset rather than starting an interactive sign-in +// that the variable would override. +// +// RPC method: account.getTokenEnvVar. +// +// Returns: The environment variable supplying a classic personal access token, when one is +// set. +// Internal: GetTokenEnvVar is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerAccountAPI) GetTokenEnvVar(ctx context.Context) (*AccountGetTokenEnvVarResult, error) { + raw, err := a.client.Request(ctx, "account.getTokenEnvVar", nil) + if err != nil { + return nil, err + } + var result AccountGetTokenEnvVarResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetWebUrl resolves a path on the identity's GitHub host into an absolute URL, so a host +// can link to settings or documentation on the enterprise instance the user is signed in to +// rather than to github.com. Falls back to the public host when no identity is supplied. +// +// RPC method: account.getWebUrl. +// +// Parameters: A path to resolve against the GitHub host an identity is signed in to. +// +// Returns: An absolute URL on the identity's GitHub host. +// Internal: GetWebUrl is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerAccountAPI) GetWebUrl(ctx context.Context, params *AccountGetWebURLRequest) (*AccountGetWebURLResult, error) { + raw, err := a.client.Request(ctx, "account.getWebUrl", params) + if err != nil { + return nil, err + } + var result AccountGetWebURLResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // Experimental: InternalServerAgentsAPI contains experimental APIs that may change or be // removed. type InternalServerAgentsAPI internalServerAPI @@ -31098,6 +31988,64 @@ func (a *InternalServerAgentsAPI) GetBuiltins(ctx context.Context) (*AgentsGetBu return &result, nil } +// Experimental: InternalServerFeatureFlagsAPI contains experimental APIs that may change or +// be removed. +type InternalServerFeatureFlagsAPI internalServerAPI + +// ListMetadata lists every feature flag this runtime declares, with the population each one +// is declared for, its experimental description, and the online-experiment flag it maps to. +// This is the static catalog: it describes how each flag is defined, not whether it is on +// for anyone. Use `featureFlags.resolve` for static values with caller overrides, not +// active runtime values or experiment assignments. +// +// RPC method: featureFlags.listMetadata. +// +// Returns: Every feature flag this runtime declares, with the shape each one was declared +// with. +// Internal: ListMetadata is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerFeatureFlagsAPI) ListMetadata(ctx context.Context) (*FeatureFlagsMetadataResult, error) { + raw, err := a.client.Request(ctx, "featureFlags.listMetadata", nil) + if err != nil { + return nil, err + } + var result FeatureFlagsMetadataResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Resolve computes static feature flags from the supplied population and overrides without +// changing runtime state or verifying audience membership. Starts from declared +// availability, then applies direct feature-flag environment values, user settings, and +// explicit `flagOverrides`. It does not apply `COPILOT_EXP_*` experiment assignments, +// authenticated startup gates, or active runtime state. Settings include +// `enabledFeatureFlags`, the legacy `feature_flags.enabled` list, and supported convenience +// settings. Supply `baseFlags` to use an existing flag set instead of declared +// availability. Omit `isStaffGitHub` or `isStaffMicrosoft` when membership was never +// recorded: a legacy staff account then counts as both populations. +// +// RPC method: featureFlags.resolve. +// +// Parameters: Caller population and overrides for static feature-flag resolution, +// independent of experiment assignments and active runtime state. +// +// Returns: The resolved feature flags, keyed by flag name. +// Internal: Resolve is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerFeatureFlagsAPI) Resolve(ctx context.Context, params *FeatureFlagsResolveRequest) (*FeatureFlagsResolveResult, error) { + raw, err := a.client.Request(ctx, "featureFlags.resolve", params) + if err != nil { + return nil, err + } + var result FeatureFlagsResolveResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // Experimental: InternalServerGitAPI contains experimental APIs that may change or be // removed. type InternalServerGitAPI internalServerAPI @@ -31508,10 +32456,114 @@ func (a *InternalServerHostAPI) ReleaseSession(ctx context.Context, params *Host return &result, nil } +// Experimental: InternalServerInstructionsAPI contains experimental APIs that may change or +// be removed. +type InternalServerInstructionsAPI internalServerAPI + +// ClearCache drops the runtime's in-memory cache of discovered custom instructions so the +// next discovery reads them from disk again. A host calls this after it changes instruction +// files, or after it trusts a folder whose instructions an earlier discovery skipped, so +// that a session started afterwards sees the current files instead of a cached earlier +// answer. The call performs no I/O of its own and removes nothing from disk; it only +// invalidates, so the cost lands on the next discovery. Returns once the cache is +// clear, which is what lets a caller order a session start after it. Marked internal +// because it exists to carry a CLI call site off the napi boundary onto the SDK contract; +// it is migration plumbing, not a surface consumers are meant to depend on. +// +// RPC method: instructions.clearCache. +// Internal: ClearCache is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerInstructionsAPI) ClearCache(ctx context.Context) (*InstructionsClearCacheResult, error) { + raw, err := a.client.Request(ctx, "instructions.clearCache", nil) + if err != nil { + return nil, err + } + var result InstructionsClearCacheResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// DiscoverRepoSources discovers the instruction sources for one caller-named location and +// returns them in the order the runtime applies them. `discover` answers for a set of +// project paths and derives the rest of its scope itself; this one instead takes every +// argument from the caller — the extra directories to scan and whether to descend into +// nested instruction files — and honors them as given. It also includes instruction +// directories from trusted repository settings, matching native repository discovery. Use +// it when the caller knows its own scope and no session exists to derive that scope from, +// such as a host reporting how many instruction files a directory contributes before any +// session starts. Marked internal because it exists to carry a CLI call site off the napi +// boundary onto the SDK contract; it is migration plumbing, not a surface consumers are +// meant to depend on. +// +// RPC method: instructions.discoverRepoSources. +// +// Parameters: Explicit discovery arguments for one location, supplied by the caller rather +// than derived from a session. +// +// Returns: Instruction sources discovered across user, repository, and plugin sources. +// Internal: DiscoverRepoSources is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerInstructionsAPI) DiscoverRepoSources(ctx context.Context, params *InstructionsDiscoverRepoSourcesRequest) (*ServerInstructionSourceList, error) { + raw, err := a.client.Request(ctx, "instructions.discoverRepoSources", params) + if err != nil { + return nil, err + } + var result ServerInstructionSourceList + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetInitPrompt returns the prompt the `init` command runs to author repository +// instructions. A host offering its own initialize action sends this text so the +// instructions it produces match the ones the CLI produces. The text is fixed for a build +// and depends on no configuration, session or repository. +// +// RPC method: instructions.getInitPrompt. +// +// Returns: The prompt the init command runs. +// Internal: GetInitPrompt is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerInstructionsAPI) GetInitPrompt(ctx context.Context) (*InstructionsInitPromptResult, error) { + raw, err := a.client.Request(ctx, "instructions.getInitPrompt", nil) + if err != nil { + return nil, err + } + var result InstructionsInitPromptResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // Experimental: InternalServerMCPAPI contains experimental APIs that may change or be // removed. type InternalServerMCPAPI internalServerAPI +// ListBuiltinServerNames lists the MCP servers the runtime supplies itself, so a host that +// disables the built-ins wholesale suppresses exactly the set the runtime would otherwise +// add. The names are fixed for a build and depend on no configuration, session or account. +// +// RPC method: mcp.listBuiltinServerNames. +// +// Returns: Names of the MCP servers the runtime supplies itself. +// Internal: ListBuiltinServerNames is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerMCPAPI) ListBuiltinServerNames(ctx context.Context) (*MCPListBuiltinServerNamesResult, error) { + raw, err := a.client.Request(ctx, "mcp.listBuiltinServerNames", nil) + if err != nil { + return nil, err + } + var result MCPListBuiltinServerNamesResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // ShouldExcludeGitHubTools reports whether the gh-replaceable GitHub MCP tools may be // clipped for a session, which a host feeds back as the `excludeGhReplaceableTools` build // option. The tools are redundant only when the session can reach a shell *and* the host @@ -31629,6 +32681,87 @@ func (s *InternalServerMCPAPI) Registry() *InternalServerMCPRegistryAPI { return (*InternalServerMCPRegistryAPI)(s) } +// Experimental: InternalServerRepoAPI contains experimental APIs that may change or be +// removed. +type InternalServerRepoAPI internalServerAPI + +// Experimental: InternalServerRepoSettingsAPI contains experimental APIs that may change or +// be removed. +type InternalServerRepoSettingsAPI internalServerAPI + +// ReadRaw reads one repository settings file without settings normalization or layering. +// The existing JSONC parser accepts comments and trailing commas and applies its +// prototype-safety rules. Missing or blank files return an empty valid config. Invalid +// files return an empty config with invalid=true; other read failures reject. +// +// RPC method: repo.settings.readRaw. +// +// Parameters: Which repository settings file to read. +// +// Returns: Parsed repository settings without normalization or layering. +// Internal: ReadRaw is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerRepoSettingsAPI) ReadRaw(ctx context.Context, params *RepoSettingsReadRawRequest) (*RepoSettingsReadRawResult, error) { + raw, err := a.client.Request(ctx, "repo.settings.readRaw", params) + if err != nil { + return nil, err + } + var result RepoSettingsReadRawResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// WriteAll replaces the repository-overridable settings in one locked write. Allowed keys +// present in settings are validated and written; allowed keys absent from settings are +// removed. Other input keys are ignored, and unknown keys already stored in the file remain +// unchanged. Invalid values or an invalid existing file reject without a partial write. +// +// RPC method: repo.settings.writeAll. +// +// Parameters: The complete set of repository-overridable settings to store. +// Internal: WriteAll is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerRepoSettingsAPI) WriteAll(ctx context.Context, params *RepoSettingsWriteAllRequest) (*RepoSettingsWriteAllResult, error) { + raw, err := a.client.Request(ctx, "repo.settings.writeAll", params) + if err != nil { + return nil, err + } + var result RepoSettingsWriteAllResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// WriteKey writes or removes one allowed top-level repository setting through the existing +// validator and file lock. Preserves unrelated stored keys. Invalid keys, values, existing +// documents, and I/O errors reject without replacing the file. Deletion requires +// delete=true; otherwise value must be present. +// +// RPC method: repo.settings.writeKey. +// +// Parameters: One key to write or remove in a repository settings file. +// Internal: WriteKey is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerRepoSettingsAPI) WriteKey(ctx context.Context, params *RepoSettingsWriteKeyRequest) (*RepoSettingsWriteKeyResult, error) { + raw, err := a.client.Request(ctx, "repo.settings.writeKey", params) + if err != nil { + return nil, err + } + var result RepoSettingsWriteKeyResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: Settings returns experimental APIs that may change or be removed. +func (s *InternalServerRepoAPI) Settings() *InternalServerRepoSettingsAPI { + return (*InternalServerRepoSettingsAPI)(s) +} + // Experimental: InternalServerSessionsAPI contains experimental APIs that may change or be // removed. type InternalServerSessionsAPI internalServerAPI @@ -31876,20 +33009,304 @@ func (a *InternalServerSessionsAPI) UpdateWorkspaceFields(ctx context.Context, p return &result, nil } +// Experimental: InternalServerUserAPI contains experimental APIs that may change or be +// removed. +type InternalServerUserAPI internalServerAPI + +// Experimental: InternalServerUserSettingsAPI contains experimental APIs that may change or +// be removed. +type InternalServerUserSettingsAPI internalServerAPI + +// ApplyTopKey validates one top-level setting subtree and writes just that key to +// settings.json as a single step. Doing both here closes the race a caller cannot close +// itself: between a separate preflight read and the write, the file may change. Rewriting +// only the touched key keeps legacy siblings out of settings.json. Answers a status rather +// than failing, so a validation problem and a write problem stay distinguishable. +// +// RPC method: user.settings.applyTopKey. +// +// Parameters: A single top-level setting subtree to validate and write. +// +// Returns: Outcome of validating and writing one top-level setting subtree. +// Internal: ApplyTopKey is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerUserSettingsAPI) ApplyTopKey(ctx context.Context, params *UserSettingsApplyTopKeyRequest) (*UserSettingsApplyTopKeyResult, error) { + raw, err := a.client.Request(ctx, "user.settings.applyTopKey", params) + if err != nil { + return nil, err + } + var result UserSettingsApplyTopKeyResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// DiagnoseProblems diagnoses a set of already-loaded settings layers, reporting each key +// that will not take effect and why. Settings load tolerantly so that one bad key does not +// stop a session from starting; this method surfaces what was dropped so a caller can +// report it instead of silently ignoring the user's intent. Takes the layers as given +// rather than reading them, so a caller can diagnose exactly the content it is showing, +// including unsaved edits. Never echoes a setting's value, because a value may be a token +// or another secret. Marked internal because it exists to carry a CLI call site off the +// native addon, not to serve a consumer-facing need; it becomes public once an SDK consumer +// needs to inspect settings health itself. +// +// RPC method: user.settings.diagnoseProblems. +// +// Parameters: The settings layers to diagnose. +// +// Returns: The settings that will not take effect across the given layers. +// Internal: DiagnoseProblems is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerUserSettingsAPI) DiagnoseProblems(ctx context.Context, params *UserSettingsProblemsRequest) (*UserSettingsProblemsResult, error) { + raw, err := a.client.Request(ctx, "user.settings.diagnoseProblems", params) + if err != nil { + return nil, err + } + var result UserSettingsProblemsResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Edit atomically edits one canonical user setting inside its settings-file lock. Reads, +// canonicalizes touched aliases, applies the edit, validates the resulting top-level +// setting and writes before releasing the lock. An explicit autoUpdatesChannel set +// completes the staff migration in the same transaction. Only a malformed existing file +// returns `invalid`; refused keys, invalid values and I/O errors reject the call. +// +// RPC method: user.settings.edit. +// +// Parameters: One atomic edit of a canonical setting in settings.json. +// +// Returns: Outcome of an atomic user or repository settings edit. +// Internal: Edit is part of the SDK's internal handshake/plumbing; external callers should +// not use it. +func (a *InternalServerUserSettingsAPI) Edit(ctx context.Context, params *UserSettingsEditRequest) (*SettingsEditResult, error) { + req := map[string]any{} + if params != nil { + req["canonicalPath"] = params.CanonicalPath + if params.ConfigDir != nil { + req["configDir"] = *params.ConfigDir + } + req["operation"] = params.Operation + if params.Value != nil { + req["value"] = params.Value + } + if params.Operation != SettingsEditOperationRemove { + if _, ok := req["value"]; !ok { + req["value"] = nil + } + } + } + raw, err := a.client.Request(ctx, "user.settings.edit", req) + if err != nil { + return nil, err + } + var result SettingsEditResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetPaths resolves the on-disk locations of the settings files this runtime reads, so a +// consumer can show or open them. The user path is the same file `user.settings.get`, +// `user.settings.load`, and `user.settings.set` operate on. Supply `repoRoot` to also +// resolve that repository's checked-in and local settings paths. A path is reported whether +// or not the file exists. +// +// RPC method: user.settings.getPaths. +// +// Parameters: Selects which settings file paths to resolve. +// +// Returns: On-disk locations of the settings files this runtime reads. A path is reported +// whether or not the file exists. +// Internal: GetPaths is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerUserSettingsAPI) GetPaths(ctx context.Context, params *UserSettingsGetPathsRequest) (*UserSettingsGetPathsResult, error) { + raw, err := a.client.Request(ctx, "user.settings.getPaths", params) + if err != nil { + return nil, err + } + var result UserSettingsGetPathsResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ListGovernanceKeys lists the top-level user-setting keys by who is allowed to govern +// them: `repo` keys a repository may override through `.github/copilot/settings.json`, +// `claudeRepo` keys a repository may override through a Claude-compatible config, and +// `managed` keys an enterprise policy may fix. The lists are static for a given runtime +// build and fail closed: a key absent from a list cannot be governed that way. +// +// RPC method: user.settings.listGovernanceKeys. +// +// Returns: Top-level user-setting keys grouped by who may govern them. +// Internal: ListGovernanceKeys is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerUserSettingsAPI) ListGovernanceKeys(ctx context.Context) (*UserSettingsGovernanceKeysResult, error) { + raw, err := a.client.Request(ctx, "user.settings.listGovernanceKeys", nil) + if err != nil { + return nil, err + } + var result UserSettingsGovernanceKeysResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// LoadForEdit reads settings.json as stored for a caller that is about to edit it. Unlike +// `user.settings.get`, this returns file values rather than per-key metadata and defaults. +// Reports `missing` for an absent file and `invalid` when the existing file will not parse. +// Retired config.json and extensionless files are not read. +// +// RPC method: user.settings.loadForEdit. +// +// Returns: Contents of settings.json as stored, for a caller about to rewrite it. +// Internal: LoadForEdit is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerUserSettingsAPI) LoadForEdit(ctx context.Context) (*UserSettingsLoadForEditResult, error) { + raw, err := a.client.Request(ctx, "user.settings.loadForEdit", nil) + if err != nil { + return nil, err + } + var result UserSettingsLoadForEditResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Normalize rewrites legacy and snake_case setting names in a settings object to their +// canonical spelling. A caller editing settings.json must normalize before writing: a +// legacy key left in place survives the write, is re-normalized on the next load, and +// silently shadows the canonical value the write just stored. +// +// RPC method: user.settings.normalize. +// +// Parameters: Settings object whose key names should be canonicalized. +// +// Returns: Settings object with canonical key names. +// Internal: Normalize is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerUserSettingsAPI) Normalize(ctx context.Context, params *UserSettingsNormalizeRequest) (*UserSettingsNormalizeResult, error) { + raw, err := a.client.Request(ctx, "user.settings.normalize", params) + if err != nil { + return nil, err + } + var result UserSettingsNormalizeResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Update merges a partial object into one top-level user setting, re-reading the stored +// value inside this runtime process's settings.json write lock so that concurrent writers +// in this process to different sub-fields of the same key do not clobber each other. Unlike +// `user.settings.set`, which replaces a key's whole value with what the caller last read, +// this keeps sub-fields the caller did not name when both the stored value and supplied +// value are objects; otherwise the supplied value replaces the stored value. Use it +// whenever two independent surfaces own different sub-fields of one setting. Returns the +// key's stored value after the write, in `value`. +// +// RPC method: user.settings.update. +// +// Parameters: Names the user setting to merge into, and the partial object to merge. +// +// Returns: The stored value of the user setting after the merge. +// Internal: Update is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerUserSettingsAPI) Update(ctx context.Context, params *UserSettingsUpdateRequest) (*UserSettingsUpdateResult, error) { + raw, err := a.client.Request(ctx, "user.settings.update", params) + if err != nil { + return nil, err + } + var result UserSettingsUpdateResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Validates one top-level setting subtree without writing it, reporting each problem with +// the path it applies to. Scoped to a single top-level key on purpose: validating the whole +// file would reject an edit whenever an unrelated pre-existing field is malformed, locking +// the user out of the very tool that could fix it. +// +// RPC method: user.settings.validate. +// +// Parameters: A single top-level setting subtree to validate. +// +// Returns: Outcome of validating one top-level setting subtree. +// Internal: Validate is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerUserSettingsAPI) Validate(ctx context.Context, params *UserSettingsValidateRequest) (*UserSettingsValidateResult, error) { + raw, err := a.client.Request(ctx, "user.settings.validate", params) + if err != nil { + return nil, err + } + var result UserSettingsValidateResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// WriteAll replaces the user settings file's entire content in one write. A key absent from +// `settings` is removed, which is what distinguishes this from `user.settings.set`: that +// one merges, so it can never clear a key the caller has dropped. For a caller saving the +// result of a raw edit, a merge would silently resurrect every key the user deleted. +// Records the same one-time mutation marks a per-key write records, so a setting the user +// has now chosen explicitly stops being migrated for them. +// +// RPC method: user.settings.writeAll. +// +// Parameters: The whole content to store in the user settings file. +// Internal: WriteAll is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerUserSettingsAPI) WriteAll(ctx context.Context, params *UserSettingsWriteAllRequest) (*UserSettingsWriteAllResult, error) { + raw, err := a.client.Request(ctx, "user.settings.writeAll", params) + if err != nil { + return nil, err + } + var result UserSettingsWriteAllResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: Settings returns experimental APIs that may change or be removed. +func (s *InternalServerUserAPI) Settings() *InternalServerUserSettingsAPI { + return (*InternalServerUserSettingsAPI)(s) +} + // InternalServerRPC provides internal SDK server-scoped RPC methods (handshake helpers // etc.). Not part of the public API. type InternalServerRPC struct { // Reuse a single struct instead of allocating one for each service on the heap. common internalServerAPI + Account *InternalServerAccountAPI Agents *InternalServerAgentsAPI + FeatureFlags *InternalServerFeatureFlagsAPI Git *InternalServerGitAPI GitHubOwners *InternalServerGitHubOwnersAPI GitHubRepository *InternalServerGitHubRepositoryAPI GlobalState *InternalServerGlobalStateAPI Host *InternalServerHostAPI + Instructions *InternalServerInstructionsAPI MCP *InternalServerMCPAPI + Repo *InternalServerRepoAPI Sessions *InternalServerSessionsAPI + User *InternalServerUserAPI } // Connect performs the SDK server connection handshake and validates the optional @@ -31924,14 +33341,19 @@ func (a *InternalServerRPC) Connect(ctx context.Context, params *ConnectRequest) func NewInternalServerRPC(client *jsonrpc2.Client) *InternalServerRPC { r := &InternalServerRPC{} r.common = internalServerAPI{client: client} + r.Account = (*InternalServerAccountAPI)(&r.common) r.Agents = (*InternalServerAgentsAPI)(&r.common) + r.FeatureFlags = (*InternalServerFeatureFlagsAPI)(&r.common) r.Git = (*InternalServerGitAPI)(&r.common) r.GitHubOwners = (*InternalServerGitHubOwnersAPI)(&r.common) r.GitHubRepository = (*InternalServerGitHubRepositoryAPI)(&r.common) r.GlobalState = (*InternalServerGlobalStateAPI)(&r.common) r.Host = (*InternalServerHostAPI)(&r.common) + r.Instructions = (*InternalServerInstructionsAPI)(&r.common) r.MCP = (*InternalServerMCPAPI)(&r.common) + r.Repo = (*InternalServerRepoAPI)(&r.common) r.Sessions = (*InternalServerSessionsAPI)(&r.common) + r.User = (*InternalServerUserAPI)(&r.common) return r } @@ -35097,6 +36519,43 @@ func (a *ModelAPI) GetCurrent(ctx context.Context) (*CurrentModel, error) { return &result, nil } +// GetReasoningSummaries computes whether the session's current model shows reasoning +// summaries and how a host should present them: the default Ctrl+T visibility, reasoning +// headers, the hidden-summaries hint, and whether a persisted `showReasoning` setting is +// redundant. The runtime folds in the session's model catalog, selection and +// reasoning-summaries experiment assignment; the host supplies only its own persisted +// setting and current visibility. This method reads the session's resolved model catalog +// rather than resolving it, so call `session.model.list` first on a session that has not +// listed models or run a turn; until then the result is `ready: false`. A session that +// resolves models without a Copilot catalog, that is a BYOK registry or an alternate +// provider, never caches one and stays `ready: false`. +// +// RPC method: session.model.getReasoningSummaries. +// +// Parameters: Host presentation state the reasoning-summaries policy depends on. +// +// Returns: Reasoning-summaries presentation policy for the session's current model. +func (a *ModelAPI) GetReasoningSummaries(ctx context.Context, params *ModelGetReasoningSummariesRequest) (*ModelGetReasoningSummariesResult, error) { + req := map[string]any{"sessionId": a.sessionID} + if params != nil { + if params.PersistedShowReasoning != nil { + req["persistedShowReasoning"] = *params.PersistedShowReasoning + } + if params.SummariesVisible != nil { + req["summariesVisible"] = *params.SummariesVisible + } + } + raw, err := a.client.Request(ctx, "session.model.getReasoningSummaries", req) + if err != nil { + return nil, err + } + var result ModelGetReasoningSummariesResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // Lists models available to this session using its own auth and integration context. // Connected hosts (CLI TUI, GitHub App) should call this through the session client so // remote sessions return the remote CLI's available models rather than the caller's. @@ -35376,6 +36835,9 @@ func (a *OptionsAPI) Update(ctx context.Context, params *SessionUpdateOptionsPar if params.AgentContext != nil { req["agentContext"] = *params.AgentContext } + if params.AgentDirectories != nil { + req["agentDirectories"] = params.AgentDirectories + } if params.AllowAllMCPServerInstructions != nil { req["allowAllMcpServerInstructions"] = *params.AllowAllMCPServerInstructions } @@ -35454,6 +36916,9 @@ func (a *OptionsAPI) Update(ctx context.Context, params *SessionUpdateOptionsPar if params.FeatureFlags != nil { req["featureFlags"] = params.FeatureFlags } + if params.HookDirectories != nil { + req["hookDirectories"] = params.HookDirectories + } if params.IgnoredSkillsLocations != nil { req["ignoredSkillsLocations"] = params.IgnoredSkillsLocations } @@ -35466,6 +36931,9 @@ func (a *OptionsAPI) Update(ctx context.Context, params *SessionUpdateOptionsPar if params.InstalledPlugins != nil { req["installedPlugins"] = params.InstalledPlugins } + if params.InstructionDirectories != nil { + req["instructionDirectories"] = params.InstructionDirectories + } if params.IntegrationID != nil { req["integrationId"] = *params.IntegrationID } diff --git a/go/rpc/zrpc_encoding.go b/go/rpc/zrpc_encoding.go index 471e491a87..fdddf41f89 100644 --- a/go/rpc/zrpc_encoding.go +++ b/go/rpc/zrpc_encoding.go @@ -7721,6 +7721,7 @@ func (r *SessionOpenOptions) UnmarshalJSON(data []byte) error { AdditionalContentExclusionPolicies []SessionOpenOptionsAdditionalContentExclusionPolicy `json:"additionalContentExclusionPolicies,omitzero"` AdditionalDirectories []string `json:"additionalDirectories,omitzero"` AgentContext *string `json:"agentContext,omitempty"` + AgentDirectories []string `json:"agentDirectories,omitzero"` AllowAllMCPServerInstructions *bool `json:"allowAllMcpServerInstructions,omitempty"` AskUserDisabled *bool `json:"askUserDisabled,omitempty"` AuthClientIDMetadataURL *string `json:"authClientIdMetadataUrl,omitempty"` @@ -7756,10 +7757,12 @@ func (r *SessionOpenOptions) UnmarshalJSON(data []byte) error { ExpAssignments any `json:"expAssignments,omitempty"` FeatureFlags map[string]bool `json:"featureFlags,omitzero"` HasSkillProvider *bool `json:"hasSkillProvider,omitempty"` + HookDirectories []string `json:"hookDirectories,omitzero"` IgnoredSkillsLocations []string `json:"ignoredSkillsLocations,omitzero"` IncludedBuiltinAgents []string `json:"includedBuiltinAgents,omitzero"` IncludedBuiltinSkills []string `json:"includedBuiltinSkills,omitzero"` InstalledPlugins []InstalledPlugin `json:"installedPlugins,omitzero"` + InstructionDirectories []string `json:"instructionDirectories,omitzero"` IntegrationID *string `json:"integrationId,omitempty"` IsExperimentalMode *bool `json:"isExperimentalMode,omitempty"` LogInteractiveShells *bool `json:"logInteractiveShells,omitempty"` @@ -7803,6 +7806,7 @@ func (r *SessionOpenOptions) UnmarshalJSON(data []byte) error { r.AdditionalContentExclusionPolicies = raw.AdditionalContentExclusionPolicies r.AdditionalDirectories = raw.AdditionalDirectories r.AgentContext = raw.AgentContext + r.AgentDirectories = raw.AgentDirectories r.AllowAllMCPServerInstructions = raw.AllowAllMCPServerInstructions r.AskUserDisabled = raw.AskUserDisabled r.AuthClientIDMetadataURL = raw.AuthClientIDMetadataURL @@ -7844,10 +7848,12 @@ func (r *SessionOpenOptions) UnmarshalJSON(data []byte) error { r.ExpAssignments = raw.ExpAssignments r.FeatureFlags = raw.FeatureFlags r.HasSkillProvider = raw.HasSkillProvider + r.HookDirectories = raw.HookDirectories r.IgnoredSkillsLocations = raw.IgnoredSkillsLocations r.IncludedBuiltinAgents = raw.IncludedBuiltinAgents r.IncludedBuiltinSkills = raw.IncludedBuiltinSkills r.InstalledPlugins = raw.InstalledPlugins + r.InstructionDirectories = raw.InstructionDirectories r.IntegrationID = raw.IntegrationID r.IsExperimentalMode = raw.IsExperimentalMode r.LogInteractiveShells = raw.LogInteractiveShells diff --git a/go/rpc/zsession_encoding.go b/go/rpc/zsession_encoding.go index 2db5b44582..89810fdf9b 100644 --- a/go/rpc/zsession_encoding.go +++ b/go/rpc/zsession_encoding.go @@ -2363,6 +2363,8 @@ func (r PermissionPromptRequestWrite) MarshalJSON() ([]byte, error) { func (r *PermissionRequestedData) UnmarshalJSON(data []byte) error { type rawPermissionRequestedData struct { AgentMode *SessionMode `json:"agentMode,omitempty"` + OwnerAgentID *string `json:"ownerAgentId,omitempty"` + OwnerSessionID *string `json:"ownerSessionId,omitempty"` PermissionMode *PermissionMode `json:"permissionMode,omitempty"` PermissionRequest json.RawMessage `json:"permissionRequest"` PromptRequest json.RawMessage `json:"promptRequest,omitempty"` @@ -2376,6 +2378,8 @@ func (r *PermissionRequestedData) UnmarshalJSON(data []byte) error { return err } r.AgentMode = raw.AgentMode + r.OwnerAgentID = raw.OwnerAgentID + r.OwnerSessionID = raw.OwnerSessionID r.PermissionMode = raw.PermissionMode if raw.PermissionRequest != nil { value, err := unmarshalPermissionRequest(raw.PermissionRequest) diff --git a/go/rpc/zsession_events.go b/go/rpc/zsession_events.go index cef0367976..cde63686ae 100644 --- a/go/rpc/zsession_events.go +++ b/go/rpc/zsession_events.go @@ -487,6 +487,10 @@ type SessionPermissionRecoveryData struct { MaxAttempts int64 `json:"maxAttempts"` // Policy selected from the current client's response capability; mode or client changes may update it during recovery OnBlocked PermissionRecoveryOnBlocked `json:"onBlocked"` + // Subagent identifier that owns this recovery episode when the request was delegated through a parent permission service + OwnerAgentID *string `json:"ownerAgentId,omitempty"` + // Root or child execution-session identifier that owns this recovery episode; omitted for legacy snapshots + OwnerSessionID *string `json:"ownerSessionId,omitempty"` // Controlled reason for the latest episode transition Reason PermissionRecoveryReason `json:"reason"` // Current lifecycle state of the recovery episode @@ -1048,12 +1052,16 @@ type SessionErrorData struct { EligibleForAutoSwitch *bool `json:"eligibleForAutoSwitch,omitempty"` // Fine-grained error code from the upstream provider, when available. For `errorType: "rate_limit"`, this is one of the `RateLimitErrorCode` values (e.g., `"user_weekly_rate_limited"`, `"user_global_rate_limited"`, `"rate_limited"`, `"user_model_rate_limited"`, `"integration_rate_limited"`). For `errorType: "quota"`, this is the CAPI quota error code (e.g., `"quota_exceeded"`, `"session_quota_exceeded"`, `"billing_not_configured"`). ErrorCode *string `json:"errorCode,omitempty"` - // Category of error (e.g., "authentication", "authorization", "quota", "rate_limit", "context_limit", "query") + // Category of error (e.g., "authentication", "authorization", "policy", "quota", "rate_limit", "context_limit", "query") ErrorType string `json:"errorType"` // Human-readable error message Message string `json:"message"` // GitHub request tracing ID (x-github-request-id header) for correlating with server-side logs ProviderCallID *string `json:"providerCallId,omitempty"` + // Sanitized provider-defined error parameter preserved from a structured upstream error envelope, when available. + ProviderErrorParam *string `json:"providerErrorParam,omitempty"` + // Provider-defined error type preserved from a structured upstream error envelope, when available (for example, `invalid_request_error`). + ProviderErrorType *string `json:"providerErrorType,omitempty"` // What the user must do to recover, when the runtime knows of an action. The `message` never names a client affordance, so a client that offers one — a slash command, a settings pane, a link — renders it from this value. Remediation *RemediationAction `json:"remediation,omitempty"` // Copilot service request ID (x-copilot-service-request-id header) for CAPI log correlation @@ -2465,6 +2473,10 @@ func (*PermissionCompletedData) Type() SessionEventType { return SessionEventTyp type PermissionRequestedData struct { // Agent mode captured from the owning turn when permission evaluation began. AgentMode *SessionMode `json:"agentMode,omitempty"` + // Delegated agent that owns permission recovery when the owner session multiplexes remote agents. Absent otherwise. + OwnerAgentID *string `json:"ownerAgentId,omitempty"` + // Execution session that owns permission recovery for this request. Absent on historical events. + OwnerSessionID *string `json:"ownerSessionId,omitempty"` // Permission mode captured when evaluation began. Absent on historical events. PermissionMode *PermissionMode `json:"permissionMode,omitempty"` // Details of the permission being requested @@ -3826,6 +3838,8 @@ type CompactionCompleteCompactionTokensUsed struct { OutputTokens *int64 `json:"outputTokens,omitempty"` // Provider captured for the compaction call; absent when attribution is unknown. Provider *ModelProviderRef `json:"provider,omitempty"` + // Number of model requests represented by this aggregated compaction usage + RequestCount *int64 `json:"requestCount,omitempty"` } // Per-request cost and usage data from the CAPI copilot_usage response field diff --git a/go/types.go b/go/types.go index cdeae3b404..6bf2eb3b5b 100644 --- a/go/types.go +++ b/go/types.go @@ -1252,6 +1252,8 @@ func (c MCPHTTPServerConfig) MarshalJSON() ([]byte, error) { // CustomAgentConfig configures a custom agent. type CustomAgentConfig struct { + // Hooks contains declarative actions keyed by event name, active only for this agent. + Hooks map[string][]map[string]any `json:"hooks,omitempty"` // Name is the unique name of the custom agent Name string `json:"name"` // DisplayName is the display name for UI purposes @@ -1477,6 +1479,13 @@ type SkillProvider interface { type SessionConfig struct { // SessionID is an optional custom session ID SessionID string + // Name names the session at creation, as session.name.set would, and is + // validated the same way: non-empty, no leading or trailing whitespace, at + // most 100 UTF-16 units, no control characters, and no double quotes. A name + // also makes the session persist from the start, so it can be listed and + // resumed without ever running a turn. Local sessions only: cloud creation + // rejects it. + Name string // ClientName identifies the application using the SDK. // Included in the User-Agent header for API requests. ClientName string @@ -1515,9 +1524,9 @@ type SessionConfig struct { // of instruction files (AGENTS.md, .github/copilot-instructions.md, etc.) after // successful file views. EnableOnDemandInstructionDiscovery *bool - // EnableFileHooks, when non-nil, controls loading of file-based hooks from - // .github/hooks/. This is separate from the Hooks callback parameter which - // gates SDK hook event registration. + // EnableFileHooks, when non-nil, controls repository-origin file hooks from + // .github/hooks/ and trusted repository-configured roots. It does not control + // explicit HookDirectories or Hooks callbacks. EnableFileHooks *bool // EnableHostGitOperations, when non-nil, controls git operations on the host // filesystem (branch detection, file status, commit history). When false, no @@ -1670,7 +1679,11 @@ type SessionConfig struct { // Agent is the name of the custom agent to activate when the session starts. // Must match the Name of one of the agents in CustomAgents. Agent string - // SkillDirectories is a list of directories to load skills from + // SkillDirectories contains explicit discovery-only skill roots, not filesystem grants. + // Available without EnableConfigDiscovery, subject to skill/managed disables. + // Relative paths resolve once when supplied against the request's effective WorkingDirectory; + // retained roots do not move on cwd changes. Nil and omission are equivalent; + // an empty non-nil list clears only the explicit SDK contribution. SkillDirectories []string // SkillProvider supplies ephemeral SDK-hosted skills for this session. The // provider is never serialized or persisted; re-supply it when resuming. @@ -1678,13 +1691,29 @@ type SessionConfig struct { // Experimental: this API may change or be removed in future SDK or CLI // releases. Implementations must be safe for concurrent calls. SkillProvider SkillProvider `json:"-"` + // AgentDirectories contains explicit discovery-only agent roots, separate from CustomAgents. + // No filesystem grant. Available without EnableConfigDiscovery, subject to source/managed + // disables. Relative paths resolve once when supplied against the request's effective + // WorkingDirectory; retained roots do not move. Nil and omission are equivalent; + // an empty non-nil list clears only the explicit SDK contribution. + AgentDirectories []string + // HookDirectories contains explicit discovery-only file-hook roots, separate from Hooks callbacks. + // No filesystem grant. Available without EnableConfigDiscovery or EnableFileHooks + // (repository-origin hooks only), subject to hook/managed disables. Relative paths resolve + // once when supplied against the request's effective WorkingDirectory; retained roots do not + // move. Nil and omission are equivalent; an empty non-nil list clears only the explicit SDK contribution. + HookDirectories []string // PluginDirectories is a list of local filesystem paths to Open Plugins-format // directories (https://open-plugins.com/) to load for this session. // Relative paths resolve against WorkingDirectory (or the runtime cwd if unset). // Treated as an explicit opt-in: plugin agents and rules load even when // EnableConfigDiscovery is false. PluginDirectories []string - // InstructionDirectories is a list of additional directories to search for custom instruction files + // InstructionDirectories contains explicit discovery-only instruction roots using existing SDK formats. + // No filesystem grant. Available without EnableConfigDiscovery, subject to instruction/managed + // disables. Relative paths resolve once when supplied against the request's effective + // WorkingDirectory; retained roots do not move. Nil and omission are equivalent; + // an empty non-nil list clears only the explicit SDK contribution. InstructionDirectories []string // DisabledSkills is a list of skill names to disable DisabledSkills []string @@ -2230,9 +2259,9 @@ type ResumeSessionConfig struct { // EnableOnDemandInstructionDiscovery, when non-nil, controls on-demand discovery // of instruction files after successful file views. EnableOnDemandInstructionDiscovery *bool - // EnableFileHooks, when non-nil, controls loading of file-based hooks from - // .github/hooks/. This is separate from the Hooks callback parameter which - // gates SDK hook event registration. + // EnableFileHooks, when non-nil, controls repository-origin file hooks from + // .github/hooks/ and trusted repository-configured roots. It does not control + // explicit HookDirectories or Hooks callbacks. EnableFileHooks *bool // EnableHostGitOperations, when non-nil, controls git operations on the host // filesystem. @@ -2272,7 +2301,11 @@ type ResumeSessionConfig struct { // Agent is the name of the custom agent to activate when the session starts. // Must match the Name of one of the agents in CustomAgents. Agent string - // SkillDirectories is a list of directories to load skills from + // SkillDirectories contains explicit discovery-only skill roots, not filesystem grants. + // Available without EnableConfigDiscovery, subject to skill/managed disables. + // Relative paths resolve once when supplied against the request's effective WorkingDirectory; + // retained roots do not move on cwd changes. Nil and omission are equivalent; + // an empty non-nil list clears only the explicit SDK contribution. SkillDirectories []string // SkillProvider supplies ephemeral SDK-hosted skills for this resumed // session. Re-supply it on every resume; omitting it unbinds any previous @@ -2281,13 +2314,29 @@ type ResumeSessionConfig struct { // Experimental: this API may change or be removed in future SDK or CLI // releases. Implementations must be safe for concurrent calls. SkillProvider SkillProvider `json:"-"` + // AgentDirectories contains explicit discovery-only agent roots, separate from CustomAgents. + // No filesystem grant. Available without EnableConfigDiscovery, subject to source/managed + // disables. Relative paths resolve once when supplied against the request's effective + // WorkingDirectory; retained roots do not move. Nil and omission are equivalent; + // an empty non-nil list clears only the explicit SDK contribution. + AgentDirectories []string + // HookDirectories contains explicit discovery-only file-hook roots, separate from Hooks callbacks. + // No filesystem grant. Available without EnableConfigDiscovery or EnableFileHooks + // (repository-origin hooks only), subject to hook/managed disables. Relative paths resolve + // once when supplied against the request's effective WorkingDirectory; retained roots do not + // move. Nil and omission are equivalent; an empty non-nil list clears only the explicit SDK contribution. + HookDirectories []string // PluginDirectories is a list of local filesystem paths to Open Plugins-format // directories (https://open-plugins.com/) to load for this session. // Relative paths resolve against WorkingDirectory (or the runtime cwd if unset). // Treated as an explicit opt-in: plugin agents and rules load even when // EnableConfigDiscovery is false. PluginDirectories []string - // InstructionDirectories is a list of additional directories to search for custom instruction files + // InstructionDirectories contains explicit discovery-only instruction roots using existing SDK formats. + // No filesystem grant. Available without EnableConfigDiscovery, subject to instruction/managed + // disables. Relative paths resolve once when supplied against the request's effective + // WorkingDirectory; retained roots do not move. Nil and omission are equivalent; + // an empty non-nil list clears only the explicit SDK contribution. InstructionDirectories []string // DisabledSkills is a list of skill names to disable DisabledSkills []string @@ -2853,6 +2902,7 @@ type SessionLifecycleHandler func(event SessionLifecycleEvent) type createSessionRequest struct { Model string `json:"model,omitempty"` SessionID string `json:"sessionId,omitempty"` + Name string `json:"name,omitempty"` ClientName string `json:"clientName,omitempty"` ReasoningEffort string `json:"reasoningEffort,omitempty"` ReasoningSummary ReasoningSummary `json:"reasoningSummary,omitempty"` @@ -2908,9 +2958,11 @@ type createSessionRequest struct { EnableSessionStore *bool `json:"enableSessionStore,omitempty"` EnableSkills *bool `json:"enableSkills,omitempty"` HasSkillProvider *bool `json:"hasSkillProvider,omitempty"` - SkillDirectories []string `json:"skillDirectories,omitempty"` + SkillDirectories []string `json:"skillDirectories,omitzero"` + AgentDirectories []string `json:"agentDirectories,omitzero"` + HookDirectories []string `json:"hookDirectories,omitzero"` PluginDirectories []string `json:"pluginDirectories,omitempty"` - InstructionDirectories []string `json:"instructionDirectories,omitempty"` + InstructionDirectories []string `json:"instructionDirectories,omitzero"` DisabledSkills []string `json:"disabledSkills,omitempty"` DisabledMCPServers *[]string `json:"disabledMcpServers,omitempty"` InfiniteSessions *InfiniteSessionConfig `json:"infiniteSessions,omitempty"` @@ -3015,9 +3067,11 @@ type resumeSessionRequest struct { CustomAgents []CustomAgentConfig `json:"customAgents,omitempty"` DefaultAgent *DefaultAgentConfig `json:"defaultAgent,omitempty"` Agent string `json:"agent,omitempty"` - SkillDirectories []string `json:"skillDirectories,omitempty"` + SkillDirectories []string `json:"skillDirectories,omitzero"` + AgentDirectories []string `json:"agentDirectories,omitzero"` + HookDirectories []string `json:"hookDirectories,omitzero"` PluginDirectories []string `json:"pluginDirectories,omitempty"` - InstructionDirectories []string `json:"instructionDirectories,omitempty"` + InstructionDirectories []string `json:"instructionDirectories,omitzero"` DisabledSkills []string `json:"disabledSkills,omitempty"` DisabledMCPServers *[]string `json:"disabledMcpServers,omitempty"` InfiniteSessions *InfiniteSessionConfig `json:"infiniteSessions,omitempty"` diff --git a/go/zsession_events.go b/go/zsession_events.go index 3755ff6e4d..81bb0f2c25 100644 --- a/go/zsession_events.go +++ b/go/zsession_events.go @@ -955,6 +955,7 @@ const ( RecommendedAutoTierIntelligence = rpc.RecommendedAutoTierIntelligence RemediationActionAllowSandboxOutbound = rpc.RemediationActionAllowSandboxOutbound RemediationActionReviewSandboxPolicy = rpc.RemediationActionReviewSandboxPolicy + RemediationActionRewindConversation = rpc.RemediationActionRewindConversation RemediationActionShowAccount = rpc.RemediationActionShowAccount RemediationActionSignIn = rpc.RemediationActionSignIn RemediationActionSwitchAccount = rpc.RemediationActionSwitchAccount diff --git a/java/README.md b/java/README.md index f8c0605b90..cb4b2d9c12 100644 --- a/java/README.md +++ b/java/README.md @@ -682,6 +682,19 @@ session.setAutoTier(null).get(); `setModel(SetModelOptions)` accepts the same preference through `SetModelOptions.setAutoTier(...)`, which stages the tier atomically with selecting `auto`. Call `setResetAutoTier(true)` instead to return to provider-default routing; the two options are mutually exclusive. +## Reasoning-summary presentation (experimental) + +Read the current model's reasoning-summary policy through `session.getRpc().model.getReasoningSummaries(...)`. Load the model catalog with `session.getRpc().model.list().get()` first, or accept a result with `ready() == false`. + +```java +import com.github.copilot.generated.rpc.SessionModelGetReasoningSummariesParams; + +var presentation = new SessionModelGetReasoningSummariesParams(null, false); +var policy = session.getRpc().model.getReasoningSummaries(presentation).get(); +``` + +The two constructor arguments are the persisted visibility setting (`null` when unset) and whether the host currently shows summaries (`null` defaults to false). The session wrapper supplies the session ID; callers do not need a placeholder ID. The original three-argument constructor remains available. `visibility()` can be `null` while experiment assignment is pending, and `clearRedundantSetting()` tells the host when its persisted setting matches the model default. + ## Session Store `enableSessionStore` on `SessionConfig` enables the cross-session store for search and retrieval across sessions. When unset in the default `CopilotClientMode.COPILOT_CLI` mode, the runtime default applies (enabled). In `CopilotClientMode.EMPTY` mode, defaults to disabled. diff --git a/java/scripts/codegen/java.ts b/java/scripts/codegen/java.ts index 36ebc4a674..eff9e6d2bc 100644 --- a/java/scripts/codegen/java.ts +++ b/java/scripts/codegen/java.ts @@ -2398,6 +2398,9 @@ function validateSharedResultOwners(sections: Record[]): void { } function schemaAllowsNull(schema: JSONSchema7): boolean { + if ((schema as Record)["x-opaque-json"] === true && schema.type === undefined) { + return true; + } if (schema.type === "null" || (Array.isArray(schema.type) && schema.type.includes("null"))) { return true; } @@ -2467,6 +2470,18 @@ export function generateRpcClass( } if (localNestedTypes.size > 0 && lines[lines.length - 1] === "") lines.pop(); + if (className === "SessionModelGetReasoningSummariesParams") { + lines.push(``); + lines.push(` /**`); + lines.push(` * Creates host presentation state; the session-scoped wrapper supplies the session ID.`); + lines.push(` *`); + lines.push(` * @param persistedShowReasoning the persisted visibility setting, or null when unset`); + lines.push(` * @param summariesVisible whether summaries are visible, or null for the default`); + lines.push(` */`); + lines.push(` public ${className}(Boolean persistedShowReasoning, Boolean summariesVisible) {`); + lines.push(` this(null, persistedShowReasoning, summariesVisible);`); + lines.push(` }`); + } const legacyConstructor = className === "McpOauthRequiredStaticClientConfig" ? { @@ -3172,7 +3187,7 @@ function wrapperResultClassName(method: RpcMethodNode): string { return javaResult.javaType; } - // Free-form object with additionalProperties (e.g., x-opaque-json) → JsonNode + // Boolean maps have a typed value contract; free-form JSON remains a JsonNode. if ( result && typeof result === "object" && @@ -3180,6 +3195,9 @@ function wrapperResultClassName(method: RpcMethodNode): string { result.additionalProperties && !result.properties ) { + if (typeof result.additionalProperties === "object" && result.additionalProperties.type === "boolean") { + return "Map"; + } return "JsonNode"; } @@ -3187,6 +3205,9 @@ function wrapperResultClassName(method: RpcMethodNode): string { } function wrapperResultTypeExpression(resultType: string): string { + if (resultType === "Map") { + return "RpcMapper.INSTANCE.getTypeFactory().constructMapType(Map.class, String.class, Boolean.class)"; + } const listMatch = resultType.match(/^List<([^<>]+)>$/); if (listMatch) { return `RpcMapper.INSTANCE.getTypeFactory().constructCollectionType(List.class, ${javaClassLiteral(listMatch[1])})`; @@ -3212,8 +3233,11 @@ function addWrapperResultImports(resultType: string, allImports: Set, pa if (resultType.startsWith("List<")) { allImports.add("java.util.List"); } + if (resultType.startsWith("Map<")) { + allImports.add("java.util.Map"); + } - const builtInTypes = new Set(["Boolean", "Double", "Long", "List", "Object", "String", "Void"]); + const builtInTypes = new Set(["Boolean", "Double", "Long", "List", "Map", "Object", "String", "Void"]); for (const typeName of resultType.match(/\b[A-Z][A-Za-z0-9_]*\b/g) ?? []) { if (!builtInTypes.has(typeName)) { allImports.add(`${packageName}.${typeName}`); diff --git a/java/sdk/pom.xml b/java/sdk/pom.xml index a87f2537ed..bbcaf41d13 100644 --- a/java/sdk/pom.xml +++ b/java/sdk/pom.xml @@ -77,7 +77,7 @@ com.fasterxml.jackson.core jackson-databind - 2.22.2 + 2.22.3 com.fasterxml.jackson.core @@ -87,7 +87,7 @@ com.fasterxml.jackson.datatype jackson-datatype-jsr310 - 2.22.2 + 2.22.3 diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/CompactionCompleteCompactionTokensUsed.java b/java/sdk/src/generated/java/com/github/copilot/generated/CompactionCompleteCompactionTokensUsed.java index c325857e59..cd6f610465 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/CompactionCompleteCompactionTokensUsed.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/CompactionCompleteCompactionTokensUsed.java @@ -21,6 +21,8 @@ @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public record CompactionCompleteCompactionTokensUsed( + /** Number of model requests represented by this aggregated compaction usage */ + @JsonProperty("requestCount") Long requestCount, /** Whether the compaction's credit amount was reported for all, some, or none of its calls. */ @JsonProperty("aiCreditsStatus") AiCreditsStatus aiCreditsStatus, /** Provider captured for the compaction call; absent when attribution is unknown. */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/PermissionRecoveryData.java b/java/sdk/src/generated/java/com/github/copilot/generated/PermissionRecoveryData.java index ed38c3c168..796da04191 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/PermissionRecoveryData.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/PermissionRecoveryData.java @@ -24,6 +24,10 @@ public record PermissionRecoveryData( /** Stable identifier shared by every transition in this recovery episode */ @JsonProperty("episodeId") String episodeId, + /** Root or child execution-session identifier that owns this recovery episode; omitted for legacy snapshots */ + @JsonProperty("ownerSessionId") String ownerSessionId, + /** Subagent identifier that owns this recovery episode when the request was delegated through a parent permission service */ + @JsonProperty("ownerAgentId") String ownerAgentId, /** Current lifecycle state of the recovery episode */ @JsonProperty("status") PermissionRecoveryStatus status, /** Policy selected from the current client's response capability; mode or client changes may update it during recovery */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/PermissionRequestedEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/PermissionRequestedEvent.java index dd18d2af2e..5dbb6300af 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/PermissionRequestedEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/PermissionRequestedEvent.java @@ -44,6 +44,10 @@ public record PermissionRequestedEventData( @JsonProperty("permissionMode") PermissionMode permissionMode, /** Agent mode captured from the owning turn when permission evaluation began. */ @JsonProperty("agentMode") SessionMode agentMode, + /** Execution session that owns permission recovery for this request. Absent on historical events. */ + @JsonProperty("ownerSessionId") String ownerSessionId, + /** Delegated agent that owns permission recovery when the owner session multiplexes remote agents. Absent otherwise. */ + @JsonProperty("ownerAgentId") String ownerAgentId, /** Neutral risk metadata supplied by the tool host. Consumers may display this value but must not use it to bypass the permission decision. */ @JsonProperty("riskAssessment") Object riskAssessment, /** When true, this permission was already resolved by a permissionRequest hook and requires no client action */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/RemediationAction.java b/java/sdk/src/generated/java/com/github/copilot/generated/RemediationAction.java index 5fba9dfc33..f009f516f1 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/RemediationAction.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/RemediationAction.java @@ -25,7 +25,9 @@ public enum RemediationAction { /** The {@code review_sandbox_policy} variant. */ REVIEW_SANDBOX_POLICY("review_sandbox_policy"), /** The {@code allow_sandbox_outbound} variant. */ - ALLOW_SANDBOX_OUTBOUND("allow_sandbox_outbound"); + ALLOW_SANDBOX_OUTBOUND("allow_sandbox_outbound"), + /** The {@code rewind_conversation} variant. */ + REWIND_CONVERSATION("rewind_conversation"); private final String value; RemediationAction(String value) { this.value = value; } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionErrorEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionErrorEvent.java index 3ef32dfd13..9c6af84ab2 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionErrorEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionErrorEvent.java @@ -34,10 +34,14 @@ public final class SessionErrorEvent extends SessionEvent { @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record SessionErrorEventData( - /** Category of error (e.g., "authentication", "authorization", "quota", "rate_limit", "context_limit", "query") */ + /** Category of error (e.g., "authentication", "authorization", "policy", "quota", "rate_limit", "context_limit", "query") */ @JsonProperty("errorType") String errorType, /** Fine-grained error code from the upstream provider, when available. For `errorType: "rate_limit"`, this is one of the `RateLimitErrorCode` values (e.g., `"user_weekly_rate_limited"`, `"user_global_rate_limited"`, `"rate_limited"`, `"user_model_rate_limited"`, `"integration_rate_limited"`). For `errorType: "quota"`, this is the CAPI quota error code (e.g., `"quota_exceeded"`, `"session_quota_exceeded"`, `"billing_not_configured"`). */ @JsonProperty("errorCode") String errorCode, + /** Provider-defined error type preserved from a structured upstream error envelope, when available (for example, `invalid_request_error`). */ + @JsonProperty("providerErrorType") String providerErrorType, + /** Sanitized provider-defined error parameter preserved from a structured upstream error envelope, when available. */ + @JsonProperty("providerErrorParam") String providerErrorParam, /** Only set on `errorType: "rate_limit"`. When `true`, the runtime will follow this error with an `auto_mode_switch.requested` event (or silently switch if `continueOnAutoMode` is enabled). UI clients can use this flag to suppress duplicate rendering of the rate-limit error when they show their own auto-mode-switch prompt. */ @JsonProperty("eligibleForAutoSwitch") Boolean eligibleForAutoSwitch, /** Human-readable error message */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/SessionPermissionRecoveryEvent.java b/java/sdk/src/generated/java/com/github/copilot/generated/SessionPermissionRecoveryEvent.java index 56d08f53b4..262bf4578d 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/SessionPermissionRecoveryEvent.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/SessionPermissionRecoveryEvent.java @@ -37,6 +37,10 @@ public final class SessionPermissionRecoveryEvent extends SessionEvent { public record SessionPermissionRecoveryEventData( /** Stable identifier shared by every transition in this recovery episode */ @JsonProperty("episodeId") String episodeId, + /** Root or child execution-session identifier that owns this recovery episode; omitted for legacy snapshots */ + @JsonProperty("ownerSessionId") String ownerSessionId, + /** Subagent identifier that owns this recovery episode when the request was delegated through a parent permission service */ + @JsonProperty("ownerAgentId") String ownerAgentId, /** Current lifecycle state of the recovery episode */ @JsonProperty("status") PermissionRecoveryStatus status, /** Policy selected from the current client's response capability; mode or client changes may update it during recovery */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountDescribeAuthInfoParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountDescribeAuthInfoParams.java new file mode 100644 index 0000000000..83a49d849a --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountDescribeAuthInfoParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The authentication identity whose shared wording should be rendered. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AccountDescribeAuthInfoParams( + /** Identity to describe. */ + @JsonProperty("identity") AuthIdentity identity +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountDescribeAuthInfoResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountDescribeAuthInfoResult.java new file mode 100644 index 0000000000..8fcc083bbb --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountDescribeAuthInfoResult.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The wording the runtime uses for an authentication identity. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AccountDescribeAuthInfoResult( + /** Sign-in banner announcing the authenticated user. */ + @JsonProperty("message") String message, + /** One-line description of the identity, suitable after a verb such as "Switched to". */ + @JsonProperty("description") String description +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetGistSupportParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetGistSupportParams.java new file mode 100644 index 0000000000..76c1a53037 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetGistSupportParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The authentication identity whose gist support should be reported. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AccountGetGistSupportParams( + /** Identity to evaluate. */ + @JsonProperty("identity") AuthIdentity identity +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetGistSupportResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetGistSupportResult.java new file mode 100644 index 0000000000..03862487a0 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetGistSupportResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Whether the identity can create gists, and why not when it cannot. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AccountGetGistSupportResult( + /** True when the identity can create gists. */ + @JsonProperty("supported") Boolean supported, + /** Machine-readable reason category when unsupported. */ + @JsonProperty("kind") String kind, + /** Human-readable explanation to show where the gist action would have been. */ + @JsonProperty("reason") String reason +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetTokenEnvVarResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetTokenEnvVarResult.java new file mode 100644 index 0000000000..5e7c2aacf5 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetTokenEnvVarResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The environment variable supplying a classic personal access token, when one is set. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AccountGetTokenEnvVarResult( + /** Variable name, for example `GH_TOKEN`. Absent when no classic token is present in the environment. */ + @JsonProperty("name") String name +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetWebUrlParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetWebUrlParams.java new file mode 100644 index 0000000000..7b4c7686c4 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetWebUrlParams.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * A path to resolve against the GitHub host an identity is signed in to. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AccountGetWebUrlParams( + /** Host-relative path, without a leading slash, for example `settings/copilot/features`. */ + @JsonProperty("path") String path, + /** Identity whose host the path resolves against. Omit to resolve against the public github.com host. */ + @JsonProperty("identity") AuthIdentity identity +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetWebUrlResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetWebUrlResult.java new file mode 100644 index 0000000000..5aa680cacd --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AccountGetWebUrlResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * An absolute URL on the identity's GitHub host. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record AccountGetWebUrlResult( + /** Absolute URL for the requested path. */ + @JsonProperty("url") String url +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentInfo.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentInfo.java index 27fd56a428..17debc1a4c 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentInfo.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentInfo.java @@ -54,6 +54,8 @@ public record AgentInfo( /** Skill names preloaded into this agent's context. Omitted means none. */ @JsonProperty("skills") List skills, /** Authored base prompt for the agent. Runtime prompt assembly may add dynamic context at invocation time. Omitted from `session.agent.list` unless `includePrompt` is true. */ - @JsonProperty("prompt") String prompt + @JsonProperty("prompt") String prompt, + /** Declarative hook actions keyed by event name, executed only while this agent is active. */ + @JsonProperty("hooks") Map> hooks ) { } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsDiscoverRequest.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsDiscoverRequest.java new file mode 100644 index 0000000000..26ead3977a --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsDiscoverRequest.java @@ -0,0 +1,107 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import java.util.Objects; +import javax.annotation.processing.Generated; + +/** + * Optional project paths to include in agent discovery. + *

+ * Required inputs are constructor arguments. Optional inputs have fluent setters. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +public final class AgentsDiscoverRequest { + + /** Optional list of project directory paths to scan for project-scoped agents. When omitted or empty, only user/plugin/remote-independent agents are returned (no project scan). */ + @JsonProperty("projectPaths") + private List projectPaths; + + /** When true, omit the host's agents (the user-level agent directory and all plugin agents), leaving only project and remote agents. For multitenant deployments. */ + @JsonProperty("excludeHostAgents") + private Boolean excludeHostAgents; + + /** Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without ambient discovery, subject to managed/source disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. */ + @JsonProperty("agentDirectories") + private List agentDirectories; + + /** + * Creates a request with its required inputs. + */ + public AgentsDiscoverRequest() { + } + + /** + * Returns the {@code projectPaths} property. + * + * @return Optional list of project directory paths to scan for project-scoped agents. When omitted or empty, only user/plugin/remote-independent agents are returned (no project scan). + */ + public List getProjectPaths() { + return projectPaths; + } + + /** + * Returns the {@code excludeHostAgents} property. + * + * @return When true, omit the host's agents (the user-level agent directory and all plugin agents), leaving only project and remote agents. For multitenant deployments. + */ + public Boolean getExcludeHostAgents() { + return excludeHostAgents; + } + + /** + * Returns the {@code agentDirectories} property. + * + * @return Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without ambient discovery, subject to managed/source disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + */ + public List getAgentDirectories() { + return agentDirectories; + } + + /** + * Sets the {@code projectPaths} property. + * + * @param value Optional list of project directory paths to scan for project-scoped agents. When omitted or empty, only user/plugin/remote-independent agents are returned (no project scan). + * @return this request + */ + public AgentsDiscoverRequest setProjectPaths(List value) { + this.projectPaths = value; + return this; + } + + /** + * Sets the {@code excludeHostAgents} property. + * + * @param value When true, omit the host's agents (the user-level agent directory and all plugin agents), leaving only project and remote agents. For multitenant deployments. + * @return this request + */ + public AgentsDiscoverRequest setExcludeHostAgents(Boolean value) { + this.excludeHostAgents = value; + return this; + } + + /** + * Sets the {@code agentDirectories} property. + * + * @param value Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without ambient discovery, subject to managed/source disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + * @return this request + */ + public AgentsDiscoverRequest setAgentDirectories(List value) { + this.agentDirectories = value; + return this; + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetDiscoveryPathsRequest.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetDiscoveryPathsRequest.java new file mode 100644 index 0000000000..fe9123f9ba --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/AgentsGetDiscoveryPathsRequest.java @@ -0,0 +1,107 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import java.util.Objects; +import javax.annotation.processing.Generated; + +/** + * Optional project paths to include when enumerating agent discovery directories. + *

+ * Required inputs are constructor arguments. Optional inputs have fluent setters. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +public final class AgentsGetDiscoveryPathsRequest { + + /** Optional list of project directory paths. When omitted or empty, only the user-level directory is returned. */ + @JsonProperty("projectPaths") + private List projectPaths; + + /** When true, omit the host's user-level agent directory, leaving only project directories. For multitenant deployments (mirrors `discover`'s `excludeHostAgents`). */ + @JsonProperty("excludeHostAgents") + private Boolean excludeHostAgents; + + /** Explicit discovery-only agent roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. */ + @JsonProperty("agentDirectories") + private List agentDirectories; + + /** + * Creates a request with its required inputs. + */ + public AgentsGetDiscoveryPathsRequest() { + } + + /** + * Returns the {@code projectPaths} property. + * + * @return Optional list of project directory paths. When omitted or empty, only the user-level directory is returned. + */ + public List getProjectPaths() { + return projectPaths; + } + + /** + * Returns the {@code excludeHostAgents} property. + * + * @return When true, omit the host's user-level agent directory, leaving only project directories. For multitenant deployments (mirrors `discover`'s `excludeHostAgents`). + */ + public Boolean getExcludeHostAgents() { + return excludeHostAgents; + } + + /** + * Returns the {@code agentDirectories} property. + * + * @return Explicit discovery-only agent roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + */ + public List getAgentDirectories() { + return agentDirectories; + } + + /** + * Sets the {@code projectPaths} property. + * + * @param value Optional list of project directory paths. When omitted or empty, only the user-level directory is returned. + * @return this request + */ + public AgentsGetDiscoveryPathsRequest setProjectPaths(List value) { + this.projectPaths = value; + return this; + } + + /** + * Sets the {@code excludeHostAgents} property. + * + * @param value When true, omit the host's user-level agent directory, leaving only project directories. For multitenant deployments (mirrors `discover`'s `excludeHostAgents`). + * @return this request + */ + public AgentsGetDiscoveryPathsRequest setExcludeHostAgents(Boolean value) { + this.excludeHostAgents = value; + return this; + } + + /** + * Sets the {@code agentDirectories} property. + * + * @param value Explicit discovery-only agent roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + * @return this request + */ + public AgentsGetDiscoveryPathsRequest setAgentDirectories(List value) { + this.agentDirectories = value; + return this; + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagAvailability.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagAvailability.java new file mode 100644 index 0000000000..953a52226c --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagAvailability.java @@ -0,0 +1,49 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * The population a feature flag is declared for, before overrides. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum FeatureFlagAvailability { + /** The {@code on} variant. */ + ON("on"), + /** The {@code team} variant. */ + TEAM("team"), + /** The {@code staff-and-experimental} variant. */ + STAFF_AND_EXPERIMENTAL("staff-and-experimental"), + /** The {@code staff-or-experimental} variant. */ + STAFF_OR_EXPERIMENTAL("staff-or-experimental"), + /** The {@code staff} variant. */ + STAFF("staff"), + /** The {@code staff-github} variant. */ + STAFF_GITHUB("staff-github"), + /** The {@code staff-microsoft} variant. */ + STAFF_MICROSOFT("staff-microsoft"), + /** The {@code experimental} variant. */ + EXPERIMENTAL("experimental"), + /** The {@code off} variant. */ + OFF("off"); + + private final String value; + FeatureFlagAvailability(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static FeatureFlagAvailability fromValue(String value) { + for (FeatureFlagAvailability v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown FeatureFlagAvailability value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagMetadata.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagMetadata.java new file mode 100644 index 0000000000..49ac33f82f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagMetadata.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The declared shape of one feature flag, independent of any caller population. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record FeatureFlagMetadata( + /** The flag's name, matching the key it is listed under. */ + @JsonProperty("name") String name, + /** The population the flag is declared for before any environment or user-settings override is applied. */ + @JsonProperty("availability") FeatureFlagAvailability availability, + /** Whether the flag participates in the CAPI sanity suite. */ + @JsonProperty("capiSanity") Boolean capiSanity, + /** Text shown to a user choosing whether to turn the flag on in experimental mode. Absent when the flag is not user-facing. */ + @JsonProperty("experimentalDescription") String experimentalDescription, + /** The online-experiment (ExP) flag this maps to, when the flag is assigned by an experiment rather than declared statically. */ + @JsonProperty("expFlag") String expFlag, + /** Environment variable that overrides this flag's experiment assignment locally in the experiment service, not in `featureFlags.resolve`. Present exactly when `expFlag` is, and derived from it, so a caller reads a local override without reproducing the naming rule. */ + @JsonProperty("expFlagEnvVar") String expFlagEnvVar +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagsMetadataResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagsMetadataResult.java new file mode 100644 index 0000000000..01e738c670 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagsMetadataResult.java @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * Every feature flag this runtime declares, with the shape each one was declared with. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record FeatureFlagsMetadataResult( + /** Declared feature flags keyed by flag name. */ + @JsonProperty("flags") Map flags +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagsResolveParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagsResolveParams.java new file mode 100644 index 0000000000..bf459ff033 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagsResolveParams.java @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * Caller population and overrides for static feature-flag resolution, independent of experiment assignments and active runtime state. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record FeatureFlagsResolveParams( + /** Whether the caller is GitHub or Microsoft staff. */ + @JsonProperty("isStaff") Boolean isStaff, + /** Whether the caller is in an experimental population. */ + @JsonProperty("isExperimental") Boolean isExperimental, + /** Whether the caller belongs to the team population used by feature availability. */ + @JsonProperty("isTeam") Boolean isTeam, + /** GitHub-staff membership. Omit when it was never recorded: a legacy staff account then counts as both staff populations and keeps every staff feature. */ + @JsonProperty("isStaffGithub") Boolean isStaffGitHub, + /** Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. */ + @JsonProperty("isStaffMicrosoft") Boolean isStaffMicrosoft, + /** Resolve against this already-computed flag set rather than each flag's declared availability. Keyed by flag name. */ + @JsonProperty("baseFlags") Map baseFlags, + /** Environment for direct feature-flag overrides and `COPILOT_CLI_ENABLED_FEATURE_FLAGS`. Does not apply `COPILOT_EXP_*` experiment assignments. Defaults to this runtime process's own environment. */ + @JsonProperty("environment") Map environment, + /** User settings to apply, including `enabledFeatureFlags`, legacy `feature_flags.enabled`, and supported convenience settings. */ + @JsonProperty("config") Object config, + /** Flags forced to a value after every other layer, keyed by flag name. */ + @JsonProperty("flagOverrides") Map flagOverrides +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubOwnersListParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubOwnersListParams.java index 224b85f6dc..fd1489b805 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubOwnersListParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/GitHubOwnersListParams.java @@ -27,6 +27,7 @@ record GitHubOwnersListParams( /** Request id from `gitHubOwners.nextRequestId`. An id that was never registered, canceled before use, released after being abandoned, or already used is refused rather than silently running uncancellable. */ @JsonProperty("requestId") Long requestId, /** The credential the listing runs under, carried opaquely because its shape is the host's own and the runtime only resolves a token and a GitHub host from it. No credential travels: this selects one the runtime already holds. */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("authInfo") Object authInfo ) { } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HooksDiscoverRequest.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HooksDiscoverRequest.java new file mode 100644 index 0000000000..5d76a6d222 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/HooksDiscoverRequest.java @@ -0,0 +1,107 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import java.util.Objects; +import javax.annotation.processing.Generated; + +/** + * Optional project paths and host-exclusion behavior for server-scoped hook discovery. + *

+ * Required inputs are constructor arguments. Optional inputs have fluent setters. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +public final class HooksDiscoverRequest { + + /** Optional project directory paths whose trusted repository and project-expanded plugin hooks should be discovered. When omitted or empty, user, managed-policy, and globally enabled installed or explicit plugin hooks are returned without project expansion. */ + @JsonProperty("projectPaths") + private List projectPaths; + + /** When true, omit host-owned user and plugin hook rows and their diagnostics. Managed-policy hooks and trusted repository hooks remain visible, and host disabledHooks still contribute to each remaining row's effective enabled state. This filters sources rather than simulating a host with no settings. */ + @JsonProperty("excludeHostHooks") + private Boolean excludeHostHooks; + + /** Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without ambient discovery or repository file-hook enablement, subject to managed/hook disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. */ + @JsonProperty("hookDirectories") + private List hookDirectories; + + /** + * Creates a request with its required inputs. + */ + public HooksDiscoverRequest() { + } + + /** + * Returns the {@code projectPaths} property. + * + * @return Optional project directory paths whose trusted repository and project-expanded plugin hooks should be discovered. When omitted or empty, user, managed-policy, and globally enabled installed or explicit plugin hooks are returned without project expansion. + */ + public List getProjectPaths() { + return projectPaths; + } + + /** + * Returns the {@code excludeHostHooks} property. + * + * @return When true, omit host-owned user and plugin hook rows and their diagnostics. Managed-policy hooks and trusted repository hooks remain visible, and host disabledHooks still contribute to each remaining row's effective enabled state. This filters sources rather than simulating a host with no settings. + */ + public Boolean getExcludeHostHooks() { + return excludeHostHooks; + } + + /** + * Returns the {@code hookDirectories} property. + * + * @return Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without ambient discovery or repository file-hook enablement, subject to managed/hook disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + */ + public List getHookDirectories() { + return hookDirectories; + } + + /** + * Sets the {@code projectPaths} property. + * + * @param value Optional project directory paths whose trusted repository and project-expanded plugin hooks should be discovered. When omitted or empty, user, managed-policy, and globally enabled installed or explicit plugin hooks are returned without project expansion. + * @return this request + */ + public HooksDiscoverRequest setProjectPaths(List value) { + this.projectPaths = value; + return this; + } + + /** + * Sets the {@code excludeHostHooks} property. + * + * @param value When true, omit host-owned user and plugin hook rows and their diagnostics. Managed-policy hooks and trusted repository hooks remain visible, and host disabledHooks still contribute to each remaining row's effective enabled state. This filters sources rather than simulating a host with no settings. + * @return this request + */ + public HooksDiscoverRequest setExcludeHostHooks(Boolean value) { + this.excludeHostHooks = value; + return this; + } + + /** + * Sets the {@code hookDirectories} property. + * + * @param value Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without ambient discovery or repository file-hook enablement, subject to managed/hook disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + * @return this request + */ + public HooksDiscoverRequest setHookDirectories(List value) { + this.hookDirectories = value; + return this; + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsDiscoverRepoSourcesParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsDiscoverRepoSourcesParams.java new file mode 100644 index 0000000000..5aee113bf8 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsDiscoverRepoSourcesParams.java @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Explicit discovery arguments for one location, supplied by the caller rather than derived from a session. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record InstructionsDiscoverRepoSourcesParams( + /** Repository location to discover. An empty string selects no repository scope; cwdPath can still supply working-directory sources. */ + @JsonProperty("location") String location, + /** When true, include the sources a command-line host reads. Hosts that are not the CLI omit it. */ + @JsonProperty("isCli") Boolean isCli, + /** Working directory whose instruction sources should also be included. Omission adds no separate working-directory scope. */ + @JsonProperty("cwdPath") String cwdPath, + /** Copilot configuration directory for user-level sources. An omitted or empty value uses the server's configuration home. */ + @JsonProperty("configDir") String configDir, + /** Extra directories to scan alongside instruction directories configured in the runtime environment. */ + @JsonProperty("additionalDirs") List additionalDirs, + /** When true, also discover instruction files nested below the location. */ + @JsonProperty("enableChildInstructions") Boolean enableChildInstructions +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsDiscoverRequest.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsDiscoverRequest.java new file mode 100644 index 0000000000..34175da41b --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsDiscoverRequest.java @@ -0,0 +1,107 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import java.util.Objects; +import javax.annotation.processing.Generated; + +/** + * Optional project paths to include in instruction discovery. + *

+ * Required inputs are constructor arguments. Optional inputs have fluent setters. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +public final class InstructionsDiscoverRequest { + + /** Optional list of project directory paths to scan for repository/working-directory instruction sources. When omitted or empty, only user-level and plugin instruction sources are returned (no project scan). */ + @JsonProperty("projectPaths") + private List projectPaths; + + /** When true, omit the host's instruction sources (user/home-level files and plugin rules), leaving only repository and working-directory sources. For multitenant deployments. */ + @JsonProperty("excludeHostInstructions") + private Boolean excludeHostInstructions; + + /** Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without ambient discovery, subject to instruction/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. */ + @JsonProperty("instructionDirectories") + private List instructionDirectories; + + /** + * Creates a request with its required inputs. + */ + public InstructionsDiscoverRequest() { + } + + /** + * Returns the {@code projectPaths} property. + * + * @return Optional list of project directory paths to scan for repository/working-directory instruction sources. When omitted or empty, only user-level and plugin instruction sources are returned (no project scan). + */ + public List getProjectPaths() { + return projectPaths; + } + + /** + * Returns the {@code excludeHostInstructions} property. + * + * @return When true, omit the host's instruction sources (user/home-level files and plugin rules), leaving only repository and working-directory sources. For multitenant deployments. + */ + public Boolean getExcludeHostInstructions() { + return excludeHostInstructions; + } + + /** + * Returns the {@code instructionDirectories} property. + * + * @return Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without ambient discovery, subject to instruction/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + */ + public List getInstructionDirectories() { + return instructionDirectories; + } + + /** + * Sets the {@code projectPaths} property. + * + * @param value Optional list of project directory paths to scan for repository/working-directory instruction sources. When omitted or empty, only user-level and plugin instruction sources are returned (no project scan). + * @return this request + */ + public InstructionsDiscoverRequest setProjectPaths(List value) { + this.projectPaths = value; + return this; + } + + /** + * Sets the {@code excludeHostInstructions} property. + * + * @param value When true, omit the host's instruction sources (user/home-level files and plugin rules), leaving only repository and working-directory sources. For multitenant deployments. + * @return this request + */ + public InstructionsDiscoverRequest setExcludeHostInstructions(Boolean value) { + this.excludeHostInstructions = value; + return this; + } + + /** + * Sets the {@code instructionDirectories} property. + * + * @param value Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without ambient discovery, subject to instruction/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + * @return this request + */ + public InstructionsDiscoverRequest setInstructionDirectories(List value) { + this.instructionDirectories = value; + return this; + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsGetDiscoveryPathsRequest.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsGetDiscoveryPathsRequest.java new file mode 100644 index 0000000000..fc328be97e --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsGetDiscoveryPathsRequest.java @@ -0,0 +1,107 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import java.util.Objects; +import javax.annotation.processing.Generated; + +/** + * Optional project paths to include when enumerating instruction discovery targets. + *

+ * Required inputs are constructor arguments. Optional inputs have fluent setters. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +public final class InstructionsGetDiscoveryPathsRequest { + + /** Optional list of project directory paths. When omitted or empty, only the user-level targets are returned. */ + @JsonProperty("projectPaths") + private List projectPaths; + + /** When true, omit the host's user-level instruction targets, leaving only repository targets. For multitenant deployments (mirrors `discover`'s `excludeHostInstructions`). */ + @JsonProperty("excludeHostInstructions") + private Boolean excludeHostInstructions; + + /** Explicit discovery-only instruction roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. */ + @JsonProperty("instructionDirectories") + private List instructionDirectories; + + /** + * Creates a request with its required inputs. + */ + public InstructionsGetDiscoveryPathsRequest() { + } + + /** + * Returns the {@code projectPaths} property. + * + * @return Optional list of project directory paths. When omitted or empty, only the user-level targets are returned. + */ + public List getProjectPaths() { + return projectPaths; + } + + /** + * Returns the {@code excludeHostInstructions} property. + * + * @return When true, omit the host's user-level instruction targets, leaving only repository targets. For multitenant deployments (mirrors `discover`'s `excludeHostInstructions`). + */ + public Boolean getExcludeHostInstructions() { + return excludeHostInstructions; + } + + /** + * Returns the {@code instructionDirectories} property. + * + * @return Explicit discovery-only instruction roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + */ + public List getInstructionDirectories() { + return instructionDirectories; + } + + /** + * Sets the {@code projectPaths} property. + * + * @param value Optional list of project directory paths. When omitted or empty, only the user-level targets are returned. + * @return this request + */ + public InstructionsGetDiscoveryPathsRequest setProjectPaths(List value) { + this.projectPaths = value; + return this; + } + + /** + * Sets the {@code excludeHostInstructions} property. + * + * @param value When true, omit the host's user-level instruction targets, leaving only repository targets. For multitenant deployments (mirrors `discover`'s `excludeHostInstructions`). + * @return this request + */ + public InstructionsGetDiscoveryPathsRequest setExcludeHostInstructions(Boolean value) { + this.excludeHostInstructions = value; + return this; + } + + /** + * Sets the {@code instructionDirectories} property. + * + * @param value Explicit discovery-only instruction roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + * @return this request + */ + public InstructionsGetDiscoveryPathsRequest setInstructionDirectories(List value) { + this.instructionDirectories = value; + return this; + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsInitPromptResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsInitPromptResult.java new file mode 100644 index 0000000000..20eb197498 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/InstructionsInitPromptResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The prompt the init command runs. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record InstructionsInitPromptResult( + /** Prompt text authoring repository instructions. */ + @JsonProperty("prompt") String prompt +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsValidateParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsValidateParams.java index 32879f689c..40a4e02992 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsValidateParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsValidateParams.java @@ -25,6 +25,7 @@ @JsonIgnoreProperties(ignoreUnknown = true) public record ManagedSettingsValidateParams( /** The document to validate: a JSON object, or a string containing the document's JSON text. Preview documents are limited to 1 MiB and 64 levels of nesting, a stricter resource limit than delivered-policy parsing; violations are returned as diagnostics. */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("content") Object content, /** Channel the document is meant for (`device`, `server`, or `policyHelper`). Some keys are only honored in some channels; for example, a `policyHelper` registration is ignored in policy-helper output. When omitted, no channel-specific checks run. */ @JsonProperty("layer") String layer diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpListBuiltinServerNamesResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpListBuiltinServerNamesResult.java new file mode 100644 index 0000000000..2a65a679d9 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpListBuiltinServerNamesResult.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Names of the MCP servers the runtime supplies itself. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record McpListBuiltinServerNamesResult( + /** Every built-in server name. A host disabling the built-ins wholesale suppresses exactly this set. */ + @JsonProperty("names") List names +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistrySearchParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistrySearchParams.java index e222f69adc..11a06de374 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistrySearchParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/McpRegistrySearchParams.java @@ -27,6 +27,7 @@ record McpRegistrySearchParams( /** Request ID from `mcp.registry.allocateRequestId`. The search refuses unknown, reclaimed, or canceled IDs and IDs that another search or request already uses. */ @JsonProperty("requestId") Long requestId, /** The credential the search runs under, carried opaquely. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("authInfo") Object authInfo, /** Free-text query. Omitted or empty asks the registry for its top servers rather than searching. A value that is not a string is refused. */ @JsonProperty("query") String query, diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionRecoveryData.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionRecoveryData.java index e4c502116d..990349ebaf 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionRecoveryData.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionRecoveryData.java @@ -24,6 +24,10 @@ public record PermissionRecoveryData( /** Stable identifier shared by every transition in this recovery episode */ @JsonProperty("episodeId") String episodeId, + /** Root or child execution-session identifier that owns this recovery episode; omitted for legacy snapshots */ + @JsonProperty("ownerSessionId") String ownerSessionId, + /** Subagent identifier that owns this recovery episode when the request was delegated through a parent permission service */ + @JsonProperty("ownerAgentId") String ownerAgentId, /** Current lifecycle state of the recovery episode */ @JsonProperty("status") PermissionRecoveryStatus status, /** Policy selected from the current client's response capability; mode or client changes may update it during recovery */ diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RemediationAction.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RemediationAction.java index 50f6256352..2da0b13624 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RemediationAction.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RemediationAction.java @@ -25,7 +25,9 @@ public enum RemediationAction { /** The {@code review_sandbox_policy} variant. */ REVIEW_SANDBOX_POLICY("review_sandbox_policy"), /** The {@code allow_sandbox_outbound} variant. */ - ALLOW_SANDBOX_OUTBOUND("allow_sandbox_outbound"); + ALLOW_SANDBOX_OUTBOUND("allow_sandbox_outbound"), + /** The {@code rewind_conversation} variant. */ + REWIND_CONVERSATION("rewind_conversation"); private final String value; RemediationAction(String value) { this.value = value; } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsReadRawParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsReadRawParams.java new file mode 100644 index 0000000000..40d25ea68c --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsReadRawParams.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Which repository settings file to read. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record RepoSettingsReadRawParams( + /** Absolute path of the repository root. */ + @JsonProperty("repoRoot") String repoRoot, + /** Use repo for shared settings or local for settings.local.json. Other scopes are rejected. */ + @JsonProperty("scope") String scope +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsReadRawResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsReadRawResult.java new file mode 100644 index 0000000000..65d5884033 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsReadRawResult.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Parsed repository settings without normalization or layering. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record RepoSettingsReadRawResult( + /** Stored JSON values after the existing JSONC parser and prototype-safety checks. Empty when the file is missing, blank, or invalid. */ + @JsonProperty("config") Object config, + /** True when the file exists but did not parse, so `config` is empty for that reason rather than because nothing is set. */ + @JsonProperty("invalid") Boolean invalid +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsWriteAllParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsWriteAllParams.java new file mode 100644 index 0000000000..8b94ff9be4 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsWriteAllParams.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The complete set of repository-overridable settings to store. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record RepoSettingsWriteAllParams( + /** Absolute path of the repository root. */ + @JsonProperty("repoRoot") String repoRoot, + /** Use repo for shared settings or local for settings.local.json. Other scopes are rejected. */ + @JsonProperty("scope") String scope, + /** Object of allowed settings to store. Missing allowlisted keys are removed. Other input keys are ignored, while unknown stored keys are preserved. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("settings") Object settings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsWriteKeyParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsWriteKeyParams.java new file mode 100644 index 0000000000..24bc205bc3 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsWriteKeyParams.java @@ -0,0 +1,38 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * One key to write or remove in a repository settings file. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record RepoSettingsWriteKeyParams( + /** Absolute path of the repository root. */ + @JsonProperty("repoRoot") String repoRoot, + /** Use repo for shared settings or local for settings.local.json. Other scopes are rejected. */ + @JsonProperty("scope") String scope, + /** Canonical top-level key permitted by the repository settings allowlist. */ + @JsonProperty("key") String key, + /** Value to validate and write. Required unless delete is true; a null value is validated, not treated as deletion. */ + @JsonProperty("value") Object value, + /** True to remove the key instead of writing it. */ + @JsonProperty("delete") Boolean delete +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerAccountApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerAccountApi.java index 714ef4ebb6..8c25672e33 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerAccountApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerAccountApi.java @@ -95,4 +95,48 @@ public CompletableFuture logout(AccountLogoutParams params) return caller.invoke("account.logout", params, AccountLogoutResult.class); } + /** + * Renders the sign-in banner and the one-line account description the runtime uses for an authentication identity. The runtime words these in several places for its own callers, so a host that announces a sign-in or an account switch should render them from here rather than composing its own, which would let the two spellings drift apart. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture describeAuthInfo(AccountDescribeAuthInfoParams params) { + return caller.invoke("account.describeAuthInfo", params, AccountDescribeAuthInfoResult.class); + } + + /** + * Reports whether the supplied identity can create gists. Gists are unavailable on GitHub Enterprise Cloud with data residency, and to Enterprise Managed Users on github.com, so a host that offers gist actions should hide or disable them when this reports no support. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getGistSupport(AccountGetGistSupportParams params) { + return caller.invoke("account.getGistSupport", params, AccountGetGistSupportResult.class); + } + + /** + * Resolves a path on the identity's GitHub host into an absolute URL, so a host can link to settings or documentation on the enterprise instance the user is signed in to rather than to github.com. Falls back to the public host when no identity is supplied. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getWebUrl(AccountGetWebUrlParams params) { + return caller.invoke("account.getWebUrl", params, AccountGetWebUrlResult.class); + } + + /** + * Names the environment variable supplying a classic personal access token, if one is set. A classic token cannot be upgraded in place, so a host that finds one should tell the user which variable to unset rather than starting an interactive sign-in that the variable would override. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getTokenEnvVar() { + return caller.invoke("account.getTokenEnvVar", java.util.Map.of(), AccountGetTokenEnvVarResult.class); + } + } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerAgentsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerAgentsApi.java index ddff436555..287c099c93 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerAgentsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerAgentsApi.java @@ -8,6 +8,7 @@ package com.github.copilot.generated.rpc; import com.github.copilot.CopilotExperimental; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import javax.annotation.processing.Generated; @@ -37,6 +38,19 @@ public CompletableFuture discover(AgentsDiscoverParams par return caller.invoke("agents.discover", params, AgentsDiscoverResult.class); } + /** + * Discovers custom agents across user, project, plugin, and remote sources. + *

+ * Accepts the extensible request, including inputs added after the params record. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture discover(AgentsDiscoverRequest request) { + return caller.invoke("agents.discover", Objects.requireNonNull(request, "request"), AgentsDiscoverResult.class); + } + /** * Returns the canonical directories where a client may create custom agents that the runtime will recognize, including ones that do not exist yet. Project directories become active once created. * @@ -48,6 +62,19 @@ public CompletableFuture getDiscoveryPaths(Agents return caller.invoke("agents.getDiscoveryPaths", params, AgentsGetDiscoveryPathsResult.class); } + /** + * Returns the canonical directories where a client may create custom agents that the runtime will recognize, including ones that do not exist yet. Project directories become active once created. + *

+ * Accepts the extensible request, including inputs added after the params record. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture getDiscoveryPaths(AgentsGetDiscoveryPathsRequest request) { + return caller.invoke("agents.getDiscoveryPaths", Objects.requireNonNull(request, "request"), AgentsGetDiscoveryPathsResult.class); + } + /** * Lists the agents this runtime ships, by name. A consumer separating shipped agents from ones the user or a plugin authored should compare against these names rather than against `AgentInfo.source`: an authored agent may carry the `builtin` source while not being one of these, and the runtime treats the two as separate questions. `disableableNames` is the subset a user may turn off, which a client needs to decide whether to offer a toggle. `yamlBasedNames` is the subset backed by a shipped YAML definition, which a client needs before asking the runtime to load one. * diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerFeatureFlagsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerFeatureFlagsApi.java new file mode 100644 index 0000000000..83c807baa6 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerFeatureFlagsApi.java @@ -0,0 +1,52 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code featureFlags} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerFeatureFlagsApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerFeatureFlagsApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Lists every feature flag this runtime declares, with the population each one is declared for, its experimental description, and the online-experiment flag it maps to. This is the static catalog: it describes how each flag is defined, not whether it is on for anyone. Use `featureFlags.resolve` for static values with caller overrides, not active runtime values or experiment assignments. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture listMetadata() { + return caller.invoke("featureFlags.listMetadata", java.util.Map.of(), FeatureFlagsMetadataResult.class); + } + + /** + * Computes static feature flags from the supplied population and overrides without changing runtime state or verifying audience membership. Starts from declared availability, then applies direct feature-flag environment values, user settings, and explicit `flagOverrides`. It does not apply `COPILOT_EXP_*` experiment assignments, authenticated startup gates, or active runtime state. Settings include `enabledFeatureFlags`, the legacy `feature_flags.enabled` list, and supported convenience settings. Supply `baseFlags` to use an existing flag set instead of declared availability. Omit `isStaffGitHub` or `isStaffMicrosoft` when membership was never recorded: a legacy staff account then counts as both populations. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture> resolve(FeatureFlagsResolveParams params) { + return caller.invoke("featureFlags.resolve", params, RpcMapper.INSTANCE.getTypeFactory().constructMapType(Map.class, String.class, Boolean.class)); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerHooksApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerHooksApi.java index f41fbd63ac..0997c6588f 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerHooksApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerHooksApi.java @@ -8,6 +8,7 @@ package com.github.copilot.generated.rpc; import com.github.copilot.CopilotExperimental; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import javax.annotation.processing.Generated; @@ -37,4 +38,17 @@ public CompletableFuture discover(HooksDiscoverParams param return caller.invoke("hooks.discover", params, HooksDiscoverResult.class); } + /** + * Discovers hook actions enabled under server-side discovery settings from user, repository, plugin, and managed-policy sources. + *

+ * Accepts the extensible request, including inputs added after the params record. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture discover(HooksDiscoverRequest request) { + return caller.invoke("hooks.discover", Objects.requireNonNull(request, "request"), HooksDiscoverResult.class); + } + } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerInstructionSourceList.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerInstructionSourceList.java new file mode 100644 index 0000000000..cddf0f9f88 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerInstructionSourceList.java @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Instruction sources discovered across user, repository, and plugin sources. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record ServerInstructionSourceList( + /** All discovered instruction sources */ + @JsonProperty("sources") List sources +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerInstructionsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerInstructionsApi.java index 23d8c7e2de..55298f8c4a 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerInstructionsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerInstructionsApi.java @@ -8,6 +8,7 @@ package com.github.copilot.generated.rpc; import com.github.copilot.CopilotExperimental; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import javax.annotation.processing.Generated; @@ -26,6 +27,17 @@ public final class ServerInstructionsApi { this.caller = caller; } + /** + * Returns the prompt the `init` command runs to author repository instructions. A host offering its own initialize action sends this text so the instructions it produces match the ones the CLI produces. The text is fixed for a build and depends on no configuration, session or repository. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getInitPrompt() { + return caller.invoke("instructions.getInitPrompt", java.util.Map.of(), InstructionsInitPromptResult.class); + } + /** * Discovers instruction sources across user, repository, and plugin sources. * @@ -37,6 +49,30 @@ public CompletableFuture discover(InstructionsDiscov return caller.invoke("instructions.discover", params, InstructionsDiscoverResult.class); } + /** + * Discovers instruction sources across user, repository, and plugin sources. + *

+ * Accepts the extensible request, including inputs added after the params record. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture discover(InstructionsDiscoverRequest request) { + return caller.invoke("instructions.discover", Objects.requireNonNull(request, "request"), InstructionsDiscoverResult.class); + } + + /** + * Discovers the instruction sources for one caller-named location and returns them in the order the runtime applies them. `discover` answers for a set of project paths and derives the rest of its scope itself; this one instead takes every argument from the caller — the extra directories to scan and whether to descend into nested instruction files — and honors them as given. It also includes instruction directories from trusted repository settings, matching native repository discovery. Use it when the caller knows its own scope and no session exists to derive that scope from, such as a host reporting how many instruction files a directory contributes before any session starts. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture discoverRepoSources(InstructionsDiscoverRepoSourcesParams params) { + return caller.invoke("instructions.discoverRepoSources", params, ServerInstructionSourceList.class); + } + /** * Returns the canonical files and directories where a client may create custom instructions that the runtime will recognize, including ones that do not exist yet. Repository targets become active once created. * @@ -48,4 +84,28 @@ public CompletableFuture getDiscoveryPaths( return caller.invoke("instructions.getDiscoveryPaths", params, InstructionsGetDiscoveryPathsResult.class); } + /** + * Returns the canonical files and directories where a client may create custom instructions that the runtime will recognize, including ones that do not exist yet. Repository targets become active once created. + *

+ * Accepts the extensible request, including inputs added after the params record. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture getDiscoveryPaths(InstructionsGetDiscoveryPathsRequest request) { + return caller.invoke("instructions.getDiscoveryPaths", Objects.requireNonNull(request, "request"), InstructionsGetDiscoveryPathsResult.class); + } + + /** + * Drops the runtime's in-memory cache of discovered custom instructions so the next discovery reads them from disk again. A host calls this after it changes instruction files, or after it trusts a folder whose instructions an earlier discovery skipped, so that a session started afterwards sees the current files instead of a cached earlier answer. The call performs no I/O of its own and removes nothing from disk; it only invalidates, so the cost lands on the next discovery. Returns once the cache is clear, which is what lets a caller order a session start after it. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture clearCache() { + return caller.invoke("instructions.clearCache", java.util.Map.of(), Void.class); + } + } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpApi.java index 05e517d864..c35de551fc 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerMcpApi.java @@ -48,6 +48,17 @@ public CompletableFuture discover(McpDiscoverParams params) { return caller.invoke("mcp.discover", params, McpDiscoverResult.class); } + /** + * Lists the MCP servers the runtime supplies itself, so a host that disables the built-ins wholesale suppresses exactly the set the runtime would otherwise add. The names are fixed for a build and depend on no configuration, session or account. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture listBuiltinServerNames() { + return caller.invoke("mcp.listBuiltinServerNames", java.util.Map.of(), McpListBuiltinServerNamesResult.class); + } + /** * Reports whether the gh-replaceable GitHub MCP tools may be clipped for a session, which a host feeds back as the `excludeGhReplaceableTools` build option. The tools are redundant only when the session can reach a shell *and* the host has the `gh` that would replace them, so both halves are decided here. The shell half runs the platform shell tool through the runtime's own tool-filter matcher, so entry forms like `builtin:bash` and `builtin:*` behave exactly as they do when a session builds its tool catalog. The host half probes for `gh`, and is skipped entirely when the filters already rule the shell out. Host presence alone is not enough: a session restricted to, say, `view` would otherwise lose the built-in issue-read fallback while having no shell to replace it with. The answer describes the host the runtime runs on, so it is never forwarded to a remote engine. * diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRepoApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRepoApi.java new file mode 100644 index 0000000000..3db04fe14a --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRepoApi.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code repo} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerRepoApi { + + private final RpcCaller caller; + + /** API methods for the {@code repo.settings} sub-namespace. */ + final ServerRepoSettingsApi settings; + + /** @param caller the RPC transport function */ + ServerRepoApi(RpcCaller caller) { + this.caller = caller; + this.settings = new ServerRepoSettingsApi(caller); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRepoSettingsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRepoSettingsApi.java new file mode 100644 index 0000000000..2c5aea2e10 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRepoSettingsApi.java @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code repo.settings} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerRepoSettingsApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerRepoSettingsApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Reads one repository settings file without settings normalization or layering. The existing JSONC parser accepts comments and trailing commas and applies its prototype-safety rules. Missing or blank files return an empty valid config. Invalid files return an empty config with invalid=true; other read failures reject. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture readRaw(RepoSettingsReadRawParams params) { + return caller.invoke("repo.settings.readRaw", params, RepoSettingsReadRawResult.class); + } + + /** + * Writes or removes one allowed top-level repository setting through the existing validator and file lock. Preserves unrelated stored keys. Invalid keys, values, existing documents, and I/O errors reject without replacing the file. Deletion requires delete=true; otherwise value must be present. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture writeKey(RepoSettingsWriteKeyParams params) { + return caller.invoke("repo.settings.writeKey", params, Void.class); + } + + /** + * Replaces the repository-overridable settings in one locked write. Allowed keys present in settings are validated and written; allowed keys absent from settings are removed. Other input keys are ignored, and unknown keys already stored in the file remain unchanged. Invalid values or an invalid existing file reject without a partial write. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture writeAll(RepoSettingsWriteAllParams params) { + return caller.invoke("repo.settings.writeAll", params, Void.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRpc.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRpc.java index 99f65a5f89..556c3cf07a 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRpc.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRpc.java @@ -45,6 +45,8 @@ public final class ServerRpc { public final ServerMcpApi mcp; /** API methods for the {@code extensions} namespace. */ public final ServerExtensionsApi extensions; + /** API methods for the {@code instructions} namespace. */ + public final ServerInstructionsApi instructions; /** API methods for the {@code skills} namespace. */ public final ServerSkillsApi skills; /** API methods for the {@code catalog} namespace. */ @@ -53,14 +55,16 @@ public final class ServerRpc { public final ServerPluginsApi plugins; /** API methods for the {@code agents} namespace. */ public final ServerAgentsApi agents; - /** API methods for the {@code instructions} namespace. */ - public final ServerInstructionsApi instructions; /** API methods for the {@code globalState} namespace. */ final ServerGlobalStateApi globalState; /** API methods for the {@code commands} namespace. */ public final ServerCommandsApi commands; /** API methods for the {@code user} namespace. */ public final ServerUserApi user; + /** API methods for the {@code featureFlags} namespace. */ + final ServerFeatureFlagsApi featureFlags; + /** API methods for the {@code repo} namespace. */ + final ServerRepoApi repo; /** API methods for the {@code gitHubRepository} namespace. */ final ServerGitHubRepositoryApi gitHubRepository; /** API methods for the {@code gitHubOwners} namespace. */ @@ -99,14 +103,16 @@ public ServerRpc(RpcCaller caller) { this.secrets = new ServerSecretsApi(caller); this.mcp = new ServerMcpApi(caller); this.extensions = new ServerExtensionsApi(caller); + this.instructions = new ServerInstructionsApi(caller); this.skills = new ServerSkillsApi(caller); this.catalog = new ServerCatalogApi(caller); this.plugins = new ServerPluginsApi(caller); this.agents = new ServerAgentsApi(caller); - this.instructions = new ServerInstructionsApi(caller); this.globalState = new ServerGlobalStateApi(caller); this.commands = new ServerCommandsApi(caller); this.user = new ServerUserApi(caller); + this.featureFlags = new ServerFeatureFlagsApi(caller); + this.repo = new ServerRepoApi(caller); this.gitHubRepository = new ServerGitHubRepositoryApi(caller); this.gitHubOwners = new ServerGitHubOwnersApi(caller); this.git = new ServerGitApi(caller); diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSkillsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSkillsApi.java index 30b35346bb..a3e7dc7c58 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSkillsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSkillsApi.java @@ -8,6 +8,7 @@ package com.github.copilot.generated.rpc; import com.github.copilot.CopilotExperimental; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import javax.annotation.processing.Generated; @@ -99,4 +100,17 @@ public CompletableFuture getDiscoveryPaths(Skills return caller.invoke("skills.getDiscoveryPaths", params, SkillsGetDiscoveryPathsResult.class); } + /** + * Returns the canonical directories where a client may create skills that the runtime will recognize, including ones that do not exist yet. Project directories become active once created. + *

+ * Accepts the extensible request, including inputs added after the params record. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture getDiscoveryPaths(SkillsGetDiscoveryPathsRequest request) { + return caller.invoke("skills.getDiscoveryPaths", Objects.requireNonNull(request, "request"), SkillsGetDiscoveryPathsResult.class); + } + } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerUserSettingsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerUserSettingsApi.java index 9c5656ff14..627d1c9866 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerUserSettingsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerUserSettingsApi.java @@ -37,6 +37,17 @@ public CompletableFuture get() { return caller.invoke("user.settings.get", java.util.Map.of(), UserSettingsGetResult.class); } + /** + * Resolves the on-disk locations of the settings files this runtime reads, so a consumer can show or open them. The user path is the same file `user.settings.get`, `user.settings.load`, and `user.settings.set` operate on. Supply `repoRoot` to also resolve that repository's checked-in and local settings paths. A path is reported whether or not the file exists. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getPaths(UserSettingsGetPathsParams params) { + return caller.invoke("user.settings.getPaths", params, UserSettingsGetPathsResult.class); + } + /** * Writes one or more user settings to settings.json, replacing each provided top-level key. A key whose value is null is removed. * @@ -48,4 +59,103 @@ public CompletableFuture set(UserSettingsSetParams params) { return caller.invoke("user.settings.set", params, Void.class); } + /** + * Lists the top-level user-setting keys by who is allowed to govern them: `repo` keys a repository may override through `.github/copilot/settings.json`, `claudeRepo` keys a repository may override through a Claude-compatible config, and `managed` keys an enterprise policy may fix. The lists are static for a given runtime build and fail closed: a key absent from a list cannot be governed that way. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture listGovernanceKeys() { + return caller.invoke("user.settings.listGovernanceKeys", java.util.Map.of(), UserSettingsGovernanceKeysResult.class); + } + + /** + * Atomically edits one canonical user setting inside its settings-file lock. Reads, canonicalizes touched aliases, applies the edit, validates the resulting top-level setting and writes before releasing the lock. An explicit autoUpdatesChannel set completes the staff migration in the same transaction. Only a malformed existing file returns `invalid`; refused keys, invalid values and I/O errors reject the call. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture edit(UserSettingsEditParams params) { + return caller.invoke("user.settings.edit", params, SettingsEditResult.class); + } + + /** + * Rewrites legacy and snake_case setting names in a settings object to their canonical spelling. A caller editing settings.json must normalize before writing: a legacy key left in place survives the write, is re-normalized on the next load, and silently shadows the canonical value the write just stored. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture normalize(UserSettingsNormalizeParams params) { + return caller.invoke("user.settings.normalize", params, UserSettingsNormalizeResult.class); + } + + /** + * Diagnoses a set of already-loaded settings layers, reporting each key that will not take effect and why. Settings load tolerantly so that one bad key does not stop a session from starting; this method surfaces what was dropped so a caller can report it instead of silently ignoring the user's intent. Takes the layers as given rather than reading them, so a caller can diagnose exactly the content it is showing, including unsaved edits. Never echoes a setting's value, because a value may be a token or another secret. Marked internal because it exists to carry a CLI call site off the native addon, not to serve a consumer-facing need; it becomes public once an SDK consumer needs to inspect settings health itself. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture diagnoseProblems(UserSettingsDiagnoseProblemsParams params) { + return caller.invoke("user.settings.diagnoseProblems", params, UserSettingsProblemsResult.class); + } + + /** + * Validates one top-level setting subtree and writes just that key to settings.json as a single step. Doing both here closes the race a caller cannot close itself: between a separate preflight read and the write, the file may change. Rewriting only the touched key keeps legacy siblings out of settings.json. Answers a status rather than failing, so a validation problem and a write problem stay distinguishable. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture applyTopKey(UserSettingsApplyTopKeyParams params) { + return caller.invoke("user.settings.applyTopKey", params, UserSettingsApplyTopKeyResult.class); + } + + /** + * Replaces the user settings file's entire content in one write. A key absent from `settings` is removed, which is what distinguishes this from `user.settings.set`: that one merges, so it can never clear a key the caller has dropped. For a caller saving the result of a raw edit, a merge would silently resurrect every key the user deleted. Records the same one-time mutation marks a per-key write records, so a setting the user has now chosen explicitly stops being migrated for them. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture writeAll(UserSettingsWriteAllParams params) { + return caller.invoke("user.settings.writeAll", params, Void.class); + } + + /** + * Merges a partial object into one top-level user setting, re-reading the stored value inside this runtime process's settings.json write lock so that concurrent writers in this process to different sub-fields of the same key do not clobber each other. Unlike `user.settings.set`, which replaces a key's whole value with what the caller last read, this keeps sub-fields the caller did not name when both the stored value and supplied value are objects; otherwise the supplied value replaces the stored value. Use it whenever two independent surfaces own different sub-fields of one setting. Returns the key's stored value after the write, in `value`. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture update(UserSettingsUpdateParams params) { + return caller.invoke("user.settings.update", params, UserSettingsUpdateResult.class); + } + + /** + * Reads settings.json as stored for a caller that is about to edit it. Unlike `user.settings.get`, this returns file values rather than per-key metadata and defaults. Reports `missing` for an absent file and `invalid` when the existing file will not parse. Retired config.json and extensionless files are not read. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture loadForEdit() { + return caller.invoke("user.settings.loadForEdit", java.util.Map.of(), UserSettingsLoadForEditResult.class); + } + + /** + * Validates one top-level setting subtree without writing it, reporting each problem with the path it applies to. Scoped to a single top-level key on purpose: validating the whole file would reject an edit whenever an unrelated pre-existing field is malformed, locking the user out of the very tool that could fix it. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture validate(UserSettingsValidateParams params) { + return caller.invoke("user.settings.validate", params, UserSettingsValidateResult.class); + } + } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCanvasProviderRegisterParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCanvasProviderRegisterParams.java index a9213671aa..4843040c6e 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCanvasProviderRegisterParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionCanvasProviderRegisterParams.java @@ -30,6 +30,7 @@ record SessionCanvasProviderRegisterParams( /** Connection identifier for callback routing */ @JsonProperty("connectionId") String connectionId, /** Provider metadata supplied by the host */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("info") Object info, /** Canvas contributions supplied by the provider */ @JsonProperty("canvases") List canvases diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpExecuteSamplingParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpExecuteSamplingParams.java index 54950ec4f4..7978c03553 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpExecuteSamplingParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionMcpExecuteSamplingParams.java @@ -31,6 +31,7 @@ public record SessionMcpExecuteSamplingParams( /** Name of the MCP server that initiated the sampling request */ @JsonProperty("serverName") String serverName, /** The original MCP JSON-RPC request ID (string or number). Used by the runtime to correlate the inference with the originating MCP request for telemetry; this is distinct from `requestId` (which is the schema-level cancellation handle). */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("mcpRequestId") Object mcpRequestId, /** Raw MCP CreateMessageRequest params, as received in the `sampling.requested` event. Treated as opaque at the schema layer; the runtime converts the embedded MCP messages into the OpenAI chat-completion shape internally. */ @JsonProperty("request") McpExecuteSamplingRequest request diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelApi.java index 1c5c1c3d39..bfd5d8a89e 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelApi.java @@ -153,6 +153,22 @@ public CompletableFuture setReasoningEffor return caller.invoke("session.model.setReasoningEffort", _p, SessionModelSetReasoningEffortResult.class); } + /** + * Computes whether the session's current model shows reasoning summaries and how a host should present them: the default Ctrl+T visibility, reasoning headers, the hidden-summaries hint, and whether a persisted `showReasoning` setting is redundant. The runtime folds in the session's model catalog, selection and reasoning-summaries experiment assignment; the host supplies only its own persisted setting and current visibility. This method reads the session's resolved model catalog rather than resolving it, so call `session.model.list` first on a session that has not listed models or run a turn; until then the result is `ready: false`. A session that resolves models without a Copilot catalog, that is a BYOK registry or an alternate provider, never caches one and stays `ready: false`. + *

+ * Note: the {@code sessionId} field in the params record is overridden + * by the session-scoped wrapper; any value provided is ignored. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture getReasoningSummaries(SessionModelGetReasoningSummariesParams params) { + com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); + _p.put("sessionId", this.sessionId); + return caller.invoke("session.model.getReasoningSummaries", _p, SessionModelGetReasoningSummariesResult.class); + } + /** * Lists models available to this session using its own auth and integration context. Connected hosts (CLI TUI, GitHub App) should call this through the session client so remote sessions return the remote CLI's available models rather than the caller's. *

diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetReasoningSummariesParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetReasoningSummariesParams.java new file mode 100644 index 0000000000..488fe67616 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetReasoningSummariesParams.java @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Host presentation state the reasoning-summaries policy depends on. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionModelGetReasoningSummariesParams( + /** Target session identifier */ + @JsonProperty("sessionId") String sessionId, + /** The host's persisted `showReasoning` user setting, omitted when unset. */ + @JsonProperty("persistedShowReasoning") Boolean persistedShowReasoning, + /** Whether the host is currently showing reasoning summaries. Defaults to false. */ + @JsonProperty("summariesVisible") Boolean summariesVisible +) { + + /** + * Creates host presentation state; the session-scoped wrapper supplies the session ID. + * + * @param persistedShowReasoning the persisted visibility setting, or null when unset + * @param summariesVisible whether summaries are visible, or null for the default + */ + public SessionModelGetReasoningSummariesParams(Boolean persistedShowReasoning, Boolean summariesVisible) { + this(null, persistedShowReasoning, summariesVisible); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetReasoningSummariesResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetReasoningSummariesResult.java new file mode 100644 index 0000000000..c23a1af9ea --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetReasoningSummariesResult.java @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Reasoning-summaries presentation policy for the session's current model. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SessionModelGetReasoningSummariesResult( + /** False until the session has a model catalog and a selected model. This read never resolves the catalog itself, and the runtime emits no readiness notification, so repeating this call alone leaves `ready` false indefinitely on a session that has neither listed models nor run a turn. `session.model.list` is the prerequisite and the signal: it resolves and caches the catalog for the session, so a successful return means the next read is ready. The exception is a session that resolves models without a Copilot catalog, that is a BYOK registry or an alternate provider: `session.model.list` returns an empty list without caching a catalog, so `ready` stays false and this policy is unavailable there. While false, every model-policy field is false and `visibility` is omitted; `experimentSettled` is independent of readiness and still reports the assignment state. */ + @JsonProperty("ready") Boolean ready, + /** Whether the session's reasoning-summaries experiment assignment has settled. False means this read does not wait for a pending assignment and reports the experiment-derived fields conservatively: `showHiddenHint` is false and `visibility` falls back to `persistedShowReasoning`, or is omitted when none was supplied. A host that wants the assigned answer re-reads until this is true. */ + @JsonProperty("experimentSettled") Boolean experimentSettled, + /** Whether turns on this session produce reasoning summaries, honouring an explicit session reasoning-summary override. */ + @JsonProperty("sessionShowsSummaries") Boolean sessionShowsSummaries, + /** Whether the selected model shows reasoning summaries by default. */ + @JsonProperty("modelDefaultShowsSummaries") Boolean modelDefaultShowsSummaries, + /** Whether the selected model emits reasoning headers. */ + @JsonProperty("showReasoningHeaders") Boolean showReasoningHeaders, + /** Default reasoning visibility, and only meaningful once `ready` is true: false when the session produces no summaries, else the persisted setting, else the experiment's default. While `ready` is true it is omitted only when all three are unavailable, that is when the session produces summaries, no `persistedShowReasoning` was supplied, and `experimentSettled` is false. While `ready` is false there is no model policy to report and this field is always omitted, so an absent value alone does not imply a pending experiment. */ + @JsonProperty("visibility") Boolean visibility, + /** Whether to show the hint that reasoning summaries are hidden. Always false while `experimentSettled` is false. */ + @JsonProperty("showHiddenHint") Boolean showHiddenHint, + /** Whether the supplied `persistedShowReasoning` setting only restates the model default. This reports a redundancy, not a standing instruction to delete the setting: it stays true for as long as the setting and the model default agree, including for a user who later chose that value deliberately. It exists for a one-time migration of a legacy setting written before the model default made it redundant, so a host that acts on it owns the cleanup and must gate it behind its own persisted `done` marker, delete only a setting whose value still matches the one it read, and never repeat the deletion on a later launch. Under an off-by-default reasoning-summaries experiment an explicit `showReasoning: true` opt-in also reads as redundant on a summary-producing model, so an ungated host would keep deleting that opt-in and hide summaries again on every launch. */ + @JsonProperty("clearRedundantSetting") Boolean clearRedundantSetting +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionOpenOptions.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionOpenOptions.java index 5d14a1458a..2ac3d57c97 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionOpenOptions.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionOpenOptions.java @@ -117,11 +117,17 @@ public record SessionOpenOptions( @JsonProperty("managedMcpServers") Map managedMcpServers, /** Whether to include instructions from every MCP server in the system prompt instead of only allowlisted servers. */ @JsonProperty("allowAllMcpServerInstructions") Boolean allowAllMcpServerInstructions, - /** Additional directories to search for skills. */ + /** Explicit discovery-only skill roots, not filesystem grants. Available without enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ @JsonProperty("skillDirectories") List skillDirectories, + /** Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ + @JsonProperty("agentDirectories") List agentDirectories, + /** Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without enableConfigDiscovery, subject to instruction/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ + @JsonProperty("instructionDirectories") List instructionDirectories, + /** Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without enableConfigDiscovery or enableFileHooks, which controls repository-origin hooks only; hook/managed disables still apply. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ + @JsonProperty("hookDirectories") List hookDirectories, /** Skill scan directories and descendants excluded from discovery. Supports `~`-relative paths. */ @JsonProperty("ignoredSkillsLocations") List ignoredSkillsLocations, - /** Whether skill loading is enabled. When omitted, an SDK skill provider enables skills by default. */ + /** Whether skill loading is enabled. When omitted, explicit SDK skill roots or an SDK skill provider enable skills independently of enableConfigDiscovery. */ @JsonProperty("enableSkills") Boolean enableSkills, /** Whether the requesting SDK session has a skill provider. The provider remains ephemeral and is never persisted in session options or history. When enableSkills is false, it remains bound but dormant and receives no callbacks. Cloud, relay, handoff, and raw sessions.open flows reject it because they cannot safely pre-register the callback handler. */ @JsonProperty("hasSkillProvider") Boolean hasSkillProvider, diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionOptionsUpdateParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionOptionsUpdateParams.java index 3a30a13527..a5862263ae 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionOptionsUpdateParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionOptionsUpdateParams.java @@ -82,8 +82,14 @@ public record SessionOptionsUpdateParams( @JsonProperty("envValueMode") OptionsUpdateEnvValueMode envValueMode, /** Whether to include instructions from every MCP server in the system prompt instead of only allowlisted servers. */ @JsonProperty("allowAllMcpServerInstructions") Boolean allowAllMcpServerInstructions, - /** Additional directories to search for skills. */ + /** Explicit discovery-only skill roots, not filesystem grants. Available without enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ @JsonProperty("skillDirectories") List skillDirectories, + /** Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ + @JsonProperty("agentDirectories") List agentDirectories, + /** Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without enableConfigDiscovery, subject to instruction/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ + @JsonProperty("instructionDirectories") List instructionDirectories, + /** Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without enableConfigDiscovery or enableFileHooks, which controls repository-origin hooks only; hook/managed disables still apply. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ + @JsonProperty("hookDirectories") List hookDirectories, /** Skill scan directories and descendants excluded from discovery. Supports `~`-relative paths. */ @JsonProperty("ignoredSkillsLocations") List ignoredSkillsLocations, /** Built-in skill names to include in this session. When specified, only these runtime-bundled skills are available. Skills from other sources with the same name remain available. Set to null to remove the allowlist restriction. */ @@ -136,13 +142,13 @@ public record SessionOptionsUpdateParams( @JsonProperty("skipEmbeddingRetrieval") Boolean skipEmbeddingRetrieval, /** Organization-level custom instructions to inject into the system prompt. */ @JsonProperty("organizationCustomInstructions") String organizationCustomInstructions, - /** Whether to enable loading of `.github/hooks/` filesystem hooks. Separate from the SDK callback hook mechanism. */ + /** Whether to enable repository-origin file hooks from `.github/hooks/` and trusted repository-configured roots. Does not control explicit hookDirectories or SDK callback hooks. */ @JsonProperty("enableFileHooks") Boolean enableFileHooks, /** Whether to enable host git operations (context resolution, child repo scanning, git info in system prompt). */ @JsonProperty("enableHostGitOperations") Boolean enableHostGitOperations, /** Whether to enable cross-session store writes and reads. */ @JsonProperty("enableSessionStore") Boolean enableSessionStore, - /** Whether skill loading is enabled. Explicit false disables every source, including a bound SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless an SDK skill provider is registered. */ + /** Whether skill loading is enabled. Explicit false disables every source, including explicit SDK roots and a bound SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless explicit SDK skill roots or an SDK skill provider are supplied. */ @JsonProperty("enableSkills") Boolean enableSkills, /** Context tier for models with tiered pricing. The session uses this to derive effective `modelCapabilitiesOverrides` so compaction, truncation, token display, and request limits honor the selected tier. */ @JsonProperty("contextTier") OptionsUpdateContextTier contextTier, diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQueueConsumeSystemNotificationsParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQueueConsumeSystemNotificationsParams.java index 3b1d844881..850afce76e 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQueueConsumeSystemNotificationsParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionQueueConsumeSystemNotificationsParams.java @@ -27,6 +27,7 @@ record SessionQueueConsumeSystemNotificationsParams( /** Target session identifier */ @JsonProperty("sessionId") String sessionId, /** Opaque runtime-owned filter object. */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("filter") Object filter ) { } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsExecuteParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsExecuteParams.java index e60023c3aa..0e118ff815 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsExecuteParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsExecuteParams.java @@ -29,6 +29,7 @@ public record SessionToolsExecuteParams( /** Name of the currently offered tool to execute. */ @JsonProperty("name") String name, /** Arguments supplied to the tool. */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("arguments") Object arguments, /** Optional identifier used to correlate this invocation with its tool call. */ @JsonProperty("toolCallId") String toolCallId diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsTaskCompleteEventDataParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsTaskCompleteEventDataParams.java index 9902fb8a99..56fbf48a11 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsTaskCompleteEventDataParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionToolsTaskCompleteEventDataParams.java @@ -27,6 +27,7 @@ public record SessionToolsTaskCompleteEventDataParams( /** Target session identifier */ @JsonProperty("sessionId") String sessionId, /** Arguments supplied to the completed task_complete tool call. */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("toolArgs") Object toolArgs, /** Final expanded result returned by the task_complete tool. */ @JsonProperty("finalResult") ToolResultExpanded finalResult diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowJournalPutParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowJournalPutParams.java index 890c69647e..6cd69c5476 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowJournalPutParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowJournalPutParams.java @@ -33,6 +33,7 @@ public record SessionWorkflowJournalPutParams( /** Namespaced journal key. */ @JsonProperty("key") String key, /** JSON result to memoize. */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("resultJson") Object resultJson ) { } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowRunFromToolParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowRunFromToolParams.java index d68976fb76..78b199562e 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowRunFromToolParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowRunFromToolParams.java @@ -29,6 +29,7 @@ record SessionWorkflowRunFromToolParams( /** Registered workflow name. */ @JsonProperty("name") String name, /** Workflow input value. */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("args") Object args, /** Tool-originated workflow invocation options. */ @JsonProperty("options") WorkflowToolRunOptions options, diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowRunParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowRunParams.java index 642e2f7fcf..84883913ff 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowRunParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionWorkflowRunParams.java @@ -29,6 +29,7 @@ public record SessionWorkflowRunParams( /** Registered workflow name. */ @JsonProperty("name") String name, /** Workflow input value. */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("args") Object args, /** Workflow invocation options. */ @JsonProperty("options") WorkflowRunOptions options diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SettingsEditOperation.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SettingsEditOperation.java new file mode 100644 index 0000000000..ff6d7a5c69 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SettingsEditOperation.java @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * One atomic settings mutation. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum SettingsEditOperation { + /** The {@code set} variant. */ + SET("set"), + /** The {@code add-item} variant. */ + ADD_ITEM("add-item"), + /** The {@code remove-item} variant. */ + REMOVE_ITEM("remove-item"), + /** The {@code remove} variant. */ + REMOVE("remove"); + + private final String value; + SettingsEditOperation(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SettingsEditOperation fromValue(String value) { + for (SettingsEditOperation v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SettingsEditOperation value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SettingsEditResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SettingsEditResult.java new file mode 100644 index 0000000000..ae05fb4237 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SettingsEditResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Outcome of an atomic user or repository settings edit. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SettingsEditResult( + /** Changed, unchanged or invalid existing file. Rejected input, validation failures and I/O errors remain RPC errors. */ + @JsonProperty("status") SettingsEditStatus status +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SettingsEditStatus.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SettingsEditStatus.java new file mode 100644 index 0000000000..4bf228fc66 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SettingsEditStatus.java @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Whether one atomic settings edit changed a file. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum SettingsEditStatus { + /** The {@code changed} variant. */ + CHANGED("changed"), + /** The {@code unchanged} variant. */ + UNCHANGED("unchanged"), + /** The {@code invalid} variant. */ + INVALID("invalid"); + + private final String value; + SettingsEditStatus(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static SettingsEditStatus fromValue(String value) { + for (SettingsEditStatus v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown SettingsEditStatus value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillsDiscoverParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillsDiscoverParams.java index 03b9d85c1b..5dbde0dfd8 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillsDiscoverParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillsDiscoverParams.java @@ -27,7 +27,7 @@ public record SkillsDiscoverParams( /** Optional list of project directory paths to scan for project-scoped skills */ @JsonProperty("projectPaths") List projectPaths, - /** Optional list of additional skill directory paths to include */ + /** Explicit discovery-only skill roots, not filesystem grants. Available without ambient discovery, subject to skill/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. */ @JsonProperty("skillDirectories") List skillDirectories, /** Optional skill scan paths to exclude from discovery. */ @JsonProperty("ignoredSkillsLocations") List ignoredSkillsLocations, diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillsGetDiscoveryPathsRequest.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillsGetDiscoveryPathsRequest.java new file mode 100644 index 0000000000..9b58939685 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SkillsGetDiscoveryPathsRequest.java @@ -0,0 +1,131 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import java.util.Objects; +import javax.annotation.processing.Generated; + +/** + * Optional project paths to enumerate. + *

+ * Required inputs are constructor arguments. Optional inputs have fluent setters. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +public final class SkillsGetDiscoveryPathsRequest { + + /** Optional list of project directory paths. When omitted or empty, only personal and custom directories are returned. */ + @JsonProperty("projectPaths") + private List projectPaths; + + /** Optional skill scan paths to exclude from discovery. */ + @JsonProperty("ignoredSkillsLocations") + private List ignoredSkillsLocations; + + /** When true, omit the host's personal and custom skill directories, leaving only project directories. For multitenant deployments. */ + @JsonProperty("excludeHostSkills") + private Boolean excludeHostSkills; + + /** Explicit discovery-only skill roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. */ + @JsonProperty("skillDirectories") + private List skillDirectories; + + /** + * Creates a request with its required inputs. + */ + public SkillsGetDiscoveryPathsRequest() { + } + + /** + * Returns the {@code projectPaths} property. + * + * @return Optional list of project directory paths. When omitted or empty, only personal and custom directories are returned. + */ + public List getProjectPaths() { + return projectPaths; + } + + /** + * Returns the {@code ignoredSkillsLocations} property. + * + * @return Optional skill scan paths to exclude from discovery. + */ + public List getIgnoredSkillsLocations() { + return ignoredSkillsLocations; + } + + /** + * Returns the {@code excludeHostSkills} property. + * + * @return When true, omit the host's personal and custom skill directories, leaving only project directories. For multitenant deployments. + */ + public Boolean getExcludeHostSkills() { + return excludeHostSkills; + } + + /** + * Returns the {@code skillDirectories} property. + * + * @return Explicit discovery-only skill roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + */ + public List getSkillDirectories() { + return skillDirectories; + } + + /** + * Sets the {@code projectPaths} property. + * + * @param value Optional list of project directory paths. When omitted or empty, only personal and custom directories are returned. + * @return this request + */ + public SkillsGetDiscoveryPathsRequest setProjectPaths(List value) { + this.projectPaths = value; + return this; + } + + /** + * Sets the {@code ignoredSkillsLocations} property. + * + * @param value Optional skill scan paths to exclude from discovery. + * @return this request + */ + public SkillsGetDiscoveryPathsRequest setIgnoredSkillsLocations(List value) { + this.ignoredSkillsLocations = value; + return this; + } + + /** + * Sets the {@code excludeHostSkills} property. + * + * @param value When true, omit the host's personal and custom skill directories, leaving only project directories. For multitenant deployments. + * @return this request + */ + public SkillsGetDiscoveryPathsRequest setExcludeHostSkills(Boolean value) { + this.excludeHostSkills = value; + return this; + } + + /** + * Sets the {@code skillDirectories} property. + * + * @param value Explicit discovery-only skill roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + * @return this request + */ + public SkillsGetDiscoveryPathsRequest setSkillDirectories(List value) { + this.skillDirectories = value; + return this; + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsApplyTopKeyParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsApplyTopKeyParams.java new file mode 100644 index 0000000000..c81c4d218b --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsApplyTopKeyParams.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * A single top-level setting subtree to validate and write. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsApplyTopKeyParams( + /** Canonical path of the setting the caller is editing. Currently informational only. */ + @JsonProperty("canonicalPath") List canonicalPath, + /** Top-level setting name to write. */ + @JsonProperty("topKey") String topKey, + /** Value to write for the whole top-level key. Omitted when `delete` is true. Explicit null is preserved and validated as null. */ + @JsonProperty("value") Object value, + /** True to remove the top-level key instead of writing it. */ + @JsonProperty("delete") Boolean delete, + /** Records that the user chose an update channel explicitly, so the one-time staff channel migration stops reapplying. Honored only for the `autoUpdatesChannel` key. */ + @JsonProperty("completeStaffUpdateChannelMigration") Boolean completeStaffUpdateChannelMigration +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsApplyTopKeyResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsApplyTopKeyResult.java new file mode 100644 index 0000000000..85bdfd1d1a --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsApplyTopKeyResult.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Outcome of validating and writing one top-level setting subtree. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsApplyTopKeyResult( + /** `ok` when the value was written, `validation-error` when it was rejected before any write, `write-error` when validation passed but the write failed. */ + @JsonProperty("status") String status, + /** Problems found, present only when `status` is `validation-error`. */ + @JsonProperty("issues") List issues, + /** Why the write failed, present only when `status` is `write-error`. */ + @JsonProperty("error") String error +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsDiagnoseProblemsParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsDiagnoseProblemsParams.java new file mode 100644 index 0000000000..de7ccae6c7 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsDiagnoseProblemsParams.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The settings layers to diagnose. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsDiagnoseProblemsParams( + /** Layers to diagnose, in the precedence order the caller applies them. */ + @JsonProperty("sources") List sources +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsEditParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsEditParams.java new file mode 100644 index 0000000000..24f1cbd7f4 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsEditParams.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * One atomic edit of a canonical setting in settings.json. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsEditParams( + /** Configuration directory to edit. Omitted or empty resolves the server's own home, as in `user.settings.loadForConfigDir`. */ + @JsonProperty("configDir") String configDir, + /** Nonempty canonical path segments of the setting to edit, starting with its top-level key. */ + @JsonProperty("canonicalPath") List canonicalPath, + /** Set a scalar, add or remove a string list item, or remove the setting. The handler rejects a missing or incompatible value. */ + @JsonProperty("operation") SettingsEditOperation operation, + /** Required boolean, string or number for set, required string for add-item and remove-item, and forbidden for remove. The runtime rejects all other JSON values. */ + @JsonProperty("value") Object value +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetPathsParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetPathsParams.java new file mode 100644 index 0000000000..d9fca8e81a --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetPathsParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Selects which settings file paths to resolve. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsGetPathsParams( + /** Absolute path of a repository root. Supply it to also resolve that repository's two settings file paths; omit it to resolve only the user path. */ + @JsonProperty("repoRoot") String repoRoot +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetPathsResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetPathsResult.java new file mode 100644 index 0000000000..2ed0ae2d5e --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetPathsResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * On-disk locations of the settings files this runtime reads. A path is reported whether or not the file exists. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsGetPathsResult( + /** The user settings file: `settings.json` under the resolved Copilot home. This is the file `user.settings.get`, `user.settings.load`, and `user.settings.set` read and write. */ + @JsonProperty("userSettings") String userSettings, + /** The repository's checked-in settings file, or null when no repository root was supplied. */ + @JsonProperty("repoSettings") String repoSettings, + /** The repository's local, untracked settings file, or null when no repository root was supplied. */ + @JsonProperty("repoLocalSettings") String repoLocalSettings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGovernanceKeysResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGovernanceKeysResult.java new file mode 100644 index 0000000000..d4c0891e8f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGovernanceKeysResult.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Top-level user-setting keys grouped by who may govern them. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsGovernanceKeysResult( + /** Top-level keys a repository may override through `.github/copilot/settings.json` or `.github/copilot/settings.local.json`. */ + @JsonProperty("repo") List repo, + /** Top-level keys a repository may override through a Claude-compatible repository config. */ + @JsonProperty("claudeRepo") List claudeRepo, + /** Top-level keys an enterprise policy may fix through managed settings. */ + @JsonProperty("managed") List managed +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadForEditResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadForEditResult.java new file mode 100644 index 0000000000..0a5b05d3c8 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadForEditResult.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Contents of settings.json as stored, for a caller about to rewrite it. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsLoadForEditResult( + /** `ok` when the file parsed, `missing` when there is no file yet, `invalid` when the file exists but will not parse. */ + @JsonProperty("status") String status, + /** Parsed contents, present only when `status` is `ok`. */ + @JsonProperty("settings") Object settings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsNormalizeParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsNormalizeParams.java new file mode 100644 index 0000000000..f43d774226 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsNormalizeParams.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Settings object whose key names should be canonicalized. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsNormalizeParams( + /** Free-form settings object, possibly using legacy or snake_case key names. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("settings") Object settings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsNormalizeResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsNormalizeResult.java new file mode 100644 index 0000000000..badb433c2a --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsNormalizeResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Settings object with canonical key names. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsNormalizeResult( + /** The same settings with every legacy or snake_case key renamed to its canonical spelling. */ + @JsonProperty("settings") Object settings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblem.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblem.java new file mode 100644 index 0000000000..057a5ac6a5 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblem.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * One setting that will not take effect, and why. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsProblem( + /** Stable identifier for this problem within the reported set, so a caller can track a selection across refreshes. */ + @JsonProperty("id") String id, + /** What is wrong in machine-readable form, for a caller that wants to branch rather than display. */ + @JsonProperty("kind") String kind, + /** Coarse grouping for the problem, for a caller that presents problems in sections. */ + @JsonProperty("category") String category, + /** The settings layer the problem was found in. */ + @JsonProperty("source") UserSettingsProblemLocation source, + /** The offending key as written in the file, when the problem is attributable to a single key. Absent when the whole file is at fault. */ + @JsonProperty("rawKey") String rawKey, + /** Why the setting will not take effect. Never contains the setting's value, which may be a token or another secret. */ + @JsonProperty("explanation") String explanation +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblemLocation.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblemLocation.java new file mode 100644 index 0000000000..454408eb8b --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblemLocation.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The settings layer a problem was found in. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsProblemLocation( + /** Which layer this is: `user`, `repo`, or `local`. */ + @JsonProperty("kind") String kind, + /** The caller-supplied display label for the layer. */ + @JsonProperty("label") String label, + /** Absolute path of the file backing this layer. */ + @JsonProperty("filePath") String filePath +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblemSource.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblemSource.java new file mode 100644 index 0000000000..1c471916c5 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblemSource.java @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * One already-loaded settings layer to diagnose. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsProblemSource( + /** Which layer this is: `user`, `repo`, or `local`. */ + @JsonProperty("kind") String kind, + /** Caller-chosen display label for the layer, echoed back on each problem so a caller can group by layer without re-deriving its own naming. */ + @JsonProperty("label") String label, + /** Absolute path of the file backing this layer. */ + @JsonProperty("filePath") String filePath, + /** The layer's settings exactly as loaded, unnormalized. Empty when the file is missing or failed to parse. */ + @JsonProperty("config") Map config, + /** True when the file itself failed to parse, so its keys could not be read at all. */ + @JsonProperty("invalid") Boolean invalid +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblemsResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblemsResult.java new file mode 100644 index 0000000000..6a5dcf5728 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsProblemsResult.java @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The settings that will not take effect across the given layers. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsProblemsResult( + /** Each setting that will not take effect, and why. Empty when every layer is healthy. */ + @JsonProperty("problems") List problems +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetParams.java index ba19886c24..d56ecaa225 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetParams.java @@ -25,6 +25,7 @@ @JsonIgnoreProperties(ignoreUnknown = true) public record UserSettingsSetParams( /** Partial user settings to write, as a free-form object keyed by setting name */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("settings") Object settings ) { } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsUpdateParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsUpdateParams.java new file mode 100644 index 0000000000..9aed7c14b3 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsUpdateParams.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Names the user setting to merge into, and the partial object to merge. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsUpdateParams( + /** Top-level user-setting key to merge into, such as `extensions`. */ + @JsonProperty("key") String key, + /** Value to store for `key`. When both the stored value and this value are objects, their fields are shallow-merged and fields this object does not name are preserved. Otherwise this value replaces the stored value. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("value") Object value, + /** Copilot configuration directory to write the settings document in, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to use the directory the server resolved for itself. */ + @JsonProperty("configDir") String configDir, + /** Single-component name for the settings document at `/settings/.json`; path separators, `.` and `..` are rejected. Omit it, or pass an empty string, to use the main settings document. */ + @JsonProperty("subDir") String subDir +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsUpdateResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsUpdateResult.java new file mode 100644 index 0000000000..2d13157a3b --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsUpdateResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The stored value of the user setting after the merge. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsUpdateResult( + /** The key's stored value after the write: the merged object when both the stored value and the supplied value are objects, otherwise the supplied value. */ + @JsonProperty("value") Object value +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsValidateParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsValidateParams.java new file mode 100644 index 0000000000..3e69f4b138 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsValidateParams.java @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * A single top-level setting subtree to validate. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsValidateParams( + /** Top-level setting name to validate. */ + @JsonProperty("topKey") String topKey, + /** Value to validate. Omitted when `delete` is true. */ + @JsonProperty("value") Object value, + /** True to validate a removal of this key. The current settings file is not read. */ + @JsonProperty("delete") Boolean delete +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsValidateResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsValidateResult.java new file mode 100644 index 0000000000..730fb00195 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsValidateResult.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Outcome of validating one top-level setting subtree. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsValidateResult( + /** True when the subtree is valid. */ + @JsonProperty("ok") Boolean ok, + /** Problems found, empty when `ok` is true. */ + @JsonProperty("issues") List issues +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsValidationIssue.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsValidationIssue.java new file mode 100644 index 0000000000..68404e53a7 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsValidationIssue.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * One problem found while validating a setting value. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsValidationIssue( + /** Where in the settings tree the problem sits, as object keys and array indices. The first element is the top-level key; a whole-value problem is reported as that single key. */ + @JsonProperty("path") List path, + /** Human-readable description of the problem. */ + @JsonProperty("message") String message +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsWriteAllParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsWriteAllParams.java new file mode 100644 index 0000000000..e5929a8289 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsWriteAllParams.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The whole content to store in the user settings file. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsWriteAllParams( + /** The settings object to store. It replaces the file's entire content, so a key absent here is removed. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("settings") Object settings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/WorkflowExecuteParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/WorkflowExecuteParams.java index 5c53ad155f..e4001bb82e 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/WorkflowExecuteParams.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/WorkflowExecuteParams.java @@ -33,6 +33,7 @@ public record WorkflowExecuteParams( /** Opaque token identifying this workflow execution attempt. */ @JsonProperty("executionToken") String executionToken, /** Workflow input value. */ + @JsonInclude(JsonInclude.Include.ALWAYS) @JsonProperty("args") Object args ) { } diff --git a/java/sdk/src/main/java/com/github/copilot/CliServerManager.java b/java/sdk/src/main/java/com/github/copilot/CliServerManager.java index 92203ab755..0ccd2995e8 100644 --- a/java/sdk/src/main/java/com/github/copilot/CliServerManager.java +++ b/java/sdk/src/main/java/com/github/copilot/CliServerManager.java @@ -11,6 +11,8 @@ import java.net.Socket; import java.net.URI; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; @@ -353,9 +355,17 @@ private List resolveCliCommand(String cliPath, List args) { return result; } - // On Windows, use cmd /c to resolve the executable + // Own native executables directly so terminating the process cannot orphan + // a child behind cmd.exe. Batch shims still require the shell. String os = System.getProperty("os.name").toLowerCase(); if (os.contains("win") && !new File(cliPath).isAbsolute()) { + String executable = resolveWindowsExecutable(cliPath); + if (executable != null) { + var result = new ArrayList(); + result.add(executable); + result.addAll(args); + return result; + } var result = new ArrayList(); result.add("cmd"); result.add("/c"); @@ -370,6 +380,59 @@ private List resolveCliCommand(String cliPath, List args) { return result; } + private String resolveWindowsExecutable(String cliPath) { + Path cwd = Path.of(options.getCwd() != null ? options.getCwd() : System.getProperty("user.dir")) + .toAbsolutePath(); + var directories = new ArrayList(); + var environment = options.getEnvironment() != null ? options.getEnvironment() : System.getenv(); + boolean hasDirectory = cliPath.contains("\\") || cliPath.contains("/"); + if (hasDirectory || environment.keySet().stream() + .noneMatch(key -> key.equalsIgnoreCase("NoDefaultCurrentDirectoryInExePath"))) { + directories.add(cwd.toString()); + } + if (!hasDirectory) { + String pathValue = environment.entrySet().stream().filter(entry -> entry.getKey().equalsIgnoreCase("PATH")) + .map(java.util.Map.Entry::getValue).findFirst().orElse(""); + directories.addAll(Arrays.asList(pathValue.split(File.pathSeparator))); + } + String pathExtensions = environment.entrySet().stream() + .filter(entry -> entry.getKey().equalsIgnoreCase("PATHEXT")).map(java.util.Map.Entry::getValue) + .findFirst().orElse(".COM;.EXE;.BAT;.CMD"); + String[] names = new File(cliPath).getName().contains(".") + ? new String[]{cliPath} + : Arrays.stream(pathExtensions.split(";")).map(extension -> cliPath + extension).toArray(String[]::new); + // Preserve invalid-command diagnostics even when implicit cwd search is + // disabled. + if (names.length > 0) { + Path.of(names[0]); + } + for (String directory : directories) { + if (directory.isBlank()) { + continue; + } + if (directory.startsWith("\"") && directory.endsWith("\"")) { + directory = directory.substring(1, directory.length() - 1); + } + Path searchDirectory; + try { + searchDirectory = cwd.resolve(directory); + } catch (InvalidPathException error) { + LOG.log(Level.FINE, "Skipping invalid PATH entry while resolving CLI executable", error); + continue; + } + for (String name : names) { + Path candidate = searchDirectory.resolve(name); + if (Files.isRegularFile(candidate)) { + String lowerName = name.toLowerCase(java.util.Locale.ROOT); + return lowerName.endsWith(".exe") || lowerName.endsWith(".com") + ? candidate.toAbsolutePath().toString() + : null; + } + } + } + return null; + } + void configureProcessEnvironment(ProcessBuilder pb) { if (options.getEnvironment() != null) { pb.environment().clear(); diff --git a/java/sdk/src/main/java/com/github/copilot/CopilotClient.java b/java/sdk/src/main/java/com/github/copilot/CopilotClient.java index b277c09fa8..de6081b39d 100644 --- a/java/sdk/src/main/java/com/github/copilot/CopilotClient.java +++ b/java/sdk/src/main/java/com/github/copilot/CopilotClient.java @@ -1442,6 +1442,9 @@ CompletableFuture updateSessionOptionsForMode(CopilotSession session, Bool null, // envValueMode null, // allowAllMcpServerInstructions null, // skillDirectories + null, // agentDirectories + null, // instructionDirectories + null, // hookDirectories null, // ignoredSkillsLocations patchSkills, // includedBuiltinSkills null, // disabledSkills diff --git a/java/sdk/src/main/java/com/github/copilot/SessionRequestBuilder.java b/java/sdk/src/main/java/com/github/copilot/SessionRequestBuilder.java index 71cf2fcded..680ff0c160 100644 --- a/java/sdk/src/main/java/com/github/copilot/SessionRequestBuilder.java +++ b/java/sdk/src/main/java/com/github/copilot/SessionRequestBuilder.java @@ -153,6 +153,7 @@ static CreateSessionRequest buildCreateRequest(SessionConfig config, String sess } request.setModel(config.getModel()); + request.setName(config.getName()); request.setClientName(config.getClientName()); request.setReasoningEffort(config.getReasoningEffort()); request.setReasoningSummary(config.getReasoningSummary()); @@ -196,6 +197,8 @@ static CreateSessionRequest buildCreateRequest(SessionConfig config, String sess request.setAgent(config.getAgent()); request.setInfiniteSessions(config.getInfiniteSessions()); request.setSkillDirectories(config.getSkillDirectories()); + request.setAgentDirectories(config.getAgentDirectories()); + request.setHookDirectories(config.getHookDirectories()); request.setInstructionDirectories(config.getInstructionDirectories()); request.setPluginDirectories(config.getPluginDirectories()); request.setLargeOutput(config.getLargeOutput()); @@ -363,6 +366,8 @@ static ResumeSessionRequest buildResumeRequest(String sessionId, ResumeSessionCo request.setDefaultAgent(config.getDefaultAgent()); request.setAgent(config.getAgent()); request.setSkillDirectories(config.getSkillDirectories()); + request.setAgentDirectories(config.getAgentDirectories()); + request.setHookDirectories(config.getHookDirectories()); request.setInstructionDirectories(config.getInstructionDirectories()); request.setPluginDirectories(config.getPluginDirectories()); request.setLargeOutput(config.getLargeOutput()); diff --git a/java/sdk/src/main/java/com/github/copilot/rpc/AgentInfo.java b/java/sdk/src/main/java/com/github/copilot/rpc/AgentInfo.java index 1f6f1688fe..96820af0ef 100644 --- a/java/sdk/src/main/java/com/github/copilot/rpc/AgentInfo.java +++ b/java/sdk/src/main/java/com/github/copilot/rpc/AgentInfo.java @@ -4,6 +4,10 @@ package com.github.copilot.rpc; +import java.util.Collections; +import java.util.List; +import java.util.Map; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -27,6 +31,30 @@ public class AgentInfo { @JsonProperty("model") private String model; + @JsonProperty("hooks") + private Map>> hooks; + + /** + * Gets declarative hook actions executed only while this agent is active. + * + * @return actions keyed by event name, or {@code null} if unset + */ + public Map>> getHooks() { + return hooks == null ? null : Collections.unmodifiableMap(hooks); + } + + /** + * Sets declarative hook actions scoped to this agent. + * + * @param hooks + * actions keyed by event name + * @return this instance for chaining + */ + public AgentInfo setHooks(Map>> hooks) { + this.hooks = hooks; + return this; + } + /** * Gets the unique identifier of the agent. * diff --git a/java/sdk/src/main/java/com/github/copilot/rpc/CreateSessionRequest.java b/java/sdk/src/main/java/com/github/copilot/rpc/CreateSessionRequest.java index fa5e7d3e16..69b2bcaf3d 100644 --- a/java/sdk/src/main/java/com/github/copilot/rpc/CreateSessionRequest.java +++ b/java/sdk/src/main/java/com/github/copilot/rpc/CreateSessionRequest.java @@ -34,6 +34,9 @@ public final class CreateSessionRequest { @JsonProperty("sessionId") private String sessionId; + @JsonProperty("name") + private String name; + @JsonProperty("clientName") private String clientName; @@ -147,6 +150,12 @@ public final class CreateSessionRequest { @JsonProperty("skillDirectories") private List skillDirectories; + @JsonProperty("agentDirectories") + private List agentDirectories; + + @JsonProperty("hookDirectories") + private List hookDirectories; + @JsonProperty("instructionDirectories") private List instructionDirectories; @@ -291,6 +300,16 @@ public void setSessionId(String sessionId) { this.sessionId = sessionId; } + /** Gets the create-time session name. @return the session name */ + public String getName() { + return name; + } + + /** Sets the create-time session name. @param name the session name */ + public void setName(String name) { + this.name = name; + } + /** Gets the client name. @return the client name */ public String getClientName() { return clientName; @@ -723,6 +742,31 @@ public void setSkillDirectories(List skillDirectories) { this.skillDirectories = skillDirectories; } + /** Gets explicit agent discovery roots. @return the directories */ + public List getAgentDirectories() { + return agentDirectories == null ? null : Collections.unmodifiableList(agentDirectories); + } + + /** + * Sets explicit agent discovery roots. @param agentDirectories the directories + */ + public void setAgentDirectories(List agentDirectories) { + this.agentDirectories = agentDirectories; + } + + /** Gets explicit file-hook discovery roots. @return the directories */ + public List getHookDirectories() { + return hookDirectories == null ? null : Collections.unmodifiableList(hookDirectories); + } + + /** + * Sets explicit file-hook discovery roots. @param hookDirectories the + * directories + */ + public void setHookDirectories(List hookDirectories) { + this.hookDirectories = hookDirectories; + } + /** Gets instruction directories. @return the instruction directories */ public List getInstructionDirectories() { return instructionDirectories == null ? null : Collections.unmodifiableList(instructionDirectories); diff --git a/java/sdk/src/main/java/com/github/copilot/rpc/CustomAgentConfig.java b/java/sdk/src/main/java/com/github/copilot/rpc/CustomAgentConfig.java index 62de19b6a0..9f9c428ab4 100644 --- a/java/sdk/src/main/java/com/github/copilot/rpc/CustomAgentConfig.java +++ b/java/sdk/src/main/java/com/github/copilot/rpc/CustomAgentConfig.java @@ -36,6 +36,30 @@ @JsonInclude(JsonInclude.Include.NON_NULL) public class CustomAgentConfig { + @JsonProperty("hooks") + private Map>> hooks; + + /** + * Gets declarative hooks scoped to this agent. + * + * @return actions keyed by event name, or null when unset + */ + public Map>> getHooks() { + return hooks == null ? null : Collections.unmodifiableMap(hooks); + } + + /** + * Sets declarative hooks scoped to this agent. + * + * @param hooks + * actions keyed by event name + * @return this config for method chaining + */ + public CustomAgentConfig setHooks(Map>> hooks) { + this.hooks = hooks; + return this; + } + @JsonProperty("name") private String name; diff --git a/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionConfig.java b/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionConfig.java index 44c965bab0..adb7d7a9cd 100644 --- a/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionConfig.java +++ b/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionConfig.java @@ -97,6 +97,8 @@ public class ResumeSessionConfig { private DefaultAgentConfig defaultAgent; private String agent; private List skillDirectories; + private List agentDirectories; + private List hookDirectories; private List includedBuiltinSkills; private List instructionDirectories; private List pluginDirectories; @@ -1177,7 +1179,9 @@ public ResumeSessionConfig clearEnableOnDemandInstructionDiscovery() { } /** - * Gets whether file-based hooks are enabled. + * Gets whether repository-origin file hooks from {@code .github/hooks/} and + * trusted repository-configured roots are enabled. Does not control explicit + * {@link #getHookDirectories()} or callback hooks. * * @return an {@link java.util.Optional} containing {@code true} to enable file * hooks or {@code false} to disable them, or @@ -1660,7 +1664,11 @@ public ResumeSessionConfig setAgent(String agent) { } /** - * Gets the skill directories. + * Gets explicit discovery-only skill roots, not general filesystem grants. + * Available without configuration discovery, subject to skill/managed disables. + * Relative paths resolve once when supplied against the request's effective + * working directory; retained roots do not move when it changes. Null and + * omission are equivalent; an empty list clears only the SDK contribution. * * @return the list of skill directory paths */ @@ -1680,6 +1688,59 @@ public ResumeSessionConfig setSkillDirectories(List skillDirectories) { return this; } + /** + * Gets explicit discovery-only agent roots, separate from custom agent objects. + * No general filesystem grant. Available without configuration discovery, + * subject to source/managed disables. Relative paths resolve once when supplied + * against the request's effective working directory; retained roots do not + * move. Null and omission are equivalent; an empty list clears only the SDK + * contribution. + * + * @return the agent directory paths + */ + public List getAgentDirectories() { + return agentDirectories == null ? null : Collections.unmodifiableList(agentDirectories); + } + + /** + * Sets explicit discovery-only agent roots. See {@link #getAgentDirectories()}. + * + * @param agentDirectories + * the agent directory paths + * @return this config for method chaining + */ + public ResumeSessionConfig setAgentDirectories(List agentDirectories) { + this.agentDirectories = agentDirectories == null ? null : new ArrayList<>(agentDirectories); + return this; + } + + /** + * Gets explicit discovery-only file-hook roots, separate from callback hooks. + * No general filesystem grant. Available without configuration discovery or + * file-hook enablement (repository-origin hooks only), subject to hook/managed + * disables. Relative paths resolve once when supplied against the request's + * effective working directory; retained roots do not move. Null and omission + * are equivalent; an empty list clears only the SDK contribution. + * + * @return the file-hook directory paths + */ + public List getHookDirectories() { + return hookDirectories == null ? null : Collections.unmodifiableList(hookDirectories); + } + + /** + * Sets explicit discovery-only file-hook roots. See + * {@link #getHookDirectories()}. + * + * @param hookDirectories + * the file-hook directory paths + * @return this config for method chaining + */ + public ResumeSessionConfig setHookDirectories(List hookDirectories) { + this.hookDirectories = hookDirectories == null ? null : new ArrayList<>(hookDirectories); + return this; + } + /** * Gets the runtime-bundled skill allowlist. * @@ -1703,7 +1764,12 @@ public ResumeSessionConfig setIncludedBuiltinSkills(List includedBuiltin } /** - * Gets the additional directories to search for custom instruction files. + * Gets explicit discovery-only instruction roots using existing SDK formats. No + * general filesystem grant. Available without configuration discovery, subject + * to instruction/managed disables. Relative paths resolve once when supplied + * against the request's effective working directory; retained roots do not + * move. Null and omission are equivalent; an empty list clears only the SDK + * contribution. * * @return the list of instruction directory paths */ @@ -2335,6 +2401,8 @@ public ResumeSessionConfig clone() { copy.defaultAgent = this.defaultAgent; copy.agent = this.agent; copy.skillDirectories = this.skillDirectories != null ? new ArrayList<>(this.skillDirectories) : null; + copy.agentDirectories = this.agentDirectories != null ? new ArrayList<>(this.agentDirectories) : null; + copy.hookDirectories = this.hookDirectories != null ? new ArrayList<>(this.hookDirectories) : null; copy.includedBuiltinSkills = this.includedBuiltinSkills != null ? new ArrayList<>(this.includedBuiltinSkills) : null; diff --git a/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionRequest.java b/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionRequest.java index 4a5e2a9a7c..9ca488e407 100644 --- a/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionRequest.java +++ b/java/sdk/src/main/java/com/github/copilot/rpc/ResumeSessionRequest.java @@ -197,6 +197,12 @@ public final class ResumeSessionRequest { @JsonProperty("skillDirectories") private List skillDirectories; + @JsonProperty("agentDirectories") + private List agentDirectories; + + @JsonProperty("hookDirectories") + private List hookDirectories; + @JsonProperty("instructionDirectories") private List instructionDirectories; @@ -996,6 +1002,31 @@ public void setSkillDirectories(List skillDirectories) { this.skillDirectories = skillDirectories; } + /** Gets explicit agent discovery roots. @return the directories */ + public List getAgentDirectories() { + return agentDirectories == null ? null : Collections.unmodifiableList(agentDirectories); + } + + /** + * Sets explicit agent discovery roots. @param agentDirectories the directories + */ + public void setAgentDirectories(List agentDirectories) { + this.agentDirectories = agentDirectories; + } + + /** Gets explicit file-hook discovery roots. @return the directories */ + public List getHookDirectories() { + return hookDirectories == null ? null : Collections.unmodifiableList(hookDirectories); + } + + /** + * Sets explicit file-hook discovery roots. @param hookDirectories the + * directories + */ + public void setHookDirectories(List hookDirectories) { + this.hookDirectories = hookDirectories; + } + /** Gets instruction directories. @return the instruction directories */ public List getInstructionDirectories() { return instructionDirectories == null ? null : Collections.unmodifiableList(instructionDirectories); diff --git a/java/sdk/src/main/java/com/github/copilot/rpc/SessionConfig.java b/java/sdk/src/main/java/com/github/copilot/rpc/SessionConfig.java index e912527abc..a6828def9d 100644 --- a/java/sdk/src/main/java/com/github/copilot/rpc/SessionConfig.java +++ b/java/sdk/src/main/java/com/github/copilot/rpc/SessionConfig.java @@ -43,6 +43,7 @@ public class SessionConfig { private String sessionId; + private String name; private String clientName; private String model; private String reasoningEffort; @@ -84,6 +85,8 @@ public class SessionConfig { private String agent; private InfiniteSessionConfig infiniteSessions; private List skillDirectories; + private List agentDirectories; + private List hookDirectories; private List includedBuiltinSkills; private List instructionDirectories; private List pluginDirectories; @@ -147,6 +150,31 @@ public SessionConfig setSessionId(String sessionId) { return this; } + /** + * Gets the create-time session name. + * + * @return the session name, or {@code null} if the session is unnamed + */ + public String getName() { + return name; + } + + /** + * Names the session at creation, as {@code session.name.set} would, and is + * validated the same way: non-empty, no leading or trailing whitespace, at most + * 100 UTF-16 units, no control characters, and no double quotes. A name also + * makes the session persist from the start, so it can be listed and resumed + * without ever running a turn. Local sessions only: cloud creation rejects it. + * + * @param name + * the session name + * @return this config instance for method chaining + */ + public SessionConfig setName(String name) { + this.name = name; + return this; + } + /** * Gets the client name used to identify the application using the SDK. * @@ -1236,7 +1264,11 @@ public SessionConfig setInfiniteSessions(InfiniteSessionConfig infiniteSessions) } /** - * Gets the skill directories. + * Gets explicit discovery-only skill roots, not general filesystem grants. + * Available without configuration discovery, subject to skill/managed disables. + * Relative paths resolve once when supplied against the request's effective + * working directory; retained roots do not move when it changes. Null and + * omission are equivalent; an empty list clears only the SDK contribution. * * @return the list of skill directory paths */ @@ -1260,6 +1292,59 @@ public SessionConfig setSkillDirectories(List skillDirectories) { return this; } + /** + * Gets explicit discovery-only agent roots, separate from custom agent objects. + * No general filesystem grant. Available without configuration discovery, + * subject to source/managed disables. Relative paths resolve once when supplied + * against the request's effective working directory; retained roots do not + * move. Null and omission are equivalent; an empty list clears only the SDK + * contribution. + * + * @return the agent directory paths + */ + public List getAgentDirectories() { + return agentDirectories == null ? null : Collections.unmodifiableList(agentDirectories); + } + + /** + * Sets explicit discovery-only agent roots. See {@link #getAgentDirectories()}. + * + * @param agentDirectories + * the agent directory paths + * @return this config for method chaining + */ + public SessionConfig setAgentDirectories(List agentDirectories) { + this.agentDirectories = agentDirectories == null ? null : new ArrayList<>(agentDirectories); + return this; + } + + /** + * Gets explicit discovery-only file-hook roots, separate from callback hooks. + * No general filesystem grant. Available without configuration discovery or + * file-hook enablement (repository-origin hooks only), subject to hook/managed + * disables. Relative paths resolve once when supplied against the request's + * effective working directory; retained roots do not move. Null and omission + * are equivalent; an empty list clears only the SDK contribution. + * + * @return the file-hook directory paths + */ + public List getHookDirectories() { + return hookDirectories == null ? null : Collections.unmodifiableList(hookDirectories); + } + + /** + * Sets explicit discovery-only file-hook roots. See + * {@link #getHookDirectories()}. + * + * @param hookDirectories + * the file-hook directory paths + * @return this config for method chaining + */ + public SessionConfig setHookDirectories(List hookDirectories) { + this.hookDirectories = hookDirectories == null ? null : new ArrayList<>(hookDirectories); + return this; + } + /** * Gets the runtime-bundled skill allowlist. * @@ -1283,7 +1368,12 @@ public SessionConfig setIncludedBuiltinSkills(List includedBuiltinSkills } /** - * Gets the additional directories to search for custom instruction files. + * Gets explicit discovery-only instruction roots using existing SDK formats. No + * general filesystem grant. Available without configuration discovery, subject + * to instruction/managed disables. Relative paths resolve once when supplied + * against the request's effective working directory; retained roots do not + * move. Null and omission are equivalent; an empty list clears only the SDK + * contribution. * * @return the list of instruction directory paths */ @@ -1648,7 +1738,9 @@ public SessionConfig clearRefreshCustomInstructions() { } /** - * Gets whether file-based hooks are enabled. + * Gets whether repository-origin file hooks from {@code .github/hooks/} and + * trusted repository-configured roots are enabled. Does not control explicit + * {@link #getHookDirectories()} or callback hooks. * * @return an {@link java.util.Optional} containing {@code true} to enable file * hooks or {@code false} to disable them, or @@ -2423,6 +2515,8 @@ public SessionConfig clone() { copy.agent = this.agent; copy.infiniteSessions = this.infiniteSessions; copy.skillDirectories = this.skillDirectories != null ? new ArrayList<>(this.skillDirectories) : null; + copy.agentDirectories = this.agentDirectories != null ? new ArrayList<>(this.agentDirectories) : null; + copy.hookDirectories = this.hookDirectories != null ? new ArrayList<>(this.hookDirectories) : null; copy.includedBuiltinSkills = this.includedBuiltinSkills != null ? new ArrayList<>(this.includedBuiltinSkills) : null; diff --git a/java/sdk/src/test/java/com/github/copilot/AgentInfoTest.java b/java/sdk/src/test/java/com/github/copilot/AgentInfoTest.java index 40654292f8..f2735cae7d 100644 --- a/java/sdk/src/test/java/com/github/copilot/AgentInfoTest.java +++ b/java/sdk/src/test/java/com/github/copilot/AgentInfoTest.java @@ -6,6 +6,9 @@ import static org.junit.jupiter.api.Assertions.*; +import java.util.List; +import java.util.Map; + import org.junit.jupiter.api.Test; import com.github.copilot.rpc.AgentInfo; @@ -22,6 +25,7 @@ void defaultValuesAreNull() { assertNull(agent.getDisplayName()); assertNull(agent.getDescription()); assertNull(agent.getModel()); + assertNull(agent.getHooks()); } @Test @@ -52,6 +56,21 @@ void modelGetterSetter() { assertEquals("alpha/sonnet", agent.getModel()); } + @Test + void hooksGetterSetterAndJsonRoundTrip() throws Exception { + Map>> hooks = Map.of("preToolUse", + List.of(Map.of("type", "command", "bash", "echo scoped-hook", "timeoutSec", 10))); + var agent = new AgentInfo().setName("coder").setHooks(hooks); + assertEquals(hooks, agent.getHooks()); + + var mapper = JsonRpcClient.getObjectMapper(); + var json = mapper.valueToTree(agent); + assertEquals(mapper.valueToTree(hooks), json.get("hooks")); + var restored = mapper.treeToValue(json, AgentInfo.class); + assertEquals(hooks, restored.getHooks()); + assertNull(mapper.readValue("{\"name\":\"plain-agent\"}", AgentInfo.class).getHooks()); + } + @Test void fluentChainingReturnsThis() { var agent = new AgentInfo().setName("coder").setDisplayName("Code Assistant") @@ -70,5 +89,6 @@ void fluentChainingReturnsSameInstance() { assertSame(agent, agent.setDisplayName("Test")); assertSame(agent, agent.setDescription("A test agent")); assertSame(agent, agent.setModel("alpha/sonnet")); + assertSame(agent, agent.setHooks(Map.of())); } } diff --git a/java/sdk/src/test/java/com/github/copilot/AutoTierIT.java b/java/sdk/src/test/java/com/github/copilot/AutoTierIT.java index d93cbf995b..1ce94b4b19 100644 --- a/java/sdk/src/test/java/com/github/copilot/AutoTierIT.java +++ b/java/sdk/src/test/java/com/github/copilot/AutoTierIT.java @@ -5,6 +5,8 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -20,6 +22,7 @@ import com.github.copilot.generated.rpc.SessionEventLogReadParams; import com.github.copilot.rpc.AutoTier; import com.github.copilot.rpc.CapiSessionOptions; +import com.github.copilot.rpc.CopilotClientOptions; import com.github.copilot.rpc.MessageOptions; import com.github.copilot.rpc.PermissionHandler; import com.github.copilot.rpc.ResumeSessionConfig; @@ -200,12 +203,19 @@ void shouldRestoreAndOverrideFastAutoTierOnColdResume() throws Exception { void shouldCommitFastAutoTierAfterSuccessfulTurn() throws Exception { ctx.configureForTest("auto_tier", "should_commit_fast_auto_tier_after_successful_turn"); - try (CopilotClient client = ctx.createClient(); + // Keep this invocation's detach trace outside the home removed by context + // teardown. + Path logDirectory = Files.createTempDirectory(Files.createDirectories(Path.of("target", "failsafe-reports")), + "auto-tier-detach-").toAbsolutePath(); + try (CopilotClient client = ctx.createClient(new CopilotClientOptions().setLogLevel("debug") + .setCliArgs(new String[]{"--log-dir", logDirectory.toString()})); CopilotSession session = client .createSession(new SessionConfig().setModel(MODEL_ID) .setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setCapi(new CapiSessionOptions() .setAutoTier(AutoTier.EFFICIENCY).setEnableWebSocketResponses(false))) .get(30, TimeUnit.SECONDS)) { + System.err.println( + "AutoTierIT detach diagnostics: session=" + session.getSessionId() + " logs=" + logDirectory); var modelChangedFuture = new CompletableFuture(); try (var subscription = session.on(SessionModelChangeEvent.class, event -> { if (event.getData().autoTier() == com.github.copilot.generated.AutoTier.FAST) { diff --git a/java/sdk/src/test/java/com/github/copilot/CliServerManagerTest.java b/java/sdk/src/test/java/com/github/copilot/CliServerManagerTest.java index 462fbc17cd..9dea8d8c2a 100644 --- a/java/sdk/src/test/java/com/github/copilot/CliServerManagerTest.java +++ b/java/sdk/src/test/java/com/github/copilot/CliServerManagerTest.java @@ -7,13 +7,22 @@ import static org.junit.jupiter.api.Assertions.*; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import java.net.ServerSocket; import java.net.URI; +import java.nio.file.Files; +import java.nio.file.InvalidPathException; import java.nio.file.Path; +import java.util.List; import java.util.Map; +import java.util.concurrent.CompletionException; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import com.github.copilot.ffi.NativeRuntimeLoader; import com.github.copilot.rpc.CopilotClientMode; @@ -190,9 +199,167 @@ void processInfoWithNullPort() { assertNull(info.port()); } - // ===== resolveCliCommand tests (via startCliServer) ===== - // resolveCliCommand is private, so we test indirectly through startCliServer - // with specific cliPath values. + // ===== resolveCliCommand tests ===== + + @ParameterizedTest + @ValueSource(strings = {"NoDefaultCurrentDirectoryInExePath", "nodefaultcurrentdirectoryinexepath"}) + @EnabledOnOs(OS.WINDOWS) + void bareWindowsCliPathHonorsCurrentDirectorySearchOptOut(String optOutKey) throws Exception { + Path bin = Files.createDirectory(tempDir.resolve("bin")); + Files.createFile(tempDir.resolve("copilot.EXE")); + Path executable = Files.createFile(bin.resolve("copilot.EXE")); + var options = new CopilotClientOptions().setCliPath("copilot").setCwd(tempDir.toString()).setUseStdio(true) + .setEnvironment(Map.of("Path", bin.toString(), "PATHEXT", ".EXE", optOutKey, "")); + + assertClientAttemptsExecutable(options, executable); + } + + @Test + @EnabledOnOs(OS.WINDOWS) + void bareWindowsCliPathSearchesCurrentDirectoryWithoutOptOut() throws Exception { + Path bin = Files.createDirectory(tempDir.resolve("bin")); + Path executable = Files.createFile(tempDir.resolve("copilot.EXE")); + Files.createFile(bin.resolve("copilot.EXE")); + var options = new CopilotClientOptions().setCliPath("copilot").setCwd(tempDir.toString()).setUseStdio(true) + .setEnvironment(Map.of("PATH", bin.toString(), "PATHEXT", ".EXE")); + + assertClientAttemptsExecutable(options, executable); + } + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + @EnabledOnOs(OS.WINDOWS) + void explicitWindowsCurrentDirectorySearchIsPreservedWithOptOut(boolean relativeCliPath) throws Exception { + Path executable = Files.createFile(tempDir.resolve(".").resolve("copilot.EXE")); + var options = new CopilotClientOptions().setCliPath(relativeCliPath ? ".\\copilot.EXE" : "copilot") + .setCwd(tempDir.toString()).setUseStdio(true).setEnvironment(Map.of("PATH", relativeCliPath ? "" : ".", + "PATHEXT", ".EXE", "NoDefaultCurrentDirectoryInExePath", "")); + + assertClientAttemptsExecutable(options, executable); + } + + @ParameterizedTest + @ValueSource(strings = {"", "C:\\invalid|entry"}) + @EnabledOnOs(OS.WINDOWS) + void invalidWindowsCommandIsNotPassedToShellWhenCurrentDirectorySearchIsDisabled(String path) { + var options = new CopilotClientOptions().setCliPath("copilot|invalid").setCwd(tempDir.toString()) + .setUseStdio(true) + .setEnvironment(Map.of("PATH", path, "PATHEXT", ".EXE", "NoDefaultCurrentDirectoryInExePath", "")); + + try (var client = new CopilotClient(options)) { + Throwable error = assertThrows(CompletionException.class, () -> client.start().join()); + while (error.getCause() != null) { + error = error.getCause(); + } + var invalidPath = assertInstanceOf(InvalidPathException.class, error); + assertEquals("copilot|invalid.EXE", invalidPath.getInput()); + } + } + + private static void assertClientAttemptsExecutable(CopilotClientOptions options, Path executable) { + // Empty executables expose the attempted OS launch path without running a + // child. + try (var client = new CopilotClient(options)) { + Throwable error = assertThrows(CompletionException.class, () -> client.start().join()); + while (!(error instanceof IOException) && error.getCause() != null) { + error = error.getCause(); + } + var launchError = assertInstanceOf(IOException.class, error); + assertTrue(launchError.getMessage().contains("\"" + executable + "\""), launchError::getMessage); + } + } + + @ParameterizedTest + @ValueSource(strings = {"tools/copilot.exe", "tools\\copilot", ".\\tools\\copilot.EXE"}) + @EnabledOnOs(OS.WINDOWS) + void relativeWindowsCliPathDoesNotSearchPathDirectories(String cliPath) throws Exception { + Path bin = Files.createDirectory(tempDir.resolve("bin")); + Path tools = Files.createDirectory(bin.resolve("tools")); + Path unrelated = Files.createFile(tools.resolve("copilot.EXE")); + var options = new CopilotClientOptions().setCliPath(cliPath).setCwd(tempDir.toString()).setUseStdio(false) + .setEnvironment(Map.of("PATH", bin.toString(), "PATHEXT", ".EXE")); + + try (var client = new CopilotClient(options)) { + Throwable error = assertThrows(CompletionException.class, () -> client.start().join()); + while (error.getCause() != null) { + error = error.getCause(); + } + var launchError = assertInstanceOf(IOException.class, error); + assertTrue(launchError.getMessage().startsWith("CLI process exited unexpectedly."), + launchError::getMessage); + assertFalse(launchError.getMessage().contains(unrelated.toString()), launchError::getMessage); + } + } + + @ParameterizedTest + @ValueSource(strings = {" C:\\invalid", "C:\\invalid ", "C:\\invalidentry", + "C:\\invalid|entry", "C:\\invalid?entry", "C:\\invalid*entry", "C:\\invalid\"entry"}) + @EnabledOnOs(OS.WINDOWS) + void windowsNativeExecutableSkipsMalformedPathEntries(String malformedEntry) throws Exception { + Path bin = Files.createDirectory(tempDir.resolve("bin with spaces")); + Path executable = Files.createFile(bin.resolve("copilot.EXE")); + var options = new CopilotClientOptions().setCliPath("copilot").setCwd(tempDir.toString()) + .setEnvironment(Map.of("Path", malformedEntry + ";\"" + bin + "\"", "PATHEXT", ".CMD;.EXE")); + + assertEquals(List.of(executable.toString(), "--server"), resolveCliCommand(new CliServerManager(options))); + } + + @ParameterizedTest + @ValueSource(strings = {".CMD", ".BAT"}) + @EnabledOnOs(OS.WINDOWS) + void windowsCommandWrapperAfterMalformedPathEntryUsesShell(String extension) throws Exception { + Path bin = Files.createDirectory(tempDir.resolve("bin")); + Files.createFile(bin.resolve("copilot" + extension)); + Files.createFile(bin.resolve("copilot.EXE")); + var options = new CopilotClientOptions().setCwd(tempDir.toString()) + .setEnvironment(Map.of(NativeRuntimeLoader.COPILOT_CLI_PATH_ENV, "copilot", "PATH", + "C:\\invalid|entry;" + bin, "PATHEXT", extension + ";.EXE")); + + assertEquals(List.of("cmd", "/c", "copilot", "--server"), resolveCliCommand(new CliServerManager(options))); + } + + @Test + @EnabledOnOs(OS.WINDOWS) + void windowsCommandFallsBackToShellWhenPathEntriesAreMalformed() throws Exception { + var options = new CopilotClientOptions().setCliPath("copilot").setCwd(tempDir.toString()) + .setEnvironment(Map.of("PATH", " C:\\invalid;C:\\invalid|entry")); + + assertEquals(List.of("cmd", "/c", "copilot", "--server"), resolveCliCommand(new CliServerManager(options))); + } + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + @EnabledOnOs(OS.WINDOWS) + void explicitWindowsExecutablePathDoesNotDependOnPath(boolean absolute) throws Exception { + Path bin = Files.createDirectory(tempDir.resolve("bin")); + Path executable = Files.createFile(bin.resolve("copilot.exe")); + String cliPath = (absolute ? executable : tempDir.relativize(executable)).toString(); + var options = new CopilotClientOptions().setCliPath(cliPath).setCwd(tempDir.toString()) + .setEnvironment(Map.of("PATH", "C:\\invalid|entry")); + + assertEquals(List.of(executable.toString(), "--server"), resolveCliCommand(new CliServerManager(options))); + } + + @Test + @EnabledOnOs(OS.WINDOWS) + void malformedWindowsCliPathIsNotSkipped() { + var options = new CopilotClientOptions().setCliPath("copilot|invalid").setCwd(tempDir.toString()) + .setEnvironment(Map.of("PATH", "C:\\invalid|entry", "PATHEXT", ".EXE")); + + var error = assertThrows(InvocationTargetException.class, + () -> resolveCliCommand(new CliServerManager(options))); + var cause = assertInstanceOf(InvalidPathException.class, error.getCause()); + assertEquals("copilot|invalid.EXE", cause.getInput()); + } + + @SuppressWarnings("unchecked") + private static List resolveCliCommand(CliServerManager manager) throws Exception { + var resolve = CliServerManager.class.getDeclaredMethod("resolveCliCommand", String.class, List.class); + resolve.setAccessible(true); + return (List) resolve.invoke(manager, manager.resolveCliLaunch().executable(), List.of("--server")); + } + + // ===== startCliServer tests ===== // On Windows, "/nonexistent/copilot" is not an absolute path (no drive letter), // so resolveCliCommand wraps it with "cmd /c" and ProcessBuilder.start() diff --git a/java/sdk/src/test/java/com/github/copilot/ClientOptionsE2ETest.java b/java/sdk/src/test/java/com/github/copilot/ClientOptionsE2ETest.java index 04afa58596..169c39fdcb 100644 --- a/java/sdk/src/test/java/com/github/copilot/ClientOptionsE2ETest.java +++ b/java/sdk/src/test/java/com/github/copilot/ClientOptionsE2ETest.java @@ -80,8 +80,8 @@ void testShouldForwardAdvancedSessionCreationOptionsToTheCli() throws Exception try (var client = fake.createClient()) { var session = client.createSession(new SessionConfig().setSessionId("java-create-session") - .setClientName("java-e2e-client").setModel("gpt-5-mini").setReasoningEffort("low") - .setReasoningSummary("none").setContextTier("long_context") + .setName("java named at create").setClientName("java-e2e-client").setModel("gpt-5-mini") + .setReasoningEffort("low").setReasoningSummary("none").setContextTier("long_context") .setAvailableTools(java.util.List.of("bash")).setExcludedTools(java.util.List.of("grep")) .setExcludedBuiltInAgents(java.util.List.of("explore")).setEnableSessionTelemetry(true) .setEnableCitations(true).setSessionLimits(new SessionLimitsConfig(42.0)) @@ -100,6 +100,7 @@ void testShouldForwardAdvancedSessionCreationOptionsToTheCli() throws Exception var create = fake.capturedRequest("session.create").path("params"); assertEquals("java-create-session", create.path("sessionId").asText()); + assertEquals("java named at create", create.path("name").asText()); assertEquals("java-e2e-client", create.path("clientName").asText()); assertEquals("gpt-5-mini", create.path("model").asText()); assertEquals("low", create.path("reasoningEffort").asText()); diff --git a/java/sdk/src/test/java/com/github/copilot/E2ETestContext.java b/java/sdk/src/test/java/com/github/copilot/E2ETestContext.java index 8a0e335758..fa96957d26 100644 --- a/java/sdk/src/test/java/com/github/copilot/E2ETestContext.java +++ b/java/sdk/src/test/java/com/github/copilot/E2ETestContext.java @@ -121,7 +121,7 @@ public static E2ETestContext create() throws IOException, InterruptedException { defaultUser.put("login", "e2e-test-user"); defaultUser.put("id", 12345); defaultUser.put("copilot_plan", "individual_pro"); - defaultUser.put("endpoints", Map.of("api", proxyUrl, "telemetry", "https://localhost:1/telemetry")); + defaultUser.put("endpoints", Map.of("api", proxyUrl, "telemetry", proxyUrl)); defaultUser.put("analytics_tracking_id", "e2e-test-tracking-id"); proxy.setCopilotUserByToken(DEFAULT_GITHUB_TOKEN, defaultUser); diff --git a/java/sdk/src/test/java/com/github/copilot/E2ETestContextTest.java b/java/sdk/src/test/java/com/github/copilot/E2ETestContextTest.java index bf307f6547..6e99145ac4 100644 --- a/java/sdk/src/test/java/com/github/copilot/E2ETestContextTest.java +++ b/java/sdk/src/test/java/com/github/copilot/E2ETestContextTest.java @@ -6,12 +6,37 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; import java.util.List; import org.junit.jupiter.api.Test; +import com.fasterxml.jackson.databind.ObjectMapper; + class E2ETestContextTest { + @Test + void defaultTelemetryEndpointUsesTheOwnedProxy() throws Exception { + try (E2ETestContext ctx = E2ETestContext.create()) { + var client = HttpClient.newHttpClient(); + var userRequest = HttpRequest.newBuilder(URI.create(ctx.getProxyUrl() + "/copilot_internal/user")) + .header("Authorization", "Bearer " + ctx.getEnvironment().get("GH_TOKEN")).build(); + var userResponse = client.send(userRequest, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, userResponse.statusCode()); + var telemetryEndpoint = new ObjectMapper().readTree(userResponse.body()).path("endpoints").path("telemetry") + .asText(); + assertEquals(ctx.getProxyUrl(), telemetryEndpoint); + var telemetryRequest = HttpRequest.newBuilder(URI.create(telemetryEndpoint + "/telemetry")) + .POST(HttpRequest.BodyPublishers.ofString("{}\n")).build(); + var telemetryResponse = client.send(telemetryRequest, HttpResponse.BodyHandlers.ofString()); + assertEquals(204, telemetryResponse.statusCode()); + assertEquals("", telemetryResponse.body()); + } + } + @Test void expectedUserPromptsParseFoldedBlockScalars() { String snapshot = """ diff --git a/java/sdk/src/test/java/com/github/copilot/RpcHandlerDispatcherTest.java b/java/sdk/src/test/java/com/github/copilot/RpcHandlerDispatcherTest.java index a92a4b561d..a610007f0e 100644 --- a/java/sdk/src/test/java/com/github/copilot/RpcHandlerDispatcherTest.java +++ b/java/sdk/src/test/java/com/github/copilot/RpcHandlerDispatcherTest.java @@ -580,6 +580,10 @@ void skillProviderReadNullReturnsNullMarkdown() throws Exception { @Test void skillProviderFailuresUseStableMessagesWithoutData() throws Exception { + // Keep dispatch and logging outside the socket-read timeout. + var immediateDispatcher = new RpcHandlerDispatcher(sessions, lifecycleEvents::add, Runnable::run, + gitHubTokenProviders); + immediateDispatcher.registerHandlers(rpc); CopilotSession session = createSession("s1"); session.registerSkillProvider(skillProvider( () -> CompletableFuture.failedFuture(new IllegalStateException("secret list failure")), name -> { diff --git a/java/sdk/src/test/java/com/github/copilot/RpcWrappersTest.java b/java/sdk/src/test/java/com/github/copilot/RpcWrappersTest.java index 3fc2b499d1..c5309a20c0 100644 --- a/java/sdk/src/test/java/com/github/copilot/RpcWrappersTest.java +++ b/java/sdk/src/test/java/com/github/copilot/RpcWrappersTest.java @@ -50,9 +50,12 @@ import com.github.copilot.generated.rpc.SessionConnectorsRefreshParams; import com.github.copilot.generated.rpc.SessionConnectorsRefreshResult; import com.github.copilot.generated.rpc.SessionMcpListConfiguredResult; +import com.github.copilot.generated.rpc.SessionModelGetReasoningSummariesParams; +import com.github.copilot.generated.rpc.SessionModelGetReasoningSummariesResult; import com.github.copilot.generated.rpc.SessionModelSwitchToParams; import com.github.copilot.generated.rpc.SessionModelSwitchToRequest; import com.github.copilot.generated.rpc.SessionRpc; +import com.github.copilot.rpc.AgentInfo; /** * Unit tests for the generated RPC wrapper classes ({@link ServerRpc} and @@ -190,6 +193,33 @@ void serverRpc_mcp_discover_passes_params() { // ── SessionRpc tests ────────────────────────────────────────────────────── + @ParameterizedTest + @CsvSource({"true,false", "false,true", "null,null"}) + void sessionRpc_reasoning_summaries_accepts_only_host_state(String persisted, String visible) { + var stub = new StubCaller(); + var session = new SessionRpc(stub, "reasoning-session"); + Boolean persistedShowReasoning = "null".equals(persisted) ? null : Boolean.valueOf(persisted); + Boolean summariesVisible = "null".equals(visible) ? null : Boolean.valueOf(visible); + var params = new SessionModelGetReasoningSummariesParams(persistedShowReasoning, summariesVisible); + + assertNull(params.sessionId()); + session.model.getReasoningSummaries(params).join(); + + assertEquals(1, stub.calls.size()); + var call = stub.calls.get(0); + assertEquals("session.model.getReasoningSummaries", call.method()); + assertEquals(SessionModelGetReasoningSummariesResult.class, call.resultType()); + var payload = assertInstanceOf(JsonNode.class, call.params()); + var expected = new ObjectMapper().createObjectNode().put("sessionId", "reasoning-session"); + if (persistedShowReasoning != null) { + expected.put("persistedShowReasoning", persistedShowReasoning); + } + if (summariesVisible != null) { + expected.put("summariesVisible", summariesVisible); + } + assertEquals(expected, payload); + } + @Test @AllowCopilotExperimental void sessionRpc_mcp_listConfigured_preserves_runtime_lifecycle() throws Exception { @@ -575,6 +605,56 @@ void serverRpc_account_getQuota_invokes_correct_method() { // RpcHandlerDispatcherTest) to construct a real CopilotSession and verify // that getRpc() returns a correctly wired SessionRpc. + @ParameterizedTest + @ValueSource(strings = {"list", "getCurrent", "select"}) + void copilotSession_agent_methods_deserialize_scoped_hooks(String method) throws Exception { + var mapper = JsonRpcClient.getObjectMapper(); + var agentJson = mapper.readTree(""" + { + "name": "hook-agent", + "displayName": "Hook Agent", + "description": "Agent with scoped hooks", + "hooks": { + "preToolUse": [{"type":"command","bash":"echo scoped-hook","timeoutSec":10}], + "sessionStart": [{"type":"command","bash":"echo started"}] + } + } + """); + try (var sockets = new SocketPair()) { + var stub = sockets.stubServer(); + var session = new CopilotSession("sess-agent-hooks", sockets.client()); + try { + CompletableFuture> future = switch (method) { + case "list" -> session.listAgents(); + case "getCurrent" -> session.getCurrentAgent().thenApply(List::of); + case "select" -> session.selectAgent("hook-agent").thenApply(List::of); + default -> throw new IllegalArgumentException(method); + }; + var request = stub.readOneMessage(); + assertEquals("session.agent." + method, request.get("method").asText()); + assertEquals("sess-agent-hooks", request.get("params").get("sessionId").asText()); + if ("select".equals(method)) { + assertEquals("hook-agent", request.get("params").get("name").asText()); + } + var result = mapper.createObjectNode(); + if ("list".equals(method)) { + result.putArray("agents").add(agentJson); + } else { + result.set("agent", agentJson); + } + stub.respond(request, result); + + var agents = future.get(3, TimeUnit.SECONDS); + assertEquals(1, agents.size()); + assertEquals("hook-agent", agents.get(0).getName()); + assertNotNull(agents.get(0).getHooks()); + assertEquals(agentJson.get("hooks"), mapper.valueToTree(agents.get(0).getHooks())); + } finally { + session.forceStopLocally(); + } + } + } + @Test void copilotSession_getRpc_returns_non_null_session_rpc() throws Exception { try (var sockets = new SocketPair()) { diff --git a/java/sdk/src/test/java/com/github/copilot/SessionEventHandlingTest.java b/java/sdk/src/test/java/com/github/copilot/SessionEventHandlingTest.java index 8f2edf52e0..64c32b4a74 100644 --- a/java/sdk/src/test/java/com/github/copilot/SessionEventHandlingTest.java +++ b/java/sdk/src/test/java/com/github/copilot/SessionEventHandlingTest.java @@ -295,8 +295,8 @@ void testSendAndWaitIgnoresChildEvents() throws Exception { dispatchEvent(childMessage); var childError = new SessionErrorEvent(); childError.setAgentId("child-1"); - childError.setData(new SessionErrorEvent.SessionErrorEventData("query", null, null, "child failed", null, - null, null, null, null, null)); + childError.setData(new SessionErrorEvent.SessionErrorEventData("query", null, null, null, null, + "child failed", null, null, null, null, null, null)); dispatchEvent(childError); var childIdle = createSessionIdleEvent(); childIdle.setAgentId("child-1"); diff --git a/java/sdk/src/test/java/com/github/copilot/SessionRequestBuilderTest.java b/java/sdk/src/test/java/com/github/copilot/SessionRequestBuilderTest.java index 978346e486..09b036c6fc 100644 --- a/java/sdk/src/test/java/com/github/copilot/SessionRequestBuilderTest.java +++ b/java/sdk/src/test/java/com/github/copilot/SessionRequestBuilderTest.java @@ -6,6 +6,8 @@ import static org.junit.jupiter.api.Assertions.*; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -100,6 +102,71 @@ void clearingTranscriptRecoveryRestoresRuntimeDefaultInAllModes() throws Excepti } } + @Test + void customizationDirectoriesArePreservedOnCreateAndResume() throws Exception { + var mapper = JsonRpcClient.getObjectMapper(); + for (int kind = 0; kind < 3; kind++) { + List roots = kind == 0 ? null : kind == 1 ? List.of() : List.of("relative-root", "other-root"); + var directories = new HashMap>(); + for (var type : List.of("skill", "agent", "instruction", "hook")) { + directories.put(type + "Directories", + roots == null ? null : roots.stream().map(root -> root + "-" + type).toList()); + } + var create = SessionRequestBuilder.buildCreateRequest( + new SessionConfig().setWorkingDirectory("request-cwd").setEnableConfigDiscovery(false) + .setEnableFileHooks(false).setSkillDirectories(directories.get("skillDirectories")) + .setAgentDirectories(directories.get("agentDirectories")) + .setInstructionDirectories(directories.get("instructionDirectories")) + .setHookDirectories(directories.get("hookDirectories")), + "created"); + var resume = SessionRequestBuilder.buildResumeRequest("resumed", + new ResumeSessionConfig().setWorkingDirectory("resume-cwd").setEnableConfigDiscovery(false) + .setEnableFileHooks(false).setSkillDirectories(directories.get("skillDirectories")) + .setAgentDirectories(directories.get("agentDirectories")) + .setInstructionDirectories(directories.get("instructionDirectories")) + .setHookDirectories(directories.get("hookDirectories"))); + for (var request : List.of(create, resume)) { + var wire = mapper.readTree(mapper.writeValueAsBytes(request)); + for (var entry : directories.entrySet()) { + if (entry.getValue() == null) { + assertFalse(wire.has(entry.getKey()), wire.toString()); + } else { + assertEquals(mapper.valueToTree(entry.getValue()), wire.get(entry.getKey())); + } + } + assertFalse(wire.path("enableConfigDiscovery").asBoolean(true)); + assertFalse(wire.path("enableFileHooks").asBoolean(true)); + assertFalse(wire.has("additionalDirectories")); + assertFalse(wire.has("customAgents")); + assertFalse(wire.path("hooks").asBoolean()); + } + } + } + + @Test + void customizationDirectoryClonesOwnTheirLists() { + var agents = new ArrayList<>(List.of("agents")); + var hooks = new ArrayList<>(List.of("hooks")); + var create = new SessionConfig().setAgentDirectories(agents).setHookDirectories(hooks); + var resume = new ResumeSessionConfig().setAgentDirectories(agents).setHookDirectories(hooks); + var createClone = create.clone(); + var resumeClone = resume.clone(); + agents.add("added-agents"); + hooks.add("added-hooks"); + assertEquals(List.of("agents"), create.getAgentDirectories()); + assertEquals(List.of("hooks"), create.getHookDirectories()); + assertEquals(List.of("agents"), resume.getAgentDirectories()); + assertEquals(List.of("hooks"), resume.getHookDirectories()); + assertEquals(List.of("agents"), createClone.getAgentDirectories()); + assertEquals(List.of("hooks"), createClone.getHookDirectories()); + assertEquals(List.of("agents"), resumeClone.getAgentDirectories()); + assertEquals(List.of("hooks"), resumeClone.getHookDirectories()); + assertThrows(UnsupportedOperationException.class, () -> createClone.getAgentDirectories().add("mutation")); + assertThrows(UnsupportedOperationException.class, () -> resumeClone.getHookDirectories().add("mutation")); + assertThrows(UnsupportedOperationException.class, () -> create.getAgentDirectories().add("mutation")); + assertThrows(UnsupportedOperationException.class, () -> resume.getHookDirectories().add("mutation")); + } + // ========================================================================= // buildCreateRequest // ========================================================================= diff --git a/java/sdk/src/test/java/com/github/copilot/generated/rpc/GeneratedRpcRecordsCoverageTest.java b/java/sdk/src/test/java/com/github/copilot/generated/rpc/GeneratedRpcRecordsCoverageTest.java index 73e0843c57..ed47710539 100644 --- a/java/sdk/src/test/java/com/github/copilot/generated/rpc/GeneratedRpcRecordsCoverageTest.java +++ b/java/sdk/src/test/java/com/github/copilot/generated/rpc/GeneratedRpcRecordsCoverageTest.java @@ -723,7 +723,7 @@ void pingResult_fields() { @Test void sessionAgentListResult_with_items() { var item = new AgentInfo("name1", "Name One", "Desc 1", "/path/to/agent1", null, null, null, null, null, null, - null, null, null, null, null, null); + null, null, null, null, null, null, null); var result = new SessionAgentListResult(List.of(item)); assertEquals(1, result.agents().size()); assertEquals("name1", result.agents().get(0).name()); @@ -735,7 +735,7 @@ void sessionAgentListResult_with_items() { @Test void sessionAgentGetCurrentResult_nested() { var agent = new AgentInfo("agent-1", "Agent One", "Does things", null, null, null, null, null, null, null, null, - null, null, null, null, null); + null, null, null, null, null, null); var result = new SessionAgentGetCurrentResult(agent); assertEquals("agent-1", result.agent().name()); assertEquals("Agent One", result.agent().displayName()); @@ -752,18 +752,25 @@ void sessionAgentGetCurrentResult_null_agent() { @Test void sessionAgentReloadResult_with_items() { var item = new AgentInfo("a", "A", "Desc", "/path/to/a", null, null, null, null, null, null, null, null, null, - null, null, null); + null, null, null, null); var result = new SessionAgentReloadResult(List.of(item)); assertEquals(1, result.agents().size()); assertEquals("a", result.agents().get(0).name()); } @Test - void sessionAgentSelectResult_nested() { + void sessionAgentSelectResult_nested() throws Exception { + Map> hooks = Map.of("Stop", + List.of(Map.of("type", "command", "command", "echo scoped-stop"))); var agent = new AgentInfo("selected", "Selected", "The selected agent", "/path/to/selected", null, null, null, - null, null, null, null, null, null, null, null, null); + null, null, null, null, null, null, null, null, null, hooks); var result = new SessionAgentSelectResult(agent); assertEquals("selected", result.agent().name()); + var mapper = new ObjectMapper(); + var json = mapper.writeValueAsString(result); + assertEquals("echo scoped-stop", + mapper.readTree(json).get("agent").get("hooks").get("Stop").get(0).get("command").asText()); + assertEquals(hooks, mapper.readValue(json, SessionAgentSelectResult.class).agent().hooks()); } @Test diff --git a/nodejs/README.md b/nodejs/README.md index cf64fac0f7..2e86f7d603 100644 --- a/nodejs/README.md +++ b/nodejs/README.md @@ -671,6 +671,23 @@ if (result.status === "pending") { See [Auto tier persistence](../docs/features/session-persistence.md#auto-tier-persistence) for the full lifecycle rules. +##### `rpc.model.getReasoningSummaries(params)` (experimental) + +Read the current model's reasoning-summary presentation policy without changing session state. Call `session.rpc.model.list()` first to load the model catalog; otherwise the result may have `ready: false`. The request and result types are exported from `@github/copilot-sdk`. + +```typescript +import type { + ModelGetReasoningSummariesRequest, + ModelGetReasoningSummariesResult, +} from "@github/copilot-sdk"; + +const presentation: ModelGetReasoningSummariesRequest = { summariesVisible: false }; +const policy: ModelGetReasoningSummariesResult = + await session.rpc.model.getReasoningSummaries(presentation); +``` + +Omit `persistedShowReasoning` when no visibility setting is saved. `visibility` can remain unset while experiment assignment is pending; `clearRedundantSetting` tells the host when its persisted setting matches the model default. + ##### `setTools(tools: Tool[]): Promise` Replace the tools this client supplies to the session, together with the handlers that serve them (experimental). `tools` takes the same definitions as `createSession` and becomes this client's complete tool set; pass `[]` to remove all of this client's tools. Built-in, MCP, and plugin tools, and tools other connected clients supply, are unaffected. @@ -1635,6 +1652,26 @@ npm ci npm test ``` +### Internal feature-flag example + +[`examples/internal-feature-flags.ts`](examples/internal-feature-flags.ts) uses +the generated internal RPC factory against a real runtime over stdio. +It lists the catalog and shows environment, settings, and explicit-override +precedence. It also checks that static resolution does not apply `COPILOT_EXP_*` +experiment assignments. It creates no session and sends no model request. + +After you prepare matching runtime artifacts, run this from the runtime repository root: + +```bash +COPILOT_RUNTIME_PROVIDER_LIB="$PWD/bazel-bin/src/native/runtime/runtime.node" \ + src/sdk/nodejs/node_modules/.bin/tsx \ + src/sdk/nodejs/examples/internal-feature-flags.ts \ + "$PWD/bazel-bin/src/runtime-bin/copilot-runtime" +``` + +The JSON output includes `staticResolution` values of `false`, `true`, `false`, +and `true`, in that order. These methods are internal, not public SDK APIs. + ## License MIT diff --git a/nodejs/examples/internal-feature-flags.ts b/nodejs/examples/internal-feature-flags.ts new file mode 100644 index 0000000000..83824012fc --- /dev/null +++ b/nodejs/examples/internal-feature-flags.ts @@ -0,0 +1,95 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import assert from "node:assert/strict"; +import { spawn } from "node:child_process"; +import { once } from "node:events"; +import { mkdtemp, rm } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join, resolve } from "node:path"; +import { createMessageConnection } from "vscode-jsonrpc/node.js"; +import { createInternalServerRpc } from "../src/generated/rpc.js"; + +async function showFeatureFlags(rpc: ReturnType) { + await rpc.connect({}); + const { flags } = await rpc.featureFlags.listMetadata(); + assert.equal(flags.TASK_ANALYTICS.name, "TASK_ANALYTICS"); + assert.equal(flags.TASK_ANALYTICS.expFlagEnvVar, "COPILOT_EXP_COPILOT_CLI_TASK_ANALYTICS"); + + const population = { isStaff: false, isExperimental: false, isTeam: false }; + const experimentOnly = await rpc.featureFlags.resolve({ + ...population, + environment: { COPILOT_EXP_COPILOT_CLI_TASK_ANALYTICS: "true" }, + }); + assert.equal(experimentOnly.TASK_ANALYTICS, false); + + const request = { + ...population, + baseFlags: { TASK_ANALYTICS: false }, + environment: { TASK_ANALYTICS: "true" }, + }; + const environment = await rpc.featureFlags.resolve(request); + const config = { enabledFeatureFlags: { TASK_ANALYTICS: false } }; + const settings = await rpc.featureFlags.resolve({ ...request, config }); + const explicit = await rpc.featureFlags.resolve({ + ...request, + config, + flagOverrides: { TASK_ANALYTICS: true }, + }); + assert.deepEqual(environment, { TASK_ANALYTICS: true }); + assert.deepEqual(settings, { TASK_ANALYTICS: false }); + assert.deepEqual(explicit, { TASK_ANALYTICS: true }); + + console.log( + JSON.stringify({ + declaredFlags: Object.keys(flags).length, + metadata: flags.TASK_ANALYTICS, + staticResolution: { + experimentOnly: experimentOnly.TASK_ANALYTICS, + environment: environment.TASK_ANALYTICS, + settings: settings.TASK_ANALYTICS, + explicit: explicit.TASK_ANALYTICS, + }, + }) + ); +} + +const runtimePath = process.argv[2]; +if (!runtimePath) { + throw new Error("Usage: tsx examples/internal-feature-flags.ts "); +} + +const home = await mkdtemp(join(tmpdir(), "copilot-feature-flags-")); +const child = spawn( + resolve(runtimePath), + ["--server", "--stdio", "--no-auto-login", "--no-auto-update", "--no-remote"], + { + cwd: home, + env: { ...process.env, COPILOT_HOME: home, COPILOT_CONNECTION_TOKEN: "" }, + stdio: ["pipe", "pipe", "inherit"], + windowsHide: true, + } +); +const closed = once(child, "close"); +const connection = createMessageConnection(child.stdout, child.stdin); +connection.listen(); +try { + await Promise.race([ + showFeatureFlags(createInternalServerRpc(connection)), + closed.then(([code, signal]) => { + throw new Error( + `Runtime exited before the example completed: code=${code}, signal=${signal}` + ); + }), + ]); +} finally { + connection.dispose(); + child.stdin.end(); + try { + const [code, signal] = await closed; + assert.equal(code, 0, `Runtime exit signal: ${signal}`); + } finally { + await rm(home, { recursive: true, force: true }); + } +} diff --git a/nodejs/examples/internal-user-settings.ts b/nodejs/examples/internal-user-settings.ts new file mode 100644 index 0000000000..8bc4641903 --- /dev/null +++ b/nodejs/examples/internal-user-settings.ts @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import type { createInternalServerRpc } from "../src/generated/rpc.js"; + +// Internal host example; these methods are not part of the public SDK API. +export async function editUserSettings( + settings: ReturnType["user"]["settings"], + configDir: string +) { + const validation = await settings.validate({ + topKey: "voice", + value: { enabled: true }, + }); + if (!validation.ok) { + throw new Error(JSON.stringify(validation.issues)); + } + await settings.update({ + key: "voice", + value: { enabled: true }, + configDir, + }); + return settings.update({ + key: "voice", + value: { selectedModel: null }, + configDir, + }); +} diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index e8104e0779..fc233f8b94 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -28,13 +28,12 @@ "json-schema": "^0.4.0", "json-schema-to-typescript": "^15.0.4", "prettier": "^3.8.1", - "quicktype-core": "^23.2.6", "rimraf": "^6.1.2", "semver": "^7.7.3", "tar": "^7.5.22", "tsx": "^4.20.6", "typescript": "^5.0.0", - "vitest": "^4.0.18", + "vitest": "^4.1.11", "ws": "^8.21.0" }, "engines": { @@ -58,37 +57,6 @@ "url": "https://github.com/sponsors/philsturgeon" } }, - "node_modules/@emnapi/core": { - "version": "1.10.0", - "integrity": "sha1-OAzMjyQS6iLR2XLff47iOjucdGc=", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.1", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.10.0", - "integrity": "sha1-SyYMDTU0IE6YxhELjbGph9JuyHw=", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "integrity": "sha1-KP7SGhuhznl8RKBwq8lNQvOuhUg=", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@esbuild/aix-ppc64": { "version": "0.28.1", "integrity": "sha1-egGo0uwvuy2seK2tCbD6eB5Agr4=", @@ -660,12 +628,6 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@glideapps/ts-necessities": { - "version": "2.2.3", - "integrity": "sha512-gXi0awOZLHk3TbW55GZLCPP6O+y/b5X1pBXKBVckFONSwF1z1E5ND2BGJsghQFah+pW7pkkyFb2VhUQI2qhL5w==", - "dev": true, - "license": "MIT" - }, "node_modules/@hpke/chacha20poly1305": { "version": "1.8.0", "integrity": "sha1-1NL248zgi0xVU5IOFbTlmMildy4=", @@ -724,27 +686,40 @@ } }, "node_modules/@humanfs/core": { - "version": "0.19.1", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "version": "0.19.2", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", "dev": true, "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, "engines": { "node": ">=18.18.0" } }, "node_modules/@humanfs/node": { - "version": "0.16.7", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "version": "0.16.8", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@humanfs/core": "^0.19.1", + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", "@humanwhocodes/retry": "^0.4.0" }, "engines": { "node": ">=18.18.0" } }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", @@ -784,8 +759,8 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "version": "1.6.0", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "dev": true, "license": "MIT" }, @@ -1072,34 +1047,13 @@ "dev": true, "license": "MIT" }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.2.3", - "integrity": "sha1-l+PUXXQk3F2h1OMvO/OykvbBtEw=", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.3" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=23.5.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", - "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" - } - }, "node_modules/@oxc-project/types": { - "version": "0.133.0", - "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", + "version": "0.153.0", + "integrity": "sha512-jSNrRIyvPVLL5E1z/tS5zLAprosGz/FuI1PWwEOz59j3E4TTTzSpqKb/RDGqJhhW0QHYISGXxq582wGx6T11Tw==", "dev": true, "license": "MIT", "funding": { - "url": "https://github.com/sponsors/Boshen" + "url": "https://github.com/sponsors/oxc-project" } }, "node_modules/@platformatic/vfs": { @@ -1111,9 +1065,25 @@ "node": ">= 22" } }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.13", + "integrity": "sha512-Vu/NICrgdRvUOeaJZIyB2FP63s6fO/4ud5l8dXmxDx9yDyn+mN0y+gsvsVviSli+T361Aqo0h46EuMoobrwawA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.3", - "integrity": "sha1-VM6Pg4IhP0oxSgwve6g/gf/q5ZI=", + "version": "1.2.13", + "integrity": "sha512-6LEoIrGy5vvCd2boNnv2soPSUZj/PRvhp8R/t9KlX+mIZxThIE/ZqxrGXxmuNX0FuvQFvLdZr7S4HrYpYBVhEQ==", "cpu": [ "arm64" ], @@ -1128,8 +1098,8 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.3", - "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", + "version": "1.2.13", + "integrity": "sha512-CaJSRzlQ6Q+zkDMVA9OkVxBjVoPRCDEE3v0FSJ9kIQBgRjFApA3Si4ijhbNVUji7ZJt+PfO0e46qy4nPInHUPA==", "cpu": [ "arm64" ], @@ -1144,8 +1114,8 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.3", - "integrity": "sha1-U/V94fWZ7PHbE4I8/IjBj7gJVK0=", + "version": "1.2.13", + "integrity": "sha512-e4r340I5hxSzJkD3YJBxgzq/rJ3wwxwdLLb2FPt1Zpyem20nrQPT11DDEEkazwxaHumH8wpglsp/Ozgj/wT6mw==", "cpu": [ "x64" ], @@ -1160,8 +1130,8 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.3", - "integrity": "sha1-bz/dobeuqsnSaKUmgEtPuW5ONfE=", + "version": "1.2.13", + "integrity": "sha512-hoBWDZ4/K/mJKVMbsgUd1jfpA2DiOrJ54mpegObU9TBHBBrtX4FLIXJJQRDPZ/2Dn91GvPob+Z2hwKJzf4E5SQ==", "cpu": [ "x64" ], @@ -1176,8 +1146,8 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.3", - "integrity": "sha1-2HpFS/WFzJZ2hJN36R1uN1KXMm8=", + "version": "1.2.13", + "integrity": "sha512-oF9fZu3vTWnTiVAkDFxU9PJLt1nh20K9RRpuHsR7ZnE2L7XookBbDBVLojCVSLGbvtSlxeUNnjAj6DbNsKyzbg==", "cpu": [ "arm" ], @@ -1192,12 +1162,15 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.3", - "integrity": "sha1-QZ/Wv2Es80jxBSjLzZTrq5YH2NE=", + "version": "1.2.13", + "integrity": "sha512-DTpb/+jMiqWMPgphn4ksW1zW+XLJ6dJJ9FMvnIk9I291LhCctMPhMYJrP5t9p6C9qa3KXadDdUEZHBaPh3kNxQ==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1208,12 +1181,15 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.3", - "integrity": "sha1-/MaRhpa7doRId+HkkwoY/Q03QGk=", + "version": "1.2.13", + "integrity": "sha512-xU+Kvv9N2A3SY35zFh1FWWNjxbadE/BKeqnkXe7vScU4GZsw757BlVmDLITZEq8DPpk6m7uoDYkK7P+x/uU5Ow==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1224,12 +1200,15 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.3", - "integrity": "sha1-Mq7LfI2uXU8qjN5XoFjshpkVQvg=", + "version": "1.2.13", + "integrity": "sha512-XMk/hnhh25oQ756Lclb1Q11h4ll0xC0Esa5w4Vzp+mAE2S3AGJgeM0SonrIgY8fHhjarb6hcoTuwoFG0VVP2ig==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1240,12 +1219,15 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.3", - "integrity": "sha1-vtk0bqgea7i5PPEfXYi3fbiQt2M=", + "version": "1.2.13", + "integrity": "sha512-U1BoTHYmlywE2n3HUWjzZ+8EQsKr+OwpxYuDWaubx42tUL8QSL7nOqRz/NVHanibbFP3M1Rxuprz/wNcbMKjqw==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1256,12 +1238,15 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.3", - "integrity": "sha1-ZMLSb3Xf/ZtaH5dVegCudyUMjLc=", + "version": "1.2.13", + "integrity": "sha512-J4cm80Pc6wEwV5AZ42o62sIQgDk+Y7R2s646jIwuvO+4V46QB58N4vVuMPWCBaNgursXLpmUWJV//WQAkPvHBQ==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1272,12 +1257,15 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.3", - "integrity": "sha1-WkUTLopHZZ7qrztUDClUqXyGD/M=", + "version": "1.2.13", + "integrity": "sha512-W0euZS40U4V6JkmEnVCIX9mcsL6cbXQ4X8c2w+MMOIjFg68TXUW+u3RT+2e1t1pv9mg/EP3pDtK3POXdQ7Rxyw==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1288,8 +1276,8 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.3", - "integrity": "sha1-KQUTBoxV6EnchFejKv7h17Csswk=", + "version": "1.2.13", + "integrity": "sha512-do/AF/4n9MRshia3a5aXoy8xM2c6mgfT6D7H/dY6my5z+hfCIR4ab7mk4IRj++nsEQpKy39kd0DQnDq+r692tw==", "cpu": [ "arm64" ], @@ -1303,27 +1291,9 @@ "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.3", - "integrity": "sha1-PZly2/GpU9PHr6pKDyDvKy458xs=", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "1.10.0", - "@emnapi/runtime": "1.10.0", - "@napi-rs/wasm-runtime": "^1.1.4" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.3", - "integrity": "sha1-oASrYHoW1vA7y1VXKP+IivdXc60=", + "version": "1.2.13", + "integrity": "sha512-6FtUf2cJZobutJdxnGYX8z0vtbgqU0b2v8vfBhkXb9wp2MppMFtkunE+IaOntyi01rkIQoPW2GHABtfzsC0BRQ==", "cpu": [ "arm64" ], @@ -1338,8 +1308,8 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.3", - "integrity": "sha1-4qJbNGkaHMihIJ195wkGMCbdDNs=", + "version": "1.2.13", + "integrity": "sha512-UKhFaZTeTcbKrb3iU82m17jVcPEAoqDkCN5MBqgPyZSwp/cQmib21crTS0DdH7T1B7wZRWEI89YQAOJMet5yhg==", "cpu": [ "x64" ], @@ -1365,16 +1335,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.3", - "integrity": "sha1-AVy6np3UfOFNA9KoxdVHv7FpZl0=", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@types/chai": { "version": "5.2.3", "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", @@ -1656,15 +1616,15 @@ } }, "node_modules/@vitest/expect": { - "version": "4.1.8", - "integrity": "sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==", + "version": "4.1.11", + "integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -1673,12 +1633,12 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.8", - "integrity": "sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==", + "version": "4.1.11", + "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.8", + "@vitest/spy": "4.1.11", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -1699,8 +1659,8 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.8", - "integrity": "sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==", + "version": "4.1.11", + "integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==", "dev": true, "license": "MIT", "dependencies": { @@ -1711,12 +1671,12 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.8", - "integrity": "sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==", + "version": "4.1.11", + "integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.8", + "@vitest/utils": "4.1.11", "pathe": "^2.0.3" }, "funding": { @@ -1724,13 +1684,13 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.8", - "integrity": "sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==", + "version": "4.1.11", + "integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/pretty-format": "4.1.11", + "@vitest/utils": "4.1.11", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -1739,8 +1699,8 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.8", - "integrity": "sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==", + "version": "4.1.11", + "integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==", "dev": true, "license": "MIT", "funding": { @@ -1748,12 +1708,12 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.8", - "integrity": "sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==", + "version": "4.1.11", + "integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.8", + "@vitest/pretty-format": "4.1.11", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -1761,18 +1721,6 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/abort-controller": { - "version": "3.0.0", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dev": true, - "license": "MIT", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, "node_modules/acorn": { "version": "8.15.0", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", @@ -1831,29 +1779,9 @@ "dev": true, "license": "MIT" }, - "node_modules/base64-js": { - "version": "1.5.1", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/brace-expansion": { - "version": "1.1.16", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "version": "1.1.21", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", "dev": true, "license": "MIT", "dependencies": { @@ -1861,36 +1789,6 @@ "concat-map": "0.0.1" } }, - "node_modules/browser-or-node": { - "version": "3.0.0", - "integrity": "sha512-iczIdVJzGEYhP5DqQxYM9Hh7Ztpqqi+CXZpSmX8ALFs9ecXkQIeqRyM6TfxEfMVpwhl3dSuDvxdzzo9sUOIVBQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/buffer": { - "version": "6.0.3", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, "node_modules/callsites": { "version": "3.1.0", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", @@ -1901,8 +1799,8 @@ } }, "node_modules/chai": { - "version": "6.2.2", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "version": "6.3.0", + "integrity": "sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==", "dev": true, "license": "MIT", "engines": { @@ -1949,12 +1847,6 @@ "node": ">=18" } }, - "node_modules/collection-utils": { - "version": "1.0.1", - "integrity": "sha512-LA2YTIlR7biSpXkKYwwuzGjwL5rjWEZVOSnvdUc7gObvWe4WkjxOpfrdhoP7Hs09YWDVfg0Mal9BpAqLfVEzQg==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/color-convert": { "version": "2.0.1", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", @@ -1985,15 +1877,6 @@ "dev": true, "license": "MIT" }, - "node_modules/cross-fetch": { - "version": "4.1.0", - "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "node-fetch": "^2.7.0" - } - }, "node_modules/cross-spawn": { "version": "7.0.6", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", @@ -2299,24 +2182,6 @@ "node": ">=0.10.0" } }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/events": { - "version": "3.3.0", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, "node_modules/expect-type": { "version": "1.3.0", "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", @@ -2488,26 +2353,6 @@ "node": ">=16.0.0" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, "node_modules/ignore": { "version": "7.0.5", "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", @@ -2563,24 +2408,12 @@ "node": ">=0.10.0" } }, - "node_modules/is-url": { - "version": "1.2.4", - "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", - "dev": true, - "license": "MIT" - }, "node_modules/isexe": { "version": "2.0.0", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true, "license": "ISC" }, - "node_modules/js-base64": { - "version": "3.7.8", - "integrity": "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==", - "dev": true, - "license": "BSD-3-Clause" - }, "node_modules/js-yaml": { "version": "4.3.2", "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", @@ -2702,8 +2535,8 @@ } }, "node_modules/lightningcss": { - "version": "1.32.0", - "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "version": "1.33.0", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", "dev": true, "license": "MPL-2.0", "dependencies": { @@ -2717,22 +2550,22 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "lightningcss-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" } }, "node_modules/lightningcss-android-arm64": { - "version": "1.32.0", - "integrity": "sha1-8DOIURbf79nG9UeHUj41FLYeGWg=", + "version": "1.33.0", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", "cpu": [ "arm64" ], @@ -2751,8 +2584,8 @@ } }, "node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", - "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "version": "1.33.0", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", "cpu": [ "arm64" ], @@ -2771,8 +2604,8 @@ } }, "node_modules/lightningcss-darwin-x64": { - "version": "1.32.0", - "integrity": "sha1-NfPpczLRMLnKGB4RtWje1q68bV4=", + "version": "1.33.0", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", "cpu": [ "x64" ], @@ -2791,8 +2624,8 @@ } }, "node_modules/lightningcss-freebsd-x64": { - "version": "1.32.0", - "integrity": "sha1-l3enZHK2Ttb/lDQq1kx7r9eUpXU=", + "version": "1.33.0", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", "cpu": [ "x64" ], @@ -2811,8 +2644,8 @@ } }, "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.32.0", - "integrity": "sha1-E65lLhq3O5E117faFy9mbEEK1T0=", + "version": "1.33.0", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", "cpu": [ "arm" ], @@ -2831,12 +2664,15 @@ } }, "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.32.0", - "integrity": "sha1-QXhYeVqUWS9oASOhsfnaig4e8zU=", + "version": "1.33.0", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2851,12 +2687,15 @@ } }, "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.32.0", - "integrity": "sha1-a+NmkugQtxgECAL9gJYjz/5zITM=", + "version": "1.33.0", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2871,12 +2710,15 @@ } }, "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.32.0", - "integrity": "sha1-C3gDr06yHP043Tn+Kru1PH3QkfY=", + "version": "1.33.0", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2891,12 +2733,15 @@ } }, "node_modules/lightningcss-linux-x64-musl": { - "version": "1.32.0", - "integrity": "sha1-iNyLqGXd3bGsXvBLDxYYBEGMFjs=", + "version": "1.33.0", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2911,8 +2756,8 @@ } }, "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.32.0", - "integrity": "sha1-TzC6P6XpJfW3n5RejMDRdsOxqzg=", + "version": "1.33.0", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", "cpu": [ "arm64" ], @@ -2931,8 +2776,8 @@ } }, "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.32.0", - "integrity": "sha1-FBqlYFZFBkkokCu0rwRfp9n0Igo=", + "version": "1.33.0", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", "cpu": [ "x64" ], @@ -3020,8 +2865,8 @@ } }, "node_modules/minimatch/node_modules/brace-expansion": { - "version": "5.0.8", - "integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==", + "version": "5.0.12", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3068,8 +2913,8 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.17", - "integrity": "sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g==", + "version": "3.3.20", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", "dev": true, "funding": [ { @@ -3091,26 +2936,6 @@ "dev": true, "license": "MIT" }, - "node_modules/node-fetch": { - "version": "2.7.0", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, "node_modules/obug": { "version": "2.1.1", "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", @@ -3174,12 +2999,6 @@ "dev": true, "license": "BlueOak-1.0.0" }, - "node_modules/pako": { - "version": "1.0.11", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true, - "license": "(MIT AND Zlib)" - }, "node_modules/parent-module": { "version": "1.0.1", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", @@ -3239,8 +3058,8 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.4", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "version": "4.0.7", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "dev": true, "license": "MIT", "engines": { @@ -3250,18 +3069,9 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pluralize": { - "version": "8.0.0", - "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/postcss": { - "version": "8.5.25", - "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==", + "version": "8.5.29", + "integrity": "sha512-49cGhUbXj8Qenv0iTMxA1cFBzxXoctpC9Ujd77t1WcbJIr6nF/eI7g/8MgxrYldFRuAXvja7xQRwavoW7kgrxQ==", "dev": true, "funding": [ { @@ -3279,9 +3089,9 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.16", + "nanoid": "^3.3.19", "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "source-map-js": "^1.2.2" }, "engines": { "node": "^10 || ^12 || >=14" @@ -3311,15 +3121,6 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/process": { - "version": "0.11.10", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/punycode": { "version": "2.3.1", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", @@ -3329,44 +3130,6 @@ "node": ">=6" } }, - "node_modules/quicktype-core": { - "version": "23.2.6", - "integrity": "sha512-asfeSv7BKBNVb9WiYhFRBvBZHcRutPRBwJMxW0pefluK4kkKu4lv0IvZBwFKvw2XygLcL1Rl90zxWDHYgkwCmA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@glideapps/ts-necessities": "2.2.3", - "browser-or-node": "^3.0.0", - "collection-utils": "^1.0.1", - "cross-fetch": "^4.0.0", - "is-url": "^1.2.4", - "js-base64": "^3.7.7", - "lodash": "^4.17.21", - "pako": "^1.0.6", - "pluralize": "^8.0.0", - "readable-stream": "4.5.2", - "unicode-properties": "^1.4.1", - "urijs": "^1.19.1", - "wordwrap": "^1.0.0", - "yaml": "^2.4.1" - } - }, - "node_modules/readable-stream": { - "version": "4.5.2", - "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "abort-controller": "^3.0.0", - "buffer": "^6.0.3", - "events": "^3.3.0", - "process": "^0.11.10", - "string_decoder": "^1.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, "node_modules/resolve-from": { "version": "4.0.0", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", @@ -3396,12 +3159,12 @@ } }, "node_modules/rolldown": { - "version": "1.0.3", - "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", + "version": "1.2.13", + "integrity": "sha512-/5apOkwWxtACcQtZ5WlrAsKS4JwXVThQPJZ3RqIruRY9UG9M8e0VlXN068xum/JRKA4aIUoJ13ghe/kGCvidiQ==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.133.0", + "@oxc-project/types": "=0.153.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -3411,42 +3174,22 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.3", - "@rolldown/binding-darwin-arm64": "1.0.3", - "@rolldown/binding-darwin-x64": "1.0.3", - "@rolldown/binding-freebsd-x64": "1.0.3", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", - "@rolldown/binding-linux-arm64-gnu": "1.0.3", - "@rolldown/binding-linux-arm64-musl": "1.0.3", - "@rolldown/binding-linux-ppc64-gnu": "1.0.3", - "@rolldown/binding-linux-s390x-gnu": "1.0.3", - "@rolldown/binding-linux-x64-gnu": "1.0.3", - "@rolldown/binding-linux-x64-musl": "1.0.3", - "@rolldown/binding-openharmony-arm64": "1.0.3", - "@rolldown/binding-wasm32-wasi": "1.0.3", - "@rolldown/binding-win32-arm64-msvc": "1.0.3", - "@rolldown/binding-win32-x64-msvc": "1.0.3" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" + "@rolldown/binding-android-arm-eabi": "1.2.13", + "@rolldown/binding-android-arm64": "1.2.13", + "@rolldown/binding-darwin-arm64": "1.2.13", + "@rolldown/binding-darwin-x64": "1.2.13", + "@rolldown/binding-freebsd-x64": "1.2.13", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.13", + "@rolldown/binding-linux-arm64-gnu": "1.2.13", + "@rolldown/binding-linux-arm64-musl": "1.2.13", + "@rolldown/binding-linux-ppc64-gnu": "1.2.13", + "@rolldown/binding-linux-s390x-gnu": "1.2.13", + "@rolldown/binding-linux-x64-gnu": "1.2.13", + "@rolldown/binding-linux-x64-musl": "1.2.13", + "@rolldown/binding-openharmony-arm64": "1.2.13", + "@rolldown/binding-win32-arm64-msvc": "1.2.13", + "@rolldown/binding-win32-x64-msvc": "1.2.13" + } }, "node_modules/semver": { "version": "7.7.3", @@ -3488,8 +3231,8 @@ "license": "ISC" }, "node_modules/source-map-js": { - "version": "1.2.1", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "version": "1.2.2", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -3508,15 +3251,6 @@ "dev": true, "license": "MIT" }, - "node_modules/string_decoder": { - "version": "1.3.0", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", @@ -3557,12 +3291,6 @@ "node": ">=18" } }, - "node_modules/tiny-inflate": { - "version": "1.0.3", - "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", - "dev": true, - "license": "MIT" - }, "node_modules/tinybench": { "version": "2.9.0", "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", @@ -3595,20 +3323,14 @@ } }, "node_modules/tinyrainbow": { - "version": "3.1.0", - "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "version": "3.2.0", + "integrity": "sha512-LgO3D9yZJjApUiuUfl9iFAwrtaX4+lok3wJIqttGoKCHlWUqHqbQpnxCf82L8FjgKsh4iGo78hqJwgL8F6To2A==", "dev": true, "license": "MIT", "engines": { "node": ">=14.0.0" } }, - "node_modules/tr46": { - "version": "0.0.3", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true, - "license": "MIT" - }, "node_modules/ts-api-utils": { "version": "2.4.0", "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", @@ -3621,13 +3343,6 @@ "typescript": ">=4.8.4" } }, - "node_modules/tslib": { - "version": "2.8.1", - "integrity": "sha1-YS7+TtI11Wfoq6Xypfq3AoCt6D8=", - "dev": true, - "license": "0BSD", - "optional": true - }, "node_modules/tsx": { "version": "4.22.4", "integrity": "sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==", @@ -3677,32 +3392,6 @@ "dev": true, "license": "MIT" }, - "node_modules/unicode-properties": { - "version": "1.4.1", - "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", - "dev": true, - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.0", - "unicode-trie": "^2.0.0" - } - }, - "node_modules/unicode-trie": { - "version": "2.0.0", - "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "pako": "^0.2.5", - "tiny-inflate": "^1.0.0" - } - }, - "node_modules/unicode-trie/node_modules/pako": { - "version": "0.2.9", - "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", - "dev": true, - "license": "MIT" - }, "node_modules/uri-js": { "version": "4.4.1", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", @@ -3712,22 +3401,16 @@ "punycode": "^2.1.0" } }, - "node_modules/urijs": { - "version": "1.19.11", - "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", - "dev": true, - "license": "MIT" - }, "node_modules/vite": { - "version": "8.0.16", - "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", + "version": "8.3.4", + "integrity": "sha512-IftLE8phJhdNRIGNEV4JCCvfNScoZQVfcXaN8TQropWGJtOHcu+iAB9pHcuGvmEb/kddw0LBe/jS8ztdC6xdiQ==", "dev": true, "license": "MIT", "dependencies": { - "lightningcss": "^1.32.0", - "picomatch": "^4.0.4", - "postcss": "^8.5.15", - "rolldown": "1.0.3", + "lightningcss": "^1.33.0", + "picomatch": "^4.0.7", + "postcss": "^8.5.29", + "rolldown": "~1.2.12", "tinyglobby": "^0.2.17" }, "bin": { @@ -3744,7 +3427,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.1.18", + "@vitejs/devtools": "^0.7.1", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", @@ -3796,18 +3479,18 @@ } }, "node_modules/vitest": { - "version": "4.1.8", - "integrity": "sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==", + "version": "4.1.11", + "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.8", - "@vitest/mocker": "4.1.8", - "@vitest/pretty-format": "4.1.8", - "@vitest/runner": "4.1.8", - "@vitest/snapshot": "4.1.8", - "@vitest/spy": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/expect": "4.1.11", + "@vitest/mocker": "4.1.11", + "@vitest/pretty-format": "4.1.11", + "@vitest/runner": "4.1.11", + "@vitest/snapshot": "4.1.11", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -3835,12 +3518,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.8", - "@vitest/browser-preview": "4.1.8", - "@vitest/browser-webdriverio": "4.1.8", - "@vitest/coverage-istanbul": "4.1.8", - "@vitest/coverage-v8": "4.1.8", - "@vitest/ui": "4.1.8", + "@vitest/browser-playwright": "4.1.11", + "@vitest/browser-preview": "4.1.11", + "@vitest/browser-webdriverio": "4.1.11", + "@vitest/coverage-istanbul": "4.1.11", + "@vitest/coverage-v8": "4.1.11", + "@vitest/ui": "4.1.11", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -3892,22 +3575,6 @@ "node": ">=14.0.0" } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/which": { "version": "2.0.2", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", @@ -3948,12 +3615,6 @@ "node": ">=0.10.0" } }, - "node_modules/wordwrap": { - "version": "1.0.0", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true, - "license": "MIT" - }, "node_modules/ws": { "version": "8.21.0", "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", @@ -3984,21 +3645,6 @@ "node": ">=18" } }, - "node_modules/yaml": { - "version": "2.9.0", - "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", diff --git a/nodejs/package.json b/nodejs/package.json index 4e68a1b0eb..70087506a9 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -5,7 +5,7 @@ "url": "https://github.com/github/copilot-sdk.git" }, "version": "0.0.0-dev", - "copilotCliVersion": "1.0.96-2", + "copilotCliVersion": "1.0.97-0", "description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC", "main": "./dist/cjs/index.js", "types": "./dist/index.d.ts", @@ -84,13 +84,12 @@ "json-schema": "^0.4.0", "json-schema-to-typescript": "^15.0.4", "prettier": "^3.8.1", - "quicktype-core": "^23.2.6", "rimraf": "^6.1.2", "semver": "^7.7.3", "tar": "^7.5.22", "tsx": "^4.20.6", "typescript": "^5.0.0", - "vitest": "^4.0.18", + "vitest": "^4.1.11", "ws": "^8.21.0" }, "engines": { diff --git a/nodejs/samples/package-lock.json b/nodejs/samples/package-lock.json index 3215d8b297..8b911dbef4 100644 --- a/nodejs/samples/package-lock.json +++ b/nodejs/samples/package-lock.json @@ -23,6 +23,7 @@ "zod": "4.3.6" }, "devDependencies": { + "@microsoft/agent-host-protocol-v09": "npm:@microsoft/agent-host-protocol@0.9.0", "@platformatic/vfs": "^0.3.0", "@types/node": "^25.2.0", "@types/semver": "7.8.0", @@ -32,16 +33,16 @@ "esbuild": "^0.28.1", "eslint": "^9.0.0", "glob": "^13.0.1", + "hpke-js": "^1.8.0", "json-schema": "^0.4.0", "json-schema-to-typescript": "^15.0.4", "prettier": "^3.8.1", - "quicktype-core": "^23.2.6", "rimraf": "^6.1.2", "semver": "^7.7.3", "tar": "^7.5.22", "tsx": "^4.20.6", "typescript": "^5.0.0", - "vitest": "^4.0.18", + "vitest": "^4.1.11", "ws": "^8.21.0" }, "engines": { @@ -222,31 +223,106 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "../node_modules/@glideapps/ts-necessities": { - "version": "2.2.3", + "../node_modules/@hpke/chacha20poly1305": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@hpke/chacha20poly1305/-/chacha20poly1305-1.8.0.tgz", + "integrity": "sha512-FcBfAQ+Y99vMNJP2yrZ9wpL8V0GOwp1+zMyzvc6alasrBygfFjFm1yeUtyADJCu/27C3Lm5mJzx6u7pwg+cX5w==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@hpke/common": "^1.10.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "../node_modules/@hpke/common": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@hpke/common/-/common-1.10.1.tgz", + "integrity": "sha512-moJwhmtLtuxiUzzNp1jpfBfx8yefKoO9D/RCR9dmwrnc7qjJqId1rEtQz+lSlU5cabX8daToMSx/7HayXOiaFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "../node_modules/@hpke/core": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@hpke/core/-/core-1.9.0.tgz", + "integrity": "sha512-pFxWl1nNJeQCSUFs7+GAblHvXBCjn9EPN65vdKlYQil2aURaRxfGMO6vBKGqm1YHTKwiAxJQNEI70PbSowMP9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@hpke/common": "^1.10.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "../node_modules/@hpke/dhkem-x25519": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@hpke/dhkem-x25519/-/dhkem-x25519-1.8.0.tgz", + "integrity": "sha512-S1MWWkAfu+TFxySgv5+2P3O4Mx/jk7BsoplzQaA1s3sfUJVJ2UsZsSzSsMc+FXJumLXncoJFlO6mK6mDGspfmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@hpke/common": "^1.10.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "../node_modules/@hpke/dhkem-x448": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@hpke/dhkem-x448/-/dhkem-x448-1.8.0.tgz", + "integrity": "sha512-mFfnZfgp4OKkUIS/FKikfUgdnDKRy25ytCKBQiV+N+HbYy3I4v4ZCPBQ69QL+TYmKmCZJeUEnYeS5K+OBRP+Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@hpke/common": "^1.10.0" + }, + "engines": { + "node": ">=16.0.0" + } }, "../node_modules/@humanfs/core": { - "version": "0.19.1", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", "dev": true, "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, "engines": { "node": ">=18.18.0" } }, "../node_modules/@humanfs/node": { - "version": "0.16.7", + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@humanfs/core": "^0.19.1", + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", "@humanwhocodes/retry": "^0.4.0" }, "engines": { "node": ">=18.18.0" } }, + "../node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, "../node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "dev": true, @@ -283,7 +359,9 @@ } }, "../node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "dev": true, "license": "MIT" }, @@ -580,12 +658,22 @@ "url": "https://liberapay.com/Koromix" } }, + "../node_modules/@microsoft/agent-host-protocol-v09": { + "name": "@microsoft/agent-host-protocol", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@microsoft/agent-host-protocol/-/agent-host-protocol-0.9.0.tgz", + "integrity": "sha512-XY6zOqLSqlNianiWbEpZkzKRB2AKwcDPk9yAbp+afxyxhWzTfpJKy+03T5rIipJDnqf45rXiJ5JV/dzUA8JHLw==", + "dev": true, + "license": "MIT" + }, "../node_modules/@oxc-project/types": { - "version": "0.133.0", + "version": "0.153.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.153.0.tgz", + "integrity": "sha512-jSNrRIyvPVLL5E1z/tS5zLAprosGz/FuI1PWwEOz59j3E4TTTzSpqKb/RDGqJhhW0QHYISGXxq582wGx6T11Tw==", "dev": true, "license": "MIT", "funding": { - "url": "https://github.com/sponsors/Boshen" + "url": "https://github.com/sponsors/oxc-project" } }, "../node_modules/@platformatic/vfs": { @@ -596,8 +684,44 @@ "node": ">= 22" } }, + "../node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.13.tgz", + "integrity": "sha512-Vu/NICrgdRvUOeaJZIyB2FP63s6fO/4ud5l8dXmxDx9yDyn+mN0y+gsvsVviSli+T361Aqo0h46EuMoobrwawA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.13.tgz", + "integrity": "sha512-6LEoIrGy5vvCd2boNnv2soPSUZj/PRvhp8R/t9KlX+mIZxThIE/ZqxrGXxmuNX0FuvQFvLdZr7S4HrYpYBVhEQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "../node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.3", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.13.tgz", + "integrity": "sha512-CaJSRzlQ6Q+zkDMVA9OkVxBjVoPRCDEE3v0FSJ9kIQBgRjFApA3Si4ijhbNVUji7ZJt+PfO0e46qy4nPInHUPA==", "cpu": [ "arm64" ], @@ -611,18 +735,246 @@ "node": "^20.19.0 || >=22.12.0" } }, + "../node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.13.tgz", + "integrity": "sha512-e4r340I5hxSzJkD3YJBxgzq/rJ3wwxwdLLb2FPt1Zpyem20nrQPT11DDEEkazwxaHumH8wpglsp/Ozgj/wT6mw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.13.tgz", + "integrity": "sha512-hoBWDZ4/K/mJKVMbsgUd1jfpA2DiOrJ54mpegObU9TBHBBrtX4FLIXJJQRDPZ/2Dn91GvPob+Z2hwKJzf4E5SQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.13.tgz", + "integrity": "sha512-oF9fZu3vTWnTiVAkDFxU9PJLt1nh20K9RRpuHsR7ZnE2L7XookBbDBVLojCVSLGbvtSlxeUNnjAj6DbNsKyzbg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.13.tgz", + "integrity": "sha512-DTpb/+jMiqWMPgphn4ksW1zW+XLJ6dJJ9FMvnIk9I291LhCctMPhMYJrP5t9p6C9qa3KXadDdUEZHBaPh3kNxQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.13.tgz", + "integrity": "sha512-xU+Kvv9N2A3SY35zFh1FWWNjxbadE/BKeqnkXe7vScU4GZsw757BlVmDLITZEq8DPpk6m7uoDYkK7P+x/uU5Ow==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.13.tgz", + "integrity": "sha512-XMk/hnhh25oQ756Lclb1Q11h4ll0xC0Esa5w4Vzp+mAE2S3AGJgeM0SonrIgY8fHhjarb6hcoTuwoFG0VVP2ig==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.13.tgz", + "integrity": "sha512-U1BoTHYmlywE2n3HUWjzZ+8EQsKr+OwpxYuDWaubx42tUL8QSL7nOqRz/NVHanibbFP3M1Rxuprz/wNcbMKjqw==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.13.tgz", + "integrity": "sha512-J4cm80Pc6wEwV5AZ42o62sIQgDk+Y7R2s646jIwuvO+4V46QB58N4vVuMPWCBaNgursXLpmUWJV//WQAkPvHBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.13.tgz", + "integrity": "sha512-W0euZS40U4V6JkmEnVCIX9mcsL6cbXQ4X8c2w+MMOIjFg68TXUW+u3RT+2e1t1pv9mg/EP3pDtK3POXdQ7Rxyw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.13.tgz", + "integrity": "sha512-do/AF/4n9MRshia3a5aXoy8xM2c6mgfT6D7H/dY6my5z+hfCIR4ab7mk4IRj++nsEQpKy39kd0DQnDq+r692tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.13.tgz", + "integrity": "sha512-6FtUf2cJZobutJdxnGYX8z0vtbgqU0b2v8vfBhkXb9wp2MppMFtkunE+IaOntyi01rkIQoPW2GHABtfzsC0BRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "../node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.13.tgz", + "integrity": "sha512-UKhFaZTeTcbKrb3iU82m17jVcPEAoqDkCN5MBqgPyZSwp/cQmib21crTS0DdH7T1B7wZRWEI89YQAOJMet5yhg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "../node_modules/@rolldown/pluginutils": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "dev": true, "license": "MIT" }, "../node_modules/@standard-schema/spec": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", "dev": true, "license": "MIT" }, "../node_modules/@types/chai": { "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", "dev": true, "license": "MIT", "dependencies": { @@ -632,6 +984,8 @@ }, "../node_modules/@types/deep-eql": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", "dev": true, "license": "MIT" }, @@ -658,6 +1012,13 @@ "undici-types": "~7.18.0" } }, + "../node_modules/@types/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-1mAINjtQCXXeLkJ9ehXkwOcBpqtLxiVtKhpUf83DdRNdQKV0iXZpaHYqRr7nj+wvxuJzoAmAwXI+sCNMv1CzLQ==", + "dev": true, + "license": "MIT" + }, "../node_modules/@types/ws": { "version": "8.18.1", "dev": true, @@ -878,14 +1239,16 @@ } }, "../node_modules/@vitest/expect": { - "version": "4.1.8", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz", + "integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -894,11 +1257,13 @@ } }, "../node_modules/@vitest/mocker": { - "version": "4.1.8", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz", + "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.8", + "@vitest/spy": "4.1.11", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -919,7 +1284,9 @@ } }, "../node_modules/@vitest/pretty-format": { - "version": "4.1.8", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz", + "integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==", "dev": true, "license": "MIT", "dependencies": { @@ -930,11 +1297,13 @@ } }, "../node_modules/@vitest/runner": { - "version": "4.1.8", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz", + "integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.8", + "@vitest/utils": "4.1.11", "pathe": "^2.0.3" }, "funding": { @@ -942,12 +1311,14 @@ } }, "../node_modules/@vitest/snapshot": { - "version": "4.1.8", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.11.tgz", + "integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/pretty-format": "4.1.11", + "@vitest/utils": "4.1.11", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -956,7 +1327,9 @@ } }, "../node_modules/@vitest/spy": { - "version": "4.1.8", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.11.tgz", + "integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==", "dev": true, "license": "MIT", "funding": { @@ -964,11 +1337,13 @@ } }, "../node_modules/@vitest/utils": { - "version": "4.1.8", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.11.tgz", + "integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.8", + "@vitest/pretty-format": "4.1.11", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -976,17 +1351,6 @@ "url": "https://opencollective.com/vitest" } }, - "../node_modules/abort-controller": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, "../node_modules/acorn": { "version": "8.15.0", "dev": true, @@ -1028,6 +1392,8 @@ }, "../node_modules/assertion-error": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, "license": "MIT", "engines": { @@ -1039,27 +1405,10 @@ "dev": true, "license": "MIT" }, - "../node_modules/base64-js": { - "version": "1.5.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "../node_modules/brace-expansion": { - "version": "1.1.16", + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", "dev": true, "license": "MIT", "dependencies": { @@ -1067,34 +1416,6 @@ "concat-map": "0.0.1" } }, - "../node_modules/browser-or-node": { - "version": "3.0.0", - "dev": true, - "license": "MIT" - }, - "../node_modules/buffer": { - "version": "6.0.3", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, "../node_modules/callsites": { "version": "3.1.0", "dev": true, @@ -1104,7 +1425,9 @@ } }, "../node_modules/chai": { - "version": "6.2.2", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.3.0.tgz", + "integrity": "sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==", "dev": true, "license": "MIT", "engines": { @@ -1148,11 +1471,6 @@ "node": ">=18" } }, - "../node_modules/collection-utils": { - "version": "1.0.1", - "dev": true, - "license": "Apache-2.0" - }, "../node_modules/color-convert": { "version": "2.0.1", "dev": true, @@ -1176,17 +1494,11 @@ }, "../node_modules/convert-source-map": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, "license": "MIT" }, - "../node_modules/cross-fetch": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "node-fetch": "^2.7.0" - } - }, "../node_modules/cross-spawn": { "version": "7.0.6", "dev": true, @@ -1223,6 +1535,8 @@ }, "../node_modules/detect-libc": { "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1458,6 +1772,8 @@ }, "../node_modules/estree-walker": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "dev": true, "license": "MIT", "dependencies": { @@ -1472,22 +1788,6 @@ "node": ">=0.10.0" } }, - "../node_modules/event-target-shim": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "../node_modules/events": { - "version": "3.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, "../node_modules/expect-type": { "version": "1.3.0", "dev": true, @@ -1628,24 +1928,22 @@ "node": ">=8" } }, - "../node_modules/ieee754": { - "version": "1.2.1", + "../node_modules/hpke-js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/hpke-js/-/hpke-js-1.8.0.tgz", + "integrity": "sha512-N0PFQlUQsIPS9++nUNn2ZsxTPSv8pONyyrXIGZl0iiherRfS0XW1SvTd+RmepD0TN1S9zzTJkEutMIWWYt0/4w==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" + "license": "MIT", + "dependencies": { + "@hpke/chacha20poly1305": "^1.8.0", + "@hpke/common": "^1.10.0", + "@hpke/core": "^1.9.0", + "@hpke/dhkem-x25519": "^1.8.0", + "@hpke/dhkem-x448": "^1.8.0" + }, + "engines": { + "node": ">=16.0.0" + } }, "../node_modules/ignore": { "version": "7.0.5", @@ -1697,21 +1995,11 @@ "node": ">=0.10.0" } }, - "../node_modules/is-url": { - "version": "1.2.4", - "dev": true, - "license": "MIT" - }, "../node_modules/isexe": { "version": "2.0.0", "dev": true, "license": "ISC" }, - "../node_modules/js-base64": { - "version": "3.7.8", - "dev": true, - "license": "BSD-3-Clause" - }, "../node_modules/js-yaml": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", @@ -1764,107 +2052,333 @@ "json2ts": "dist/src/cli.js" }, "engines": { - "node": ">=16.0.0" + "node": ">=16.0.0" + } + }, + "../node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "../node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "../node_modules/keyv": { + "version": "4.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "../node_modules/koffi": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/koffi/-/koffi-3.2.1.tgz", + "integrity": "sha512-0qE3lZ8jllRqPN4Ob6Ajl7c2bJSJDhQWuKLGP5hIEpHLllJWv1ydHFMhHmHc5p/W9GticKVDbYzZd7TBoQ4CZg==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "url": "https://liberapay.com/Koromix" + }, + "optionalDependencies": { + "@koromix/koffi-android-arm64": "3.2.1", + "@koromix/koffi-android-x64": "3.2.1", + "@koromix/koffi-darwin-arm64": "3.2.1", + "@koromix/koffi-darwin-x64": "3.2.1", + "@koromix/koffi-freebsd-arm64": "3.2.1", + "@koromix/koffi-freebsd-ia32": "3.2.1", + "@koromix/koffi-freebsd-x64": "3.2.1", + "@koromix/koffi-linux-arm": "3.2.1", + "@koromix/koffi-linux-arm64": "3.2.1", + "@koromix/koffi-linux-ia32": "3.2.1", + "@koromix/koffi-linux-loong64": "3.2.1", + "@koromix/koffi-linux-riscv64": "3.2.1", + "@koromix/koffi-linux-x64": "3.2.1", + "@koromix/koffi-openbsd-ia32": "3.2.1", + "@koromix/koffi-openbsd-x64": "3.2.1", + "@koromix/koffi-win32-arm64": "3.2.1", + "@koromix/koffi-win32-ia32": "3.2.1", + "@koromix/koffi-win32-x64": "3.2.1" + } + }, + "../node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "../node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "../node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "../node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "../node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "../node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "../node_modules/json-schema-traverse": { - "version": "0.4.1", + "../node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], "dev": true, - "license": "MIT" + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "../node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", + "../node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT" + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "../node_modules/keyv": { - "version": "4.5.4", + "../node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "../node_modules/koffi": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/koffi/-/koffi-3.2.1.tgz", - "integrity": "sha512-0qE3lZ8jllRqPN4Ob6Ajl7c2bJSJDhQWuKLGP5hIEpHLllJWv1ydHFMhHmHc5p/W9GticKVDbYzZd7TBoQ4CZg==", - "hasInstallScript": true, - "license": "MIT", - "funding": { - "url": "https://liberapay.com/Koromix" + "../node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" }, - "optionalDependencies": { - "@koromix/koffi-android-arm64": "3.2.1", - "@koromix/koffi-android-x64": "3.2.1", - "@koromix/koffi-darwin-arm64": "3.2.1", - "@koromix/koffi-darwin-x64": "3.2.1", - "@koromix/koffi-freebsd-arm64": "3.2.1", - "@koromix/koffi-freebsd-ia32": "3.2.1", - "@koromix/koffi-freebsd-x64": "3.2.1", - "@koromix/koffi-linux-arm": "3.2.1", - "@koromix/koffi-linux-arm64": "3.2.1", - "@koromix/koffi-linux-ia32": "3.2.1", - "@koromix/koffi-linux-loong64": "3.2.1", - "@koromix/koffi-linux-riscv64": "3.2.1", - "@koromix/koffi-linux-x64": "3.2.1", - "@koromix/koffi-openbsd-ia32": "3.2.1", - "@koromix/koffi-openbsd-x64": "3.2.1", - "@koromix/koffi-win32-arm64": "3.2.1", - "@koromix/koffi-win32-ia32": "3.2.1", - "@koromix/koffi-win32-x64": "3.2.1" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "../node_modules/levn": { - "version": "0.4.1", + "../node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.8.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "../node_modules/lightningcss": { - "version": "1.32.0", + "../node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { "node": ">= 12.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" } }, - "../node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", + "../node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", "cpu": [ - "arm64" + "x64" ], "dev": true, "license": "MPL-2.0", "optional": true, "os": [ - "darwin" + "win32" ], "engines": { "node": ">= 12.0.0" @@ -1908,6 +2422,8 @@ }, "../node_modules/magic-string": { "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1937,7 +2453,9 @@ } }, "../node_modules/minimatch/node_modules/brace-expansion": { - "version": "5.0.8", + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1980,7 +2498,9 @@ "license": "MIT" }, "../node_modules/nanoid": { - "version": "3.3.17", + "version": "3.3.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", "dev": true, "funding": [ { @@ -2001,25 +2521,6 @@ "dev": true, "license": "MIT" }, - "../node_modules/node-fetch": { - "version": "2.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, "../node_modules/obug": { "version": "2.1.1", "dev": true, @@ -2078,11 +2579,6 @@ "dev": true, "license": "BlueOak-1.0.0" }, - "../node_modules/pako": { - "version": "1.0.11", - "dev": true, - "license": "(MIT AND Zlib)" - }, "../node_modules/parent-module": { "version": "1.0.1", "dev": true, @@ -2127,16 +2623,22 @@ }, "../node_modules/pathe": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, "license": "MIT" }, "../node_modules/picocolors": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, "license": "ISC" }, "../node_modules/picomatch": { - "version": "4.0.4", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "dev": true, "license": "MIT", "engines": { @@ -2146,16 +2648,10 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "../node_modules/pluralize": { - "version": "8.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "../node_modules/postcss": { - "version": "8.5.25", + "version": "8.5.29", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.29.tgz", + "integrity": "sha512-49cGhUbXj8Qenv0iTMxA1cFBzxXoctpC9Ujd77t1WcbJIr6nF/eI7g/8MgxrYldFRuAXvja7xQRwavoW7kgrxQ==", "dev": true, "funding": [ { @@ -2173,9 +2669,9 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.16", + "nanoid": "^3.3.19", "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "source-map-js": "^1.2.2" }, "engines": { "node": "^10 || ^12 || >=14" @@ -2203,14 +2699,6 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "../node_modules/process": { - "version": "0.11.10", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6.0" - } - }, "../node_modules/punycode": { "version": "2.3.1", "dev": true, @@ -2219,42 +2707,6 @@ "node": ">=6" } }, - "../node_modules/quicktype-core": { - "version": "23.2.6", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@glideapps/ts-necessities": "2.2.3", - "browser-or-node": "^3.0.0", - "collection-utils": "^1.0.1", - "cross-fetch": "^4.0.0", - "is-url": "^1.2.4", - "js-base64": "^3.7.7", - "lodash": "^4.17.21", - "pako": "^1.0.6", - "pluralize": "^8.0.0", - "readable-stream": "4.5.2", - "unicode-properties": "^1.4.1", - "urijs": "^1.19.1", - "wordwrap": "^1.0.0", - "yaml": "^2.4.1" - } - }, - "../node_modules/readable-stream": { - "version": "4.5.2", - "dev": true, - "license": "MIT", - "dependencies": { - "abort-controller": "^3.0.0", - "buffer": "^6.0.3", - "events": "^3.3.0", - "process": "^0.11.10", - "string_decoder": "^1.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, "../node_modules/resolve-from": { "version": "4.0.0", "dev": true, @@ -2282,11 +2734,13 @@ } }, "../node_modules/rolldown": { - "version": "1.0.3", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.13.tgz", + "integrity": "sha512-/5apOkwWxtACcQtZ5WlrAsKS4JwXVThQPJZ3RqIruRY9UG9M8e0VlXN068xum/JRKA4aIUoJ13ghe/kGCvidiQ==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.133.0", + "@oxc-project/types": "=0.153.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -2296,41 +2750,22 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.3", - "@rolldown/binding-darwin-arm64": "1.0.3", - "@rolldown/binding-darwin-x64": "1.0.3", - "@rolldown/binding-freebsd-x64": "1.0.3", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", - "@rolldown/binding-linux-arm64-gnu": "1.0.3", - "@rolldown/binding-linux-arm64-musl": "1.0.3", - "@rolldown/binding-linux-ppc64-gnu": "1.0.3", - "@rolldown/binding-linux-s390x-gnu": "1.0.3", - "@rolldown/binding-linux-x64-gnu": "1.0.3", - "@rolldown/binding-linux-x64-musl": "1.0.3", - "@rolldown/binding-openharmony-arm64": "1.0.3", - "@rolldown/binding-wasm32-wasi": "1.0.3", - "@rolldown/binding-win32-arm64-msvc": "1.0.3", - "@rolldown/binding-win32-x64-msvc": "1.0.3" - } - }, - "../node_modules/safe-buffer": { - "version": "5.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" + "@rolldown/binding-android-arm-eabi": "1.2.13", + "@rolldown/binding-android-arm64": "1.2.13", + "@rolldown/binding-darwin-arm64": "1.2.13", + "@rolldown/binding-darwin-x64": "1.2.13", + "@rolldown/binding-freebsd-x64": "1.2.13", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.13", + "@rolldown/binding-linux-arm64-gnu": "1.2.13", + "@rolldown/binding-linux-arm64-musl": "1.2.13", + "@rolldown/binding-linux-ppc64-gnu": "1.2.13", + "@rolldown/binding-linux-s390x-gnu": "1.2.13", + "@rolldown/binding-linux-x64-gnu": "1.2.13", + "@rolldown/binding-linux-x64-musl": "1.2.13", + "@rolldown/binding-openharmony-arm64": "1.2.13", + "@rolldown/binding-win32-arm64-msvc": "1.2.13", + "@rolldown/binding-win32-x64-msvc": "1.2.13" + } }, "../node_modules/semver": { "version": "7.7.3", @@ -2368,7 +2803,9 @@ "license": "ISC" }, "../node_modules/source-map-js": { - "version": "1.2.1", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -2385,14 +2822,6 @@ "dev": true, "license": "MIT" }, - "../node_modules/string_decoder": { - "version": "1.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "../node_modules/strip-json-comments": { "version": "3.1.1", "dev": true, @@ -2430,11 +2859,6 @@ "node": ">=18" } }, - "../node_modules/tiny-inflate": { - "version": "1.0.3", - "dev": true, - "license": "MIT" - }, "../node_modules/tinybench": { "version": "2.9.0", "dev": true, @@ -2464,18 +2888,15 @@ } }, "../node_modules/tinyrainbow": { - "version": "3.1.0", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.2.0.tgz", + "integrity": "sha512-LgO3D9yZJjApUiuUfl9iFAwrtaX4+lok3wJIqttGoKCHlWUqHqbQpnxCf82L8FjgKsh4iGo78hqJwgL8F6To2A==", "dev": true, "license": "MIT", "engines": { "node": ">=14.0.0" } }, - "../node_modules/tr46": { - "version": "0.0.3", - "dev": true, - "license": "MIT" - }, "../node_modules/ts-api-utils": { "version": "2.4.0", "dev": true, @@ -2532,29 +2953,6 @@ "dev": true, "license": "MIT" }, - "../node_modules/unicode-properties": { - "version": "1.4.1", - "dev": true, - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.0", - "unicode-trie": "^2.0.0" - } - }, - "../node_modules/unicode-trie": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "pako": "^0.2.5", - "tiny-inflate": "^1.0.0" - } - }, - "../node_modules/unicode-trie/node_modules/pako": { - "version": "0.2.9", - "dev": true, - "license": "MIT" - }, "../node_modules/uri-js": { "version": "4.4.1", "dev": true, @@ -2563,20 +2961,17 @@ "punycode": "^2.1.0" } }, - "../node_modules/urijs": { - "version": "1.19.11", - "dev": true, - "license": "MIT" - }, "../node_modules/vite": { - "version": "8.0.16", + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.4.tgz", + "integrity": "sha512-IftLE8phJhdNRIGNEV4JCCvfNScoZQVfcXaN8TQropWGJtOHcu+iAB9pHcuGvmEb/kddw0LBe/jS8ztdC6xdiQ==", "dev": true, "license": "MIT", "dependencies": { - "lightningcss": "^1.32.0", - "picomatch": "^4.0.4", - "postcss": "^8.5.15", - "rolldown": "1.0.3", + "lightningcss": "^1.33.0", + "picomatch": "^4.0.7", + "postcss": "^8.5.29", + "rolldown": "~1.2.12", "tinyglobby": "^0.2.17" }, "bin": { @@ -2593,7 +2988,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.1.18", + "@vitejs/devtools": "^0.7.1", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", @@ -2645,17 +3040,19 @@ } }, "../node_modules/vitest": { - "version": "4.1.8", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz", + "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.8", - "@vitest/mocker": "4.1.8", - "@vitest/pretty-format": "4.1.8", - "@vitest/runner": "4.1.8", - "@vitest/snapshot": "4.1.8", - "@vitest/spy": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/expect": "4.1.11", + "@vitest/mocker": "4.1.11", + "@vitest/pretty-format": "4.1.11", + "@vitest/runner": "4.1.11", + "@vitest/snapshot": "4.1.11", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -2683,12 +3080,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.8", - "@vitest/browser-preview": "4.1.8", - "@vitest/browser-webdriverio": "4.1.8", - "@vitest/coverage-istanbul": "4.1.8", - "@vitest/coverage-v8": "4.1.8", - "@vitest/ui": "4.1.8", + "@vitest/browser-playwright": "4.1.11", + "@vitest/browser-preview": "4.1.11", + "@vitest/browser-webdriverio": "4.1.11", + "@vitest/coverage-istanbul": "4.1.11", + "@vitest/coverage-v8": "4.1.11", + "@vitest/ui": "4.1.11", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -2739,20 +3136,6 @@ "node": ">=14.0.0" } }, - "../node_modules/webidl-conversions": { - "version": "3.0.1", - "dev": true, - "license": "BSD-2-Clause" - }, - "../node_modules/whatwg-url": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "../node_modules/which": { "version": "2.0.2", "dev": true, @@ -2790,11 +3173,6 @@ "node": ">=0.10.0" } }, - "../node_modules/wordwrap": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, "../node_modules/ws": { "version": "8.21.0", "dev": true, @@ -2823,20 +3201,6 @@ "node": ">=18" } }, - "../node_modules/yaml": { - "version": "2.9.0", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, "../node_modules/yocto-queue": { "version": "0.1.0", "dev": true, diff --git a/nodejs/src/cliVersion.ts b/nodejs/src/cliVersion.ts index 884f2a267e..2bcc588cde 100644 --- a/nodejs/src/cliVersion.ts +++ b/nodejs/src/cliVersion.ts @@ -1,3 +1,3 @@ -export const COPILOT_CLI_VERSION = "1.0.96-2"; +export const COPILOT_CLI_VERSION = "1.0.97-0"; export const COPILOT_CLI_USE_NPM_PACKAGE = false; diff --git a/nodejs/src/client.ts b/nodejs/src/client.ts index ed10b482b2..464a525427 100644 --- a/nodejs/src/client.ts +++ b/nodejs/src/client.ts @@ -1790,6 +1790,7 @@ export class CopilotClient { model: config.model, allowedModels: config.allowedModels, sessionId: localSessionId, + name: config.name, clientName: config.clientName, reasoningEffort: config.reasoningEffort, reasoningSummary: config.reasoningSummary, @@ -1872,6 +1873,8 @@ export class CopilotClient { enableSkills: config.enableSkills, skillDirectories: config.skillDirectories, ...(config.skillProvider ? { hasSkillProvider: true } : {}), + agentDirectories: config.agentDirectories, + hookDirectories: config.hookDirectories, pluginDirectories: config.pluginDirectories, instructionDirectories: config.instructionDirectories, disabledSkills: config.disabledSkills, @@ -2178,6 +2181,8 @@ export class CopilotClient { agent: config.agent, skillDirectories: config.skillDirectories, ...(config.skillProvider ? { hasSkillProvider: true } : {}), + agentDirectories: config.agentDirectories, + hookDirectories: config.hookDirectories, pluginDirectories: config.pluginDirectories, instructionDirectories: config.instructionDirectories, disabledSkills: config.disabledSkills, diff --git a/nodejs/src/generated/rpc.ts b/nodejs/src/generated/rpc.ts index 68d1021d1f..e751771174 100644 --- a/nodejs/src/generated/rpc.ts +++ b/nodejs/src/generated/rpc.ts @@ -34,6 +34,32 @@ export type AuthInfo = | AccountAuthInfo | GhCliAuthInfo | ApiKeyAuthInfo; +/** + * Authentication type + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "AuthInfoType". + */ +/** @experimental */ +export type AuthInfoType = + /** Authentication provided by a GitHub App HMAC credential. */ + | "hmac" + /** Authentication resolved from environment-provided credentials. */ + | "env" + /** Authentication from an interactive user sign-in. */ + | "user" + /** Authentication from a selected provider-owned account, without a GitHub credential. */ + | "account" + /** Authentication delegated to the GitHub CLI. */ + | "gh-cli" + /** Authentication from an API key credential. */ + | "api-key" + /** Authentication from a GitHub token. */ + | "token" + /** Authentication from an SDK GitHub token callback. */ + | "token-provider" + /** Authentication from a Copilot API token. */ + | "copilot-api-token"; /** * The provider kind stamped on a signed-in account. * @@ -403,32 +429,6 @@ export type LoginProviderKind = | "proxima" /** Microsoft Entra sign-in that derives a GitHub (EMU) credential. */ | "entra"; -/** - * Authentication type - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "AuthInfoType". - */ -/** @experimental */ -export type AuthInfoType = - /** Authentication provided by a GitHub App HMAC credential. */ - | "hmac" - /** Authentication resolved from environment-provided credentials. */ - | "env" - /** Authentication from an interactive user sign-in. */ - | "user" - /** Authentication from a selected provider-owned account, without a GitHub credential. */ - | "account" - /** Authentication delegated to the GitHub CLI. */ - | "gh-cli" - /** Authentication from an API key credential. */ - | "api-key" - /** Authentication from a GitHub token. */ - | "token" - /** Authentication from an SDK GitHub token callback. */ - | "token-provider" - /** Authentication from a Copilot API token. */ - | "copilot-api-token"; /** * One step in an interactive login flow. The consumer acts on the step and calls advance to proceed. Browser-open is encoded as two distinct steps by design: `open-url` is CONSUMER-driven (the provider surfaces the authorize URL and the consumer opens it — github.com/GHEC web), while `needs-interaction` is PROVIDER-driven (the provider opens the browser or broker UI itself and does not surface a URL — Entra). * @@ -2030,6 +2030,33 @@ export type ExternalToolTextResultForLlmContentResourceLinkIconTheme = export type ExternalToolTextResultForLlmContentResourceDetails = | EmbeddedTextResourceContents | EmbeddedBlobResourceContents; +/** + * The population a feature flag is declared for, before overrides. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "FeatureFlagAvailability". + */ +/** @experimental */ +/** @internal */ +export type FeatureFlagAvailability = + /** Enabled for everyone, before any override. */ + | "on" + /** Enabled only for accounts on the owning team. */ + | "team" + /** Enabled only for staff accounts that have also opted into experimental features. */ + | "staff-and-experimental" + /** Enabled for staff accounts and for accounts that opted into experimental features. */ + | "staff-or-experimental" + /** Enabled for any staff account, GitHub or Microsoft. */ + | "staff" + /** Enabled for GitHub staff accounts only. */ + | "staff-github" + /** Enabled for Microsoft staff accounts only. */ + | "staff-microsoft" + /** Enabled only for accounts that opted into experimental features. */ + | "experimental" + /** Disabled for everyone, before any override. */ + | "off"; /** * Content filtering mode to apply to all tools, or a map of tool name to content filtering mode. * @@ -5205,6 +5232,38 @@ export type SessionVisibilityStatus = | "repo" /** The session is restricted to its creator and collaborators. */ | "unshared"; +/** + * One atomic settings mutation. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SettingsEditOperation". + */ +/** @experimental */ +/** @internal */ +export type SettingsEditOperation = + /** Set one scalar value. */ + | "set" + /** Add one string to a list, unless present. */ + | "add-item" + /** Remove one string from a list, unless absent. */ + | "remove-item" + /** Remove the setting without supplying a value. */ + | "remove"; +/** + * Whether one atomic settings edit changed a file. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SettingsEditStatus". + */ +/** @experimental */ +/** @internal */ +export type SettingsEditStatus = + /** The edit changed the setting and was stored. */ + | "changed" + /** The setting already had the requested state. */ + | "unchanged" + /** The existing settings file could not be edited safely; nothing was written. */ + | "invalid"; /** * Signal to send (default: SIGTERM) * @@ -6944,6 +7003,62 @@ export interface ApiKeyAuthInfo { host: string; copilotUser?: CopilotUserResponse; } +/** + * The authentication identity whose shared wording should be rendered. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "AccountDescribeAuthInfoRequest". + */ +/** @experimental */ +/** @internal */ +export interface AccountDescribeAuthInfoRequest { + identity: AuthIdentity; +} +/** + * Credential-free authentication identity safe to expose to hosts and user interfaces. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "AuthIdentity". + */ +/** @experimental */ +export interface AuthIdentity { + type: AuthInfoType; + /** + * Authentication host + */ + host: string; + /** + * Authenticated login, when available + */ + login?: string; + /** + * Name of the environment variable that supplied the credential, when applicable + */ + envVar?: string; + /** + * Opaque SDK GitHub credential registration backing this identity. Routing metadata only; never a credential. + */ + registrationId?: string; + copilotUser?: CopilotUserResponse; +} +/** + * The wording the runtime uses for an authentication identity. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "AccountDescribeAuthInfoResult". + */ +/** @experimental */ +/** @internal */ +export interface AccountDescribeAuthInfoResult { + /** + * Sign-in banner announcing the authenticated user. + */ + message: string; + /** + * One-line description of the identity, suitable after a verb such as "Switched to". + */ + description: string; +} /** * Current authentication state * @@ -6958,6 +7073,39 @@ export interface AccountGetCurrentAuthResult { */ authErrors?: string[]; } +/** + * The authentication identity whose gist support should be reported. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "AccountGetGistSupportRequest". + */ +/** @experimental */ +/** @internal */ +export interface AccountGetGistSupportRequest { + identity: AuthIdentity; +} +/** + * Whether the identity can create gists, and why not when it cannot. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "AccountGetGistSupportResult". + */ +/** @experimental */ +/** @internal */ +export interface AccountGetGistSupportResult { + /** + * True when the identity can create gists. + */ + supported: boolean; + /** + * Machine-readable reason category when unsupported. + */ + kind?: string; + /** + * Human-readable explanation to show where the gist action would have been. + */ + reason?: string; +} /** @experimental */ export interface AccountGetQuotaRequest { @@ -7026,6 +7174,49 @@ export interface AccountQuotaSnapshot { */ resetDate?: string; } +/** + * The environment variable supplying a classic personal access token, when one is set. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "AccountGetTokenEnvVarResult". + */ +/** @experimental */ +/** @internal */ +export interface AccountGetTokenEnvVarResult { + /** + * Variable name, for example `GH_TOKEN`. Absent when no classic token is present in the environment. + */ + name?: string; +} +/** + * A path to resolve against the GitHub host an identity is signed in to. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "AccountGetWebUrlRequest". + */ +/** @experimental */ +/** @internal */ +export interface AccountGetWebUrlRequest { + /** + * Host-relative path, without a leading slash, for example `settings/copilot/features`. + */ + path: string; + identity?: AuthIdentity; +} +/** + * An absolute URL on the identity's GitHub host. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "AccountGetWebUrlResult". + */ +/** @experimental */ +/** @internal */ +export interface AccountGetWebUrlResult { + /** + * Absolute URL for the requested path. + */ + url: string; +} /** * Credentials to validate and store. Omit login to resolve the authenticated user from the token. * @@ -7255,6 +7446,12 @@ export interface AgentInfo { * Authored base prompt for the agent. Runtime prompt assembly may add dynamic context at invocation time. Omitted from `session.agent.list` unless `includePrompt` is true. */ prompt?: string; + /** + * Declarative hook actions keyed by event name, executed only while this agent is active. + */ + hooks?: { + [k: string]: JsonValue[] | undefined; + }; } /** * Agents available to the session. @@ -7534,6 +7731,10 @@ export interface AgentsCustomAgentInitialModelDecisionResult { */ /** @experimental */ export interface AgentsDiscoverRequest { + /** + * Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without ambient discovery, subject to managed/source disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + */ + agentDirectories?: string[]; /** * Optional list of project directory paths to scan for project-scoped agents. When omitted or empty, only user/plugin/remote-independent agents are returned (no project scan). */ @@ -7727,6 +7928,10 @@ export interface AgentsGetBuiltinsResult { */ /** @experimental */ export interface AgentsGetDiscoveryPathsRequest { + /** + * Explicit discovery-only agent roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + */ + agentDirectories?: string[]; /** * Optional list of project directory paths. When omitted or empty, only the user-level directory is returned. */ @@ -7754,33 +7959,6 @@ export interface ProviderDescriptor { */ available: boolean; } -/** - * Credential-free authentication identity safe to expose to hosts and user interfaces. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "AuthIdentity". - */ -/** @experimental */ -export interface AuthIdentity { - type: AuthInfoType; - /** - * Authentication host - */ - host: string; - /** - * Authenticated login, when available - */ - login?: string; - /** - * Name of the environment variable that supplied the credential, when applicable - */ - envVar?: string; - /** - * Opaque SDK GitHub credential registration backing this identity. Routing metadata only; never a credential. - */ - registrationId?: string; - copilotUser?: CopilotUserResponse; -} /** * Credential-free identity metadata. * @@ -12021,6 +12199,105 @@ export interface ExternalToolTextResultForLlmContentResource { type: "resource"; resource: ExternalToolTextResultForLlmContentResourceDetails; } +/** + * The declared shape of one feature flag, independent of any caller population. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "FeatureFlagMetadata". + */ +/** @experimental */ +/** @internal */ +export interface FeatureFlagMetadata { + /** + * The flag's name, matching the key it is listed under. + */ + name: string; + availability: FeatureFlagAvailability; + /** + * Whether the flag participates in the CAPI sanity suite. + */ + capiSanity: boolean; + /** + * Text shown to a user choosing whether to turn the flag on in experimental mode. Absent when the flag is not user-facing. + */ + experimentalDescription?: string; + /** + * The online-experiment (ExP) flag this maps to, when the flag is assigned by an experiment rather than declared statically. + */ + expFlag?: string; + /** + * Environment variable that overrides this flag's experiment assignment locally in the experiment service, not in `featureFlags.resolve`. Present exactly when `expFlag` is, and derived from it, so a caller reads a local override without reproducing the naming rule. + */ + expFlagEnvVar?: string; +} +/** + * Every feature flag this runtime declares, with the shape each one was declared with. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "FeatureFlagsMetadataResult". + */ +/** @experimental */ +/** @internal */ +export interface FeatureFlagsMetadataResult { + /** + * Declared feature flags keyed by flag name. + */ + flags: { + [k: string]: FeatureFlagMetadata; + }; +} +/** + * Caller population and overrides for static feature-flag resolution, independent of experiment assignments and active runtime state. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "FeatureFlagsResolveRequest". + */ +/** @experimental */ +/** @internal */ +export interface FeatureFlagsResolveRequest { + /** + * Whether the caller is GitHub or Microsoft staff. + */ + isStaff: boolean; + /** + * Whether the caller is in an experimental population. + */ + isExperimental: boolean; + /** + * Whether the caller belongs to the team population used by feature availability. + */ + isTeam: boolean; + /** + * GitHub-staff membership. Omit when it was never recorded: a legacy staff account then counts as both staff populations and keeps every staff feature. + */ + isStaffGithub?: boolean; + /** + * Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. + */ + isStaffMicrosoft?: boolean; + /** + * Resolve against this already-computed flag set rather than each flag's declared availability. Keyed by flag name. + */ + baseFlags?: { + [k: string]: boolean | undefined; + }; + /** + * Environment for direct feature-flag overrides and `COPILOT_CLI_ENABLED_FEATURE_FLAGS`. Does not apply `COPILOT_EXP_*` experiment assignments. Defaults to this runtime process's own environment. + */ + environment?: { + [k: string]: string | undefined; + }; + /** + * User settings to apply, including `enabledFeatureFlags`, legacy `feature_flags.enabled`, and supported convenience settings. + */ + config?: JsonValue; + /** + * Flags forced to a value after every other layer, keyed by flag name. + */ + flagOverrides?: { + [k: string]: boolean | undefined; + }; +} /** * Parameters for starting fleet orchestration: an optional user prompt combined with the fleet instructions, plus the send options forwarded to the resulting turn. * @@ -13141,6 +13418,10 @@ export interface HookInvokeResponse { */ /** @experimental */ export interface HooksDiscoverRequest { + /** + * Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without ambient discovery or repository file-hook enablement, subject to managed/hook disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + */ + hookDirectories?: string[]; /** * Optional project directory paths whose trusted repository and project-expanded plugin hooks should be discovered. When omitted or empty, user, managed-policy, and globally enabled installed or explicit plugin hooks are returned without project expansion. */ @@ -14225,6 +14506,40 @@ export interface InstructionDiscoveryPathList { */ paths: InstructionDiscoveryPath[]; } +/** + * Explicit discovery arguments for one location, supplied by the caller rather than derived from a session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "InstructionsDiscoverRepoSourcesRequest". + */ +/** @experimental */ +/** @internal */ +export interface InstructionsDiscoverRepoSourcesRequest { + /** + * Repository location to discover. An empty string selects no repository scope; cwdPath can still supply working-directory sources. + */ + location: string; + /** + * When true, include the sources a command-line host reads. Hosts that are not the CLI omit it. + */ + isCli?: boolean; + /** + * Working directory whose instruction sources should also be included. Omission adds no separate working-directory scope. + */ + cwdPath?: string; + /** + * Copilot configuration directory for user-level sources. An omitted or empty value uses the server's configuration home. + */ + configDir?: string; + /** + * Extra directories to scan alongside instruction directories configured in the runtime environment. + */ + additionalDirs?: string[]; + /** + * When true, also discover instruction files nested below the location. + */ + enableChildInstructions?: boolean; +} /** * Optional project paths to include in instruction discovery. * @@ -14233,6 +14548,10 @@ export interface InstructionDiscoveryPathList { */ /** @experimental */ export interface InstructionsDiscoverRequest { + /** + * Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without ambient discovery, subject to instruction/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + */ + instructionDirectories?: string[]; /** * Optional list of project directory paths to scan for repository/working-directory instruction sources. When omitted or empty, only user-level and plugin instruction sources are returned (no project scan). */ @@ -14250,6 +14569,10 @@ export interface InstructionsDiscoverRequest { */ /** @experimental */ export interface InstructionsGetDiscoveryPathsRequest { + /** + * Explicit discovery-only instruction roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + */ + instructionDirectories?: string[]; /** * Optional list of project directory paths. When omitted or empty, only the user-level targets are returned. */ @@ -14315,6 +14638,20 @@ export interface InstructionSource { */ projectPath?: string; } +/** + * The prompt the init command runs. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "InstructionsInitPromptResult". + */ +/** @experimental */ +/** @internal */ +export interface InstructionsInitPromptResult { + /** + * Prompt text authoring repository instructions. + */ + prompt: string; +} /** * Parameters for interrupting the main agent turn. * @@ -16369,6 +16706,20 @@ export interface McpIsServerRunningResult { */ running: boolean; } +/** + * Names of the MCP servers the runtime supplies itself. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpListBuiltinServerNamesResult". + */ +/** @experimental */ +/** @internal */ +export interface McpListBuiltinServerNamesResult { + /** + * Every built-in server name. A host disabling the built-ins wholesale suppresses exactly this set. + */ + names: string[]; +} /** * Server name whose tool list should be returned. * @@ -18500,6 +18851,64 @@ export interface ModelClearStartupSeedRequest { export interface ModelClearStartupSeedResult { cleared: boolean; } +/** + * Host presentation state the reasoning-summaries policy depends on. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelGetReasoningSummariesRequest". + */ +/** @experimental */ +export interface ModelGetReasoningSummariesRequest { + /** + * The host's persisted `showReasoning` user setting, omitted when unset. + */ + persistedShowReasoning?: boolean; + /** + * Whether the host is currently showing reasoning summaries. Defaults to false. + */ + summariesVisible?: boolean; +} +/** + * Reasoning-summaries presentation policy for the session's current model. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelGetReasoningSummariesResult". + */ +/** @experimental */ +export interface ModelGetReasoningSummariesResult { + /** + * False until the session has a model catalog and a selected model. This read never resolves the catalog itself, and the runtime emits no readiness notification, so repeating this call alone leaves `ready` false indefinitely on a session that has neither listed models nor run a turn. `session.model.list` is the prerequisite and the signal: it resolves and caches the catalog for the session, so a successful return means the next read is ready. The exception is a session that resolves models without a Copilot catalog, that is a BYOK registry or an alternate provider: `session.model.list` returns an empty list without caching a catalog, so `ready` stays false and this policy is unavailable there. While false, every model-policy field is false and `visibility` is omitted; `experimentSettled` is independent of readiness and still reports the assignment state. + */ + ready: boolean; + /** + * Whether the session's reasoning-summaries experiment assignment has settled. False means this read does not wait for a pending assignment and reports the experiment-derived fields conservatively: `showHiddenHint` is false and `visibility` falls back to `persistedShowReasoning`, or is omitted when none was supplied. A host that wants the assigned answer re-reads until this is true. + */ + experimentSettled: boolean; + /** + * Whether turns on this session produce reasoning summaries, honouring an explicit session reasoning-summary override. + */ + sessionShowsSummaries: boolean; + /** + * Whether the selected model shows reasoning summaries by default. + */ + modelDefaultShowsSummaries: boolean; + /** + * Whether the selected model emits reasoning headers. + */ + showReasoningHeaders: boolean; + /** + * Default reasoning visibility, and only meaningful once `ready` is true: false when the session produces no summaries, else the persisted setting, else the experiment's default. While `ready` is true it is omitted only when all three are unavailable, that is when the session produces summaries, no `persistedShowReasoning` was supplied, and `experimentSettled` is false. While `ready` is false there is no model policy to report and this field is always omitted, so an absent value alone does not imply a pending experiment. + */ + visibility?: boolean; + /** + * Whether to show the hint that reasoning summaries are hidden. Always false while `experimentSettled` is false. + */ + showHiddenHint: boolean; + /** + * Whether the supplied `persistedShowReasoning` setting only restates the model default. This reports a redundancy, not a standing instruction to delete the setting: it stays true for as long as the setting and the model default agree, including for a user who later chose that value deliberately. It exists for a one-time migration of a legacy setting written before the model default made it redundant, so a host that acts on it owns the cleanup and must gate it behind its own persisted `done` marker, delete only a setting whose value still matches the one it read, and never repeat the deletion on a later launch. Under an off-by-default reasoning-summaries experiment an explicit `showReasoning: true` opt-in also reads as redundant on a summary-producing model, so an ungated host would keep deleting that opt-in and hide summaries again on every launch. + */ + clearRedundantSetting: boolean; +} /** * List of Copilot models available to the resolved user, including capabilities and billing metadata. * @@ -23100,6 +23509,94 @@ export interface RemoteSessionRepository { */ branch?: string; } +/** + * Which repository settings file to read. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "RepoSettingsReadRawRequest". + */ +/** @experimental */ +/** @internal */ +export interface RepoSettingsReadRawRequest { + /** + * Absolute path of the repository root. + */ + repoRoot: string; + /** + * Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + */ + scope: string; +} +/** + * Parsed repository settings without normalization or layering. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "RepoSettingsReadRawResult". + */ +/** @experimental */ +/** @internal */ +export interface RepoSettingsReadRawResult { + /** + * Stored JSON values after the existing JSONC parser and prototype-safety checks. Empty when the file is missing, blank, or invalid. + */ + config: JsonValue; + /** + * True when the file exists but did not parse, so `config` is empty for that reason rather than because nothing is set. + */ + invalid: boolean; +} +/** + * The complete set of repository-overridable settings to store. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "RepoSettingsWriteAllRequest". + */ +/** @experimental */ +/** @internal */ +export interface RepoSettingsWriteAllRequest { + /** + * Absolute path of the repository root. + */ + repoRoot: string; + /** + * Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + */ + scope: string; + /** + * Object of allowed settings to store. Missing allowlisted keys are removed. Other input keys are ignored, while unknown stored keys are preserved. + */ + settings: JsonValue; +} +/** + * One key to write or remove in a repository settings file. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "RepoSettingsWriteKeyRequest". + */ +/** @experimental */ +/** @internal */ +export interface RepoSettingsWriteKeyRequest { + /** + * Absolute path of the repository root. + */ + repoRoot: string; + /** + * Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + */ + scope: string; + /** + * Canonical top-level key permitted by the repository settings allowlist. + */ + key: string; + /** + * Value to validate and write. Required unless delete is true; a null value is validated, not treated as deletion. + */ + value?: JsonValue; + /** + * True to remove the key instead of writing it. + */ + delete?: boolean; +} /** * Resolved sandbox configuration. * @@ -25319,15 +25816,27 @@ export interface SessionOpenOptions { */ allowAllMcpServerInstructions?: boolean; /** - * Additional directories to search for skills. + * Explicit discovery-only skill roots, not filesystem grants. Available without enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ skillDirectories?: string[]; + /** + * Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + */ + agentDirectories?: string[]; + /** + * Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without enableConfigDiscovery, subject to instruction/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + */ + instructionDirectories?: string[]; + /** + * Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without enableConfigDiscovery or enableFileHooks, which controls repository-origin hooks only; hook/managed disables still apply. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + */ + hookDirectories?: string[]; /** * Skill scan directories and descendants excluded from discovery. Supports `~`-relative paths. */ ignoredSkillsLocations?: string[]; /** - * Whether skill loading is enabled. When omitted, an SDK skill provider enables skills by default. + * Whether skill loading is enabled. When omitted, explicit SDK skill roots or an SDK skill provider enable skills independently of enableConfigDiscovery. */ enableSkills?: boolean; /** @@ -27133,9 +27642,21 @@ export interface SessionUpdateOptionsParams { */ allowAllMcpServerInstructions?: boolean; /** - * Additional directories to search for skills. + * Explicit discovery-only skill roots, not filesystem grants. Available without enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ skillDirectories?: string[]; + /** + * Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + */ + agentDirectories?: string[]; + /** + * Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without enableConfigDiscovery, subject to instruction/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + */ + instructionDirectories?: string[]; + /** + * Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without enableConfigDiscovery or enableFileHooks, which controls repository-origin hooks only; hook/managed disables still apply. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + */ + hookDirectories?: string[]; /** * Skill scan directories and descendants excluded from discovery. Supports `~`-relative paths. */ @@ -27243,7 +27764,7 @@ export interface SessionUpdateOptionsParams { */ organizationCustomInstructions?: string; /** - * Whether to enable loading of `.github/hooks/` filesystem hooks. Separate from the SDK callback hook mechanism. + * Whether to enable repository-origin file hooks from `.github/hooks/` and trusted repository-configured roots. Does not control explicit hookDirectories or SDK callback hooks. */ enableFileHooks?: boolean; /** @@ -27255,7 +27776,7 @@ export interface SessionUpdateOptionsParams { */ enableSessionStore?: boolean; /** - * Whether skill loading is enabled. Explicit false disables every source, including a bound SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless an SDK skill provider is registered. + * Whether skill loading is enabled. Explicit false disables every source, including explicit SDK roots and a bound SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless explicit SDK skill roots or an SDK skill provider are supplied. */ enableSkills?: boolean; contextTier?: OptionsUpdateContextTier; @@ -27281,6 +27802,17 @@ export interface SessionUpdateOptionsResult { */ pluginHookCount?: number; } +/** + * Outcome of an atomic user or repository settings edit. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SettingsEditResult". + */ +/** @experimental */ +/** @internal */ +export interface SettingsEditResult { + status: SettingsEditStatus; +} /** * User-requested shell execution cancellation handle. * @@ -27758,7 +28290,7 @@ export interface SkillsDiscoverRequest { */ projectPaths?: string[]; /** - * Optional list of additional skill directory paths to include + * Explicit discovery-only skill roots, not filesystem grants. Available without ambient discovery, subject to skill/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. */ skillDirectories?: string[]; /** @@ -27813,6 +28345,10 @@ export interface SkillSetEnabledRequest { */ /** @experimental */ export interface SkillsGetDiscoveryPathsRequest { + /** + * Explicit discovery-only skill roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + */ + skillDirectories?: string[]; /** * Optional list of project directory paths. When omitted or empty, only personal and custom directories are returned. */ @@ -29900,6 +30436,132 @@ export interface UserSettingMetadata { */ isDefault: boolean; } +/** + * A single top-level setting subtree to validate and write. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsApplyTopKeyRequest". + */ +/** @experimental */ +export interface UserSettingsApplyTopKeyRequest { + /** + * Canonical path of the setting the caller is editing. Currently informational only. + */ + canonicalPath: string[]; + /** + * Top-level setting name to write. + */ + topKey: string; + /** + * Value to write for the whole top-level key. Omitted when `delete` is true. Explicit null is preserved and validated as null. + */ + value?: JsonValue | null; + /** + * True to remove the top-level key instead of writing it. + */ + delete?: boolean; + /** + * Records that the user chose an update channel explicitly, so the one-time staff channel migration stops reapplying. Honored only for the `autoUpdatesChannel` key. + */ + completeStaffUpdateChannelMigration?: boolean; +} +/** + * Outcome of validating and writing one top-level setting subtree. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsApplyTopKeyResult". + */ +/** @experimental */ +export interface UserSettingsApplyTopKeyResult { + /** + * `ok` when the value was written, `validation-error` when it was rejected before any write, `write-error` when validation passed but the write failed. + */ + status: string; + /** + * Problems found, present only when `status` is `validation-error`. + */ + issues?: UserSettingsValidationIssue[]; + /** + * Why the write failed, present only when `status` is `write-error`. + */ + error?: string | null; +} +/** + * One problem found while validating a setting value. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsValidationIssue". + */ +/** @experimental */ +export interface UserSettingsValidationIssue { + /** + * Where in the settings tree the problem sits, as object keys and array indices. The first element is the top-level key; a whole-value problem is reported as that single key. + */ + path: JsonValue[]; + /** + * Human-readable description of the problem. + */ + message: string; +} +/** + * One atomic edit of a canonical setting in settings.json. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsEditRequest". + */ +/** @experimental */ +/** @internal */ +export interface UserSettingsEditRequest { + /** + * Configuration directory to edit. Omitted or empty resolves the server's own home, as in `user.settings.loadForConfigDir`. + */ + configDir?: string; + /** + * Nonempty canonical path segments of the setting to edit, starting with its top-level key. + * + * @minItems 1 + */ + canonicalPath: [string, ...string[]]; + operation: SettingsEditOperation; + /** + * Required boolean, string or number for set, required string for add-item and remove-item, and forbidden for remove. The runtime rejects all other JSON values. + */ + value?: JsonValue; +} +/** + * Selects which settings file paths to resolve. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsGetPathsRequest". + */ +/** @experimental */ +export interface UserSettingsGetPathsRequest { + /** + * Absolute path of a repository root. Supply it to also resolve that repository's two settings file paths; omit it to resolve only the user path. + */ + repoRoot?: string; +} +/** + * On-disk locations of the settings files this runtime reads. A path is reported whether or not the file exists. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsGetPathsResult". + */ +/** @experimental */ +export interface UserSettingsGetPathsResult { + /** + * The user settings file: `settings.json` under the resolved Copilot home. This is the file `user.settings.get`, `user.settings.load`, and `user.settings.set` read and write. + */ + userSettings: string; + /** + * The repository's checked-in settings file, or null when no repository root was supplied. + */ + repoSettings?: string | null; + /** + * The repository's local, untracked settings file, or null when no repository root was supplied. + */ + repoLocalSettings?: string | null; +} /** * Per-key metadata for every known user setting in settings.json, including settings left at their default. Excludes repository- and enterprise-managed overrides. * @@ -29915,6 +30577,178 @@ export interface UserSettingsGetResult { [k: string]: UserSettingMetadata; }; } +/** + * Top-level user-setting keys grouped by who may govern them. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsGovernanceKeysResult". + */ +/** @experimental */ +export interface UserSettingsGovernanceKeysResult { + /** + * Top-level keys a repository may override through `.github/copilot/settings.json` or `.github/copilot/settings.local.json`. + */ + repo: string[]; + /** + * Top-level keys a repository may override through a Claude-compatible repository config. + */ + claudeRepo: string[]; + /** + * Top-level keys an enterprise policy may fix through managed settings. + */ + managed: string[]; +} +/** + * Contents of settings.json as stored, for a caller about to rewrite it. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsLoadForEditResult". + */ +/** @experimental */ +export interface UserSettingsLoadForEditResult { + /** + * `ok` when the file parsed, `missing` when there is no file yet, `invalid` when the file exists but will not parse. + */ + status: string; + /** + * Parsed contents, present only when `status` is `ok`. + */ + settings?: JsonValue; +} +/** + * Settings object whose key names should be canonicalized. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsNormalizeRequest". + */ +/** @experimental */ +export interface UserSettingsNormalizeRequest { + /** + * Free-form settings object, possibly using legacy or snake_case key names. + */ + settings: JsonValue; +} +/** + * Settings object with canonical key names. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsNormalizeResult". + */ +/** @experimental */ +export interface UserSettingsNormalizeResult { + /** + * The same settings with every legacy or snake_case key renamed to its canonical spelling. + */ + settings: JsonValue; +} +/** + * One setting that will not take effect, and why. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsProblem". + */ +/** @experimental */ +export interface UserSettingsProblem { + /** + * Stable identifier for this problem within the reported set, so a caller can track a selection across refreshes. + */ + id: string; + /** + * What is wrong in machine-readable form, for a caller that wants to branch rather than display. + */ + kind: string; + /** + * Coarse grouping for the problem, for a caller that presents problems in sections. + */ + category: string; + source: UserSettingsProblemLocation; + /** + * The offending key as written in the file, when the problem is attributable to a single key. Absent when the whole file is at fault. + */ + rawKey?: string; + /** + * Why the setting will not take effect. Never contains the setting's value, which may be a token or another secret. + */ + explanation: string; +} +/** + * The settings layer a problem was found in. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsProblemLocation". + */ +/** @experimental */ +export interface UserSettingsProblemLocation { + /** + * Which layer this is: `user`, `repo`, or `local`. + */ + kind: string; + /** + * The caller-supplied display label for the layer. + */ + label: string; + /** + * Absolute path of the file backing this layer. + */ + filePath: string; +} +/** + * One already-loaded settings layer to diagnose. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsProblemSource". + */ +/** @experimental */ +export interface UserSettingsProblemSource { + /** + * Which layer this is: `user`, `repo`, or `local`. + */ + kind: string; + /** + * Caller-chosen display label for the layer, echoed back on each problem so a caller can group by layer without re-deriving its own naming. + */ + label: string; + /** + * Absolute path of the file backing this layer. + */ + filePath: string; + /** + * The layer's settings exactly as loaded, unnormalized. Empty when the file is missing or failed to parse. + */ + config?: { + [k: string]: unknown | undefined; + }; + /** + * True when the file itself failed to parse, so its keys could not be read at all. + */ + invalid?: boolean; +} +/** + * The settings layers to diagnose. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsProblemsRequest". + */ +/** @experimental */ +export interface UserSettingsProblemsRequest { + /** + * Layers to diagnose, in the precedence order the caller applies them. + */ + sources?: UserSettingsProblemSource[]; +} +/** + * The settings that will not take effect across the given layers. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsProblemsResult". + */ +/** @experimental */ +export interface UserSettingsProblemsResult { + /** + * Each setting that will not take effect, and why. Empty when every layer is healthy. + */ + problems?: UserSettingsProblem[]; +} /** * Partial user settings to write to settings.json. Each top-level key is written individually, replacing the existing value; a key whose value is null is removed. * @@ -29928,6 +30762,97 @@ export interface UserSettingsSetRequest { */ settings: JsonValue; } +/** + * Names the user setting to merge into, and the partial object to merge. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsUpdateRequest". + */ +/** @experimental */ +/** @internal */ +export interface UserSettingsUpdateRequest { + /** + * Top-level user-setting key to merge into, such as `extensions`. + */ + key: string; + /** + * Value to store for `key`. When both the stored value and this value are objects, their fields are shallow-merged and fields this object does not name are preserved. Otherwise this value replaces the stored value. + */ + value: JsonValue; + /** + * Copilot configuration directory to write the settings document in, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to use the directory the server resolved for itself. + */ + configDir?: string; + /** + * Single-component name for the settings document at `/settings/.json`; path separators, `.` and `..` are rejected. Omit it, or pass an empty string, to use the main settings document. + */ + subDir?: string; +} +/** + * The stored value of the user setting after the merge. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsUpdateResult". + */ +/** @experimental */ +/** @internal */ +export interface UserSettingsUpdateResult { + /** + * The key's stored value after the write: the merged object when both the stored value and the supplied value are objects, otherwise the supplied value. + */ + value: JsonValue; +} +/** + * A single top-level setting subtree to validate. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsValidateRequest". + */ +/** @experimental */ +export interface UserSettingsValidateRequest { + /** + * Top-level setting name to validate. + */ + topKey: string; + /** + * Value to validate. Omitted when `delete` is true. + */ + value?: JsonValue; + /** + * True to validate a removal of this key. The current settings file is not read. + */ + delete?: boolean; +} +/** + * Outcome of validating one top-level setting subtree. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsValidateResult". + */ +/** @experimental */ +export interface UserSettingsValidateResult { + /** + * True when the subtree is valid. + */ + ok: boolean; + /** + * Problems found, empty when `ok` is true. + */ + issues?: UserSettingsValidationIssue[]; +} +/** + * The whole content to store in the user settings file. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsWriteAllRequest". + */ +/** @experimental */ +export interface UserSettingsWriteAllRequest { + /** + * The settings object to store. It replaces the file's entire content, so a key absent here is removed. + */ + settings: JsonValue; +} /** * Current sharing status and shareable GitHub URL for a session. * @@ -31680,6 +32605,19 @@ export interface HostGetConfigurationResult { */ /** @experimental */ export interface HostReadyResult {} +/** + * The resolved feature flags, keyed by flag name. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "FeatureFlagsResolveResult". + */ +/** @experimental */ +export interface FeatureFlagsResolveResult { + /** + * Whether the flag is enabled for this population. + */ + [k: string]: boolean | undefined; +} /** * Ordered managed permission verdicts and the supplied policy's fail-closed posture. * @@ -32644,6 +33582,27 @@ export function createServerRpc(connection: MessageConnection) { connection.sendRequest("extensions.disable", params), }, /** @experimental */ + instructions: { + /** + * Discovers instruction sources across user, repository, and plugin sources. + * + * @param params Optional project paths to include in instruction discovery. + * + * @returns Instruction sources discovered across user, repository, and plugin sources. + */ + discover: async (params: InstructionsDiscoverRequest): Promise => + connection.sendRequest("instructions.discover", params), + /** + * Returns the canonical files and directories where a client may create custom instructions that the runtime will recognize, including ones that do not exist yet. Repository targets become active once created. + * + * @param params Optional project paths to include when enumerating instruction discovery targets. + * + * @returns Canonical files and directories where custom instructions can be created so the runtime will recognize them. + */ + getDiscoveryPaths: async (params: InstructionsGetDiscoveryPathsRequest): Promise => + connection.sendRequest("instructions.getDiscoveryPaths", params), + }, + /** @experimental */ skills: { /** * Plans installation of a verified Agent Finder Skill candidate without writing files. The returned review is safe to present to a user and installing always leaves the Skill disabled until separately enabled. @@ -32927,27 +33886,6 @@ export function createServerRpc(connection: MessageConnection) { connection.sendRequest("agents.getDiscoveryPaths", params), }, /** @experimental */ - instructions: { - /** - * Discovers instruction sources across user, repository, and plugin sources. - * - * @param params Optional project paths to include in instruction discovery. - * - * @returns Instruction sources discovered across user, repository, and plugin sources. - */ - discover: async (params: InstructionsDiscoverRequest): Promise => - connection.sendRequest("instructions.discover", params), - /** - * Returns the canonical files and directories where a client may create custom instructions that the runtime will recognize, including ones that do not exist yet. Repository targets become active once created. - * - * @param params Optional project paths to include when enumerating instruction discovery targets. - * - * @returns Canonical files and directories where custom instructions can be created so the runtime will recognize them. - */ - getDiscoveryPaths: async (params: InstructionsGetDiscoveryPathsRequest): Promise => - connection.sendRequest("instructions.getDiscoveryPaths", params), - }, - /** @experimental */ commands: { /** * Lists the well-known built-in slash commands that work as the first message in a new session (e.g. /plan, /env), without requiring an active session. Commands that depend on session state, authentication, or a synced session are omitted. @@ -33423,6 +34361,43 @@ export function createInternalServerRpc(connection: MessageConnection) { connect: async (params: ConnectRequest): Promise => connection.sendRequest("connect", params), /** @experimental */ + account: { + /** + * Renders the sign-in banner and the one-line account description the runtime uses for an authentication identity. The runtime words these in several places for its own callers, so a host that announces a sign-in or an account switch should render them from here rather than composing its own, which would let the two spellings drift apart. + * + * @param params The authentication identity whose shared wording should be rendered. + * + * @returns The wording the runtime uses for an authentication identity. + */ + describeAuthInfo: async (params: AccountDescribeAuthInfoRequest): Promise => + connection.sendRequest("account.describeAuthInfo", params), + /** + * Reports whether the supplied identity can create gists. Gists are unavailable on GitHub Enterprise Cloud with data residency, and to Enterprise Managed Users on github.com, so a host that offers gist actions should hide or disable them when this reports no support. + * + * @param params The authentication identity whose gist support should be reported. + * + * @returns Whether the identity can create gists, and why not when it cannot. + */ + getGistSupport: async (params: AccountGetGistSupportRequest): Promise => + connection.sendRequest("account.getGistSupport", params), + /** + * Resolves a path on the identity's GitHub host into an absolute URL, so a host can link to settings or documentation on the enterprise instance the user is signed in to rather than to github.com. Falls back to the public host when no identity is supplied. + * + * @param params A path to resolve against the GitHub host an identity is signed in to. + * + * @returns An absolute URL on the identity's GitHub host. + */ + getWebUrl: async (params: AccountGetWebUrlRequest): Promise => + connection.sendRequest("account.getWebUrl", params), + /** + * Names the environment variable supplying a classic personal access token, if one is set. A classic token cannot be upgraded in place, so a host that finds one should tell the user which variable to unset rather than starting an interactive sign-in that the variable would override. + * + * @returns The environment variable supplying a classic personal access token, when one is set. + */ + getTokenEnvVar: async (): Promise => + connection.sendRequest("account.getTokenEnvVar", {}), + }, + /** @experimental */ mcp: { /** @experimental */ registry: { @@ -33452,6 +34427,13 @@ export function createInternalServerRpc(connection: MessageConnection) { cancel: async (params: McpRegistryCancelRequest): Promise => connection.sendRequest("mcp.registry.cancel", params), }, + /** + * Lists the MCP servers the runtime supplies itself, so a host that disables the built-ins wholesale suppresses exactly the set the runtime would otherwise add. The names are fixed for a build and depend on no configuration, session or account. + * + * @returns Names of the MCP servers the runtime supplies itself. + */ + listBuiltinServerNames: async (): Promise => + connection.sendRequest("mcp.listBuiltinServerNames", {}), /** * Reports whether the gh-replaceable GitHub MCP tools may be clipped for a session, which a host feeds back as the `excludeGhReplaceableTools` build option. The tools are redundant only when the session can reach a shell *and* the host has the `gh` that would replace them, so both halves are decided here. The shell half runs the platform shell tool through the runtime's own tool-filter matcher, so entry forms like `builtin:bash` and `builtin:*` behave exactly as they do when a session builds its tool catalog. The host half probes for `gh`, and is skipped entirely when the filters already rule the shell out. Host presence alone is not enough: a session restricted to, say, `view` would otherwise lose the built-in issue-read fallback while having no shell to replace it with. The answer describes the host the runtime runs on, so it is never forwarded to a remote engine. * @@ -33463,6 +34445,30 @@ export function createInternalServerRpc(connection: MessageConnection) { connection.sendRequest("mcp.shouldExcludeGitHubTools", params), }, /** @experimental */ + instructions: { + /** + * Returns the prompt the `init` command runs to author repository instructions. A host offering its own initialize action sends this text so the instructions it produces match the ones the CLI produces. The text is fixed for a build and depends on no configuration, session or repository. + * + * @returns The prompt the init command runs. + */ + getInitPrompt: async (): Promise => + connection.sendRequest("instructions.getInitPrompt", {}), + /** + * Discovers the instruction sources for one caller-named location and returns them in the order the runtime applies them. `discover` answers for a set of project paths and derives the rest of its scope itself; this one instead takes every argument from the caller — the extra directories to scan and whether to descend into nested instruction files — and honors them as given. It also includes instruction directories from trusted repository settings, matching native repository discovery. Use it when the caller knows its own scope and no session exists to derive that scope from, such as a host reporting how many instruction files a directory contributes before any session starts. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. + * + * @param params Explicit discovery arguments for one location, supplied by the caller rather than derived from a session. + * + * @returns Instruction sources discovered across user, repository, and plugin sources. + */ + discoverRepoSources: async (params: InstructionsDiscoverRepoSourcesRequest): Promise => + connection.sendRequest("instructions.discoverRepoSources", params), + /** + * Drops the runtime's in-memory cache of discovered custom instructions so the next discovery reads them from disk again. A host calls this after it changes instruction files, or after it trusts a folder whose instructions an earlier discovery skipped, so that a session started afterwards sees the current files instead of a cached earlier answer. The call performs no I/O of its own and removes nothing from disk; it only invalidates, so the cost lands on the next discovery. Returns once the cache is clear, which is what lets a caller order a session start after it. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. + */ + clearCache: async (): Promise => + connection.sendRequest("instructions.clearCache", {}), + }, + /** @experimental */ agents: { /** * Lists the agents this runtime ships, by name. A consumer separating shipped agents from ones the user or a plugin authored should compare against these names rather than against `AgentInfo.source`: an authored agent may carry the `builtin` source while not being one of these, and the runtime treats the two as separate questions. `disableableNames` is the subset a user may turn off, which a client needs to decide whether to offer a toggle. `yamlBasedNames` is the subset backed by a shipped YAML definition, which a client needs before asking the runtime to load one. @@ -33535,6 +34541,144 @@ export function createInternalServerRpc(connection: MessageConnection) { connection.sendRequest("globalState.writeKey", params), }, /** @experimental */ + user: { + /** @experimental */ + settings: { + /** + * Resolves the on-disk locations of the settings files this runtime reads, so a consumer can show or open them. The user path is the same file `user.settings.get`, `user.settings.load`, and `user.settings.set` operate on. Supply `repoRoot` to also resolve that repository's checked-in and local settings paths. A path is reported whether or not the file exists. + * + * @param params Selects which settings file paths to resolve. + * + * @returns On-disk locations of the settings files this runtime reads. A path is reported whether or not the file exists. + */ + getPaths: async (params: UserSettingsGetPathsRequest): Promise => + connection.sendRequest("user.settings.getPaths", params), + /** + * Lists the top-level user-setting keys by who is allowed to govern them: `repo` keys a repository may override through `.github/copilot/settings.json`, `claudeRepo` keys a repository may override through a Claude-compatible config, and `managed` keys an enterprise policy may fix. The lists are static for a given runtime build and fail closed: a key absent from a list cannot be governed that way. + * + * @returns Top-level user-setting keys grouped by who may govern them. + */ + listGovernanceKeys: async (): Promise => + connection.sendRequest("user.settings.listGovernanceKeys", {}), + /** + * Atomically edits one canonical user setting inside its settings-file lock. Reads, canonicalizes touched aliases, applies the edit, validates the resulting top-level setting and writes before releasing the lock. An explicit autoUpdatesChannel set completes the staff migration in the same transaction. Only a malformed existing file returns `invalid`; refused keys, invalid values and I/O errors reject the call. + * + * @param params One atomic edit of a canonical setting in settings.json. + * + * @returns Outcome of an atomic user or repository settings edit. + */ + edit: async (params: UserSettingsEditRequest): Promise => + connection.sendRequest("user.settings.edit", params), + /** + * Rewrites legacy and snake_case setting names in a settings object to their canonical spelling. A caller editing settings.json must normalize before writing: a legacy key left in place survives the write, is re-normalized on the next load, and silently shadows the canonical value the write just stored. + * + * @param params Settings object whose key names should be canonicalized. + * + * @returns Settings object with canonical key names. + */ + normalize: async (params: UserSettingsNormalizeRequest): Promise => + connection.sendRequest("user.settings.normalize", params), + /** + * Diagnoses a set of already-loaded settings layers, reporting each key that will not take effect and why. Settings load tolerantly so that one bad key does not stop a session from starting; this method surfaces what was dropped so a caller can report it instead of silently ignoring the user's intent. Takes the layers as given rather than reading them, so a caller can diagnose exactly the content it is showing, including unsaved edits. Never echoes a setting's value, because a value may be a token or another secret. Marked internal because it exists to carry a CLI call site off the native addon, not to serve a consumer-facing need; it becomes public once an SDK consumer needs to inspect settings health itself. + * + * @param params The settings layers to diagnose. + * + * @returns The settings that will not take effect across the given layers. + */ + diagnoseProblems: async (params: UserSettingsProblemsRequest): Promise => + connection.sendRequest("user.settings.diagnoseProblems", params), + /** + * Validates one top-level setting subtree and writes just that key to settings.json as a single step. Doing both here closes the race a caller cannot close itself: between a separate preflight read and the write, the file may change. Rewriting only the touched key keeps legacy siblings out of settings.json. Answers a status rather than failing, so a validation problem and a write problem stay distinguishable. + * + * @param params A single top-level setting subtree to validate and write. + * + * @returns Outcome of validating and writing one top-level setting subtree. + */ + applyTopKey: async (params: UserSettingsApplyTopKeyRequest): Promise => + connection.sendRequest("user.settings.applyTopKey", params), + /** + * Replaces the user settings file's entire content in one write. A key absent from `settings` is removed, which is what distinguishes this from `user.settings.set`: that one merges, so it can never clear a key the caller has dropped. For a caller saving the result of a raw edit, a merge would silently resurrect every key the user deleted. Records the same one-time mutation marks a per-key write records, so a setting the user has now chosen explicitly stops being migrated for them. + * + * @param params The whole content to store in the user settings file. + */ + writeAll: async (params: UserSettingsWriteAllRequest): Promise => + connection.sendRequest("user.settings.writeAll", params), + /** + * Merges a partial object into one top-level user setting, re-reading the stored value inside this runtime process's settings.json write lock so that concurrent writers in this process to different sub-fields of the same key do not clobber each other. Unlike `user.settings.set`, which replaces a key's whole value with what the caller last read, this keeps sub-fields the caller did not name when both the stored value and supplied value are objects; otherwise the supplied value replaces the stored value. Use it whenever two independent surfaces own different sub-fields of one setting. Returns the key's stored value after the write, in `value`. + * + * @param params Names the user setting to merge into, and the partial object to merge. + * + * @returns The stored value of the user setting after the merge. + */ + update: async (params: UserSettingsUpdateRequest): Promise => + connection.sendRequest("user.settings.update", params), + /** + * Reads settings.json as stored for a caller that is about to edit it. Unlike `user.settings.get`, this returns file values rather than per-key metadata and defaults. Reports `missing` for an absent file and `invalid` when the existing file will not parse. Retired config.json and extensionless files are not read. + * + * @returns Contents of settings.json as stored, for a caller about to rewrite it. + */ + loadForEdit: async (): Promise => + connection.sendRequest("user.settings.loadForEdit", {}), + /** + * Validates one top-level setting subtree without writing it, reporting each problem with the path it applies to. Scoped to a single top-level key on purpose: validating the whole file would reject an edit whenever an unrelated pre-existing field is malformed, locking the user out of the very tool that could fix it. + * + * @param params A single top-level setting subtree to validate. + * + * @returns Outcome of validating one top-level setting subtree. + */ + validate: async (params: UserSettingsValidateRequest): Promise => + connection.sendRequest("user.settings.validate", params), + }, + }, + /** @experimental */ + featureFlags: { + /** + * Lists every feature flag this runtime declares, with the population each one is declared for, its experimental description, and the online-experiment flag it maps to. This is the static catalog: it describes how each flag is defined, not whether it is on for anyone. Use `featureFlags.resolve` for static values with caller overrides, not active runtime values or experiment assignments. + * + * @returns Every feature flag this runtime declares, with the shape each one was declared with. + */ + listMetadata: async (): Promise => + connection.sendRequest("featureFlags.listMetadata", {}), + /** + * Computes static feature flags from the supplied population and overrides without changing runtime state or verifying audience membership. Starts from declared availability, then applies direct feature-flag environment values, user settings, and explicit `flagOverrides`. It does not apply `COPILOT_EXP_*` experiment assignments, authenticated startup gates, or active runtime state. Settings include `enabledFeatureFlags`, the legacy `feature_flags.enabled` list, and supported convenience settings. Supply `baseFlags` to use an existing flag set instead of declared availability. Omit `isStaffGitHub` or `isStaffMicrosoft` when membership was never recorded: a legacy staff account then counts as both populations. + * + * @param params Caller population and overrides for static feature-flag resolution, independent of experiment assignments and active runtime state. + * + * @returns The resolved feature flags, keyed by flag name. + */ + resolve: async (params: FeatureFlagsResolveRequest): Promise => + connection.sendRequest("featureFlags.resolve", params), + }, + /** @experimental */ + repo: { + /** @experimental */ + settings: { + /** + * Reads one repository settings file without settings normalization or layering. The existing JSONC parser accepts comments and trailing commas and applies its prototype-safety rules. Missing or blank files return an empty valid config. Invalid files return an empty config with invalid=true; other read failures reject. + * + * @param params Which repository settings file to read. + * + * @returns Parsed repository settings without normalization or layering. + */ + readRaw: async (params: RepoSettingsReadRawRequest): Promise => + connection.sendRequest("repo.settings.readRaw", params), + /** + * Writes or removes one allowed top-level repository setting through the existing validator and file lock. Preserves unrelated stored keys. Invalid keys, values, existing documents, and I/O errors reject without replacing the file. Deletion requires delete=true; otherwise value must be present. + * + * @param params One key to write or remove in a repository settings file. + */ + writeKey: async (params: RepoSettingsWriteKeyRequest): Promise => + connection.sendRequest("repo.settings.writeKey", params), + /** + * Replaces the repository-overridable settings in one locked write. Allowed keys present in settings are validated and written; allowed keys absent from settings are removed. Other input keys are ignored, and unknown keys already stored in the file remain unchanged. Invalid values or an invalid existing file reject without a partial write. + * + * @param params The complete set of repository-overridable settings to store. + */ + writeAll: async (params: RepoSettingsWriteAllRequest): Promise => + connection.sendRequest("repo.settings.writeAll", params), + }, + }, + /** @experimental */ gitHubRepository: { /** * Resolves the GitHub repository that owns a working-tree path by reading the selected git remote configured for it, preferring `origin`. Returns a null `repository` when the path is inside a git working tree but that selected remote does not resolve to a GitHub host. Fails when the path is not inside a git working tree at all, so a caller can tell 'not a repository' apart from 'a repository with no GitHub remote'. @@ -34145,6 +35289,15 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin */ setReasoningEffort: async (params: ModelSetReasoningEffortRequest): Promise => connection.sendRequest("session.model.setReasoningEffort", { ...params, sessionId }), + /** + * Computes whether the session's current model shows reasoning summaries and how a host should present them: the default Ctrl+T visibility, reasoning headers, the hidden-summaries hint, and whether a persisted `showReasoning` setting is redundant. The runtime folds in the session's model catalog, selection and reasoning-summaries experiment assignment; the host supplies only its own persisted setting and current visibility. This method reads the session's resolved model catalog rather than resolving it, so call `session.model.list` first on a session that has not listed models or run a turn; until then the result is `ready: false`. A session that resolves models without a Copilot catalog, that is a BYOK registry or an alternate provider, never caches one and stays `ready: false`. + * + * @param params Host presentation state the reasoning-summaries policy depends on. + * + * @returns Reasoning-summaries presentation policy for the session's current model. + */ + getReasoningSummaries: async (params: ModelGetReasoningSummariesRequest): Promise => + connection.sendRequest("session.model.getReasoningSummaries", { ...params, sessionId }), /** * Lists models available to this session using its own auth and integration context. Connected hosts (CLI TUI, GitHub App) should call this through the session client so remote sessions return the remote CLI's available models rather than the caller's. * diff --git a/nodejs/src/generated/session-events.ts b/nodejs/src/generated/session-events.ts index 3b15ae7d4f..6e7bb5bd02 100644 --- a/nodejs/src/generated/session-events.ts +++ b/nodejs/src/generated/session-events.ts @@ -217,7 +217,9 @@ export type RemediationAction = /** Review or widen the sandbox policy. The blocked path or host is named by the accompanying message or by the tool result the action arrived with. */ | "review_sandbox_policy" /** Permit outbound network access in the sandbox policy. */ - | "allow_sandbox_outbound"; + | "allow_sandbox_outbound" + /** Discard conversation history back through the blocked request before continuing. */ + | "rewind_conversation"; /** * The session mode the agent is operating in */ @@ -2187,7 +2189,7 @@ export interface ErrorData { */ errorCode?: string; /** - * Category of error (e.g., "authentication", "authorization", "quota", "rate_limit", "context_limit", "query") + * Category of error (e.g., "authentication", "authorization", "policy", "quota", "rate_limit", "context_limit", "query") */ errorType: string; /** @@ -2198,6 +2200,14 @@ export interface ErrorData { * GitHub request tracing ID (x-github-request-id header) for correlating with server-side logs */ providerCallId?: string; + /** + * Sanitized provider-defined error parameter preserved from a structured upstream error envelope, when available. + */ + providerErrorParam?: string; + /** + * Provider-defined error type preserved from a structured upstream error envelope, when available (for example, `invalid_request_error`). + */ + providerErrorType?: string; remediation?: RemediationAction; /** * Copilot service request ID (x-copilot-service-request-id header) for CAPI log correlation @@ -4389,6 +4399,10 @@ export interface CompactionCompleteCompactionTokensUsed { */ outputTokens?: number; provider?: ModelProviderRef; + /** + * Number of model requests represented by this aggregated compaction usage + */ + requestCount?: number; } /** * Per-request cost and usage data from the CAPI copilot_usage response field @@ -4537,6 +4551,14 @@ export interface PermissionRecoveryData { */ maxAttempts: number; onBlocked: PermissionRecoveryOnBlocked; + /** + * Subagent identifier that owns this recovery episode when the request was delegated through a parent permission service + */ + ownerAgentId?: string; + /** + * Root or child execution-session identifier that owns this recovery episode; omitted for legacy snapshots + */ + ownerSessionId?: string; reason: PermissionRecoveryReason; status: PermissionRecoveryStatus; } @@ -9672,6 +9694,14 @@ export interface PermissionRequestedEvent { */ export interface PermissionRequestedData { agentMode?: SessionMode; + /** + * Delegated agent that owns permission recovery when the owner session multiplexes remote agents. Absent otherwise. + */ + ownerAgentId?: string; + /** + * Execution session that owns permission recovery for this request. Absent on historical events. + */ + ownerSessionId?: string; permissionMode?: PermissionMode; permissionRequest: PermissionRequest; promptRequest?: PermissionPromptRequest; diff --git a/nodejs/src/index.ts b/nodejs/src/index.ts index ad9e427287..e95b5362de 100644 --- a/nodejs/src/index.ts +++ b/nodejs/src/index.ts @@ -9,7 +9,12 @@ */ export { CopilotClient } from "./client.js"; -export type { HostLocalServerOptions, HostGitHubEnvironmentOptions } from "./generated/rpc.js"; +export type { + HostLocalServerOptions, + HostGitHubEnvironmentOptions, + ModelGetReasoningSummariesRequest, + ModelGetReasoningSummariesResult, +} from "./generated/rpc.js"; export { AhpHost, type AhpHostExit, diff --git a/nodejs/src/types.ts b/nodejs/src/types.ts index 80588c2627..d3722a99d8 100644 --- a/nodejs/src/types.ts +++ b/nodejs/src/types.ts @@ -2025,6 +2025,8 @@ export type MCPServerConfig = MCPStdioServerConfig | MCPHTTPServerConfig; * Configuration for a custom agent. */ export interface CustomAgentConfig { + /** Declarative hook actions keyed by event name, active only for this agent. */ + hooks?: Record[]>; /** * Unique name of the custom agent. */ @@ -2960,7 +2962,11 @@ export interface SessionConfigBase { agent?: string; /** - * Directories to load skills from. + * Explicit discovery-only skill roots. No general filesystem access is granted. + * Available without `enableConfigDiscovery`; skill and managed disables still apply. + * Relative paths resolve once when supplied against the request's effective + * `workingDirectory`, and retained roots do not move when it changes. + * Null and omission are equivalent; `[]` clears only the explicit SDK contribution. */ skillDirectories?: string[]; @@ -2981,6 +2987,27 @@ export interface SessionConfigBase { */ skillProvider?: SkillProvider; + /** + * Explicit discovery-only agent roots, separate from `customAgents` objects. + * No general filesystem access is granted. Available without `enableConfigDiscovery`; + * source and managed disables still apply. + * Relative paths resolve once when supplied against the request's effective + * `workingDirectory`, and retained roots do not move when it changes. + * Null and omission are equivalent; `[]` clears only the explicit SDK contribution. + */ + agentDirectories?: string[]; + + /** + * Explicit discovery-only file-hook roots, separate from callback `hooks`. + * No general filesystem access is granted. Available without `enableConfigDiscovery` + * or `enableFileHooks` (which controls repository-origin hooks only); + * hook and managed disables still apply. + * Relative paths resolve once when supplied against the request's effective + * `workingDirectory`, and retained roots do not move when it changes. + * Null and omission are equivalent; `[]` clears only the explicit SDK contribution. + */ + hookDirectories?: string[]; + /** * Local filesystem paths to Open Plugins-format directories * (https://open-plugins.com/) to load for this session. @@ -2997,7 +3024,12 @@ export interface SessionConfigBase { pluginDirectories?: string[]; /** - * Additional directories to search for custom instruction files. + * Explicit discovery-only instruction roots using the existing SDK instruction formats. + * No general filesystem access is granted. Available without `enableConfigDiscovery`; + * instruction and managed disables still apply. + * Relative paths resolve once when supplied against the request's effective + * `workingDirectory`, and retained roots do not move when it changes. + * Null and omission are equivalent; `[]` clears only the explicit SDK contribution. */ instructionDirectories?: string[]; @@ -3115,9 +3147,9 @@ export interface SessionConfigBase { enableOnDemandInstructionDiscovery?: boolean; /** - * When true, enables loading of file-based hooks from `.github/hooks/`. - * This is separate from the `hooks` callback parameter which gates SDK - * hook event registration. + * When true, enables repository-origin file hooks from `.github/hooks/` and + * trusted repository-configured roots. Does not control explicit `hookDirectories` + * or the `hooks` callback parameter. */ enableFileHooks?: boolean; @@ -3197,6 +3229,15 @@ export interface SessionConfig extends SessionConfigBase { */ sessionId?: string; + /** + * Names the session at creation, as `session.name.set` would, and is validated the + * same way: non-empty, no leading or trailing whitespace, at most 100 UTF-16 units, + * no control characters, and no double quotes. A name also makes the session persist + * from the start, so it can be listed and resumed without ever running a turn. + * Local sessions only: cloud creation rejects it. + */ + name?: string; + /** * Invalidates the process-wide custom-instruction discovery cache before * creating this session. Use when instruction files changed in the same runtime. diff --git a/nodejs/test/account-facts-projection.test.ts b/nodejs/test/account-facts-projection.test.ts new file mode 100644 index 0000000000..5e689bb423 --- /dev/null +++ b/nodejs/test/account-facts-projection.test.ts @@ -0,0 +1,45 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import { readFileSync } from "node:fs"; +import { describe, expect, it } from "vitest"; + +describe("account facts Go projection", () => { + const source = readFileSync(new URL("../../go/rpc/zrpc.go", import.meta.url), "utf8"); + + for (const name of ["AccountGetWebURLRequest", "AccountGetWebURLResult"]) { + it(`marks ${name} as internal after Go initialism normalization`, () => { + const comment = source.match(new RegExp(`((?://[^\\n]*\\n)+)type ${name} struct`))?.[1]; + expect(comment).toContain(`// Internal: ${name} `); + }); + } +}); + +describe("account facts Python projection", () => { + const source = readFileSync( + new URL("../../python/copilot/generated/rpc.py", import.meta.url), + "utf8" + ); + const exports = source.match(/^__all__ = \[([\s\S]*?)^\]/m)?.[1]; + + for (const [name, keys] of [ + ["AccountGetWebURLRequest", ["identity", "path"]], + ["AccountGetWebURLResult", ["url"]], + ] as const) { + it(`keeps ${name} private without changing its wire keys`, () => { + const declaration = source.match( + new RegExp(`^class _${name}:\\n[\\s\\S]*?(?=^class )`, "m") + )?.[0]; + expect(declaration).toBeDefined(); + expect(source).not.toMatch(new RegExp(`^class ${name}\\b`, "m")); + expect(exports).toBeDefined(); + expect(exports).not.toContain(`"${name}"`); + expect(exports).not.toContain(`"_${name}"`); + for (const key of keys) { + expect(declaration).toContain(`obj.get("${key}")`); + expect(declaration).toContain(`result["${key}"]`); + } + }); + } +}); diff --git a/nodejs/test/csharp-codegen.test.ts b/nodejs/test/csharp-codegen.test.ts index d234e4a107..5120fabc95 100644 --- a/nodejs/test/csharp-codegen.test.ts +++ b/nodejs/test/csharp-codegen.test.ts @@ -31,6 +31,21 @@ function legacySignatureFixture(scope: "server" | "session", legacy: unknown) { return { schema, params, methods }; } +describe("C# required opaque JSON parameters", () => { + it.each(["server", "session"] as const)("preserves JSON null in %s requests", (scope) => { + const { schema, params } = legacySignatureFixture(scope, undefined); + params.required!.push("config"); + const code = generateRpcCode(schema); + + expect(code).toContain("RunAsync(string name, object? config,"); + expect(code).toContain( + 'Config = CopilotClient.ToJsonElementForWire(config) ?? JsonElement.Parse("null")' + ); + expect(code).not.toContain("ArgumentNullException.ThrowIfNull(config);"); + expect(code).toContain("ArgumentNullException.ThrowIfNull(name);"); + }); +}); + describe("C# additive request entry compatibility", () => { it.each(["server", "session"] as const)( "preserves the exact legacy %s signature and adds a same-name request overload", diff --git a/nodejs/test/customization-directories.test.ts b/nodejs/test/customization-directories.test.ts new file mode 100644 index 0000000000..af06711fa1 --- /dev/null +++ b/nodejs/test/customization-directories.test.ts @@ -0,0 +1,100 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. + +import { once } from "node:events"; +import { createServer, type Socket } from "node:net"; +import { describe, expect, it, onTestFinished } from "vitest"; +import { + createMessageConnection, + StreamMessageReader, + StreamMessageWriter, + type MessageConnection, +} from "vscode-jsonrpc/node.js"; +import { CopilotClient, RuntimeConnection, approveAll } from "../src/index.js"; +import { getSdkProtocolVersion } from "../src/sdkProtocolVersion.js"; + +describe("customization directory adapters", () => { + it.each([ + { name: "omitted", roots: undefined }, + { name: "empty", roots: [] }, + { name: "relative", roots: ["relative-root", "other-root"] }, + ])("preserves supplied roots on create and resume: $name", async ({ roots }) => { + const requests = new Map>(); + const peers: { connection: MessageConnection; socket: Socket }[] = []; + let client: CopilotClient | undefined; + const server = createServer((socket) => { + const connection = createMessageConnection( + new StreamMessageReader(socket), + new StreamMessageWriter(socket) + ); + peers.push({ connection, socket }); + connection.onRequest("connect", () => ({ + ok: true, + protocolVersion: getSdkProtocolVersion(), + version: "adapter-test", + })); + for (const method of ["session.create", "session.resume"]) { + connection.onRequest(method, (params: Record) => { + requests.set(method, params); + return { sessionId: params.sessionId }; + }); + } + connection.onRequest("session.options.update", () => ({})); + connection.onRequest("session.detach", () => ({ success: true })); + connection.onRequest("session.skills.reload", () => ({})); + connection.listen(); + }); + onTestFinished(async () => { + try { + await client?.forceStop(); + } finally { + for (const peer of peers) { + peer.connection.dispose(); + peer.socket.destroy(); + } + if (server.listening) { + await new Promise((resolve, reject) => + server.close((error) => (error ? reject(error) : resolve())) + ); + } + } + }); + server.listen(0, "127.0.0.1"); + await once(server, "listening"); + const address = server.address(); + if (!address || typeof address === "string") throw new Error("Missing test listener"); + client = new CopilotClient({ + connection: RuntimeConnection.forUri(`127.0.0.1:${address.port}`), + }); + const directories = { + skillDirectories: roots?.map((root) => `${root}-skills`), + agentDirectories: roots?.map((root) => `${root}-agents`), + instructionDirectories: roots?.map((root) => `${root}-instructions`), + hookDirectories: roots?.map((root) => `${root}-hooks`), + }; + const config = { + workingDirectory: "request-cwd", + enableConfigDiscovery: false, + enableFileHooks: false, + ...directories, + onPermissionRequest: approveAll, + }; + const session = await client.createSession(config); + await client.resumeSession(session.sessionId, config); + for (const method of ["session.create", "session.resume"]) { + const request = requests.get(method); + expect(request).toBeDefined(); + for (const [key, expected] of Object.entries(directories)) { + if (expected === undefined) { + expect(request).not.toHaveProperty(key); + } else { + expect(request).toHaveProperty(key, expected); + } + } + expect(request).toHaveProperty("enableConfigDiscovery", false); + expect(request).toHaveProperty("enableFileHooks", false); + expect(request).not.toHaveProperty("additionalDirectories"); + expect(request).not.toHaveProperty("customAgents"); + expect(request).toHaveProperty("hooks", false); + } + }); +}); diff --git a/nodejs/test/e2e/agent_scoped_hooks.e2e.test.ts b/nodejs/test/e2e/agent_scoped_hooks.e2e.test.ts new file mode 100644 index 0000000000..56664421bb --- /dev/null +++ b/nodejs/test/e2e/agent_scoped_hooks.e2e.test.ts @@ -0,0 +1,69 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import { readFile, writeFile } from "node:fs/promises"; +import { join } from "node:path"; +import { describe, expect, it } from "vitest"; +import { approveAll } from "../../src/index.js"; +import { createSdkTestContext } from "./harness/sdkTestContext.js"; + +describe("Agent-scoped hooks", async () => { + const { copilotClient: client, workDir } = await createSdkTestContext(); + + it("runs scoped commands additively and follows selection without model requests", async () => { + const script = join(workDir, "scoped-hook.cjs"); + const log = join(workDir, "scoped-hook.log"); + await writeFile( + script, + `const fs = require("node:fs"); +const [log, label] = process.argv.slice(2); +fs.appendFileSync(log, label + "\\n"); +process.stdout.write(JSON.stringify({ handled: true, responseContent: label })); +` + ); + let sessionHookCalls = 0; + const scoped = (name: string) => ({ + name, + prompt: "No model request is necessary for this test.", + hooks: { + userPromptSubmitted: [ + { type: "command", exec: process.execPath, args: [script, log, name] }, + ], + }, + }); + const session = await client.createSession({ + onPermissionRequest: approveAll, + customAgents: [scoped("FIRST_SCOPE"), scoped("SECOND_SCOPE")], + hooks: { + onUserPromptSubmitted: () => { + sessionHookCalls++; + return { + additionalContext: "Session hook ran.", + handled: true, + responseContent: "SESSION_ONLY", + }; + }, + }, + }); + try { + const selected = await session.rpc.agent.select({ name: "FIRST_SCOPE" }); + expect(selected.agent.hooks).toBeDefined(); + expect((await session.sendAndWait({ prompt: "First request" }))?.data.content).toBe( + "FIRST_SCOPE" + ); + await session.rpc.agent.select({ name: "SECOND_SCOPE" }); + expect((await session.sendAndWait({ prompt: "Second request" }))?.data.content).toBe( + "SECOND_SCOPE" + ); + await session.rpc.agent.deselect(); + expect((await session.sendAndWait({ prompt: "Default request" }))?.data.content).toBe( + "SESSION_ONLY" + ); + expect(sessionHookCalls).toBe(3); + expect(await readFile(log, "utf8")).toBe("FIRST_SCOPE\nSECOND_SCOPE\n"); + } finally { + await session.disconnect(); + } + }); +}); diff --git a/nodejs/test/e2e/assisted_autopilot_permission.e2e.test.ts b/nodejs/test/e2e/assisted_autopilot_permission.e2e.test.ts index 5577d03761..37d6346089 100644 --- a/nodejs/test/e2e/assisted_autopilot_permission.e2e.test.ts +++ b/nodejs/test/e2e/assisted_autopilot_permission.e2e.test.ts @@ -8,7 +8,7 @@ import { mkdir, realpath, rm, writeFile } from "node:fs/promises"; import { createServer } from "node:http"; import { join } from "node:path"; import { text } from "node:stream/consumers"; -import { describe, expect, it, onTestFinished } from "vitest"; +import { describe, expect, it, onTestFailed, onTestFinished } from "vitest"; import { createAttributedPermissionResult, type CopilotSession, @@ -45,11 +45,38 @@ function contractFixtureName(scope: ContractScope, recommendation: ContractRecom describe("Assisted permission handling in Autopilot", async () => { const { copilotClient: client, workDir } = await createSdkTestContext({ useStdio: true }); - it("resolves Assisted recommendations before Autopilot permission recovery", async () => { + const scenarioGroups = ["routing", "updated authorization", "recovery"] as const; + it.each(scenarioGroups)("Assisted Autopilot permissions (%s)", async (group) => { let agentCalls = 0; const judgeOutputs: string[] = []; const authorizationJudgeRequests: string[] = []; const providerFailures: Error[] = []; + const progress = { + scenario: "fixture", + phase: "setup", + permissionCallbacks: 0, + permissionRequests: 0, + toolCompletions: 0, + taskCompletions: 0, + lastEventType: "none", + }; + const recordEvent = (type: string) => { + progress.lastEventType = type; + if (type === "permission.requested") progress.permissionRequests++; + if (type === "tool.execution_complete") progress.toolCompletions++; + if (type === "session.task_complete") progress.taskCompletions++; + }; + onTestFailed(() => { + console.error( + `[Assisted fixture progress] ${JSON.stringify({ + ...progress, + agentCalls, + judgeCalls: judgeOutputs.length, + authorizationJudgeCalls: authorizationJudgeRequests.length, + providerFailures: providerFailures.length, + })}` + ); + }); const outsideDir = `${workDir}-outside`; await mkdir(outsideDir, { recursive: true }); await writeFile(join(outsideDir, "approval-probe.txt"), "ASSISTED_READ_PROBE\n"); @@ -443,17 +470,22 @@ describe("Assisted permission handling in Autopilot", async () => { modelId: "gpt-4o", wireModel: id, })); - const scenarios = [ - { route: "shell", lifecycle: "create", decision: "judge" }, - { route: "path", lifecycle: "create", decision: "judge" }, - { route: "shell", lifecycle: "resume", decision: "judge" }, - { route: "path", lifecycle: "resume", decision: "judge" }, - { route: "human", lifecycle: "create", decision: "approve" }, - { route: "human", lifecycle: "create", decision: "deny" }, - { route: "human", lifecycle: "resume", decision: "approve" }, - { route: "human", lifecycle: "resume", decision: "deny" }, - ] as const; + const scenarios = + group === "routing" + ? ([ + { route: "shell", lifecycle: "create", decision: "judge" }, + { route: "path", lifecycle: "create", decision: "judge" }, + { route: "shell", lifecycle: "resume", decision: "judge" }, + { route: "path", lifecycle: "resume", decision: "judge" }, + { route: "human", lifecycle: "create", decision: "approve" }, + { route: "human", lifecycle: "create", decision: "deny" }, + { route: "human", lifecycle: "resume", decision: "approve" }, + { route: "human", lifecycle: "resume", decision: "deny" }, + ] as const) + : []; for (const scenario of scenarios) { + progress.scenario = `routing:${JSON.stringify(scenario)}`; + progress.phase = "create-session"; let permissionCallbacks = 0; const expectedRecommendation = scenario.decision === "judge" ? "approve" : "requireApproval"; @@ -484,6 +516,7 @@ describe("Assisted permission handling in Autopilot", async () => { ASSISTED_PERMISSIONS_V2: true, }, onPermissionRequest: async (request: PermissionRequest) => { + progress.permissionCallbacks++; permissionCallbacks++; if (!request.toolCallId) { throw new Error( @@ -530,19 +563,27 @@ describe("Assisted permission handling in Autopilot", async () => { session = await client.createSession(sessionConfig); if (scenario.lifecycle === "resume") { const sessionId = session.sessionId; + progress.phase = "prime-turn"; await session.sendAndWait({ prompt: "ASSISTED_SESSION_PRIME: Reply with prime-ready without tools.", }); + progress.phase = "configure-before-resume"; await configureAssistedAutopilot(session, workDir); + progress.phase = "verify-before-resume"; await expectAssistedAutopilotConfigured(session, workDir); + progress.phase = "disconnect-before-resume"; await session.disconnect(); session = undefined; + progress.phase = "resume-session"; session = await client.resumeSession(sessionId, sessionConfig); + progress.phase = "verify-after-resume"; await expectAssistedAutopilotConfigured(session, workDir); } else { + progress.phase = "configure-session"; await configureAssistedAutopilot(session, workDir); } session.on((event) => { + recordEvent(event.type); if (event.type === "permission.requested") { const promptRequest = ( event.data as { @@ -584,6 +625,7 @@ describe("Assisted permission handling in Autopilot", async () => { try { const taskComplete = getNextEventOfType(session, "session.task_complete"); + progress.phase = "send-turn"; await session.send({ prompt: scenario.route === "shell" @@ -592,11 +634,13 @@ describe("Assisted permission handling in Autopilot", async () => { ? `ASSISTED_PATH_ROUTE: Use only glob to find *.txt in ${outsideDir} and report the matching filename.` : `ASSISTED_HUMAN_${scenario.decision.toUpperCase()}_${scenario.lifecycle.toUpperCase()}_ROUTE: Try to create the human-reviewed fixture directory once and report human-${scenario.decision === "approve" ? "approved" : "denied"}.`, }); + progress.phase = "await-task-complete"; await taskComplete; } catch (error) { throw new Error(`${JSON.stringify(scenario)} failed`, { cause: error }); } + progress.phase = "assert-results"; const expectedCompletions = scenario.route === "path" && scenario.lifecycle === "create" ? 2 : 1; expect(permissionCallbacks, JSON.stringify(scenario)).toBe(expectedCompletions); @@ -646,138 +690,166 @@ describe("Assisted permission handling in Autopilot", async () => { } } finally { if (session) { + progress.phase = "abort-session"; await session.abort(); + progress.phase = "disconnect-session"; await session.disconnect(); } } } - expect(providerFailures).toEqual([]); - expect(judgeOutputs).toEqual([ - ...Array(4).fill(JUDGE_OUTPUT), - ...Array(4).fill(HUMAN_REVIEW_OUTPUT), - ]); - expect(agentCalls).toBe(scenarios.length * 2 + 4); + if (group === "routing") { + progress.phase = "assert-routing-totals"; + expect(providerFailures).toEqual([]); + expect(judgeOutputs).toEqual([ + ...Array(4).fill(JUDGE_OUTPUT), + ...Array(4).fill(HUMAN_REVIEW_OUTPUT), + ]); + expect(agentCalls).toBe(scenarios.length * 2 + 4); + progress.phase = "complete"; + return; + } - const authorizationJudgeStart = judgeOutputs.length; - let authorizationPermissionCallbacks = 0; - const authorizationRecommendations: string[] = []; - const authorizationDecisionSources: string[] = []; - const authorizationRecoveryStatuses: string[] = []; - const authorizationToolResults: Array<{ toolCallId?: string; success?: boolean }> = []; - const authorizationTaskOutcomes: Array<{ success?: boolean; summary?: string }> = []; - let resolveAuthorizationRecommendation: (recommendation: string | undefined) => void; - const authorizationRecommendation = new Promise((resolve) => { - resolveAuthorizationRecommendation = resolve; - }); - let authorizationSession: CopilotSession | undefined; - try { - authorizationSession = await client.createSession({ - model: "local/gpt-5.6-sol", - providers, - models, - availableTools: [SHELL_TOOL, "task_complete"], - streaming: false, - skipCustomInstructions: true, - featureFlags: { - AUTO_APPROVAL: true, - ASSISTED_PERMISSIONS_V2: true, - }, - onPermissionRequest: async (request) => { - authorizationPermissionCallbacks++; - if (request.toolCallId !== "assisted-authorization-shell") { - throw new Error( - `Expected authorization shell permission, got ${String( - request.toolCallId - )}` - ); - } - const recommendation = await authorizationRecommendation; - if (recommendation !== "approve") { - throw new Error( - `Expected later authorization to reach the judge as approve, got ${String( - recommendation - )}` - ); - } - return createAttributedPermissionResult( - { kind: "approve-once" }, - { - outcome: "auto_approved", - source: "assisted_approval", - surface: "sdk", - responseCapability: "headless", - } - ); - }, + if (group === "updated authorization") { + const authorizationJudgeStart = judgeOutputs.length; + let authorizationPermissionCallbacks = 0; + const authorizationRecommendations: string[] = []; + const authorizationDecisionSources: string[] = []; + const authorizationRecoveryStatuses: string[] = []; + const authorizationToolResults: Array<{ toolCallId?: string; success?: boolean }> = []; + const authorizationTaskOutcomes: Array<{ success?: boolean; summary?: string }> = []; + let resolveAuthorizationRecommendation: (recommendation: string | undefined) => void; + const authorizationRecommendation = new Promise((resolve) => { + resolveAuthorizationRecommendation = resolve; }); - await authorizationSession.sendAndWait({ - prompt: `${EARLIER_RESTRICTION_MARKER}: Do not create the authorization fixture. Reply restriction-recorded without tools.`, - }); - await configureAssistedAutopilot(authorizationSession, workDir); - authorizationSession.on((event) => { - if (event.type === "permission.requested") { - const recommendation = ( - event.data as { - promptRequest?: { - assistedApproval?: { recommendation?: string }; - }; + let authorizationSession: CopilotSession | undefined; + progress.scenario = "updated-authorization"; + progress.phase = "create-session"; + try { + authorizationSession = await client.createSession({ + model: "local/gpt-5.6-sol", + providers, + models, + availableTools: [SHELL_TOOL, "task_complete"], + streaming: false, + skipCustomInstructions: true, + featureFlags: { + AUTO_APPROVAL: true, + ASSISTED_PERMISSIONS_V2: true, + }, + onPermissionRequest: async (request) => { + progress.permissionCallbacks++; + authorizationPermissionCallbacks++; + if (request.toolCallId !== "assisted-authorization-shell") { + throw new Error( + `Expected authorization shell permission, got ${String( + request.toolCallId + )}` + ); + } + const recommendation = await authorizationRecommendation; + if (recommendation !== "approve") { + throw new Error( + `Expected later authorization to reach the judge as approve, got ${String( + recommendation + )}` + ); } - ).promptRequest?.assistedApproval?.recommendation; - if (recommendation) { - authorizationRecommendations.push(recommendation); + return createAttributedPermissionResult( + { kind: "approve-once" }, + { + outcome: "auto_approved", + source: "assisted_approval", + surface: "sdk", + responseCapability: "headless", + } + ); + }, + }); + progress.phase = "restriction-turn"; + await authorizationSession.sendAndWait({ + prompt: `${EARLIER_RESTRICTION_MARKER}: Do not create the authorization fixture. Reply restriction-recorded without tools.`, + }); + progress.phase = "configure-session"; + await configureAssistedAutopilot(authorizationSession, workDir); + authorizationSession.on((event) => { + recordEvent(event.type); + if (event.type === "permission.requested") { + const recommendation = ( + event.data as { + promptRequest?: { + assistedApproval?: { recommendation?: string }; + }; + } + ).promptRequest?.assistedApproval?.recommendation; + if (recommendation) { + authorizationRecommendations.push(recommendation); + } + resolveAuthorizationRecommendation(recommendation); + } else if (event.type === "permission.completed") { + const source = (event.data as { decisionSource?: string }).decisionSource; + if (source) authorizationDecisionSources.push(source); + } else if (event.type === "session.permission_recovery") { + authorizationRecoveryStatuses.push( + (event.data as { status: string }).status + ); + } else if (event.type === "tool.execution_complete") { + authorizationToolResults.push({ + toolCallId: event.data.toolCallId, + success: event.data.success, + }); + } else if (event.type === "session.task_complete") { + authorizationTaskOutcomes.push(event.data); } - resolveAuthorizationRecommendation(recommendation); - } else if (event.type === "permission.completed") { - const source = (event.data as { decisionSource?: string }).decisionSource; - if (source) authorizationDecisionSources.push(source); - } else if (event.type === "session.permission_recovery") { - authorizationRecoveryStatuses.push((event.data as { status: string }).status); - } else if (event.type === "tool.execution_complete") { - authorizationToolResults.push({ - toolCallId: event.data.toolCallId, - success: event.data.success, - }); - } else if (event.type === "session.task_complete") { - authorizationTaskOutcomes.push(event.data); - } - }); + }); - const taskComplete = getNextEventOfType(authorizationSession, "session.task_complete"); - await authorizationSession.send({ - prompt: `${LATER_AUTHORIZATION_MARKER}: The earlier restriction is superseded. Create the authorization fixture now and report authorization-updated.`, - }); - await taskComplete; + const taskComplete = getNextEventOfType( + authorizationSession, + "session.task_complete" + ); + progress.phase = "send-turn"; + await authorizationSession.send({ + prompt: `${LATER_AUTHORIZATION_MARKER}: The earlier restriction is superseded. Create the authorization fixture now and report authorization-updated.`, + }); + progress.phase = "await-task-complete"; + await taskComplete; - expect(judgeOutputs.slice(authorizationJudgeStart)).toEqual([JUDGE_OUTPUT]); - expect(authorizationJudgeRequests).toHaveLength(1); - const authorizationRequest = authorizationJudgeRequests[0] ?? ""; - expect(authorizationRequest.indexOf(EARLIER_RESTRICTION_MARKER)).toBeGreaterThanOrEqual( - 0 - ); - expect(authorizationRequest.indexOf(LATER_AUTHORIZATION_MARKER)).toBeGreaterThan( - authorizationRequest.indexOf(EARLIER_RESTRICTION_MARKER) - ); - expect(authorizationPermissionCallbacks).toBe(1); - expect(authorizationRecommendations).toEqual(["approve"]); - expect(authorizationDecisionSources).toEqual(["assisted_approval"]); - expect(authorizationRecoveryStatuses).toEqual([]); - expect(authorizationToolResults).toContainEqual({ - toolCallId: "assisted-authorization-shell", - success: true, - }); - expect(authorizationTaskOutcomes).toEqual([ - expect.objectContaining({ + progress.phase = "assert-results"; + expect(judgeOutputs.slice(authorizationJudgeStart)).toEqual([JUDGE_OUTPUT]); + expect(authorizationJudgeRequests).toHaveLength(1); + const authorizationRequest = authorizationJudgeRequests[0] ?? ""; + expect( + authorizationRequest.indexOf(EARLIER_RESTRICTION_MARKER) + ).toBeGreaterThanOrEqual(0); + expect(authorizationRequest.indexOf(LATER_AUTHORIZATION_MARKER)).toBeGreaterThan( + authorizationRequest.indexOf(EARLIER_RESTRICTION_MARKER) + ); + expect(authorizationPermissionCallbacks).toBe(1); + expect(authorizationRecommendations).toEqual(["approve"]); + expect(authorizationDecisionSources).toEqual(["assisted_approval"]); + expect(authorizationRecoveryStatuses).toEqual([]); + expect(authorizationToolResults).toContainEqual({ + toolCallId: "assisted-authorization-shell", success: true, - summary: "authorization-updated", - }), - ]); - expect(existsSync(join(workDir, AUTHORIZATION_FIXTURE))).toBe(true); - } finally { - if (authorizationSession) { - await authorizationSession.abort(); - await authorizationSession.disconnect(); + }); + expect(authorizationTaskOutcomes).toEqual([ + expect.objectContaining({ + success: true, + summary: "authorization-updated", + }), + ]); + expect(existsSync(join(workDir, AUTHORIZATION_FIXTURE))).toBe(true); + } finally { + if (authorizationSession) { + progress.phase = "abort-session"; + await authorizationSession.abort(); + progress.phase = "disconnect-session"; + await authorizationSession.disconnect(); + } } + expect(providerFailures).toEqual([]); + progress.phase = "complete"; + return; } const contractScenarios = [ @@ -794,6 +866,8 @@ describe("Assisted permission handling in Autopilot", async () => { }[]; const contractJudgeStart = judgeOutputs.length; for (const scenario of contractScenarios) { + progress.scenario = `recovery:${JSON.stringify(scenario)}`; + progress.phase = "create-session"; let permissionCallbacks = 0; const recommendations: string[] = []; const recoveryStatuses: string[] = []; @@ -810,6 +884,7 @@ describe("Assisted permission handling in Autopilot", async () => { }> = []; const taskOutcomes: Array<{ success?: boolean; summary?: string }> = []; const onPermissionRequest = () => { + progress.permissionCallbacks++; permissionCallbacks++; sequence.push("host"); if (scenario.recommendation === "approve") { @@ -866,8 +941,10 @@ describe("Assisted permission handling in Autopilot", async () => { let session: CopilotSession | undefined; try { session = await client.createSession(sessionConfig); + progress.phase = "configure-session"; await configureAssistedAutopilot(session, workDir); session.on((event) => { + recordEvent(event.type); if (event.type === "permission.requested") { const promptRequest = ( event.data as { @@ -914,12 +991,15 @@ describe("Assisted permission handling in Autopilot", async () => { : `ASSISTED_CONTRACT_SUBAGENT_${marker}: Use the task tool once so a task subagent runs the requested shell command.`; try { const taskComplete = getNextEventOfType(session, "session.task_complete"); + progress.phase = "send-turn"; await session.send({ prompt }); + progress.phase = "await-task-complete"; await taskComplete; } catch (error) { throw new Error(`${JSON.stringify(scenario)} failed`, { cause: error }); } + progress.phase = "assert-results"; if (scenario.handler === "none") { expect(permissionCallbacks, JSON.stringify(scenario)).toBe(0); expect(recommendations, JSON.stringify(scenario)).toEqual([]); @@ -1002,6 +1082,7 @@ describe("Assisted permission handling in Autopilot", async () => { ), JSON.stringify(scenario) ).toBe(scenario.recommendation === "approve" && scenario.handler === "registered"); + progress.phase = "read-pending-requests"; expect( (await session.rpc.permissions.pendingRequests()).items, JSON.stringify(scenario) @@ -1018,12 +1099,15 @@ describe("Assisted permission handling in Autopilot", async () => { } } finally { if (session) { + progress.phase = "abort-session"; await session.abort(); + progress.phase = "disconnect-session"; await session.disconnect(); } } } + progress.phase = "assert-recovery-totals"; expect(providerFailures).toEqual([]); expect(judgeOutputs.slice(contractJudgeStart)).toEqual([ JUDGE_OUTPUT, @@ -1032,6 +1116,7 @@ describe("Assisted permission handling in Autopilot", async () => { HUMAN_REVIEW_OUTPUT, HUMAN_REVIEW_OUTPUT, ]); + progress.phase = "complete"; }); }); diff --git a/nodejs/test/e2e/commands.e2e.test.ts b/nodejs/test/e2e/commands.e2e.test.ts index 0a4327370e..9cd17759ff 100644 --- a/nodejs/test/e2e/commands.e2e.test.ts +++ b/nodejs/test/e2e/commands.e2e.test.ts @@ -2,7 +2,10 @@ * Copyright (c) Microsoft Corporation. All rights reserved. *--------------------------------------------------------------------------------------------*/ -import { afterAll, describe, expect, it } from "vitest"; +import { randomUUID } from "node:crypto"; +import { writeFile } from "node:fs/promises"; +import { join } from "node:path"; +import { afterAll, describe, expect, it, onTestFinished } from "vitest"; import { CopilotClient, approveAll, RuntimeConnection } from "../../src/index.js"; import type { CommandContext, SessionEvent } from "../../src/index.js"; import { createSdkTestContext } from "./harness/sdkTestContext.js"; @@ -273,6 +276,82 @@ describe("Commands", async () => { }); }); +describe("Usage command after restart", async () => { + // Custom-provider sessions bypass the server's Copilot billing account. + const { createClient, openAiEndpoint, env } = await createSdkTestContext({ + backend: "capi", + }); + + it.each([ + { + status: "partial", + totalNanoAiu: 23_275_500_000, + expected: "Requests: 23.28 AI Credits reported (partial)", + }, + { + status: "unavailable", + totalNanoAiu: 0, + expected: "Requests: unavailable AI Credits", + }, + ])("reports $status checkpoint AI credits", async ({ status, totalNanoAiu, expected }) => { + const token = `usage-command-checkpoint-token-${randomUUID()}`; + await openAiEndpoint.setCopilotUserByToken(token, { + login: "usage-command-user", + copilot_plan: "individual_pro", + token_based_billing: true, + endpoints: { api: openAiEndpoint.url }, + }); + const originalClient = createClient({ + connection: RuntimeConnection.forStdio(), + gitHubToken: token, + }); + onTestFinished(async () => { + expect(await originalClient.stop()).toHaveLength(0); + }); + const original = await originalClient.createSession({ + onPermissionRequest: approveAll, + }); + await original.rpc.name.set({ name: "Usage checkpoint fixture" }); + const events = await original.getEvents(); + const checkpoint: SessionEvent = { + type: "session.usage_checkpoint", + id: randomUUID(), + timestamp: new Date().toISOString(), + parentId: events.at(-1)?.id ?? null, + data: { totalNanoAiu, totalPremiumRequests: 1 }, + }; + await originalClient.rpc.sessions.save({ sessionId: original.sessionId }); + await originalClient.rpc.sessions.close({ sessionId: original.sessionId }); + expect(await originalClient.stop()).toHaveLength(0); + + // Seed durable accounting only after the session writer has stopped. + await writeFile( + join(env.COPILOT_HOME, "session-state", original.sessionId, "events.jsonl"), + `${[...events, checkpoint].map((event) => JSON.stringify(event)).join("\n")}\n` + ); + const resumedClient = createClient({ + connection: RuntimeConnection.forStdio(), + gitHubToken: token, + }); + onTestFinished(async () => { + expect(await resumedClient.stop()).toHaveLength(0); + }); + const resumed = await resumedClient.resumeSession(original.sessionId, { + onPermissionRequest: approveAll, + }); + expect(await resumed.rpc.usage.getMetrics()).toMatchObject({ + totalNanoAiu: checkpoint.data.totalNanoAiu, + totalPremiumRequestCost: checkpoint.data.totalPremiumRequests, + aiCreditsStatus: status, + }); + const result = await resumed.rpc.commands.invoke({ name: "usage" }); + expect(result.kind).toBe("text"); + if (result.kind !== "text") throw new Error(`Unexpected usage result: ${result.kind}`); + expect(result.text).toContain(expected); + expect(result.text).not.toContain("1 AI Units"); + }); +}); + function isCommand(command: { name: string; kind: string }, name: string, kind: string): boolean { return command.name.toLowerCase() === name.toLowerCase() && command.kind === kind; } diff --git a/nodejs/test/e2e/compaction.e2e.test.ts b/nodejs/test/e2e/compaction.e2e.test.ts index fa9cc328fe..f42e515cdf 100644 --- a/nodejs/test/e2e/compaction.e2e.test.ts +++ b/nodejs/test/e2e/compaction.e2e.test.ts @@ -15,6 +15,7 @@ import { } from "../../src/index.js"; import { createSdkTestContext, isCI } from "./harness/sdkTestContext.js"; import { testBackend } from "./harness/testBackend.js"; +import { withTestCleanup } from "../helpers/withTestCleanup.js"; const compactionTimeoutMs = 60_000; @@ -22,6 +23,7 @@ interface CacheWireBlock { text?: string; cache_control?: unknown; copilot_cache_control?: unknown; + output_config?: { effort?: string }; } interface CacheWireRequest extends CacheWireBlock { @@ -661,6 +663,300 @@ class BudgetReplayHandler extends CopilotRequestHandler { } } +interface CompactionEffortRequest { + model: string; + stream?: boolean; + reasoning?: { effort?: string }; + input: Array<{ type?: string; role?: string; reasoning?: { effort?: string } }>; +} + +class CompactionEffortReplayHandler extends CopilotRequestHandler { + readonly requests: CompactionEffortRequest[] = []; + summaryGate?: { + entered: ReturnType>; + release: ReturnType>; + }; + + protected override async sendRequest(request: Request): Promise { + expect(new URL(request.url).pathname).toBe("/responses"); + const body = (await request.json()) as CompactionEffortRequest; + this.requests.push(body); + expect(body.stream).not.toBe(true); + const incompleteSummary = this.requests.length === 2 && this.summaryGate; + if (incompleteSummary) { + incompleteSummary.entered.resolve(); + await incompleteSummary.release.promise; + } + return Response.json({ + id: "compaction-effort-response", + object: "response", + model: body.model, + status: incompleteSummary ? "incomplete" : "completed", + ...(incompleteSummary ? { incomplete_details: { reason: "max_output_tokens" } } : {}), + output: [ + { + id: "compaction-effort-message", + type: "message", + role: "assistant", + status: "completed", + content: [ + { + type: "output_text", + text: incompleteSummary ? "SUMMARY_PART_ONE" : "COMPACTION_EFFORT_OK", + }, + ], + }, + ], + usage: { input_tokens: 100, output_tokens: 10, total_tokens: 110 }, + }); + } +} + +describe("Compaction reasoning effort", async () => { + const { createClient } = await createSdkTestContext({ replayOnly: true }); + + it("reduces only the OpenAI summary request and retains the session effort", async () => { + const handler = new CompactionEffortReplayHandler(); + const effortClient = createClient({ requestHandler: handler }); + try { + await using session = await effortClient.createSession({ + onPermissionRequest: approveAll, + model: "gpt-6-sol", + reasoningEffort: "max", + provider: { + type: "openai", + wireApi: "responses", + baseUrl: "https://compaction-effort.invalid", + apiKey: "fake-byok-credential-for-e2e-tests", + modelId: "gpt-6-sol", + }, + streaming: false, + featureFlags: { COMPACTION_MEDIUM_REASONING_EFFORT: true }, + expAssignments: { + Features: [], + Flights: {}, + Configs: [], + AssignmentContext: "compaction-medium-effort", + }, + infiniteSessions: { enabled: false }, + }); + expect( + (await session.sendAndWait({ prompt: "Initialize the effort scenario." }))?.data + .content + ).toBe("COMPACTION_EFFORT_OK"); + expect(handler.requests).toHaveLength(1); + expect(handler.requests[0].reasoning?.effort).toBe("max"); + + const compacted = await session.rpc.history.compact({ trigger: "manual" }); + expect(compacted).toMatchObject({ + success: true, + summaryContent: "COMPACTION_EFFORT_OK", + }); + expect(handler.requests).toHaveLength(2); + const summaryRequest = handler.requests[1]; + expect(summaryRequest.reasoning?.effort).toBe("max"); + expect( + summaryRequest.input.filter((item) => item.type === "configuration_update") + ).toEqual([{ type: "configuration_update", reasoning: { effort: "medium" } }]); + expect(summaryRequest.input.at(-2)?.reasoning?.effort).toBe("medium"); + expect((await session.rpc.model.getCurrent()).reasoningEffort).toBe("max"); + + expect( + (await session.sendAndWait({ prompt: "Continue after the summary." }))?.data.content + ).toBe("COMPACTION_EFFORT_OK"); + expect(handler.requests).toHaveLength(3); + const nextRequest = handler.requests[2]; + expect(nextRequest.reasoning?.effort).toBe("max"); + expect( + nextRequest.input.filter((item) => item.type === "configuration_update") + ).toEqual([]); + } finally { + await effortClient.stop(); + } + }); + + it("preserves Anthropic compaction effort even when the reduction is enabled", async () => { + const handler = new RefusalBudgetReplayHandler(); + const effortClient = createClient({ requestHandler: handler }); + try { + await using session = await effortClient.createSession({ + onPermissionRequest: approveAll, + model: "claude-opus-5.5", + reasoningEffort: "max", + provider: { + type: "anthropic", + baseUrl: "https://compaction-effort.invalid", + bearerToken: "fake-byok-credential-for-e2e-tests", + modelId: "claude-opus-5.5", + }, + featureFlags: { COMPACTION_MEDIUM_REASONING_EFFORT: true }, + expAssignments: { + Features: [], + Flights: {}, + Configs: [], + AssignmentContext: "compaction-medium-effort", + }, + infiniteSessions: { enabled: false }, + }); + expect( + (await session.sendAndWait({ prompt: "Initialize the effort scenario." }))?.data + .content + ).toBe("FALLBACK_BUDGET_OK"); + expect(handler.requests).toHaveLength(1); + expect(handler.requests[0].output_config?.effort).toBe("max"); + + const compacted = await session.rpc.history.compact({ trigger: "manual" }); + expect(compacted).toMatchObject({ + success: true, + summaryContent: "FALLBACK_BUDGET_OK", + }); + expect(handler.requests).toHaveLength(2); + const summaryRequest = handler.requests[1]; + expect(summaryRequest.output_config?.effort).toBe("max"); + expect( + summaryRequest.messages.flatMap((message) => + message.output_config?.effort ? [message.output_config.effort] : [] + ) + ).toEqual([]); + expect((await session.rpc.model.getCurrent()).reasoningEffort).toBe("max"); + + expect( + (await session.sendAndWait({ prompt: "Continue after the summary." }))?.data.content + ).toBe("FALLBACK_BUDGET_OK"); + expect(handler.requests).toHaveLength(3); + const nextRequest = handler.requests[2]; + expect(nextRequest.output_config?.effort).toBe("max"); + expect(nextRequest.messages.filter((message) => message.output_config)).toEqual([]); + } finally { + await effortClient.stop(); + } + }); + + it("isolates compaction effort from concurrent sampling and selected effort changes", async ({ + expect, + onTestFinished, + }) => { + const handler = new CompactionEffortReplayHandler(); + const gate = { + entered: Promise.withResolvers(), + release: Promise.withResolvers(), + }; + handler.summaryGate = gate; + const effortClient = createClient({ requestHandler: handler }); + const stopClient = async () => { + gate.release.resolve(); + const errors = await effortClient.stop(); + if (errors.length) { + throw new AggregateError(errors, "Failed to stop compaction overlap client"); + } + }; + onTestFinished(stopClient); + await withTestCleanup(async () => { + const session = await effortClient.createSession({ + onPermissionRequest: approveAll, + model: "gpt-6-sol", + reasoningEffort: "max", + provider: { + type: "openai", + wireApi: "responses", + baseUrl: "https://compaction-effort.invalid", + apiKey: "fake-byok-credential-for-e2e-tests", + modelId: "gpt-6-sol", + }, + streaming: false, + featureFlags: { COMPACTION_MEDIUM_REASONING_EFFORT: true }, + expAssignments: { + Features: [], + Flights: {}, + Configs: [], + AssignmentContext: "compaction-overlap", + }, + infiniteSessions: { enabled: false }, + }); + expect( + (await session.sendAndWait({ prompt: "Initialize the overlap scenario." }))?.data + .content + ).toBe("COMPACTION_EFFORT_OK"); + const compaction = session.rpc.history.compact({ trigger: "manual" }); + await withTestCleanup( + async () => { + await Promise.race([ + gate.entered.promise, + compaction.then((result) => { + throw new Error( + `Compaction completed before its summary gate: ${JSON.stringify(result)}` + ); + }), + ]); + expect(handler.requests).toHaveLength(2); + expect(handler.requests[1].input.at(-2)?.reasoning?.effort).toBe("medium"); + expect((await session.rpc.model.getCurrent()).reasoningEffort).toBe("max"); + + expect( + await session.rpc.mcp.executeSampling({ + requestId: "compaction-overlap-sampling", + serverName: "compaction-overlap-server", + mcpRequestId: "compaction-overlap-mcp", + request: { + messages: [ + { + role: "user", + content: { + type: "text", + text: "Compute a sampling result.", + }, + }, + ], + maxTokens: 4096, + }, + }) + ).toMatchObject({ + action: "success", + result: { content: { type: "text", text: "COMPACTION_EFFORT_OK" } }, + }); + expect(handler.requests).toHaveLength(3); + expect(handler.requests[2].reasoning?.effort).toBe("max"); + expect( + handler.requests[2].input.filter( + (item) => item.type === "configuration_update" + ) + ).toEqual([]); + + await session.rpc.model.setReasoningEffort({ reasoningEffort: "high" }); + expect((await session.rpc.model.getCurrent()).reasoningEffort).toBe("high"); + }, + () => gate.release.resolve(), + async () => { + expect(await compaction).toMatchObject({ + success: true, + summaryContent: expect.stringContaining("COMPACTION_EFFORT_OK"), + }); + } + ); + expect(handler.requests).toHaveLength(4); + const continuation = handler.requests[3]; + expect(continuation.reasoning?.effort).toBe("max"); + expect( + continuation.input.filter((item) => item.type === "configuration_update") + ).toEqual([{ type: "configuration_update", reasoning: { effort: "medium" } }]); + expect((await session.rpc.model.getCurrent()).reasoningEffort).toBe("high"); + expect( + (await session.sendAndWait({ prompt: "Continue after the held summary." }))?.data + .content + ).toBe("COMPACTION_EFFORT_OK"); + expect(handler.requests).toHaveLength(5); + // The cache baseline stays pinned; the durable user boundary selects high. + expect(handler.requests[4].reasoning?.effort).toBe("max"); + expect( + handler.requests[4].input.filter((item) => item.type === "configuration_update") + ).toEqual([{ type: "configuration_update", reasoning: { effort: "high" } }]); + expect(handler.requests[4].input.at(-2)?.reasoning?.effort).toBe("high"); + expect((await session.rpc.model.getCurrent()).reasoningEffort).toBe("high"); + await session.disconnect(); + }, stopClient); + }); +}); + describe("Refusal fallback output budget", async () => { const { createClient } = await createSdkTestContext(); diff --git a/nodejs/test/e2e/copilot_request_handler.e2e.test.ts b/nodejs/test/e2e/copilot_request_handler.e2e.test.ts index af79d84ae3..6faaf40a32 100644 --- a/nodejs/test/e2e/copilot_request_handler.e2e.test.ts +++ b/nodejs/test/e2e/copilot_request_handler.e2e.test.ts @@ -4,6 +4,8 @@ import { createServer, IncomingMessage, Server as HttpServer, ServerResponse } from "http"; import { AddressInfo } from "net"; +import { writeFile } from "node:fs/promises"; +import { join } from "node:path"; import { afterAll, describe, expect, it } from "vitest"; import { WebSocketServer } from "ws"; import { @@ -12,9 +14,11 @@ import { CopilotWebSocketForwarder, defineTool, type CopilotRequestContext, + type SessionConfig, } from "../../src/index.js"; import { createSdkTestContext } from "./harness/sdkTestContext.js"; import { waitForCondition } from "./harness/sdkTestHelper.js"; +import { mcpTestServerConfig } from "./harness/mcpTestServer.js"; const HTTP_TEXT = "OK from synthetic HTTP upstream."; const WS_TEXT = "OK from synthetic WS upstream."; @@ -36,11 +40,13 @@ async function startFakeUpstream(): Promise<{ wsRequestCount: () => number; wsBodies: () => Array>; httpBodies: () => Array>; + chatBodies: () => Array>; close: () => Promise; }> { let wsRequests = 0; const wsBodies: Array> = []; const httpBodies: Array> = []; + const chatBodies: Array> = []; const httpServer = createServer((req, res) => { const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`); @@ -72,6 +78,20 @@ async function startFakeUpstream(): Promise<{ }, }, }, + { + id: "gpt-5.5", + name: "GPT-5.5", + vendor: "OpenAI", + model_picker_enabled: true, + supported_endpoints: ["/chat/completions"], + capabilities: { + type: "chat", + family: "gpt-5.5", + tokenizer: "o200k_base", + limits: { max_context_window_tokens: 200000, max_output_tokens: 8192 }, + supports: { streaming: true, tool_calls: true }, + }, + }, { id: "gpt-6-sol", name: "GPT-6 Sol", @@ -108,12 +128,73 @@ async function startFakeUpstream(): Promise<{ sendJson(res, 200, { state: "enabled" }); return; } + if (url.pathname.endsWith("/chat/completions") && req.method === "POST") { + drainBody(req) + .then((raw) => { + const body = JSON.parse(raw.toString()) as Record; + chatBodies.push(body); + const serialized = JSON.stringify(body.messages); + const toolResult = (body.messages as Array<{ role: string }>).some( + (message) => message.role === "tool" + ); + const call = + serialized.includes("SDK_CHAT_RESTORED") && + !serialized.includes("SDK_CHAT_EXECUTED_RESULT"); + const removedCall = serialized.includes("SDK_CHAT_REMOVED") && !toolResult; + const message = + call || removedCall + ? { + role: "assistant", + content: null, + tool_calls: [ + { + index: 0, + id: "chat_call", + type: "function", + function: { name: "sdk_chat_removed", arguments: "{}" }, + }, + ], + } + : { + role: "assistant", + content: serialized.includes("SDK_CHAT_RESTORED") + ? "SDK_CHAT_RESTORED_OK" + : serialized.includes("SDK_CHAT_REMOVED") + ? "SDK_CHAT_REMOVED_OK" + : "SDK_CHAT_FIRST_OK", + }; + const finishReason = call || removedCall ? "tool_calls" : "stop"; + if (body.stream !== true) { + sendJson(res, 200, { + id: "chat_response", + choices: [{ index: 0, message, finish_reason: finishReason }], + usage: { prompt_tokens: 5, completion_tokens: 7 }, + }); + return; + } + res.writeHead(200, { "content-type": "text/event-stream" }); + res.write( + `data: ${JSON.stringify({ id: "chat_response", choices: [{ index: 0, delta: message, finish_reason: null }] })}\n\n` + ); + res.end( + `data: ${JSON.stringify({ id: "chat_response", choices: [{ index: 0, delta: {}, finish_reason: finishReason }] })}\n\ndata: [DONE]\n\n` + ); + }) + .catch((error: unknown) => { + sendJson(res, 500, { error: String(error) }); + }); + return; + } if (url.pathname.endsWith("/responses") && req.method === "POST") { drainBody(req) .then((raw) => { const body = JSON.parse(raw.toString()) as Record; httpBodies.push(body); - const events = buildResponsesEvents(HTTP_TEXT, "resp_stub_http"); + const events = toolUpdateEvents(body, "resp_stub_http", HTTP_TEXT); + if (events[0]?.type === "error") { + sendJson(res, 422, { error: events[0].error }); + return; + } if (body.stream !== true) { sendJson(res, 200, events.at(-1)!.response); return; @@ -143,69 +224,8 @@ async function startFakeUpstream(): Promise<{ wsRequests++; const body = JSON.parse(raw.toString()) as Record; wsBodies.push(body); - const input = JSON.stringify(body.input); const id = `resp_stub_ws_${wsRequests}`; - const positionedUpdate = - Array.isArray(body.input) && - body.input.some((item: { type?: string }) => item.type === "additional_tools"); - const rejection = { - type: "error", - error: { - code: "bad_request", - type: "websocket_error", - message: "additional_tools rejected", - }, - }; - const restricted = - (body.tool_choice as { type?: string } | undefined)?.type === "allowed_tools"; - let events: Array>; - if (restricted && input.includes("SDK_ALLOWLIST_REJECT_BEFORE")) { - events = [ - { - ...rejection, - error: { - ...rejection.error, - code: "invalid_request_body", - message: "allowed_tools rejected", - }, - }, - ]; - } else if (restricted && input.includes("SDK_ALLOWLIST_REJECT_AFTER")) { - events = [ - ...buildResponsesEvents("already streamed", id).slice(0, 4), - { - ...rejection, - error: { - ...rejection.error, - code: "invalid_request_body", - message: "allowed_tools rejected", - }, - }, - ]; - } else if (input.includes("SDK_REMOVAL_RESTORED")) { - events = buildResponsesEvents("SDK_REMOVAL_RESTORED_OK", id); - } else if (input.includes("SDK_ALLOWLIST_REJECT_BEFORE")) { - events = buildResponsesEvents("SDK_ALLOWLIST_RECOVERED", id); - } else if (positionedUpdate && input.includes("SDK_RESPONSES_REJECT_BEFORE")) { - events = [rejection]; - } else if (positionedUpdate && input.includes("SDK_RESPONSES_REJECT_AFTER")) { - events = [...buildResponsesEvents("already streamed", id).slice(0, 4), rejection]; - } else if (input.includes("SDK_RESPONSES_LEGACY_FOLLOW_UP")) { - events = buildResponsesEvents("SDK_RESPONSES_LEGACY_OK", id); - } else if (input.includes("SDK_RESPONSES_REJECT_BEFORE")) { - events = buildResponsesEvents("SDK_RESPONSES_RECOVERED", id); - } else if ( - input.includes("SDK_RESPONSES_AFTER") && - !input.includes("SDK_ADDED_TOOL_RESULT") - ) { - events = buildFunctionCallEvents(id); - } else { - events = buildResponsesEvents( - input.includes("SDK_ADDED_TOOL_RESULT") ? "SDK_RESPONSES_TOOL_OK" : WS_TEXT, - id - ); - } - for (const event of events) { + for (const event of toolUpdateEvents(body, id, WS_TEXT)) { socket.send(JSON.stringify(event)); } }); @@ -221,6 +241,7 @@ async function startFakeUpstream(): Promise<{ wsRequestCount: () => wsRequests, wsBodies: () => [...wsBodies], httpBodies: () => [...httpBodies], + chatBodies: () => [...chatBodies], async close() { wss.clients.forEach((c) => c.terminate()); await new Promise((resolve) => wss.close(() => resolve())); @@ -229,13 +250,107 @@ async function startFakeUpstream(): Promise<{ }; } -function buildFunctionCallEvents(id: string): Array> { +function toolUpdateEvents( + body: Record, + id: string, + defaultText: string +): Array> { + const input = JSON.stringify(body.input); + const positionedUpdate = + Array.isArray(body.input) && + body.input.some((item: { type?: string }) => item.type === "additional_tools"); + const rejection = { + type: "error", + error: { + code: "bad_request", + type: "websocket_error", + message: "additional_tools rejected", + }, + }; + const restricted = + (body.tool_choice as { type?: string } | undefined)?.type === "allowed_tools"; + if (positionedUpdate && input.includes("SDK_RESPONSES_REJECT_GENERIC")) { + return [{ type: "error", error: { message: "invalid request" } }]; + } + if (restricted && input.includes("SDK_ALLOWLIST_REJECT_BEFORE")) { + return [ + { + ...rejection, + error: { + ...rejection.error, + code: "invalid_request_body", + message: "allowed_tools rejected", + }, + }, + ]; + } + if (restricted && input.includes("SDK_ALLOWLIST_REJECT_AFTER")) { + return [ + ...buildResponsesEvents("already streamed", id).slice(0, 4), + { + ...rejection, + error: { + ...rejection.error, + code: "invalid_request_body", + message: "allowed_tools rejected", + }, + }, + ]; + } + if (input.includes("SDK_REMOVAL_RESTORED")) { + return buildResponsesEvents("SDK_REMOVAL_RESTORED_OK", id); + } + if (input.includes("SDK_REMOVAL_ALL")) { + return buildResponsesEvents(defaultText, id); + } + if (input.includes("SDK_ALLOWLIST_REJECT_BEFORE")) { + return buildResponsesEvents("SDK_ALLOWLIST_RECOVERED", id); + } + if (positionedUpdate && input.includes("SDK_RESPONSES_REJECT_BEFORE")) { + return [rejection]; + } + if (positionedUpdate && input.includes("SDK_RESPONSES_REJECT_AFTER")) { + return [...buildResponsesEvents("already streamed", id).slice(0, 4), rejection]; + } + if (input.includes("SDK_RESPONSES_LEGACY_FOLLOW_UP")) { + return buildResponsesEvents("SDK_RESPONSES_LEGACY_OK", id); + } + if (input.includes("SDK_RESPONSES_REJECT_BEFORE")) { + return buildResponsesEvents("SDK_RESPONSES_RECOVERED", id); + } + if (input.includes("MCP_RESPONSES_REMOVED_AGAIN")) { + return buildResponsesEvents("MCP_RESPONSES_REMOVED_OK", id); + } + if (input.includes("MCP_RESPONSES_AFTER") && !input.includes("MCP_ADDED_TOOL_RESULT")) { + return buildFunctionCallEvents( + id, + "a_server-get_env", + JSON.stringify({ name: "CACHE_TEST_RESULT" }) + ); + } + if (input.includes("MCP_ADDED_TOOL_RESULT")) { + return buildResponsesEvents("MCP_RESPONSES_TOOL_OK", id); + } + if (input.includes("SDK_RESPONSES_AFTER") && !input.includes("SDK_ADDED_TOOL_RESULT")) { + return buildFunctionCallEvents(id); + } + return buildResponsesEvents( + input.includes("SDK_ADDED_TOOL_RESULT") ? "SDK_RESPONSES_TOOL_OK" : defaultText, + id + ); +} + +function buildFunctionCallEvents( + id: string, + name = "sdk_epoch_added", + args = "{}" +): Array> { const call = { type: "function_call", id: "fc_sdk_added", call_id: "call_sdk_added", - name: "sdk_epoch_added", - arguments: "{}", + name, + arguments: args, status: "completed", }; return [ @@ -333,7 +448,8 @@ interface Counters { class TestHandler extends CopilotRequestHandler { constructor( private readonly upstreamUrl: string, - private readonly counters: Counters + private readonly counters: Counters, + private readonly failWebSocket = false ) { super(); } @@ -384,6 +500,9 @@ class TestHandler extends CopilotRequestHandler { protected override async openWebSocket( ctx: CopilotRequestContext ): Promise { + if (this.failWebSocket) { + throw new Error("Synthetic WebSocket handshake refused"); + } ctx.url = this.rewriteWsUrl(ctx.url); return new CountingSocketForwarder(ctx, this.counters); } @@ -417,7 +536,11 @@ describe("CopilotRequestHandler — single subclass handles HTTP + WebSocket", a wsResponseMessages: 0, }; - const { copilotClient: client, env } = await createSdkTestContext({ + const { + copilotClient: client, + env, + workDir, + } = await createSdkTestContext({ copilotClientOptions: { requestHandler: new TestHandler(upstream.url, counters), }, @@ -551,6 +674,470 @@ describe("CopilotRequestHandler — single subclass handles HTTP + WebSocket", a } }, 90_000); + const routes: Array<{ + name: string; + config: Partial; + bodies: () => Array>; + firstText: string; + }> = [ + { + name: "CAPI WebSocket", + config: { capi: { enableWebSocketResponses: true } }, + bodies: upstream.wsBodies, + firstText: WS_TEXT, + }, + { + name: "CAPI HTTP", + config: { capi: { enableWebSocketResponses: false } }, + bodies: upstream.httpBodies, + firstText: HTTP_TEXT, + }, + ...(["http", "websockets"] as const).map((transport) => ({ + name: `BYOK ${transport}`, + config: { + provider: { + type: "openai" as const, + wireApi: "responses" as const, + transport, + baseUrl: upstream.url, + apiKey: "synthetic-provider-key", + modelId: "gpt-6-sol", + wireModel: "gpt-6-sol", + }, + }, + bodies: transport === "http" ? upstream.httpBodies : upstream.wsBodies, + firstText: transport === "http" ? HTTP_TEXT : WS_TEXT, + })), + ]; + for (const route of routes) { + describe(route.name, async () => { + const routeClient = + route.config.capi?.enableWebSocketResponses === false + ? ( + await createSdkTestContext({ + copilotClientOptions: { + requestHandler: new TestHandler(upstream.url, counters), + // This runtime does not yet wire the session-level CAPI transport opt-out. + env: { COPILOT_CLI_DISABLE_WEBSOCKET_RESPONSES: "true" }, + }, + }) + ).copilotClient + : client; + it(`${route.config.provider ? "sends current tools" : "preserves the prefix"} on ${route.name} and executes a tool from a newly enabled MCP server`, async () => { + const config = mcpTestServerConfig("MCP_ADDED_TOOL_RESULT"); + await routeClient.start(); + const beforeRequests = route.bodies().length; + const session = await routeClient.createSession({ + model: "gpt-6-sol", + onPermissionRequest: approveAll, + ...route.config, + toolSearch: { enabled: false }, + mcpServers: { z_server: config, a_server: config }, + disabledMcpServers: ["a_server"], + }); + try { + await session.rpc.tools.initializeAndValidate(); + expect( + (await session.rpc.tools.getCurrentMetadata()).tools.map( + (tool) => tool.name + ) + ).toContain("z_server-get_env"); + expect( + (await session.rpc.tools.getCurrentMetadata()).tools.map( + (tool) => tool.name + ) + ).not.toContain("a_server-get_env"); + const first = await session.sendAndWait({ prompt: "MCP_RESPONSES_FIRST" }); + expect(first?.data.content).toContain(route.firstText); + + await session.rpc.mcp.setEnvValueMode({ mode: "direct" }); + await session.rpc.mcp.enable({ serverName: "a_server" }); + await session.rpc.tools.initializeAndValidate(); + expect( + (await session.rpc.tools.getCurrentMetadata()).tools.map( + (tool) => tool.name + ) + ).toContain("a_server-get_env"); + const second = await session.sendAndWait({ + prompt: "MCP_RESPONSES_AFTER: call a_server-get_env.", + }); + expect(second?.data.content).toContain("MCP_RESPONSES_TOOL_OK"); + + const requests = route.bodies().slice(beforeRequests); + expect(requests).toHaveLength(3); + const [before, update, afterTool] = requests; + expect(before.tools).toEqual( + expect.arrayContaining([ + expect.objectContaining({ name: "z_server-get_env" }), + ]) + ); + expect(JSON.stringify(before.tools)).not.toContain('"name":"a_server-get_env"'); + for (const request of [update, afterTool]) { + if (route.config.provider) { + expect(request.tools).toEqual( + expect.arrayContaining([ + expect.objectContaining({ name: "a_server-get_env" }), + expect.objectContaining({ name: "z_server-get_env" }), + ]) + ); + expect(request.tools).toEqual(update.tools); + } else { + expect(JSON.stringify(request.tools)).toBe( + JSON.stringify(before.tools) + ); + } + expect(request.instructions).toEqual(before.instructions); + } + expect(update.previous_response_id ?? null).toBeNull(); + const input = update.input as Array>; + expect(JSON.stringify(input[0])).toBe( + JSON.stringify((before.input as Array>)[0]) + ); + if (route.config.provider) { + expect(JSON.stringify(input)).not.toContain('"type":"additional_tools"'); + } else { + expect(input).toContainEqual( + expect.objectContaining({ + type: "additional_tools", + tools: expect.arrayContaining([ + expect.objectContaining({ name: "a_server-get_env" }), + ]), + }) + ); + const additionIndex = input.findIndex( + (item) => item.type === "additional_tools" + ); + expect(additionIndex).toBeGreaterThan(0); + expect(JSON.stringify(input.slice(0, additionIndex))).toContain( + "MCP_RESPONSES_AFTER" + ); + } + expect(JSON.stringify(afterTool.input)).toContain("MCP_ADDED_TOOL_RESULT"); + } finally { + await session.disconnect(); + } + }, 90_000); + + it(`removes MCP tools on ${route.name} and executes a restored tool`, async () => { + const toolName = "a_server-get_env"; + const survivor = "z_server-get_env"; + const config = mcpTestServerConfig("MCP_ADDED_TOOL_RESULT"); + await client.start(); + const beforeRequests = route.bodies().length; + const session = await routeClient.createSession({ + model: "gpt-6-sol", + onPermissionRequest: approveAll, + ...route.config, + toolSearch: { enabled: false }, + availableTools: [toolName, survivor], + mcpServers: { a_server: config, z_server: config }, + }); + try { + await session.rpc.mcp.setEnvValueMode({ mode: "direct" }); + await session.rpc.tools.initializeAndValidate(); + expect( + (await session.rpc.tools.getCurrentMetadata()).tools.map( + (tool) => tool.name + ) + ).toEqual(expect.arrayContaining([toolName, survivor])); + expect( + (await session.sendAndWait({ prompt: "MCP_RESPONSES_FIRST" }))?.data.content + ).toContain(route.firstText); + + await session.rpc.mcp.disable({ serverName: "a_server" }); + await session.rpc.tools.initializeAndValidate(); + // Tool metadata includes the previous request; the host reports live availability. + const disabled = await session.rpc.mcp.list(); + expect(disabled.host?.disabledServers).toContain("a_server"); + expect(disabled.host?.disabledServers).not.toContain("z_server"); + expect(disabled.servers).toContainEqual( + expect.objectContaining({ name: "a_server", status: "disabled" }) + ); + expect( + (await session.sendAndWait({ prompt: "MCP_RESPONSES_REMOVED" }))?.data + .content + ).toContain(route.firstText); + + await session.rpc.mcp.enable({ serverName: "a_server" }); + await session.rpc.tools.initializeAndValidate(); + expect( + (await session.rpc.tools.getCurrentMetadata()).tools.map( + (tool) => tool.name + ) + ).toContain(toolName); + expect( + ( + await session.sendAndWait({ + prompt: `MCP_RESPONSES_AFTER: call ${toolName}.`, + }) + )?.data.content + ).toContain("MCP_RESPONSES_TOOL_OK"); + + await session.rpc.mcp.disable({ serverName: "a_server" }); + await session.rpc.tools.initializeAndValidate(); + const disabledAgain = await session.rpc.mcp.list(); + expect(disabledAgain.host?.disabledServers).toContain("a_server"); + expect(disabledAgain.host?.disabledServers).not.toContain("z_server"); + expect(disabledAgain.servers).toContainEqual( + expect.objectContaining({ name: "a_server", status: "disabled" }) + ); + expect( + (await session.sendAndWait({ prompt: "MCP_RESPONSES_REMOVED_AGAIN" }))?.data + .content + ).toContain("MCP_RESPONSES_REMOVED_OK"); + + const requests = route.bodies().slice(beforeRequests); + expect(requests).toHaveLength(5); + const [before, removed, restored, afterTool, removedAgain] = requests; + expect(before.tools).toEqual( + expect.arrayContaining([ + expect.objectContaining({ name: toolName }), + expect.objectContaining({ name: survivor }), + ]) + ); + for (const request of [removed, restored, afterTool, removedAgain]) { + expect(request.instructions).toEqual(before.instructions); + expect(JSON.stringify(request.input)).not.toContain( + '"type":"additional_tools"' + ); + } + const choice = { + type: "allowed_tools", + mode: "auto", + tools: [{ type: "function", name: survivor }], + }; + for (const request of [removed, removedAgain]) { + if (route.config.provider) { + expect(request.tools).toEqual( + (before.tools as Array>).filter( + (tool) => tool.name !== toolName + ) + ); + expect(request.tool_choice).not.toEqual( + expect.objectContaining({ type: "allowed_tools" }) + ); + } else { + expect(JSON.stringify(request.tools)).toBe( + JSON.stringify(before.tools) + ); + expect(request.tool_choice).toEqual(choice); + } + expect(request.previous_response_id ?? null).toBeNull(); + } + for (const request of [restored, afterTool]) { + expect(JSON.stringify(request.tools)).toBe(JSON.stringify(before.tools)); + expect(request.tool_choice).not.toEqual( + expect.objectContaining({ type: "allowed_tools" }) + ); + } + expect(restored.previous_response_id ?? null).toBeNull(); + expect(JSON.stringify(afterTool.input)).toContain("MCP_ADDED_TOOL_RESULT"); + } finally { + await session.disconnect(); + } + }, 90_000); + }); + } + + for (const byok of [false, true]) { + it(`preserves ${byok ? "BYOK" : "CAPI"} Chat Completions tools through removal and restores real execution`, async () => { + const original = { + name: "sdk_chat_original", + description: "Original", + parameters: { type: "object", properties: {} }, + defer: "never", + } as const; + const removable = { ...original, name: "sdk_chat_removed", description: "Removable" }; + let calls = 0; + const start = upstream.chatBodies().length; + const session = await client.createSession({ + model: "gpt-5.5", + ...(byok + ? { + provider: { + type: "openai" as const, + wireApi: "completions" as const, + baseUrl: upstream.url, + apiKey: "synthetic-provider-key", + modelId: "gpt-5.5", + wireModel: "gpt-5.5", + }, + } + : {}), + toolSearch: { enabled: false }, + onPermissionRequest: approveAll, + availableTools: [original.name, removable.name], + tools: [ + defineTool(original.name, { + description: original.description, + handler: () => "SDK_CHAT_ORIGINAL_RESULT", + }), + defineTool(removable.name, { + description: removable.description, + handler: () => { + calls++; + return "SDK_CHAT_EXECUTED_RESULT"; + }, + }), + ], + }); + try { + await session.rpc.tools.initializeAndValidate(); + expect( + (await session.sendAndWait({ prompt: "SDK_CHAT_FIRST" }))?.data.content + ).toContain("SDK_CHAT_FIRST_OK"); + await session.rpc.tools.set({ tools: [original] }); + expect( + (await session.sendAndWait({ prompt: "SDK_CHAT_REMOVED" }))?.data.content + ).toContain("SDK_CHAT_REMOVED_OK"); + expect(calls).toBe(0); + const removedRequests = upstream.chatBodies().slice(start); + expect(removedRequests).toHaveLength(3); + const [before, removed, afterRejectedCall] = removedRequests; + expect(JSON.stringify(removed.tools)).toBe(JSON.stringify(before.tools)); + expect(removed.tool_choice).toEqual({ + type: "allowed_tools", + allowed_tools: { + mode: "auto", + tools: [{ type: "function", function: { name: original.name } }], + }, + }); + expect(JSON.stringify(afterRejectedCall.messages)).toContain("does not exist"); + await session.rpc.tools.set({ tools: [original, removable] }); + expect( + (await session.sendAndWait({ prompt: "SDK_CHAT_RESTORED" }))?.data.content + ).toContain("SDK_CHAT_RESTORED_OK"); + expect(calls).toBe(1); + const requests = upstream.chatBodies().slice(start); + expect(requests).toHaveLength(5); + for (const request of requests.slice(3)) { + expect(JSON.stringify(request.tools)).toBe(JSON.stringify(before.tools)); + expect(request.tool_choice).not.toEqual( + expect.objectContaining({ type: "allowed_tools" }) + ); + } + expect(JSON.stringify(requests[4].messages)).toContain("SDK_CHAT_EXECUTED_RESULT"); + } finally { + await session.disconnect(); + } + }); + } + + describe("WebSocket to HTTP tool-update fallback", async () => { + const { copilotClient: fallbackClient } = await createSdkTestContext({ + copilotClientOptions: { requestHandler: new TestHandler(upstream.url, counters, true) }, + }); + it("recovers an unrecognized HTTP 422 once and keeps later turns on current tools", async () => { + const original = { + name: "sdk_epoch_original", + description: "Original", + parameters: { type: "object", properties: {} }, + defer: "never", + } as const; + const added = { ...original, name: "sdk_epoch_added", description: "Added" }; + const start = upstream.httpBodies().length; + const session = await fallbackClient.createSession({ + model: "gpt-6-sol", + capi: { enableWebSocketResponses: true }, + toolSearch: { enabled: false }, + onPermissionRequest: approveAll, + tools: [ + defineTool(original.name, { handler: () => "original" }), + defineTool(added.name, { handler: () => "added" }), + ], + }); + try { + await session.rpc.tools.initializeAndValidate(); + await session.rpc.tools.set({ tools: [original] }); + expect( + (await session.sendAndWait({ prompt: "SDK_RESPONSES_FIRST" }))?.data.content + ).toContain(HTTP_TEXT); + await session.rpc.tools.set({ tools: [original, added] }); + expect( + (await session.sendAndWait({ prompt: "SDK_RESPONSES_REJECT_GENERIC" }))?.data + .content + ).toContain(HTTP_TEXT); + expect( + (await session.sendAndWait({ prompt: "SDK_RESPONSES_LEGACY_FOLLOW_UP" }))?.data + .content + ).toContain("SDK_RESPONSES_LEGACY_OK"); + const requests = upstream.httpBodies().slice(start); + expect(requests).toHaveLength(4); + const [before, rejected, recovered, later] = requests; + expect(JSON.stringify(rejected.tools)).toBe(JSON.stringify(before.tools)); + expect(JSON.stringify(rejected.input)).toContain('"type":"additional_tools"'); + for (const request of [recovered, later]) { + expect(JSON.stringify(request.input)).not.toContain( + '"type":"additional_tools"' + ); + expect(request.tools).toEqual( + expect.arrayContaining([expect.objectContaining({ name: added.name })]) + ); + } + } finally { + await session.disconnect(); + } + }); + }); + + it("rebases a refreshed MCP definition before executing the restarted server", async () => { + const toolName = "a_server-get_env"; + const descriptionFile = join(workDir, "tool-description.txt"); + await writeFile(descriptionFile, "MCP_ORIGINAL_DESCRIPTION"); + await client.start(); + const beforeRequests = upstream.wsBodies().length; + const session = await client.createSession({ + model: "gpt-6-sol", + onPermissionRequest: approveAll, + capi: { enableWebSocketResponses: true }, + toolSearch: { enabled: false }, + mcpServers: { + a_server: mcpTestServerConfig("MCP_ADDED_TOOL_RESULT", descriptionFile), + }, + }); + try { + await session.rpc.mcp.setEnvValueMode({ mode: "direct" }); + await session.rpc.tools.initializeAndValidate(); + expect( + (await session.rpc.tools.getCurrentMetadata()).tools.find( + (tool) => tool.name === toolName + )?.description + ).toContain("MCP_ORIGINAL_DESCRIPTION"); + expect( + (await session.sendAndWait({ prompt: "MCP_RESPONSES_FIRST" }))?.data.content + ).toContain(WS_TEXT); + + await writeFile(descriptionFile, "MCP_REPLACEMENT_DESCRIPTION"); + await session.rpc.mcp.restartServer({ serverName: "a_server" }); + await session.rpc.tools.initializeAndValidate(); + expect( + (await session.rpc.tools.getCurrentMetadata()).tools.find( + (tool) => tool.name === toolName + )?.description + ).toContain("MCP_REPLACEMENT_DESCRIPTION"); + expect( + (await session.sendAndWait({ prompt: `MCP_RESPONSES_AFTER: call ${toolName}.` })) + ?.data.content + ).toContain("MCP_RESPONSES_TOOL_OK"); + + const requests = upstream.wsBodies().slice(beforeRequests); + expect(requests).toHaveLength(3); + const [before, update, afterTool] = requests; + expect(JSON.stringify(before.tools)).toContain("MCP_ORIGINAL_DESCRIPTION"); + expect(JSON.stringify(update.tools)).toContain("MCP_REPLACEMENT_DESCRIPTION"); + expect(JSON.stringify(update.tools)).not.toContain("MCP_ORIGINAL_DESCRIPTION"); + expect(update.instructions).toEqual(before.instructions); + expect(update.previous_response_id ?? null).toBeNull(); + for (const request of [update, afterTool]) { + expect(JSON.stringify(request.input)).not.toContain('"type":"additional_tools"'); + } + expect(JSON.stringify(afterTool.tools)).toBe(JSON.stringify(update.tools)); + expect(JSON.stringify(afterTool.input)).toContain("MCP_ADDED_TOOL_RESULT"); + } finally { + await session.disconnect(); + } + }, 90_000); + it("keeps the SDK removal prefix while restricting tools across continuations and restoration", async () => { const original = { name: "sdk_epoch_original", @@ -619,12 +1206,12 @@ describe("CopilotRequestHandler — single subclass handles HTTP + WebSocket", a expect( (await session.sendAndWait({ prompt: "SDK_REMOVAL_ALL" }))?.data.content ).toContain(HTTP_TEXT); - // No remaining tools selects the runtime's single-shot HTTP route. + // No remaining tools selects HTTP, which keeps the prefix and forbids all calls. const allRemoved = upstream .httpBodies() .findLast((body) => JSON.stringify(body.input).includes("SDK_REMOVAL_ALL"))!; - expect(allRemoved.tools).toEqual([]); - expect(allRemoved.tool_choice).toBeUndefined(); + expect(JSON.stringify(allRemoved.tools)).toBe(JSON.stringify(before.tools)); + expect(allRemoved.tool_choice).toBe("none"); expect(allRemoved.previous_response_id ?? null).toBeNull(); await session.rpc.tools.set({ tools: [original, added] }); diff --git a/nodejs/test/e2e/customization_directories.e2e.test.ts b/nodejs/test/e2e/customization_directories.e2e.test.ts new file mode 100644 index 0000000000..2a3adefa51 --- /dev/null +++ b/nodejs/test/e2e/customization_directories.e2e.test.ts @@ -0,0 +1,387 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import { execFileSync } from "node:child_process"; +import fs from "node:fs"; +import path from "node:path"; +import { beforeEach, describe, expect, it } from "vitest"; +import { approveAll, RuntimeConnection } from "../../src/index.js"; +import { createSdkTestContext } from "./harness/sdkTestContext.js"; + +function writeFile(root: string, relative: string[], content: string): string { + const file = path.join(root, ...relative); + fs.mkdirSync(path.dirname(file), { recursive: true }); + fs.writeFileSync(file, content); + return file; +} + +function writeSkill(root: string, directory: string, name: string): void { + writeFile( + root, + [directory, name, "SKILL.md"], + `---\nname: ${name}\ndescription: Discovery directory regression fixture.\n---\n\nUse this skill.\n` + ); +} + +describe("Customization directory discovery", async () => { + const { + copilotClient: client, + env, + workDir: testRoot, + createClient, + } = await createSdkTestContext({ + copilotClientOptions: { env: { COPILOT_ALLOW_ALL: "1" } }, + }); + let workDir: string; + + beforeEach(async () => { + workDir = fs.realpathSync.native(fs.mkdtempSync(path.join(testRoot, "customizations-"))); + execFileSync("git", ["init", "--quiet"], { cwd: workDir, windowsHide: true }); + writeFile( + env.COPILOT_HOME, + ["config.json"], + JSON.stringify({ trustedFolders: [testRoot] }) + ); + await client.start(); + }); + + it("discovers all four repository lists and applies independent local replacements", async () => { + writeSkill(workDir, "vendor-skills", "repository-directory-skill"); + writeFile( + workDir, + ["vendor-agents", "directory.agent.md"], + "---\nname: repository-directory-agent\ndescription: Directory fixture.\n---\n\nRead the repository.\n" + ); + const instruction = writeFile( + workDir, + ["vendor-instructions", "guard.instructions.md"], + "---\napplyTo: '**/*.ts'\n---\n\nRepository directory instruction sentinel.\n" + ); + writeFile( + workDir, + ["vendor-instructions", "AGENTS.md"], + "Do not inject this package hierarchy." + ); + writeFile( + workDir, + ["vendor-hooks", "hooks.json"], + JSON.stringify({ hooks: { sessionStart: [{ command: "echo directory-hook" }] } }) + ); + writeFile( + workDir, + [".github", "copilot", "settings.json"], + JSON.stringify({ + skillDirectories: ["vendor-skills"], + agentDirectories: ["vendor-agents"], + instructionDirectories: ["vendor-instructions"], + hookDirectories: ["vendor-hooks"], + }) + ); + const projectPaths = [workDir]; + const skills = await client.rpc.skills.discover({ projectPaths, excludeHostSkills: true }); + expect( + skills.skills.filter((skill) => skill.name === "repository-directory-skill") + ).toHaveLength(1); + const agents = await client.rpc.agents.discover({ projectPaths, excludeHostAgents: true }); + expect( + agents.agents.filter((agent) => agent.name === "repository-directory-agent") + ).toHaveLength(1); + const instructions = await client.rpc.instructions.discover({ + projectPaths, + excludeHostInstructions: true, + }); + expect( + instructions.sources.filter((source) => source.sourcePath === instruction) + ).toHaveLength(1); + expect( + instructions.sources.some((source) => + source.content.includes("Do not inject this package hierarchy.") + ) + ).toBe(false); + const hooks = await client.rpc.hooks.discover({ projectPaths, excludeHostHooks: true }); + expect(hooks.hooks.some((hook) => hook.source.includes("vendor-hooks"))).toBe(true); + + writeFile( + workDir, + [".github", "copilot", "settings.local.json"], + JSON.stringify({ skillDirectories: [], hookDirectories: [] }) + ); + const clearedSkills = await client.rpc.skills.discover({ + projectPaths, + excludeHostSkills: true, + }); + expect( + clearedSkills.skills.some((skill) => skill.name === "repository-directory-skill") + ).toBe(false); + const retainedAgents = await client.rpc.agents.discover({ + projectPaths, + excludeHostAgents: true, + }); + expect( + retainedAgents.agents.some((agent) => agent.name === "repository-directory-agent") + ).toBe(true); + const clearedHooks = await client.rpc.hooks.discover({ + projectPaths, + excludeHostHooks: true, + }); + expect(clearedHooks.hooks.some((hook) => hook.source.includes("vendor-hooks"))).toBe(false); + }); + + it("anchors SDK relative roots once and reanchors only newly supplied lists", async () => { + const original = path.join(workDir, "original"); + const next = path.join(workDir, "next"); + writeSkill(original, "skills", "original-directory-skill"); + writeSkill(next, "skills", "next-directory-skill"); + const session = await client.createSession({ + onPermissionRequest: approveAll, + workingDirectory: original, + enableConfigDiscovery: false, + skillDirectories: ["skills"], + }); + try { + await session.rpc.skills.ensureLoaded(); + expect( + (await session.rpc.skills.list()).skills.some( + (skill) => skill.name === "original-directory-skill" + ) + ).toBe(true); + expect((await session.rpc.options.update({ workingDirectory: next })).success).toBe( + true + ); + await session.rpc.skills.ensureLoaded(); + const retained = await session.rpc.skills.list(); + expect(retained.skills.some((skill) => skill.name === "original-directory-skill")).toBe( + true + ); + expect(retained.skills.some((skill) => skill.name === "next-directory-skill")).toBe( + false + ); + expect( + (await session.rpc.options.update({ skillDirectories: ["skills"] })).success + ).toBe(true); + await session.rpc.skills.ensureLoaded(); + const changed = await session.rpc.skills.list(); + expect(changed.skills.some((skill) => skill.name === "original-directory-skill")).toBe( + false + ); + expect(changed.skills.some((skill) => skill.name === "next-directory-skill")).toBe( + true + ); + expect((await session.rpc.options.update({ skillDirectories: [] })).success).toBe(true); + await session.rpc.skills.ensureLoaded(); + expect( + (await session.rpc.skills.list()).skills.some( + (skill) => skill.name === "next-directory-skill" + ) + ).toBe(false); + } finally { + await session.disconnect(); + } + }); + + it("anchors newly supplied roots to the persisted workspace on cold resume", async () => { + const original = path.join(workDir, "nested"); + fs.mkdirSync(original); + writeSkill(workDir, path.join("vendor", "alternate-skills"), "cold-resume-directory-skill"); + const first = createClient({ connection: RuntimeConnection.forStdio() }); + const next = createClient({ connection: RuntimeConnection.forStdio() }); + try { + await first.start(); + const session = await first.createSession({ + onPermissionRequest: approveAll, + workingDirectory: original, + enableConfigDiscovery: false, + requestExtensions: false, + }); + await session.rpc.workspaces.ensure({}); + const { sessionId } = await first.rpc.sessions.fork({ sessionId: session.sessionId }); + await session.disconnect(); + await first.stop(); + await next.start(); + const resumed = await next.resumeSession(sessionId, { + onPermissionRequest: approveAll, + enableConfigDiscovery: false, + requestExtensions: false, + skillDirectories: [path.join("..", "vendor", "alternate-skills")], + }); + try { + expect((await resumed.rpc.metadata.snapshot()).workingDirectory).toBe(original); + await resumed.rpc.skills.ensureLoaded(); + const skills = await resumed.rpc.skills.list(); + expect( + skills.skills.some((skill) => skill.name === "cold-resume-directory-skill") + ).toBe(true); + } finally { + await resumed.disconnect(); + } + } finally { + await next.stop(); + await first.stop(); + } + }); + + it("retains explicit file hooks when repository hooks and ambient discovery are disabled", async () => { + const hooks = path.join(workDir, "explicit-hooks"); + writeFile(hooks, ["resource.txt"], "resource-sentinel"); + writeFile( + hooks, + ["probe.cjs"], + "const fs = require('node:fs'); const path = require('node:path');\n" + + "fs.appendFileSync(path.join(process.cwd(), 'hook-observations.jsonl'), JSON.stringify({" + + "directory: process.env.COPILOT_HOOK_DIR, cwd: process.cwd(), " + + "resource: fs.readFileSync(path.join(process.env.COPILOT_HOOK_DIR, 'resource.txt'), 'utf8')" + + "}) + '\\n');\n" + ); + writeFile( + hooks, + ["hooks.json"], + JSON.stringify({ + hooks: { + preToolUse: [ + { + type: "command", + bash: `"${process.execPath}" "$COPILOT_HOOK_DIR/probe.cjs"`, + powershell: `& "${process.execPath}" (Join-Path $env:COPILOT_HOOK_DIR 'probe.cjs')`, + }, + ], + }, + }) + ); + writeFile( + workDir, + [".github", "hooks", "ambient.json"], + JSON.stringify({ + hooks: { preToolUse: [{ command: "echo ambient-hook" }] }, + }) + ); + let callbackInvocations = 0; + const session = await client.createSession({ + onPermissionRequest: approveAll, + workingDirectory: workDir, + enableConfigDiscovery: false, + enableFileHooks: false, + hookDirectories: [hooks], + hooks: { + onPreToolUse: async () => { + callbackInvocations++; + return { permissionDecision: "allow" }; + }, + }, + }); + try { + await client.rpc.sessions.reloadPluginHooks({ + sessionId: session.sessionId, + deferRepoHooks: true, + }); + await session.rpc.tools.initializeAndValidate(); + const result = await session.rpc.tools.execute({ + name: "view", + arguments: { path: path.join(hooks, "resource.txt") }, + toolCallId: "explicit-hook-directory-probe", + }); + expect(JSON.stringify(result)).toContain("resource-sentinel"); + expect(callbackInvocations).toBe(1); + const observations = path.join(workDir, "hook-observations.jsonl"); + const first = fs.readFileSync(observations, "utf8").trim().split("\n"); + expect(first).toHaveLength(1); + expect(JSON.parse(first[0])).toEqual({ + directory: hooks, + cwd: workDir, + resource: "resource-sentinel", + }); + expect((await session.rpc.options.update({ hookDirectories: [] })).success).toBe(true); + await client.rpc.sessions.reloadPluginHooks({ + sessionId: session.sessionId, + deferRepoHooks: true, + }); + await session.rpc.tools.execute({ + name: "view", + arguments: { path: path.join(hooks, "resource.txt") }, + toolCallId: "cleared-hook-directory-probe", + }); + expect(fs.readFileSync(observations, "utf8").trim().split("\n")).toHaveLength(1); + expect(callbackInvocations).toBe(2); + } finally { + await session.disconnect(); + } + }); + + it("retains conventional and configured guard hooks after changing to a repository subdirectory", async () => { + const observations = path.join(workDir, "cwd-hooks.jsonl"); + const subdir = path.join(workDir, "subdir"); + fs.mkdirSync(subdir); + for (const parts of [[".github", "hooks"], ["vendor-hooks"]]) { + const hooks = path.join(workDir, ...parts); + writeFile( + hooks, + ["probe.cjs"], + "require('node:fs').appendFileSync(" + + JSON.stringify(observations) + + ", JSON.stringify({directory: process.env.COPILOT_HOOK_DIR, cwd: process.cwd()}) + '\\n');\n" + ); + writeFile( + hooks, + ["hooks.json"], + JSON.stringify({ + hooks: { + preToolUse: [ + { + type: "command", + bash: `"${process.execPath}" "$COPILOT_HOOK_DIR/probe.cjs"`, + powershell: `& "${process.execPath}" (Join-Path $env:COPILOT_HOOK_DIR 'probe.cjs')`, + }, + ], + }, + }) + ); + } + writeFile( + workDir, + [".github", "copilot", "settings.json"], + JSON.stringify({ hookDirectories: ["vendor-hooks"] }) + ); + const resource = writeFile(workDir, ["resource.txt"], "cwd-hook-resource"); + const session = await client.createSession({ + onPermissionRequest: approveAll, + workingDirectory: workDir, + enableConfigDiscovery: true, + requestExtensions: false, + }); + try { + await session.rpc.tools.initializeAndValidate(); + await session.rpc.tools.execute({ + name: "view", + arguments: { path: resource }, + toolCallId: "guard-before-cwd-change", + }); + expect(fs.readFileSync(observations, "utf8").trim().split("\n")).toHaveLength(2); + expect( + await session.rpc.metadata.setWorkingDirectory({ workingDirectory: subdir }) + ).toMatchObject({ workingDirectory: subdir }); + await session.rpc.tools.execute({ + name: "view", + arguments: { path: resource }, + toolCallId: "guard-after-cwd-change", + }); + const rows = fs + .readFileSync(observations, "utf8") + .trim() + .split("\n") + .map((row) => JSON.parse(row)); + expect(rows).toHaveLength(4); + expect( + rows + .slice(2) + .map((row) => row.directory) + .sort() + ).toEqual( + [path.join(workDir, ".github", "hooks"), path.join(workDir, "vendor-hooks")].sort() + ); + // Hooks without an explicit cwd remain anchored to the consuming project root. + expect(rows.slice(2).map((row) => row.cwd)).toEqual([workDir, workDir]); + } finally { + await session.disconnect(); + } + }); +}); diff --git a/nodejs/test/e2e/disabled_mcp_servers.e2e.test.ts b/nodejs/test/e2e/disabled_mcp_servers.e2e.test.ts index 5a240bbd76..e62de0e5d9 100644 --- a/nodejs/test/e2e/disabled_mcp_servers.e2e.test.ts +++ b/nodejs/test/e2e/disabled_mcp_servers.e2e.test.ts @@ -721,11 +721,26 @@ describe("disabled MCP servers", async () => { onPermissionRequest: approveAll, enableSessionStore: true, pluginDirectories: [pluginDirectory], - disabledMcpServers: ["disabled"], + disabledMcpServers: ["disabled", "github-mcp-server", "computer-use"], }); await waitForMcpStatus(resumedSession, "control", "connected"); await waitForMcpStatus(resumedSession, "disabled", "disabled"); await waitForMarkerCount(controlMarker, 1); + const inventory = await resumedSession.rpc.mcp.listConfigured(); + expect( + inventory.servers + .filter((server) => ["control", "disabled"].includes(server.name)) + .map(({ name, enabled }) => ({ name, enabled })) + .sort((a, b) => a.name.localeCompare(b.name)) + ).toEqual([ + { name: "control", enabled: true }, + { name: "disabled", enabled: false }, + ]); + expect( + inventory.servers.filter( + (server) => server.source === "builtin" && server.enabled + ) + ).toEqual([]); expect(existsSync(disabledMarker)).toBe(false); } finally { await initialClient.stop().catch(() => {}); diff --git a/nodejs/test/e2e/entra_identity_first.e2e.test.ts b/nodejs/test/e2e/entra_identity_first.e2e.test.ts index 38da660fb7..7df4d67c50 100644 --- a/nodejs/test/e2e/entra_identity_first.e2e.test.ts +++ b/nodejs/test/e2e/entra_identity_first.e2e.test.ts @@ -5,11 +5,12 @@ import { randomUUID } from "node:crypto"; import { mkdir, readFile, writeFile } from "node:fs/promises"; import { join } from "node:path"; -import { describe, expect, it, onTestFinished } from "vitest"; +import { describe, expect, it, onTestFailed, onTestFinished } from "vitest"; import { approveAll, CopilotClient, RuntimeConnection } from "../../src/index.js"; import { createSdkTestContext } from "./harness/sdkTestContext.js"; import { ConnectProxy } from "../../../test/harness/connectProxy.js"; import { createE2eRequestHandler } from "../../../test/harness/mockHandlers.js"; +import { readDiagnosticTail } from "../../../test/harness/sdk-diagnostics.mjs"; const { env, workDir, openAiEndpoint } = await createSdkTestContext({ useStdio: true, @@ -20,6 +21,19 @@ const M365_SCOPE = "42c8f7bd-c7a8-4ba9-bc1c-91edfb716247/.default"; const LOKI_HOST = "loki.identity-first.example"; const VERIFICATION_UNAVAILABLE = "Microsoft sign-in succeeded, but GitHub account verification is temporarily unavailable. Please try again later. Your active account has not changed."; +type CatalogReceipt = { + resource: "capi_models" | "loki_models" | "loki_quota"; + authenticated: boolean; + receivedAtMs: number; + status?: number; + /** Fixture-selected class, not proof that the runtime decoded the response. */ + responseClass?: "catalog" | "quota" | "mos_disabled" | "access_denied"; + replyAtMs?: number; + finishedAtMs?: number; + closedAtMs?: number; + closedBeforeFinish?: boolean; + requestAborted?: boolean; +}; const scenarios = [ { name: "both", emuGrant: true, staff: true, capi: 200, loki: 200, expected: "choices" }, { name: "emu only", emuGrant: true, staff: true, capi: 200, loki: 403, expected: "entraEmu" }, @@ -198,12 +212,70 @@ describe("Entra identity-first resource discovery", () => { } const grants: URLSearchParams[] = []; const catalogs: string[] = []; + const receipts: CatalogReceipt[] = []; + let omittedReceipts = 0; + let loginOutcome: + | "pending" + | "fulfilled" + | "rejected_no_backend" + | "rejected_verification" + | "rejected_rpc_timeout" + | "rejected_other" = "pending"; + const startedAt = performance.now(); + const elapsedMs = () => Math.round(performance.now() - startedAt); + onTestFailed(async () => { + console.error( + `[Entra discovery fixture] ${JSON.stringify({ loginOutcome, receipts, omittedReceipts })}` + ); + try { + const diagnostics = await readDiagnosticTail(profile); + console.error( + `[SDK diagnostics: last ${diagnostics.length} audited records]\n${diagnostics.join("\n")}` + ); + } catch { + console.error("SDK diagnostics unavailable"); + } + }); let latestRefresh = "identity-refresh"; const fallback = createE2eRequestHandler({ capiProxyUrl: openAiEndpoint.url }); const proxy = new ConnectProxy( async (request, response, host) => { const path = request.url ?? "/"; - const reply = (status: number, body: unknown) => { + const resource = + host === "api.githubcopilot.com" && path === "/models" + ? "capi_models" + : host === LOKI_HOST && path === "/api/models" + ? "loki_models" + : host === LOKI_HOST && path === "/api/quota" + ? "loki_quota" + : undefined; + const receipt: CatalogReceipt | undefined = resource + ? { resource, authenticated: false, receivedAtMs: elapsedMs() } + : undefined; + if (receipt) { + if (receipts.length < 32) receipts.push(receipt); + else omittedReceipts++; + request.once("aborted", () => { + receipt.requestAborted = true; + }); + response.once("finish", () => { + receipt.finishedAtMs = elapsedMs(); + }); + response.once("close", () => { + receipt.closedAtMs = elapsedMs(); + receipt.closedBeforeFinish = !response.writableFinished; + }); + } + const reply = ( + status: number, + body: unknown, + responseClass?: CatalogReceipt["responseClass"] + ) => { + if (receipt) { + receipt.status = status; + receipt.responseClass = responseClass; + receipt.replyAtMs = elapsedMs(); + } response.writeHead(status, { "content-type": "application/json" }); response.end(JSON.stringify(body)); return true; @@ -291,50 +363,69 @@ describe("Entra identity-first resource discovery", () => { if (host === "api.githubcopilot.com" && path === "/models") { expect(request.headers.authorization).toBe(`Bearer ${emuToken}`); catalogs.push("capi"); - return reply(scenario.capi, { - data: - "emptyCapi" in scenario && scenario.emptyCapi - ? [] - : [ - { - id: "gpt-5.2", - name: "Candidate CAPI model", - capabilities: { supports: { tool_calls: true } }, - model_picker_enabled: !( - "hiddenCapi" in scenario && scenario.hiddenCapi - ), - ...("restrictedCapi" in scenario - ? { billing: { restricted_to: ["enterprise"] } } - : {}), - }, - ], - }); + if (receipt) receipt.authenticated = true; + return reply( + scenario.capi, + { + data: + "emptyCapi" in scenario && scenario.emptyCapi + ? [] + : [ + { + id: "gpt-5.2", + name: "Candidate CAPI model", + capabilities: { supports: { tool_calls: true } }, + model_picker_enabled: !( + "hiddenCapi" in scenario && + scenario.hiddenCapi + ), + ...("restrictedCapi" in scenario + ? { + billing: { + restricted_to: ["enterprise"], + }, + } + : {}), + }, + ], + }, + scenario.capi === 200 ? "catalog" : "access_denied" + ); } if (host === LOKI_HOST && (path === "/api/models" || path === "/api/quota")) { expect(request.headers.authorization).toBe("Bearer m365-resource-token"); + if (receipt) receipt.authenticated = true; if ("mosDenied" in scenario && path === `/api/${scenario.mosDenied}`) { if (scenario.mosDenied === "models") catalogs.push("loki"); - return reply(403, { - error: { - message: - "Copilot CLI Entra access is not enabled for this user.", - type: "invalid_request_error", - code: "copilot_cli_entra_access_disabled", + return reply( + 403, + { + error: { + message: + "Copilot CLI Entra access is not enabled for this user.", + type: "invalid_request_error", + code: "copilot_cli_entra_access_disabled", + }, }, - }); + "mos_disabled" + ); } - if (path === "/api/quota") return reply(200, {}); + if (path === "/api/quota") return reply(200, {}, "quota"); catalogs.push("loki"); - return reply(scenario.loki, { - data: [ - { - id: "loki-test", - name: "Candidate M365 model", - capabilities: { supports: { tool_calls: true } }, - model_picker_enabled: true, - }, - ], - }); + return reply( + scenario.loki, + { + data: [ + { + id: "loki-test", + name: "Candidate M365 model", + capabilities: { supports: { tool_calls: true } }, + model_picker_enabled: true, + }, + ], + }, + scenario.loki === 200 ? "catalog" : "access_denied" + ); } return fallback(request, response, host); }, @@ -364,9 +455,11 @@ describe("Entra identity-first resource discovery", () => { connection: RuntimeConnection.forStdio({ path: process.env.COPILOT_CLI_PATH }), workingDirectory: workDir, useLoggedInUser: false, + logLevel: "debug" as const, env: { ...env, COPILOT_HOME: profile, + RUST_LOG: "error,sdk_diagnostics=debug", COPILOT_DISABLE_KEYTAR: "1", GH_TOKEN: "", GITHUB_TOKEN: "", @@ -428,6 +521,21 @@ describe("Entra identity-first resource discovery", () => { } return step; }); + void completing.then( + () => { + loginOutcome = "fulfilled"; + }, + (error: unknown) => { + const message = error instanceof Error ? error.message : ""; + loginOutcome = message.includes("No usable inference backend") + ? "rejected_no_backend" + : message.includes(VERIFICATION_UNAVAILABLE) + ? "rejected_verification" + : /timed out|timeout/i.test(message) + ? "rejected_rpc_timeout" + : "rejected_other"; + } + ); // Attach the failure assertion before the callback can complete the request. const completed = scenario.expected === "failure" diff --git a/nodejs/test/e2e/harness/mcpTestServer.ts b/nodejs/test/e2e/harness/mcpTestServer.ts new file mode 100644 index 0000000000..76e50a5837 --- /dev/null +++ b/nodejs/test/e2e/harness/mcpTestServer.ts @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +export function mcpTestServerConfig(result: string, descriptionFile?: string) { + const serverPath = resolve( + dirname(fileURLToPath(import.meta.url)), + "../../../../test/harness/test-mcp-server.mjs" + ); + return { + type: "stdio" as const, + command: process.execPath, + args: [ + serverPath, + ...(descriptionFile ? ["--tool-description-file", descriptionFile] : []), + ], + workingDirectory: dirname(serverPath), + env: { CACHE_TEST_RESULT: result }, + tools: ["get_env"], + }; +} diff --git a/nodejs/test/e2e/harness/sdkTestContext.ts b/nodejs/test/e2e/harness/sdkTestContext.ts index 633fd4aa0a..515177ee44 100644 --- a/nodejs/test/e2e/harness/sdkTestContext.ts +++ b/nodejs/test/e2e/harness/sdkTestContext.ts @@ -3,10 +3,11 @@ *--------------------------------------------------------------------------------------------*/ import fs, { realpathSync } from "fs"; -import { rm } from "fs/promises"; +import { readdir, rm } from "fs/promises"; import os from "os"; import { basename, dirname, join, resolve } from "path"; import { rimraf } from "rimraf"; +import { createInterface } from "readline"; import { fileURLToPath } from "url"; import { afterAll, afterEach, beforeEach, onTestFailed, onTestFinished, TestContext } from "vitest"; import { CopilotClient, CopilotClientOptions, RuntimeConnection } from "../../../src"; @@ -277,6 +278,30 @@ export async function createSdkTestContext({ console.error( `[SDK diagnostics: last ${diagnostics.length} audited records]\n${diagnostics.join("\n")}` ); + const logDir = join(copilotHomeDir, "logs"); + for (const file of await readdir(logDir)) { + if (!file.endsWith(".log")) continue; + const lines = createInterface({ + input: fs.createReadStream(join(logDir, file)), + }); + const mcpClosureDiagnostics: string[] = []; + for await (const line of lines) { + const mcpClosure = line.match( + /^\S+ \[(?:DEBUG|WARN)\] \[rust:mcp::client\] MCP (?:liveness probe (?:found the (?:session expired|transport (?:closed|channel closed))|failed; awaiting corroboration|went unanswered; inconclusive|could not be sent in time; inconclusive|failed inconclusively|failed with an unrecognised transport error)|liveness probes are neither proving life nor consistently failing|session reported closed)/ + ); + if (mcpClosure) { + // Keep only static messages; transport error fields can contain user data. + mcpClosureDiagnostics.push(mcpClosure[0]); + if (mcpClosureDiagnostics.length > 32) + mcpClosureDiagnostics.shift(); + } + } + if (mcpClosureDiagnostics.length > 0) { + console.error( + `[MCP session-closure diagnostics: ${file}; last ${mcpClosureDiagnostics.length} matching lines]\n${mcpClosureDiagnostics.join("\n")}` + ); + } + } } catch { console.error("SDK diagnostics unavailable"); } diff --git a/nodejs/test/e2e/hydrafusion_max.e2e.test.ts b/nodejs/test/e2e/hydrafusion_max.e2e.test.ts index a4a7c52c93..078dbeeaab 100644 --- a/nodejs/test/e2e/hydrafusion_max.e2e.test.ts +++ b/nodejs/test/e2e/hydrafusion_max.e2e.test.ts @@ -3,8 +3,10 @@ *--------------------------------------------------------------------------------------------*/ import { describe, expect, it } from "vitest"; +import { z } from "zod"; import { approveAll, + defineTool, CopilotRequestHandler, RuntimeConnection, type SessionEvent, @@ -19,9 +21,37 @@ import { isByokBackend } from "./harness/testBackend.js"; const MODEL = "gpt-5.6-sol"; const REPLY = "SDK_HYDRAFUSION_MAX_DONE: Au"; +interface ChatToolCall { + id: string; + type: "function"; + function: { name: string; arguments: string }; +} + +interface ChatMessage { + role: string; + content?: unknown; + tool_calls?: ChatToolCall[]; + tool_call_id?: string; +} + +interface ChatRequest { + model?: string; + stream?: boolean; + messages: ChatMessage[]; +} + class FusionRequestHandler extends CopilotRequestHandler { readonly plans: unknown[] = []; - readonly inference: unknown[] = []; + readonly inference: ChatRequest[] = []; + + constructor( + private readonly reply: (request: ChatRequest) => ChatMessage = () => ({ + role: "assistant", + content: REPLY, + }) + ) { + super(); + } protected override async sendRequest(request: Request): Promise { const path = new URL(request.url).pathname; @@ -57,23 +87,19 @@ class FusionRequestHandler extends CopilotRequestHandler { }); } if (path === "/chat/completions") { - const body = (await request.json()) as { model?: string; stream?: boolean }; + const body = (await request.json()) as ChatRequest; this.inference.push(body); if (body.model !== MODEL) { throw new Error(`Expected concrete Fusion constituent, received ${body.model}`); } + const message = this.reply(body); + const finishReason = message.tool_calls ? "tool_calls" : "stop"; const completion = { id: "chatcmpl-sdk-max", object: "chat.completion", created: 0, model: MODEL, - choices: [ - { - index: 0, - message: { role: "assistant", content: REPLY }, - finish_reason: "stop", - }, - ], + choices: [{ index: 0, message, finish_reason: finishReason }], usage: { prompt_tokens: 11, completion_tokens: 7, total_tokens: 18 }, }; if (!body.stream) return Response.json(completion); @@ -84,8 +110,18 @@ class FusionRequestHandler extends CopilotRequestHandler { choices: [ { index: 0, - delta: { role: "assistant", content: REPLY }, - finish_reason: "stop", + delta: { + ...message, + ...(message.tool_calls + ? { + tool_calls: message.tool_calls.map((call, index) => ({ + index, + ...call, + })), + } + : {}), + }, + finish_reason: finishReason, }, ], })}\n\ndata: [DONE]\n\n`, @@ -264,3 +300,191 @@ describe.skipIf(isByokBackend).each([false, true])( } } ); + +const DRAFT_NOTE = "FUSION_DRAFT_NOTE_BEFORE_STOP"; +const RECORD_CALL_ID = "call_fusion_record_progress"; +const RECORD_RESULT = "FUSION_PROGRESS_RECORDED"; +const WAIT_CALL_ID = "call_fusion_wait_for_stop"; +const FOLLOW_UP_PROMPT = "FUSION_FOLLOW_UP_AFTER_STOP: continue where you left off."; +const FOLLOW_UP_REPLY = "FUSION_FOLLOW_UP_DONE"; + +function messageText(content: unknown): string { + if (typeof content === "string") return content; + if (Array.isArray(content)) { + return content + .map((part) => (typeof part?.text === "string" ? (part.text as string) : "")) + .join(""); + } + return ""; +} + +// The draft writes a note and finishes one tool call, then blocks in a second one until the +// user stops the turn. The follow-up turn answers once it sees the user's next prompt. +function interruptedDraftReply(request: ChatRequest): ChatMessage { + if ( + request.messages.some((message) => messageText(message.content).includes(FOLLOW_UP_PROMPT)) + ) { + return { role: "assistant", content: FOLLOW_UP_REPLY }; + } + const recorded = request.messages.some( + (message) => message.role === "tool" && message.tool_call_id === RECORD_CALL_ID + ); + const call = (id: string, name: string, args: object): ChatToolCall => ({ + id, + type: "function", + function: { name, arguments: JSON.stringify(args) }, + }); + return recorded + ? { role: "assistant", content: "", tool_calls: [call(WAIT_CALL_ID, "wait_for_stop", {})] } + : { + role: "assistant", + content: DRAFT_NOTE, + tool_calls: [call(RECORD_CALL_ID, "record_progress", { note: "alpha" })], + }; +} + +async function withTimeout(promise: Promise, ms: number, label: string): Promise { + let timer: ReturnType | undefined; + try { + return await Promise.race([ + promise, + new Promise((_, reject) => { + timer = setTimeout(() => reject(new Error(`Timeout: ${label}`)), ms); + }), + ]); + } finally { + if (timer) clearTimeout(timer); + } +} + +describe.skipIf(isByokBackend)("HydraFusion interrupted turn", async () => { + const handler = new FusionRequestHandler(interruptedDraftReply); + const { copilotClient: client, workDir } = await createSdkTestContext({ + copilotClientOptions: { + gitHubToken: DEFAULT_GITHUB_TOKEN, + requestHandler: handler, + env: { + HYDRAFUSION: "true", + HYDRAFUSION_ROLLOUT: "true", + HYDRAFUSION_PLAN_V2: "true", + COPILOT_EXP_COPILOT_CLI_HYDRAFUSION_PLAN_V2: "true", + HYDRAFUSION_INTERRUPTED_COMMIT: "true", + }, + }, + }); + + it("keeps the stopped draft's work in history and in the next turn", async () => { + let markWaitStarted!: () => void; + const waitStarted = new Promise((resolve) => { + markWaitStarted = resolve; + }); + let releaseWait!: () => void; + const waitReleased = new Promise((resolve) => { + releaseWait = resolve; + }); + const session = await client.createSession({ + model: "hydrafusion-max", + enableExperimentalMode: true, + workingDirectory: workDir, + onPermissionRequest: approveAll, + tools: [ + defineTool("record_progress", { + description: "Records a progress note.", + parameters: z.object({ note: z.string() }), + handler: async () => RECORD_RESULT, + }), + defineTool("wait_for_stop", { + description: "Blocks until released.", + parameters: z.object({}), + handler: async (_args, invocation) => { + markWaitStarted(); + await new Promise((resolve) => { + void waitReleased.then(resolve); + invocation.signal?.addEventListener("abort", () => resolve(), { + once: true, + }); + }); + return "RELEASED_AFTER_STOP"; + }, + }), + ], + }); + let stopRequested = false; + let markStoppedIdle!: () => void; + const stoppedIdle = new Promise((resolve) => { + markStoppedIdle = resolve; + }); + const unsubscribe = session.on((event) => { + if (stopRequested && event.type === "session.idle") markStoppedIdle(); + }); + try { + void session.send({ prompt: "Record progress, then wait for the stop signal." }); + await withTimeout(waitStarted, 60_000, "wait_for_stop start"); + stopRequested = true; + await session.abort(); + releaseWait(); + await withTimeout(stoppedIdle, 60_000, "idle after stop"); + + const history = await session.getEvents(); + const commit = history.find((event) => event.type === "session.fusion_commit_started"); + expect(commit?.data).toMatchObject({ + commitId: expect.stringMatching(/:commit:interrupted:0$/), + }); + const commitId = (commit?.data as { commitId: string }).commitId; + const committed = history.filter( + (event) => + (event.data as { fusion?: { commitId?: string } }).fusion?.commitId === commitId + ); + expect(committed).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + type: "assistant.message", + data: expect.objectContaining({ content: DRAFT_NOTE }), + }), + expect.objectContaining({ + type: "tool.execution_complete", + data: expect.objectContaining({ + toolCallId: RECORD_CALL_ID, + success: true, + }), + }), + ]) + ); + expect(history.some((event) => event.type === "session.fusion_completed")).toBe(false); + + const reply = await session.sendAndWait({ prompt: FOLLOW_UP_PROMPT }); + expect(reply?.data.content).toBe(FOLLOW_UP_REPLY); + const followUp = handler.inference.find((request) => + request.messages.some((message) => + messageText(message.content).includes(FOLLOW_UP_PROMPT) + ) + ); + const messages = followUp?.messages ?? []; + const followUpIndex = messages.findIndex((message) => + messageText(message.content).includes(FOLLOW_UP_PROMPT) + ); + const earlier = messages.slice(0, followUpIndex); + expect( + earlier.some( + (message) => + message.role === "assistant" && + messageText(message.content).includes(DRAFT_NOTE) + ) + ).toBe(true); + expect( + earlier.flatMap((message) => message.tool_calls?.map((call) => call.id) ?? []) + ).toEqual(expect.arrayContaining([RECORD_CALL_ID, WAIT_CALL_ID])); + const results = new Map( + earlier + .filter((message) => message.role === "tool") + .map((message) => [message.tool_call_id, messageText(message.content)]) + ); + expect(results.get(RECORD_CALL_ID)).toContain(RECORD_RESULT); + expect(results.has(WAIT_CALL_ID)).toBe(true); + } finally { + releaseWait(); + unsubscribe(); + await session.disconnect(); + } + }); +}); diff --git a/nodejs/test/e2e/mcp_and_agents.e2e.test.ts b/nodejs/test/e2e/mcp_and_agents.e2e.test.ts index 414e760ea2..443d5699f0 100644 --- a/nodejs/test/e2e/mcp_and_agents.e2e.test.ts +++ b/nodejs/test/e2e/mcp_and_agents.e2e.test.ts @@ -2,9 +2,11 @@ * Copyright (c) Microsoft Corporation. All rights reserved. *--------------------------------------------------------------------------------------------*/ -import { dirname, resolve } from "path"; +import { createHash } from "node:crypto"; +import { readFile } from "node:fs/promises"; +import { dirname, join, resolve } from "path"; import { fileURLToPath } from "url"; -import { describe, expect, it } from "vitest"; +import { describe, expect, it, onTestFinished } from "vitest"; import { z } from "zod"; import type { CopilotSession, @@ -12,7 +14,7 @@ import type { MCPStdioServerConfig, MCPServerConfig, } from "../../src/index.js"; -import { approveAll, defineTool } from "../../src/index.js"; +import { approveAll, defineTool, RuntimeConnection } from "../../src/index.js"; import { createSdkTestContext } from "./harness/sdkTestContext.js"; const __filename = fileURLToPath(import.meta.url); @@ -57,7 +59,12 @@ async function waitForMcpServerStatus( } describe("MCP Servers and Custom Agents", async () => { - const { copilotClient: client, openAiEndpoint } = await createSdkTestContext(); + const { + copilotClient: client, + openAiEndpoint, + createClient, + workDir, + } = await createSdkTestContext(); describe("MCP Servers", () => { it("should accept MCP server configuration on session create", async () => { @@ -133,6 +140,18 @@ describe("MCP Servers and Custom Agents", async () => { }); it("should pass literal env values to MCP server subprocess", async () => { + const telemetryPath = join(workDir, "mcp-telemetry.jsonl"); + const telemetryClient = createClient({ + connection: RuntimeConnection.forStdio(), + telemetry: { + exporterType: "file", + filePath: telemetryPath, + captureContent: true, + }, + }); + onTestFinished(async () => { + expect(await telemetryClient.stop()).toEqual([]); + }); const mcpServers: Record = { "env-echo": { type: "local", @@ -144,20 +163,50 @@ describe("MCP Servers and Custom Agents", async () => { } as MCPStdioServerConfig, }; - const session = await client.createSession({ + const session = await telemetryClient.createSession({ mcpServers, onPermissionRequest: approveAll, }); - - expect(session.sessionId).toBeDefined(); - await waitForMcpServerStatus(session, "env-echo"); - - const message = await session.sendAndWait({ - prompt: "Use the env-echo/get_env tool to read the TEST_SECRET environment variable. Reply with just the value, nothing else.", - }); - expect(message?.data.content).toContain("hunter2"); - - await session.disconnect(); + try { + expect(session.sessionId).toBeDefined(); + await waitForMcpServerStatus(session, "env-echo"); + + const message = await session.sendAndWait({ + prompt: "Use the env-echo/get_env tool to read the TEST_SECRET environment variable. Reply with just the value, nothing else.", + }); + expect(message?.data.content).toContain("hunter2"); + } finally { + await session.disconnect(); + } + expect(await telemetryClient.stop()).toEqual([]); + + const entries: Array<{ type: string; attributes?: Record }> = ( + await readFile(telemetryPath, "utf8") + ) + .split(/\r?\n/) + .filter((line) => line.trim()) + .map((line) => JSON.parse(line)); + const mcpSpans = entries.filter( + (entry) => + entry.type === "span" && + entry.attributes?.["gen_ai.operation.name"] === "execute_tool" && + typeof entry.attributes[ + "github.copilot.tool.parameters.mcp_server_name_hash" + ] === "string" + ); + expect(mcpSpans.length).toBeGreaterThan(0); + for (const span of mcpSpans) { + expect(span.attributes).toMatchObject({ + "gen_ai.tool.type": "function", + "github.copilot.tool.parameters.mcp_server_name_hash": createHash("sha256") + .update("env-echo") + .digest("hex"), + "github.copilot.tool.parameters.mcp_server_name": "env-echo", + "github.copilot.tool.parameters.mcp_tool_name": "get_env", + "github.copilot.mcp.server.transport": "stdio", + "github.copilot.mcp.server.source": "user", + }); + } }); }); diff --git a/nodejs/test/e2e/mcp_remote_session_closure.e2e.test.ts b/nodejs/test/e2e/mcp_remote_session_closure.e2e.test.ts index 4b6ebf174a..1878998d25 100644 --- a/nodejs/test/e2e/mcp_remote_session_closure.e2e.test.ts +++ b/nodejs/test/e2e/mcp_remote_session_closure.e2e.test.ts @@ -6,7 +6,7 @@ import { spawn } from "node:child_process"; import { dirname, resolve } from "node:path"; import { createInterface } from "node:readline"; import { fileURLToPath } from "node:url"; -import { describe, expect, it, onTestFinished } from "vitest"; +import { describe, expect, it, onTestFailed, onTestFinished } from "vitest"; import type { CopilotSession, MCPServerConfig } from "../../src/index.js"; import { approveAll } from "../../src/index.js"; import { createSdkTestContext } from "./harness/sdkTestContext.js"; @@ -29,10 +29,19 @@ interface McpServerStats { expiredRequestLog: { method: string; elapsedMs: number }[]; protocolVersions: string[]; expiredSessionProbes: number; + recentRequests: Array<{ + elapsedMs: number; + httpMethod: string; + sessionAttached: boolean; + expiredSession: boolean; + rpcMethods: string[]; + status: number | null; + }>; } describe("MCP remote session closure", async () => { const { copilotClient: client } = await createSdkTestContext({ + logLevel: "debug", copilotClientOptions: { env: { COPILOT_MCP_APPS: "true", @@ -46,6 +55,10 @@ describe("MCP remote session closure", async () => { { timeout: 180_000 }, async () => { const remoteServer = await startSessionExpiryMcpServer(); + let lastStats = await remoteServer.stats(); + onTestFailed(() => { + console.error("Last MCP session-expiry observation:", JSON.stringify(lastStats)); + }); const serverName = "remote-server"; const session = await client.createSession({ onPermissionRequest: approveAll, @@ -73,8 +86,8 @@ describe("MCP remote session closure", async () => { await waitForCondition( async () => { - const stats = await remoteServer.stats(); - return stats.expiredSessionProbes >= 1 || stats.initializations >= 2; + lastStats = await remoteServer.stats(); + return lastStats.expiredSessionProbes >= 1 || lastStats.initializations >= 2; }, { timeoutMs: 120_000, @@ -83,7 +96,6 @@ describe("MCP remote session closure", async () => { "remote MCP session expiry was neither probed nor re-initialized", } ); - let lastStats: McpServerStats | undefined; try { await waitForCondition( async () => { @@ -124,20 +136,20 @@ async function waitForMcpServerStatus( serverName: string, expectedStatus: string ): Promise { - let lastStatus = ""; - await waitForCondition( - async () => { - const result = await session.rpc.mcp.list(); - const server = result.servers.find((entry) => entry.name === serverName); - lastStatus = server?.status ?? ""; - return server?.status === expectedStatus; - }, - { - timeoutMs: 120_000, - intervalMs: 200, - timeoutMessage: `${serverName} did not reach ${expectedStatus}; last status was ${lastStatus}`, - } - ); + await expect + .poll( + async () => { + const result = await session.rpc.mcp.list(); + const server = result.servers.find((entry) => entry.name === serverName); + return server?.status ?? ""; + }, + { + timeout: 120_000, + interval: 200, + message: `${serverName} did not reach ${expectedStatus}`, + } + ) + .toBe(expectedStatus); } async function disconnectSession(session: CopilotSession): Promise { @@ -160,6 +172,9 @@ async function startSessionExpiryMcpServer(): Promise<{ const stderr: string[] = []; child.stderr.on("data", (chunk) => stderr.push(String(chunk))); + onTestFailed(() => { + console.error("Session-expiry server stderr:", stderr.join("").slice(-16_384)); + }); const url = await new Promise((resolvePromise, reject) => { const rl = createInterface({ input: child.stdout }); diff --git a/nodejs/test/e2e/mcp_scoped_sign_in.e2e.test.ts b/nodejs/test/e2e/mcp_scoped_sign_in.e2e.test.ts index d872e2c1c2..d067c2bcf2 100644 --- a/nodejs/test/e2e/mcp_scoped_sign_in.e2e.test.ts +++ b/nodejs/test/e2e/mcp_scoped_sign_in.e2e.test.ts @@ -126,6 +126,20 @@ describe("MCP sign-in for one server", async () => { await waitForMcpServerStatus(session, "alpha", "connected"); await waitForMcpServerStatus(session, "bravo", "needs-auth"); await waitForMcpServerStatus(session, "delta", "needs-auth"); + // Live status can precede delivery of its initial notification. + await waitForCondition( + () => + events.some( + (event) => + event.type === "session.mcp_server_status_changed" && + event.data.serverName === "alpha" && + event.data.status === "connected" + ), + { + timeoutMs: STEP_TIMEOUT_MS, + timeoutMessage: "alpha did not deliver its initial connected status", + } + ); const deltaLogin = await session.rpc.mcp.oauth.login({ serverName: "delta", redirectUri: REDIRECT_URI, diff --git a/nodejs/test/e2e/pending_work_resume.e2e.test.ts b/nodejs/test/e2e/pending_work_resume.e2e.test.ts index b4bf6fa352..ecb5294a59 100644 --- a/nodejs/test/e2e/pending_work_resume.e2e.test.ts +++ b/nodejs/test/e2e/pending_work_resume.e2e.test.ts @@ -602,18 +602,30 @@ describe("Pending work resume", async () => { .filter(Boolean) .map((line) => JSON.parse(line) as SessionEvent); }; + // Live SDK callbacks do not prove that both parallel boundaries reached the journal. await waitForCondition( - () => - readPersistedEvents().some( - (event) => - event.type === "tool.execution_complete" && - event.data.toolCallId === toolA.data.toolCallId && - event.data.success && - event.data.result?.content === "PARALLEL_A_ALPHA" - ), + () => { + const persistedEvents = readPersistedEvents(); + return ( + persistedEvents.some( + (event) => + event.type === "tool.execution_complete" && + event.data.toolCallId === toolA.data.toolCallId && + event.data.success && + event.data.result?.content === "PARALLEL_A_ALPHA" + ) && + persistedEvents.some( + (event) => + event.type === "external_tool.requested" && + event.data.requestId === toolB.data.requestId && + event.data.toolCallId === toolB.data.toolCallId + ) + ); + }, { timeoutMs: PENDING_WORK_TIMEOUT_MS, - timeoutMessage: "Tool A's result was not flushed to events.jsonl before B", + timeoutMessage: + "Tool A's result and tool B's pending request were not both flushed to events.jsonl before shutdown", } ); expect( diff --git a/nodejs/test/e2e/rpc_mcp_lifecycle.e2e.test.ts b/nodejs/test/e2e/rpc_mcp_lifecycle.e2e.test.ts index 40f837434d..b47eed190d 100644 --- a/nodejs/test/e2e/rpc_mcp_lifecycle.e2e.test.ts +++ b/nodejs/test/e2e/rpc_mcp_lifecycle.e2e.test.ts @@ -86,6 +86,103 @@ describe("Session-scoped MCP lifecycle RPC", async () => { expect(message.toLowerCase()).not.toContain("unhandled method"); } + async function offeredToolNames(session: CopilotSession): Promise { + await session.rpc.tools.initializeAndValidate(); + const { tools } = await session.rpc.tools.getCurrentMetadata(); + if (tools === null) { + throw new Error("initializeAndValidate did not initialize session tools"); + } + return tools.map((tool) => tool.name); + } + + it("should start an ephemeral server from caller config and reuse its replacement", async () => { + const serverName = missingName("ephemeral"); + const session = await client.createSession({ onPermissionRequest: approveAll }); + try { + const persistedBefore = await client.rpc.mcp.config.list(); + const initialConfig = { + type: "stdio" as const, + command: "node", + args: [TEST_MCP_SERVER, "--tool-name", "ephemeral_initial"], + cwd: TEST_HARNESS_DIR, + excludeTools: ["ephemeral_initial"], + disableToolCache: true, + }; + await session.rpc.mcp.startServer({ serverName, config: initialConfig }); + expect( + (await session.rpc.mcp.listTools({ serverName })).tools.map((tool) => tool.name) + ).toEqual(["ephemeral_initial"]); + expect(await offeredToolNames(session)).not.toContain( + `${serverName}-ephemeral_initial` + ); + expect((await session.rpc.mcp.isServerRunning({ serverName })).running).toBe(true); + + await session.rpc.mcp.restartServer({ + serverName, + config: { + ...initialConfig, + args: [TEST_MCP_SERVER, "--tool-name", "ephemeral_replacement"], + }, + }); + expect(await offeredToolNames(session)).toContain( + `${serverName}-ephemeral_replacement` + ); + await session.rpc.mcp.stopServer({ serverName }); + expect((await session.rpc.mcp.isServerRunning({ serverName })).running).toBe(false); + await session.rpc.mcp.startServer({ serverName }); + await session.rpc.mcp.restartServer({ serverName }); + expect( + (await session.rpc.mcp.listTools({ serverName })).tools.map((tool) => tool.name) + ).toEqual(["ephemeral_replacement"]); + expect(await client.rpc.mcp.config.list()).toEqual(persistedBefore); + } finally { + await session.disconnect(); + } + const nextSession = await client.createSession({ onPermissionRequest: approveAll }); + try { + expect( + (await nextSession.rpc.mcp.listConfigured()).servers.some( + (server) => server.name === serverName + ) + ).toBe(false); + } finally { + await nextSession.disconnect(); + } + }); + + it("should replace the registered config when restarting an installed server", async () => { + const serverName = "rpc-lifecycle-replace-server"; + const session = await createSessionWithMcp(serverName); + try { + await waitForMcpServerStatus(session, serverName); + expect( + (await session.rpc.mcp.listTools({ serverName })).tools.map((tool) => tool.name) + ).toEqual(["get_env"]); + expect(await offeredToolNames(session)).toContain(`${serverName}-get_env`); + await session.rpc.mcp.restartServer({ + serverName, + config: { + type: "stdio", + command: "node", + args: [TEST_MCP_SERVER, "--tool-name", "installed_replacement"], + cwd: TEST_HARNESS_DIR, + tools: ["*"], + excludeTools: ["installed_replacement"], + disableToolCache: true, + }, + }); + expect( + (await session.rpc.mcp.listTools({ serverName })).tools.map((tool) => tool.name) + ).toEqual(["installed_replacement"]); + const offered = await offeredToolNames(session); + expect(offered).not.toContain(`${serverName}-installed_replacement`); + expect(offered).not.toContain(`${serverName}-get_env`); + expect((await session.rpc.mcp.isServerRunning({ serverName })).running).toBe(true); + } finally { + await session.disconnect(); + } + }); + it( "should list tools and report running status for connected server", { timeout: 120_000 }, diff --git a/nodejs/test/e2e/rpc_session_state.e2e.test.ts b/nodejs/test/e2e/rpc_session_state.e2e.test.ts index 76e7ff2261..9efa6dfdc9 100644 --- a/nodejs/test/e2e/rpc_session_state.e2e.test.ts +++ b/nodejs/test/e2e/rpc_session_state.e2e.test.ts @@ -304,6 +304,60 @@ describe("Session-scoped RPC", async () => { } }); + it("should read the reasoning-summaries policy for the current model", async () => { + const session = await client.createSession({ + onPermissionRequest: approveAll, + model: "claude-sonnet-5", + // This policy needs the CAPI catalog; legacy BYOK sessions skip it. + // An explicit provider roster keeps the harness from replacing CAPI. + providers: [], + }); + + try { + // `ready` stays false until the session has resolved its model + // catalog, which only happens once something asks for it. Prime the + // session's model-list cache so the policy reports the real answer + // instead of the not-ready placeholder. + await session.rpc.model.list(); + + const policy = await session.rpc.model.getReasoningSummaries({}); + expect(policy.ready).toBe(true); + expect(typeof policy.experimentSettled).toBe("boolean"); + expect(typeof policy.modelDefaultShowsSummaries).toBe("boolean"); + expect(typeof policy.showReasoningHeaders).toBe("boolean"); + // No session-level reasoning-summary override, so the session + // follows the selected model's default. + expect(policy.sessionShowsSummaries).toBe(policy.modelDefaultShowsSummaries); + + // A persisted setting decides visibility whatever the experiment + // assignment is, and one that restates the model default is + // reported as redundant. + const redundant = await session.rpc.model.getReasoningSummaries({ + persistedShowReasoning: policy.modelDefaultShowsSummaries, + }); + expect(redundant.visibility).toBe(policy.modelDefaultShowsSummaries); + expect(redundant.clearRedundantSetting).toBe(true); + + const opposed = await session.rpc.model.getReasoningSummaries({ + persistedShowReasoning: !policy.modelDefaultShowsSummaries, + }); + expect(opposed.visibility).toBe(!policy.modelDefaultShowsSummaries); + expect(opposed.clearRedundantSetting).toBe(false); + + // A visible view never asks for the "summaries are hidden" hint, + // and a pending experiment assignment never asks for it either. + const visible = await session.rpc.model.getReasoningSummaries({ + summariesVisible: true, + }); + expect(visible.showHiddenHint).toBe(false); + if (!policy.experimentSettled) { + expect(policy.showHiddenHint).toBe(false); + } + } finally { + await session.disconnect(); + } + }); + it("should get and set session metadata", async () => { const session = await client.createSession({ onPermissionRequest: approveAll }); diff --git a/nodejs/test/e2e/rpc_settings.e2e.test.ts b/nodejs/test/e2e/rpc_settings.e2e.test.ts new file mode 100644 index 0000000000..7d0ce82023 --- /dev/null +++ b/nodejs/test/e2e/rpc_settings.e2e.test.ts @@ -0,0 +1,138 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import { spawn } from "node:child_process"; +import { once } from "node:events"; +import { mkdir, readFile, writeFile } from "node:fs/promises"; +import { join } from "node:path"; +import { describe, it, onTestFinished } from "vitest"; +import { + createMessageConnection, + StreamMessageReader, + StreamMessageWriter, +} from "vscode-jsonrpc/node.js"; +import { createInternalServerRpc, createServerRpc } from "../../src/generated/rpc.js"; +import { createSdkTestContext, getLegacyCliPathForTests } from "./harness/sdkTestContext.js"; +import { stopChildProcess } from "./harness/sdkTestHelper.js"; + +describe("Internal settings RPC through the CLI SDK server", async () => { + const { env, workDir } = await createSdkTestContext(); + + it("preserves settings semantics through the generated SDK methods", async ({ expect }) => { + const home = join(workDir, "settings-home"); + const repoRoot = join(workDir, "repository"); + await mkdir(home, { recursive: true }); + await mkdir(join(repoRoot, ".github", "copilot"), { recursive: true }); + const legacy = { model: "legacy-model", render_markdown: false }; + await writeFile(join(home, "config.json"), JSON.stringify(legacy)); + + // These methods are internal, so use their generated projection over a real CLI transport. + const cliPath = await getLegacyCliPathForTests(); + const args = ["--headless", "--stdio", "--no-auto-update", "--log-level", "error"]; + const child = spawn( + cliPath.endsWith(".js") ? process.execPath : cliPath, + cliPath.endsWith(".js") ? [cliPath, ...args] : args, + { cwd: workDir, env: { ...env, COPILOT_HOME: home }, stdio: "pipe" } + ); + let stderr = ""; + child.stderr.on("data", (chunk) => { + stderr += String(chunk); + }); + const connection = createMessageConnection( + new StreamMessageReader(child.stdout), + new StreamMessageWriter(child.stdin) + ); + onTestFinished(async () => { + connection.dispose(); + await stopChildProcess(child); + }); + await once(child, "spawn"); + connection.listen(); + const rpc = createInternalServerRpc(connection); + expect(await rpc.connect({}), stderr).toMatchObject({ + protocolVersion: expect.any(Number), + }); + + const paths = await rpc.user.settings.getPaths({ repoRoot }); + expect(paths).toEqual({ + userSettings: join(home, "settings.json"), + repoSettings: join(repoRoot, ".github", "copilot", "settings.json"), + repoLocalSettings: join(repoRoot, ".github", "copilot", "settings.local.json"), + }); + expect((await rpc.user.settings.listGovernanceKeys()).repo).toContain("model"); + expect(await rpc.user.settings.normalize({ settings: { render_markdown: true } })).toEqual({ + settings: { renderMarkdown: true }, + }); + const problems = await rpc.user.settings.diagnoseProblems({ + sources: [ + { + kind: "user", + label: "User", + filePath: paths.userSettings, + config: { notASetting: true }, + }, + ], + }); + expect(problems.problems).toEqual([ + expect.objectContaining({ kind: "unknown-key", rawKey: "notASetting" }), + ]); + + await rpc.user.settings.writeAll({ settings: { model: "initial-model", beep: true } }); + expect( + await rpc.user.settings.edit({ + canonicalPath: ["model"], + operation: "set", + value: "edited-model", + }) + ).toEqual({ status: "changed" }); + expect( + await rpc.user.settings.applyTopKey({ + canonicalPath: ["model"], + topKey: "model", + value: null, + }) + ).toMatchObject({ status: "validation-error" }); + expect( + await rpc.user.settings.applyTopKey({ + canonicalPath: ["model"], + topKey: "model", + value: "applied-model", + }) + ).toEqual({ status: "ok" }); + expect(JSON.parse(await readFile(paths.userSettings, "utf8"))).toEqual({ + model: "applied-model", + beep: true, + }); + await rpc.user.settings.writeAll({ settings: { model: "replacement-model" } }); + expect(JSON.parse(await readFile(paths.userSettings, "utf8"))).toEqual({ + model: "replacement-model", + }); + const loaded = await createServerRpc(connection).user.settings.get(); + expect(loaded.settings.model.value).toBe("replacement-model"); + + const repoPath = join(repoRoot, ".github", "copilot", "settings.json"); + await writeFile(repoPath, '{"custom":{"items":[true,null,12.5]}}'); + const target = { repoRoot, scope: "repo" }; + await rpc.repo.settings.writeKey({ ...target, key: "model", value: "repo-model" }); + expect(await rpc.repo.settings.readRaw(target)).toEqual({ + config: { custom: { items: [true, null, 12.5] }, model: "repo-model" }, + invalid: false, + }); + await rpc.repo.settings.writeAll({ ...target, settings: {} }); + expect(await rpc.repo.settings.readRaw(target)).toEqual({ + config: { custom: { items: [true, null, 12.5] } }, + invalid: false, + }); + await writeFile(repoPath, "{ invalid"); + expect(await rpc.repo.settings.readRaw(target)).toEqual({ config: {}, invalid: true }); + await expect( + rpc.repo.settings.writeKey({ + ...target, + key: "model", + value: "must-not-replace-invalid-file", + }) + ).rejects.toThrow(); + expect(await readFile(repoPath, "utf8")).toBe("{ invalid"); + }); +}); diff --git a/nodejs/test/e2e/rpc_shell_and_fleet.e2e.test.ts b/nodejs/test/e2e/rpc_shell_and_fleet.e2e.test.ts index 5df5024b14..51e5855e13 100644 --- a/nodejs/test/e2e/rpc_shell_and_fleet.e2e.test.ts +++ b/nodejs/test/e2e/rpc_shell_and_fleet.e2e.test.ts @@ -14,7 +14,12 @@ import { createSdkTestContext } from "./harness/sdkTestContext.js"; import { waitForCondition, waitForFileText } from "./harness/sdkTestHelper.js"; describe("Shell and fleet RPC", async () => { - const { copilotClient: client, workDir } = await createSdkTestContext(); + const { copilotClient: client, workDir } = await createSdkTestContext({ + logLevel: "debug", + copilotClientOptions: { + env: { RUST_LOG: "error,sdk_diagnostics=debug" }, + }, + }); function createWriteFileCommand(markerPath: string, marker: string): string { if (os.platform() === "win32") { @@ -23,6 +28,12 @@ describe("Shell and fleet RPC", async () => { return `sh -c "printf '%s' '${marker}' > '${markerPath}'"`; } + function createWindowsBatchCommand(command: string): string { + const filename = `shell-command-${randomUUID()}.cmd`; + fs.writeFileSync(path.join(workDir, filename), `@echo off\r\n${command}\r\n`); + return `cmd.exe /d /c ${filename}`; + } + async function waitForMessages( session: CopilotSession, predicate: (events: SessionEvent[]) => boolean, @@ -140,7 +151,9 @@ describe("Shell and fleet RPC", async () => { const timeout = os.platform() === "win32" ? 10_000 : 1_000; const command = os.platform() === "win32" - ? `echo started>"${started}" & ping.exe -n 31 127.0.0.1 >nul & echo completed>"${completed}"` + ? createWindowsBatchCommand( + `echo started>"${started}" & ping.exe -n 31 127.0.0.1 >nul & echo completed>"${completed}"` + ) : `printf started > '${started}'; sleep 30; printf completed > '${completed}'`; try { const result = await session.rpc.shell.exec({ command, cwd: workDir, timeout }); @@ -273,7 +286,7 @@ describe("Shell and fleet RPC", async () => { const missingCommand = `not-a-command-${randomUUID()}`; const command = os.platform() === "win32" - ? `${missingCommand} & echo done>"${marker}" & exit /b 1` + ? createWindowsBatchCommand(`${missingCommand} & echo done>"${marker}" & exit /b 1`) : `${missingCommand}; code=$?; printf done > '${marker}'; exit $code`; try { const result = await session.rpc.shell.exec({ command, cwd: workDir }); @@ -294,32 +307,40 @@ describe("Shell and fleet RPC", async () => { async (outputKind) => { const session = await client.createSession({ onPermissionRequest: approveAll }); const marker = path.join(workDir, `shell-${outputKind}-${randomUUID()}.txt`); + const outputFile = path.join(workDir, `shell-output-${randomUUID()}.txt`); + const started = `${marker}.started`; const phase = `${marker}.phase`; - const recordPhase = (value: string) => - `[IO.File]::WriteAllText('${phase}', '${value}')`; - // Publish only after Set-Content has closed its exclusive Windows writer. + const recordPhase = (value: string) => `echo ${value}>"${phase}"`; + // Run cmd syntax in an owned batch even when the RPC selects PowerShell. const publishMarker = - `${recordPhase("output-written")}; ` + - `Set-Content -LiteralPath '${marker}.pending' -Value done; ` + - `${recordPhase("marker-written")}; ` + - `Move-Item -LiteralPath '${marker}.pending' -Destination '${marker}'; ` + + `${recordPhase("output-written")} & ` + + `echo done>"${marker}.pending" & ` + + `${recordPhase("marker-written")} & ` + + `move /y "${marker}.pending" "${marker}" >nul & ` + recordPhase("marker-published"); const command = outputKind === "stderr" ? os.platform() === "win32" - ? `powershell -NoLogo -NoProfile -Command "${recordPhase("started")}; [Console]::Error.WriteLine('boom'); ${publishMarker}; exit 2"` - : `echo boom 1>&2; printf done > '${marker}'; exit 2` + ? createWindowsBatchCommand( + `${recordPhase("started")} & echo boom 1>&2 & ${publishMarker} & exit /b 2` + ) + : `printf started > '${started}'; echo boom 1>&2; printf done > '${marker}'; exit 2` : os.platform() === "win32" - ? `powershell -NoLogo -NoProfile -Command "${recordPhase("started")}; Write-Host ('x' * 71680); ${publishMarker}"` - : `printf '%71680s' '' | tr ' ' '='; printf done > '${marker}'`; + ? createWindowsBatchCommand( + `${recordPhase("started")} & type "${outputFile}" & ${publishMarker}` + ) + : `printf started > '${started}'; printf '%71680s' '' | tr ' ' '='; printf done > '${marker}'`; try { + if (outputKind === "large-stdout" && os.platform() === "win32") { + fs.writeFileSync(outputFile, "x".repeat(71680)); + } const result = await session.rpc.shell.exec({ command, cwd: workDir }); expect(result.processId).toBeTruthy(); await waitForFileText( marker, "done", 30_000, - os.platform() === "win32" ? [phase, `${marker}.pending`] : [] + os.platform() === "win32" ? [phase, `${marker}.pending`] : [started] ); // The process map is updated after the output stream closes. await new Promise((resolve) => setTimeout(resolve, 2_000)); diff --git a/nodejs/test/e2e/rpc_surface_coverage.e2e.test.ts b/nodejs/test/e2e/rpc_surface_coverage.e2e.test.ts index 1b71849db7..daa26e42a3 100644 --- a/nodejs/test/e2e/rpc_surface_coverage.e2e.test.ts +++ b/nodejs/test/e2e/rpc_surface_coverage.e2e.test.ts @@ -327,7 +327,19 @@ describe("Generated RPC surface coverage", () => { ...collectRuntimeFunctions(session.rpc, "session"), ]); - expect(inventory).toHaveLength(407); + expect(inventory).toHaveLength(408); + expect( + inventory.filter( + (method) => method.wireMethod === "session.model.getReasoningSummaries" + ) + ).toEqual([ + expect.objectContaining({ + scope: "session", + path: "model.getReasoningSummaries", + parameterCount: 1, + returnType: "Promise", + }), + ]); expect(inventory.filter((method) => method.wireMethod === "host.listSessions")).toEqual([ expect.objectContaining({ scope: "server", path: "host.listSessions" }), ]); diff --git a/nodejs/test/e2e/sandbox_network.e2e.test.ts b/nodejs/test/e2e/sandbox_network.e2e.test.ts index 9e476d4aff..0a78088696 100644 --- a/nodejs/test/e2e/sandbox_network.e2e.test.ts +++ b/nodejs/test/e2e/sandbox_network.e2e.test.ts @@ -5,6 +5,7 @@ import { createServer } from "node:http"; import { describe, it } from "vitest"; import type { CopilotSession } from "../../src/index.js"; +import { getRuntimePlatform } from "../../src/runtimeArtifacts.js"; import { createSdkTestContext } from "./harness/sdkTestContext.js"; const TEST_NAME = @@ -17,6 +18,25 @@ describe("Sandbox network", async () => { }, }); + it("reports the shipped platform's sandbox support and refusal", async ({ expect }) => { + await client.start(); + const support = await client.rpc.sandbox.getHostSupport(); + if (getRuntimePlatform().startsWith("linuxmusl-")) { + expect(support).toEqual({ + supported: false, + reason: "Sandboxed shell execution is not supported on Alpine Linux/musl.", + capabilities: [], + }); + } else if (support.supported) { + expect(support.reason).toBeUndefined(); + expect(support.capabilities).toContainEqual({ name: "shell", supported: true }); + } else { + expect(support.reason).toEqual(expect.any(String)); + expect(support.reason).not.toBe(""); + expect(support.capabilities).toEqual([]); + } + }); + it(TEST_NAME, async ({ expect, onTestFinished, skip }) => { await client.start(); const support = await client.rpc.sandbox.getHostSupport(); diff --git a/nodejs/test/e2e/session_fs.e2e.test.ts b/nodejs/test/e2e/session_fs.e2e.test.ts index 81309ee5a8..963f80aae9 100644 --- a/nodejs/test/e2e/session_fs.e2e.test.ts +++ b/nodejs/test/e2e/session_fs.e2e.test.ts @@ -4,12 +4,13 @@ import { SessionCompactionCompleteEvent } from "@github/copilot/sdk"; import { MemoryProvider, VirtualProvider } from "@platformatic/vfs"; -import { createHash } from "crypto"; +import { createHash, randomUUID } from "crypto"; import { existsSync, mkdtempSync, realpathSync } from "fs"; import { mkdir, readFile, readdir, rm, writeFile } from "fs/promises"; import { createServer } from "http"; import { tmpdir } from "os"; import { join } from "path"; +import { fileURLToPath } from "url"; import { describe, expect, it, onTestFinished, vi } from "vitest"; import { CopilotClient } from "../../src/client.js"; import { getRuntimePlatform } from "../../src/runtimeArtifacts.js"; @@ -51,6 +52,7 @@ describe("Session Fs", async () => { createClient, env, openAiEndpoint, + workDir, } = await createSdkTestContext({ copilotClientOptions: { sessionFs: sessionFsConfig }, }); @@ -179,6 +181,131 @@ describe("Session Fs", async () => { expect(msg2?.data.content).toContain("300"); }); + it("should roll context through native tools.execute from an active SDK handler", async () => { + await openAiEndpoint.updateConfig({ + filePath: fileURLToPath( + new URL( + "../../../test/snapshots/session_fs/should_route_file_operations_through_the_session_fs_provider.yaml", + import.meta.url + ) + ), + workDir, + replayOnly: true, + }); + const original = await client.createSession({ + onPermissionRequest: approveAll, + createSessionFsProvider, + featureFlags: { CONTEXT_MANAGEMENT_TOOLS: false }, + }); + const sessionId = original.sessionId; + try { + expect( + (await original.sendAndWait({ prompt: "What is 100 + 200?" }))?.data.content + ).toContain("300"); + } finally { + await original.disconnect(); + } + + // Resume a valid large user event so a fresh window can reclaim context. + const request: SessionEvent = { + id: randomUUID(), + timestamp: new Date().toISOString(), + parentId: null, + type: "user.message", + data: { + content: + "Preserve SDK rollover state. " + "Rollover fixture context. ".repeat(3_000), + source: "user", + }, + }; + await provider.appendFile( + p(sessionId, `${sessionStatePath}/events.jsonl`), + JSON.stringify(request) + "\n" + ); + + let resumed: CopilotSession; + let innerResult: Awaited> | undefined; + resumed = await client.resumeSession(sessionId, { + onPermissionRequest: approveAll, + createSessionFsProvider, + featureFlags: { CONTEXT_MANAGEMENT_TOOLS: true }, + continuePendingWork: false, + tools: [ + defineTool("sdk_context_rollover", { + description: "Roll context from an active SDK tool handler", + isTerminal: true, + defer: "never", + handler: async () => { + innerResult = await resumed.rpc.tools.execute({ + name: "new_context", + arguments: {}, + toolCallId: "sdk-context-rollover-native", + }); + return JSON.stringify(innerResult); + }, + }), + ], + }); + try { + await resumed.rpc.tools.initializeAndValidate(); + expect((await resumed.rpc.tools.getCurrentMetadata()).tools).toEqual( + expect.arrayContaining([expect.objectContaining({ name: "new_context" })]) + ); + const remaining = await resumed.rpc.tools.execute({ + name: "get_context_remaining", + arguments: {}, + }); + expect(remaining, JSON.stringify(remaining)).toMatchObject({ resultType: "success" }); + expect(JSON.parse(remaining.textResultForLlm)).toMatchObject({ + context_window: { number: 1, previous_window_id: null }, + }); + const checkpoint = await resumed.rpc.tools.execute({ + name: "session_artifacts", + arguments: { + operation: "append", + path: "checkpoint.md", + content: "\nPreserve SDK rollover state.", + }, + }); + expect(checkpoint, JSON.stringify(checkpoint)).toMatchObject({ resultType: "success" }); + + const outerResult = await resumed.rpc.tools.execute({ + name: "sdk_context_rollover", + arguments: {}, + toolCallId: "sdk-context-rollover-handler", + }); + expect(outerResult, JSON.stringify(outerResult)).toMatchObject({ + resultType: "success", + }); + expect(innerResult, JSON.stringify(innerResult)).toMatchObject({ + resultType: "success", + }); + await expect + .poll(async () => + (await resumed.getEvents()).filter( + (event) => event.type === "session.context_cleared" + ) + ) + .toEqual([ + expect.objectContaining({ + data: expect.objectContaining({ + initialMessage: expect.stringContaining("Preserve SDK rollover state."), + }), + }), + ]); + const next = await resumed.rpc.tools.execute({ + name: "get_context_remaining", + arguments: {}, + }); + expect(next, JSON.stringify(next)).toMatchObject({ resultType: "success" }); + expect(JSON.parse(next.textResultForLlm)).toMatchObject({ + context_window: { number: 2, previous_window_id: expect.any(String) }, + }); + } finally { + await resumed.disconnect(); + } + }); + it("should reject setProvider when sessions already exist", async () => { const tcpConnectionToken = "session-fs-test-token"; const client = new CopilotClient({ diff --git a/nodejs/test/e2e/structured_output.e2e.test.ts b/nodejs/test/e2e/structured_output.e2e.test.ts index ae08a9d16b..fbc84ab261 100644 --- a/nodejs/test/e2e/structured_output.e2e.test.ts +++ b/nodejs/test/e2e/structured_output.e2e.test.ts @@ -44,7 +44,7 @@ describe("Structured output", async () => { it("infers_typed_result_after_custom_tool", async () => { let calls = 0; const schema = z.object({ count: z.number().int(), color: z.string() }); - const session = await client.createSession({ + await using session = await client.createSession({ model, provider, onPermissionRequest: approveAll, @@ -89,8 +89,7 @@ describe("Structured output", async () => { it("typed_result_after_terminal_tool_and_steering", async () => { const events: SessionEvent[] = []; let calls = 0; - let session: CopilotSession; - session = await client.createSession({ + await using session: CopilotSession = await client.createSession({ model, provider, onPermissionRequest: approveAll, @@ -146,7 +145,7 @@ describe("Structured output", async () => { let calls = 0; let stops = 0; const replies: AssistantMessageEvent[] = []; - const session = await client.createSession({ + await using session = await client.createSession({ model, provider, onPermissionRequest: approveAll, @@ -204,7 +203,7 @@ describe("Structured output", async () => { it("rejects_unsupported_or_oversized_schemas_before_admission", async () => { for (const model of ["gpt-4.1", "hydrafusion"]) { - const session = await client.createSession({ + await using session = await client.createSession({ model, provider, ...(model === "hydrafusion" @@ -258,7 +257,7 @@ describe("Structured output", async () => { const hookReleased = new Promise((resolve) => { releaseHook = resolve; }); - const session = await client.createSession({ + await using session = await client.createSession({ model, provider, onPermissionRequest: approveAll, @@ -279,14 +278,20 @@ describe("Structured output", async () => { }, }); const replies: AssistantMessageEvent[] = []; - const errors: string[] = []; + const errors: "session.error"[] = []; + let errorCount = 0; + const startedAt = Date.now(); + const progress: { type: SessionEvent["type"]; elapsedMs: number }[] = []; let idle = false; const unsubscribe = session.on((event) => { if (event.agentId) return; + progress.push({ type: event.type, elapsedMs: Date.now() - startedAt }); + if (progress.length > 20) progress.shift(); if (event.type === "assistant.message") { replies.push(event); } else if (event.type === "session.error") { - errors.push(event.data.message); + errorCount++; + if (errors.length === 0) errors.push("session.error"); } else if (event.type === "session.idle") { idle = true; } @@ -320,6 +325,24 @@ describe("Structured output", async () => { expect(replies.some((event) => event.data.toolRequests?.length)).toBe(true); expect(reply.data.toolRequests ?? []).toEqual([]); expect(replies.at(-1)).toBe(reply); + } catch (error) { + console.error( + "Structured-output stop-hook diagnostics:", + JSON.stringify({ + sessionId: session.sessionId, + hookEntered, + idle, + errorCount, + errorCategories: errors, + progress, + replies: replies.slice(-20).map((reply) => ({ + originatingMessageId: reply.data.originatingMessageId, + toolRequestCount: reply.data.toolRequests?.length ?? 0, + contentLength: reply.data.content.length, + })), + }) + ); + throw error; } finally { releaseHook(); unsubscribe(); @@ -330,7 +353,7 @@ describe("Structured output", async () => { let stops = 0; const replies: AssistantMessageEvent[] = []; const schema = z.object({ answer: z.number().int() }); - const session = await client.createSession({ + await using session = await client.createSession({ model, provider, onPermissionRequest: approveAll, @@ -370,10 +393,9 @@ describe("Structured output", async () => { it("typed_wait_returns_late_steering_response", async () => { let stops = 0; let steeringId: string | undefined; - let session: CopilotSession; const replies: AssistantMessageEvent[] = []; const schema = z.object({ answer: z.number().int() }); - session = await client.createSession({ + await using session: CopilotSession = await client.createSession({ model, provider, onPermissionRequest: approveAll, @@ -423,7 +445,7 @@ describe("Structured output", async () => { const toolReleased = new Promise((resolve) => { releaseTool = resolve; }); - const session = await client.createSession({ + await using session = await client.createSession({ model, provider, onPermissionRequest: approveAll, @@ -480,7 +502,7 @@ describe("Structured output", async () => { }); it("sends_explicit_schema_for_message_and_batch", async () => { - const session = await client.createSession({ + await using session = await client.createSession({ model, provider, onPermissionRequest: approveAll, diff --git a/nodejs/test/e2e/subagent_prompt_resume.e2e.test.ts b/nodejs/test/e2e/subagent_prompt_resume.e2e.test.ts index 00d0469647..62faad1221 100644 --- a/nodejs/test/e2e/subagent_prompt_resume.e2e.test.ts +++ b/nodejs/test/e2e/subagent_prompt_resume.e2e.test.ts @@ -2,7 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. *--------------------------------------------------------------------------------------------*/ -import { writeFile } from "node:fs/promises"; +import { readFile, writeFile } from "node:fs/promises"; import { dirname, join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; import { describe, expect, it } from "vitest"; @@ -11,6 +11,7 @@ import type { CopilotSession, CustomAgentConfig, MCPStdioServerConfig, + SessionEvent, } from "../../src/index.js"; import { approveAll, CopilotRequestHandler } from "../../src/index.js"; import { createSdkTestContext } from "./harness/sdkTestContext.js"; @@ -248,7 +249,11 @@ describe("Subagent prompt resume", async () => { const { copilotClient: client, env } = await createSdkTestContext({ copilotClientOptions: { requestHandler, - env: { COPILOT_EXP_COPILOT_CLI_SESSION_BASED_SUBAGENTS: "true" }, + env: { + COPILOT_EXP_COPILOT_CLI_SESSION_BASED_SUBAGENTS: "true", + STABILITY_ORDERED_SYSTEM_PROMPT_V2: "false", + COPILOT_EXP_COPILOT_CLI_STABILITY_ORDERED_SYSTEM_PROMPT_V2: "false", + }, }, }); @@ -277,7 +282,7 @@ describe("Subagent prompt resume", async () => { beforeAgentStart: (session: CopilotSession) => Promise = async () => {}, agentType = "explore", agentModel: string | null = "claude-sonnet-5" - ): Promise<[InferenceRequest, InferenceRequest]> { + ): Promise<[InferenceRequest, InferenceRequest, string]> { await writeFile(join(env.COPILOT_HOME, "settings.json"), "{}"); const requestBaseline = requestHandler.inferenceRequests.length; const session = await client.createSession({ @@ -321,7 +326,7 @@ describe("Subagent prompt resume", async () => { .slice(requestBaseline) .filter((request) => request.agentId === agentId && request.parentAgentId); expect(childRequests).toHaveLength(2); - return [childRequests[0]!, childRequests[1]!]; + return [childRequests[0]!, childRequests[1]!, session.sessionId]; } finally { const tasks = await session.rpc.tasks.list(); for (const task of tasks.tasks) { @@ -357,16 +362,104 @@ describe("Subagent prompt resume", async () => { } it("preserves the adapted prompt on an ordinary idle-agent wake", async () => { - const [initial, resumed] = await runResumeScenario(async () => {}); + const [initial, resumed, sessionId] = await runResumeScenario(async () => {}); expectAdaptedExplorePrompt(initial.systemPrompt); expect(resumed.systemPrompt).toBe(initial.systemPrompt); + const journal = await readFile( + join(env.COPILOT_HOME, "session-state", sessionId, "events.jsonl"), + "utf8" + ); + const events = journal + .trim() + .split("\n") + .map((line) => JSON.parse(line) as SessionEvent); + const childEvents = events.filter((event) => event.agentId === initial.agentId); + const childPrompts = childEvents.filter((event) => event.type === "system.message"); + expect(childPrompts).toHaveLength(1); + expect( + childEvents + .filter((event) => event.type === "assistant.message") + .map((event) => event.data.content) + ).toEqual(["SUBAGENT_TURN_COMPLETE", "SUBAGENT_TURN_COMPLETE"]); + const ids = new Set(events.map((event) => event.id)); + for (const event of events) { + if (event.parentId) { + expect(ids.has(event.parentId), `Missing parent of ${event.id}`).toBe(true); + } + } + await using reopened = await client.resumeSession(sessionId, { + model: "claude-sonnet-5", + onPermissionRequest: approveAll, + }); + const history = await reopened.getEvents(); + expect(history.find((event) => event.id === childPrompts[0]!.id)).toEqual(childPrompts[0]); + }); + + it("keeps legacy prompt blocks live while persisting only their reconstructible content", async () => { + const content = + "sharedlimits\n\nper-user instructions"; + const systemMessage = { + mode: "replace" as const, + content, + contentBlocks: [ + { + content: "sharedlimits", + isStatic: true, + }, + { content: "per-user instructions" }, + ], + }; + await using session = await client.createSession({ + model: "claude-sonnet-5", + systemMessage, + onPermissionRequest: approveAll, + }); + const livePrompts: SessionEvent[] = []; + const unsubscribe = session.on("system.message", (event) => livePrompts.push(event)); + try { + const response = await session.sendAndWait({ + prompt: "Reply with exactly SUBAGENT_TURN_COMPLETE.", + }); + expect(response?.data.content).toBe("SUBAGENT_TURN_COMPLETE"); + } finally { + unsubscribe(); + } + await session.disconnect(); + const live = livePrompts.find((event) => event.type === "system.message"); + expect(live?.type).toBe("system.message"); + if (live?.type !== "system.message") { + throw new Error("Expected a live system prompt."); + } + expect(live.data.content).toBe(content); + expect(live.data.contentBlocks).toEqual(systemMessage.contentBlocks); + const journal = await readFile( + join(env.COPILOT_HOME, "session-state", session.sessionId, "events.jsonl"), + "utf8" + ); + const persisted = journal + .trim() + .split("\n") + .map((line) => JSON.parse(line) as SessionEvent) + .find((event) => event.id === live.id); + expect(persisted?.type).toBe("system.message"); + if (persisted?.type !== "system.message") { + throw new Error("Expected the persisted system prompt."); + } + expect(persisted.data.content).toBe(content); + expect(persisted.data.contentBlocks).toBeUndefined(); + await using reopened = await client.resumeSession(session.sessionId, { + model: "claude-sonnet-5", + onPermissionRequest: approveAll, + }); + const history = await reopened.getEvents(); + expect(history.find((event) => event.id === live.id)).toEqual(persisted); }); capiIt.each(["minimal", "max", "xhigh", "none", "high"])( "reconciles a concrete child's composed %s effort on its first and resumed requests", async (effort) => { - const requests = await runResumeScenario( + const [initial, resumed] = await runResumeScenario( async () => {}, { customAgents: [ @@ -383,7 +476,7 @@ describe("Subagent prompt resume", async () => { null ); - for (const request of requests) { + for (const request of [initial, resumed]) { expect(request.model).toBe("gpt-5.4-mini"); expect(request.reasoningEffort).toBe(effort === "high" ? "high" : "medium"); } @@ -393,7 +486,7 @@ describe("Subagent prompt resume", async () => { capiIt( "reconciles an independently declared child effort without changing its model", async () => { - const requests = await runResumeScenario( + const [initial, resumed] = await runResumeScenario( async () => {}, { customAgents: [ @@ -411,7 +504,7 @@ describe("Subagent prompt resume", async () => { null ); - for (const request of requests) { + for (const request of [initial, resumed]) { expect(request.model).toBe("gpt-5.4-mini"); expect(request.reasoningEffort).toBe("medium"); } diff --git a/nodejs/test/e2e/telemetry.e2e.test.ts b/nodejs/test/e2e/telemetry.e2e.test.ts index 6d2915744e..3c6aecda89 100644 --- a/nodejs/test/e2e/telemetry.e2e.test.ts +++ b/nodejs/test/e2e/telemetry.e2e.test.ts @@ -186,6 +186,11 @@ describe("Telemetry export", async () => { `{"value":"${marker}"}` ); expect(getStringAttribute(toolSpan!, "gen_ai.tool.call.result")).toBe(marker); + expect(toolSpan!.attributes).not.toHaveProperty( + "github.copilot.tool.parameters.mcp_server_name_hash" + ); + expect(toolSpan!.attributes).not.toHaveProperty("github.copilot.mcp.server.transport"); + expect(toolSpan!.attributes).not.toHaveProperty("github.copilot.mcp.server.source"); }); it("should export per request subagent chat spans", { timeout: 90_000 }, async () => { diff --git a/nodejs/test/e2e/telemetry_preparation.e2e.test.ts b/nodejs/test/e2e/telemetry_preparation.e2e.test.ts new file mode 100644 index 0000000000..8c8f79c5a1 --- /dev/null +++ b/nodejs/test/e2e/telemetry_preparation.e2e.test.ts @@ -0,0 +1,170 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import { readFile, writeFile } from "node:fs/promises"; +import { join } from "node:path"; +import { describe, it, onTestFinished } from "vitest"; +import { z } from "zod"; +import { + type CopilotSession, + defineTool, + type PermissionRequestResult, + RuntimeConnection, + type SessionEvent, +} from "../../src/index.js"; +import { + createSdkTestContext, + DEFAULT_GITHUB_TOKEN, + getLegacyCliPathForTests, +} from "./harness/sdkTestContext.js"; + +async function telemetryWarnings(session: CopilotSession) { + return (await session.getEvents()).filter( + (event) => event.type === "session.warning" && event.data.warningType === "telemetry" + ); +} + +describe.each(["native", "legacy"] as const)("Telemetry preparation (%s)", async (host) => { + const policyFile = "managed-telemetry-policy.json"; + const telemetryFile = "session-telemetry.jsonl"; + const harness = await createSdkTestContext({ + copilotClientOptions: { + connection: RuntimeConnection.forStdio(), + env: { + COPILOT_E2E_TEST_HOOKS: "1", + COPILOT_TEST_MANAGED_SETTINGS_FILE_PATH: policyFile, + COPILOT_MANAGED_SETTINGS_CACHE: "false", + }, + }, + }); + + it("keeps create and resume usable after exporter failure", async ({ expect }) => { + await writeFile( + join(harness.workDir, policyFile), + JSON.stringify({ + telemetry: { + enabled: true, + endpoint: "ftp://collector.example", + headers: { "x-routing-key": "managed-value" }, + }, + }) + ); + const options = { + gitHubToken: DEFAULT_GITHUB_TOKEN, + connection: RuntimeConnection.forStdio({ + path: + host === "legacy" + ? await getLegacyCliPathForTests() + : process.env.COPILOT_CLI_PATH, + }), + telemetry: { + exporterType: "file" as const, + filePath: telemetryFile, + sourceName: "ts-sdk-telemetry-e2e", + captureContent: true, + }, + }; + const client = harness.createClient(options); + onTestFinished(() => client.stop()); + const receivedWarnings: SessionEvent[] = []; + const sessionOptions = { + enableManagedSettings: true, + onEvent: (event: SessionEvent) => { + if (event.type === "session.warning" && event.data.warningType === "telemetry") { + receivedWarnings.push(event); + } + }, + onPermissionRequest: (): PermissionRequestResult => ({ kind: "approve-once" }), + tools: [ + defineTool("echo_telemetry_marker", { + description: "Echoes a marker string for telemetry validation.", + parameters: z.object({ value: z.string() }), + handler: ({ value }) => value, + }), + ], + }; + const session = await client.createSession(sessionOptions); + const failedSessionId = session.sessionId; + const initialWarnings = await telemetryWarnings(session); + expect(initialWarnings).toMatchObject([ + { + data: { + warningType: "telemetry", + message: + "OpenTelemetry could not be initialized and is disabled for this session. You can continue using the session.", + }, + }, + ]); + const replay = { + filePath: join( + import.meta.dirname, + "..", + "..", + "..", + "test", + "snapshots", + "telemetry", + "should_export_file_telemetry_for_sdk_interactions.yaml" + ), + workDir: harness.workDir, + }; + const prompt = + "Use the echo_telemetry_marker tool with value 'copilot-sdk-telemetry-e2e', then respond with TELEMETRY_E2E_DONE."; + await harness.openAiEndpoint.updateConfig(replay); + const assistant = await session.sendAndWait({ prompt }, 90_000); + expect(assistant?.data.content).toContain("TELEMETRY_E2E_DONE"); + expect(receivedWarnings.map((event) => event.id)).toEqual( + initialWarnings.map((event) => event.id) + ); + await client.rpc.sessions.save({ sessionId: failedSessionId }); + const resident = await client.resumeSession(failedSessionId, sessionOptions); + expect(resident.sessionId).toBe(failedSessionId); + await expect(resident.rpc.model.getCurrent()).resolves.toHaveProperty("modelId"); + expect(await telemetryWarnings(resident)).toHaveLength(1); + await resident.disconnect(); + await session.disconnect(); + expect(await client.stop()).toEqual([]); + + const resumedClient = harness.createClient(options); + onTestFinished(() => resumedClient.stop()); + const cold = await resumedClient.resumeSession(failedSessionId, sessionOptions); + expect(cold.sessionId).toBe(failedSessionId); + await expect(cold.rpc.model.getCurrent()).resolves.toHaveProperty("modelId"); + expect(await telemetryWarnings(cold)).toHaveLength(1); + await cold.disconnect(); + + await writeFile(join(harness.workDir, policyFile), "{}"); + let healthyClient = resumedClient; + if (host === "legacy") { + // The legacy host retains its startup device policy until the next process. + expect(await resumedClient.stop()).toEqual([]); + healthyClient = harness.createClient(options); + onTestFinished(() => healthyClient.stop()); + } + const healthy = await healthyClient.createSession(sessionOptions); + await harness.openAiEndpoint.updateConfig(replay); + const healthyAssistant = await healthy.sendAndWait({ prompt }, 90_000); + expect(healthyAssistant?.data.content).toContain("TELEMETRY_E2E_DONE"); + expect(await telemetryWarnings(healthy)).toEqual([]); + await healthy.disconnect(); + expect(await healthyClient.stop()).toEqual([]); + + const entries: Array<{ attributes?: Record }> = ( + await readFile(join(harness.workDir, telemetryFile), "utf8") + ) + .split(/\r?\n/) + .filter(Boolean) + .map((line) => JSON.parse(line)); + expect( + entries.some( + (entry) => entry.attributes?.["gen_ai.conversation.id"] === healthy.sessionId + ) + ).toBe(true); + expect( + entries.some( + (entry) => entry.attributes?.["gen_ai.conversation.id"] === failedSessionId + ) + ).toBe(false); + }); +}); diff --git a/nodejs/test/e2e/tools_anthropic_updates.e2e.test.ts b/nodejs/test/e2e/tools_anthropic_updates.e2e.test.ts index 721b432ae1..71985070d7 100644 --- a/nodejs/test/e2e/tools_anthropic_updates.e2e.test.ts +++ b/nodejs/test/e2e/tools_anthropic_updates.e2e.test.ts @@ -2,15 +2,19 @@ * Copyright (c) Microsoft Corporation. All rights reserved. *--------------------------------------------------------------------------------------------*/ +import { writeFile } from "node:fs/promises"; +import { join } from "node:path"; import { describe, expect, it } from "vitest"; import { approveAll, CopilotRequestHandler, defineTool, type CopilotRequestContext, + type SessionConfig, } from "../../src/index.js"; import { createSdkTestContext } from "./harness/sdkTestContext.js"; import { waitForCondition } from "./harness/sdkTestHelper.js"; +import { mcpTestServerConfig } from "./harness/mcpTestServer.js"; interface AnthropicRequest { system: unknown; @@ -110,7 +114,11 @@ class AnthropicToolUpdateHandler extends CopilotRequestHandler { readonly requests: Array<{ body: AnthropicRequest; beta: string | null }> = []; constructor( - private readonly rejectPositionedUpdate: false | "before-output" | "after-output" = false + private readonly rejectPositionedUpdate: false | "before-output" | "after-output" = false, + private readonly addedTool: { name: string; input: Record } = { + name: "sdk_epoch_added", + input: {}, + } ) { super(); } @@ -119,7 +127,28 @@ class AnthropicToolUpdateHandler extends CopilotRequestHandler { request: Request, ctx: CopilotRequestContext ): Promise { - if (new URL(request.url).hostname !== "api.anthropic.com") { + const url = new URL(request.url); + if (url.pathname === "/models") { + return Response.json({ + data: [ + { + id: "claude-opus-5.5", + name: "Claude Opus 5.5", + vendor: "Anthropic", + model_picker_enabled: true, + supported_endpoints: ["/v1/messages"], + capabilities: { + type: "chat", + family: "claude-opus-5.5", + tokenizer: "o200k_base", + limits: { max_context_window_tokens: 200000, max_output_tokens: 32000 }, + supports: { streaming: true, tool_calls: true }, + }, + }, + ], + }); + } + if (!url.pathname.endsWith("/messages")) { return super.sendRequest(request, ctx); } const body = (await request.json()) as AnthropicRequest; @@ -133,6 +162,27 @@ class AnthropicToolUpdateHandler extends CopilotRequestHandler { } this.requests.push({ body, beta: request.headers.get("anthropic-beta") }); + if ( + body.messages.some( + (message) => + message.role !== "system" && + Array.isArray(message.content) && + message.content.some((block: { type?: string }) => + ["tool_addition", "tool_removal"].includes(block.type ?? "") + ) + ) + ) { + return Response.json( + { + error: { + type: "invalid_request_error", + message: "tool_addition/tool_removal require role: system", + }, + }, + { status: 400 } + ); + } + if (serialized.includes("SDK_ANTHROPIC_FOLLOW_UP")) { return streamResponse({ type: "text", text: "SDK_ANTHROPIC_LEGACY_OK" }, "end_turn"); } @@ -167,7 +217,7 @@ class AnthropicToolUpdateHandler extends CopilotRequestHandler { ); } return streamResponse( - { type: "tool_use", id: "toolu_sdk_added", name: "sdk_epoch_added", input: {} }, + { type: "tool_use", id: "toolu_sdk_added", ...this.addedTool }, "tool_use" ); } @@ -181,6 +231,426 @@ describe("SDK tool updates on direct Anthropic Messages", async () => { copilotClientOptions: { requestHandler: handler }, }); + describe("MCP tool updates on direct Anthropic Messages", async () => { + const toolName = "a_server-get_env"; + const handler = new AnthropicToolUpdateHandler(false, { + name: toolName, + input: { name: "CACHE_TEST_RESULT" }, + }); + const { copilotClient: client, workDir } = await createSdkTestContext({ + copilotClientOptions: { requestHandler: handler }, + }); + + const routes: Array<{ name: string; config: Partial }> = [ + { + name: "direct BYOK", + config: { + provider: { + type: "anthropic", + baseUrl: "https://api.anthropic.com", + apiKey: "synthetic-provider-key", + modelId: "claude-opus-5.5", + wireModel: "claude-opus-5.5", + }, + }, + }, + { + name: "compatible BYOK proxy", + config: { + provider: { + type: "anthropic", + baseUrl: "https://messages.example.test", + apiKey: "synthetic-provider-key", + modelId: "claude-opus-5.5", + wireModel: "claude-opus-5.5", + }, + }, + }, + { name: "CAPI", config: {} }, + ]; + for (const route of routes) { + it(`keeps the serialized prefix on ${route.name} when enabling an MCP server adds tools before existing ones`, async () => { + const config = mcpTestServerConfig("SDK_ADDED_TOOL_RESULT"); + const beforeRequests = handler.requests.length; + const session = await client.createSession({ + model: "claude-opus-5.5", + toolSearch: { enabled: false }, + onPermissionRequest: approveAll, + ...route.config, + mcpServers: { z_server: config, a_server: config }, + disabledMcpServers: ["a_server"], + }); + try { + await session.rpc.tools.initializeAndValidate(); + expect( + (await session.rpc.tools.getCurrentMetadata()).tools.map( + (tool) => tool.name + ) + ).toContain("z_server-get_env"); + expect( + (await session.rpc.tools.getCurrentMetadata()).tools.map( + (tool) => tool.name + ) + ).not.toContain(toolName); + const first = await session.sendAndWait({ prompt: "SDK_ANTHROPIC_FIRST" }); + expect(first?.data.content).toContain("SDK_ANTHROPIC_FIRST_OK"); + + await session.rpc.mcp.setEnvValueMode({ mode: "direct" }); + await session.rpc.mcp.enable({ serverName: "a_server" }); + await session.rpc.tools.initializeAndValidate(); + expect( + (await session.rpc.tools.getCurrentMetadata()).tools.map( + (tool) => tool.name + ) + ).toContain(toolName); + const second = await session.sendAndWait({ + prompt: `SDK_ANTHROPIC_AFTER: call ${toolName}.`, + }); + expect(second?.data.content).toContain("SDK_ANTHROPIC_TOOL_OK"); + + const requests = handler.requests.slice(beforeRequests); + expect(requests).toHaveLength(3); + const [before, update, afterTool] = requests; + expect(before.body.tools).toEqual( + expect.arrayContaining([ + expect.objectContaining({ name: "z_server-get_env" }), + ]) + ); + expect(JSON.stringify(before.body.tools)).not.toContain(`"name":"${toolName}"`); + for (const request of [update, afterTool]) { + expect(JSON.stringify(request.body.system)).toBe( + JSON.stringify(before.body.system) + ); + expect(JSON.stringify(request.body.tools)).toBe( + JSON.stringify(before.body.tools) + ); + } + expect(update.body.messages).toContainEqual( + expect.objectContaining({ + role: "system", + content: [ + expect.objectContaining({ + type: "tool_addition", + tool: expect.objectContaining({ + type: "tool_definition", + definition: expect.objectContaining({ name: toolName }), + }), + }), + ], + }) + ); + expect(update.beta).toContain("inline-tools-2026-09-15"); + expect(JSON.stringify(afterTool.body.messages)).toContain( + "SDK_ADDED_TOOL_RESULT" + ); + expect( + (await session.rpc.tools.getCurrentMetadata()).tools.map( + (tool) => tool.name + ) + ).toEqual(expect.arrayContaining(["a_server-get_env", "z_server-get_env"])); + } finally { + await session.disconnect(); + } + }); + } + + describe("CAPI Messages compatibility", async () => { + const handler = new AnthropicToolUpdateHandler(); + const { copilotClient: client } = await createSdkTestContext({ + copilotClientOptions: { requestHandler: handler }, + }); + it("preserves the prefix across CAPI reordering, removal and restoration without a rejected attempt", async () => { + let addedCalls = 0; + const original = { + name: "sdk_epoch_original", + description: "Original SDK tool", + parameters: { type: "object", properties: {} }, + defer: "never", + } as const; + const added = { + ...original, + name: "sdk_epoch_added", + description: "Added SDK tool", + }; + const session = await client.createSession({ + model: "claude-opus-5.5", + toolSearch: { enabled: false }, + onPermissionRequest: approveAll, + availableTools: [original.name, added.name], + tools: [ + defineTool(original.name, { + description: original.description, + handler: () => "original", + }), + defineTool(added.name, { + description: added.description, + handler: () => { + addedCalls++; + return "SDK_ADDED_TOOL_RESULT"; + }, + }), + ], + }); + try { + await session.rpc.tools.initializeAndValidate(); + await session.rpc.tools.set({ tools: [original, added] }); + expect( + (await session.sendAndWait({ prompt: "SDK_ANTHROPIC_FIRST" }))?.data.content + ).toContain("SDK_ANTHROPIC_FIRST_OK"); + await session.rpc.tools.set({ tools: [added, original] }); + expect( + (await session.sendAndWait({ prompt: "SDK_ANTHROPIC_FIRST_REORDERED" })) + ?.data.content + ).toContain("SDK_ANTHROPIC_FIRST_OK"); + await session.rpc.tools.set({ tools: [original] }); + expect( + (await session.sendAndWait({ prompt: "SDK_ANTHROPIC_FIRST_REMOVED" }))?.data + .content + ).toContain("SDK_ANTHROPIC_FIRST_OK"); + await session.rpc.tools.set({ tools: [added, original] }); + expect( + ( + await session.sendAndWait({ + prompt: "SDK_ANTHROPIC_AFTER: call sdk_epoch_added.", + }) + )?.data.content + ).toContain("SDK_ANTHROPIC_TOOL_OK"); + expect(addedCalls).toBe(1); + expect(handler.requests).toHaveLength(5); + const [before, reordered, removed, restored, afterTool] = handler.requests; + expect(JSON.stringify(reordered.body.tools)).toBe( + JSON.stringify(before.body.tools) + ); + expect(removed.body.messages).toContainEqual({ + role: "system", + content: [ + { + type: "tool_removal", + tool: { type: "tool_reference", name: added.name }, + }, + ], + }); + expect(removed.beta).toContain("mid-conversation-tool-changes-2026-07-01"); + expect(restored.body.messages).toContainEqual( + expect.objectContaining({ + role: "system", + content: [ + expect.objectContaining({ + type: "tool_addition", + tool: expect.objectContaining({ + definition: expect.objectContaining({ name: added.name }), + }), + }), + ], + }) + ); + expect(restored.beta).toContain("inline-tools-2026-09-15"); + expect(JSON.stringify(afterTool.body.messages)).toContain( + "SDK_ADDED_TOOL_RESULT" + ); + for (const request of handler.requests) { + expect(JSON.stringify(request.body.system)).toBe( + JSON.stringify(before.body.system) + ); + expect(JSON.stringify(request.body.tools)).toBe( + JSON.stringify(before.body.tools) + ); + } + } finally { + await session.disconnect(); + } + }); + }); + + it.each(routes)( + "keeps the prefix across MCP removal and restoration on $name and executes the restored tool", + async (route) => { + const config = mcpTestServerConfig("SDK_ADDED_TOOL_RESULT"); + const beforeRequests = handler.requests.length; + const session = await client.createSession({ + model: "claude-opus-5.5", + toolSearch: { enabled: false }, + onPermissionRequest: approveAll, + availableTools: [toolName, "z_server-get_env"], + ...route.config, + mcpServers: { a_server: config, z_server: config }, + }); + try { + await session.rpc.mcp.setEnvValueMode({ mode: "direct" }); + await session.rpc.tools.initializeAndValidate(); + expect( + (await session.rpc.tools.getCurrentMetadata()).tools.map( + (tool) => tool.name + ) + ).toEqual(expect.arrayContaining([toolName, "z_server-get_env"])); + expect( + (await session.sendAndWait({ prompt: "SDK_ANTHROPIC_FIRST" }))?.data.content + ).toContain("SDK_ANTHROPIC_FIRST_OK"); + + await session.rpc.mcp.disable({ serverName: "a_server" }); + await session.rpc.tools.initializeAndValidate(); + // Tool metadata includes the previous request; the host reports live availability. + const disabled = await session.rpc.mcp.list(); + expect(disabled.host?.disabledServers).toContain("a_server"); + expect(disabled.host?.disabledServers).not.toContain("z_server"); + expect(disabled.servers).toContainEqual( + expect.objectContaining({ name: "a_server", status: "disabled" }) + ); + expect( + (await session.sendAndWait({ prompt: "SDK_ANTHROPIC_FIRST_REMOVED" }))?.data + .content + ).toContain("SDK_ANTHROPIC_FIRST_OK"); + + await session.rpc.mcp.enable({ serverName: "a_server" }); + await session.rpc.tools.initializeAndValidate(); + expect( + (await session.rpc.tools.getCurrentMetadata()).tools.map( + (tool) => tool.name + ) + ).toContain(toolName); + expect( + ( + await session.sendAndWait({ + prompt: `SDK_ANTHROPIC_AFTER: call ${toolName}.`, + }) + )?.data.content + ).toContain("SDK_ANTHROPIC_TOOL_OK"); + + const requests = handler.requests.slice(beforeRequests); + expect(requests).toHaveLength(4); + const [before, removed, restored, afterTool] = requests; + expect(before.body.tools).toEqual( + expect.arrayContaining([expect.objectContaining({ name: toolName })]) + ); + for (const request of [removed, restored, afterTool]) { + expect(JSON.stringify(request.body.system)).toBe( + JSON.stringify(before.body.system) + ); + expect(JSON.stringify(request.body.tools)).toBe( + JSON.stringify(before.body.tools) + ); + } + const blocks = (request: AnthropicRequest) => + request.messages.flatMap((message) => + Array.isArray(message.content) ? message.content : [] + ); + expect(blocks(removed.body)).toContainEqual({ + type: "tool_removal", + tool: { type: "tool_reference", name: toolName }, + }); + expect(removed.beta).toContain("mid-conversation-tool-changes-2026-07-01"); + expect(restored.beta).toContain("inline-tools-2026-09-15"); + expect( + blocks(restored.body) + .filter((block) => + ["tool_removal", "tool_addition"].includes(block.type) + ) + .map((block) => block.type) + ).toEqual(["tool_removal", "tool_addition"]); + expect(blocks(restored.body)).toContainEqual( + expect.objectContaining({ + type: "tool_addition", + tool: expect.objectContaining({ + definition: expect.objectContaining({ name: toolName }), + }), + }) + ); + expect(JSON.stringify(afterTool.body.messages)).toContain( + "SDK_ADDED_TOOL_RESULT" + ); + } finally { + await session.disconnect(); + } + } + ); + + it.each(routes)( + "replaces a refreshed MCP definition inline on $name and executes the restarted server", + async (route) => { + const descriptionFile = join(workDir, `tool-description-${route.name}.txt`); + await writeFile(descriptionFile, "MCP_ORIGINAL_DESCRIPTION"); + const beforeRequests = handler.requests.length; + const session = await client.createSession({ + model: "claude-opus-5.5", + toolSearch: { enabled: false }, + onPermissionRequest: approveAll, + ...route.config, + mcpServers: { + a_server: mcpTestServerConfig("SDK_ADDED_TOOL_RESULT", descriptionFile), + }, + }); + try { + await session.rpc.mcp.setEnvValueMode({ mode: "direct" }); + await session.rpc.tools.initializeAndValidate(); + expect( + (await session.rpc.tools.getCurrentMetadata()).tools.find( + (tool) => tool.name === toolName + )?.description + ).toContain("MCP_ORIGINAL_DESCRIPTION"); + expect( + (await session.sendAndWait({ prompt: "SDK_ANTHROPIC_FIRST" }))?.data.content + ).toContain("SDK_ANTHROPIC_FIRST_OK"); + + await writeFile(descriptionFile, "MCP_REPLACEMENT_DESCRIPTION"); + await session.rpc.mcp.restartServer({ serverName: "a_server" }); + await session.rpc.tools.initializeAndValidate(); + expect( + (await session.rpc.tools.getCurrentMetadata()).tools.find( + (tool) => tool.name === toolName + )?.description + ).toContain("MCP_REPLACEMENT_DESCRIPTION"); + expect( + ( + await session.sendAndWait({ + prompt: `SDK_ANTHROPIC_AFTER: call ${toolName}.`, + }) + )?.data.content + ).toContain("SDK_ANTHROPIC_TOOL_OK"); + + const requests = handler.requests.slice(beforeRequests); + expect(requests).toHaveLength(3); + const [before, update, afterTool] = requests; + expect(before.body.tools).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + name: toolName, + description: expect.stringContaining("MCP_ORIGINAL_DESCRIPTION"), + }), + ]) + ); + for (const request of [update, afterTool]) { + expect(JSON.stringify(request.body.system)).toBe( + JSON.stringify(before.body.system) + ); + expect(JSON.stringify(request.body.tools)).toBe( + JSON.stringify(before.body.tools) + ); + } + const additions = update.body.messages + .flatMap((message) => + Array.isArray(message.content) ? message.content : [] + ) + .filter((block) => block.type === "tool_addition"); + expect(additions).toHaveLength(1); + expect(additions[0]).toMatchObject({ + tool: { + definition: { + name: toolName, + description: expect.stringContaining("MCP_REPLACEMENT_DESCRIPTION"), + }, + }, + }); + expect(update.beta).toContain("inline-tools-2026-09-15"); + expect(JSON.stringify(afterTool.body.messages)).toContain( + "SDK_ADDED_TOOL_RESULT" + ); + } finally { + await session.disconnect(); + } + } + ); + }); + it("keeps the top-level prefix and executes a newly added inline tool", async () => { let addedToolCalls = 0; const session = await client.createSession({ @@ -263,149 +733,169 @@ describe("SDK tool updates on direct Anthropic Messages", async () => { }); }); -describe("SDK tool updates on direct Anthropic Messages", async () => { - const rejectingHandler = new AnthropicToolUpdateHandler("before-output"); - const { copilotClient: retryClient } = await createSdkTestContext({ - copilotClientOptions: { requestHandler: rejectingHandler }, - }); - - it("retries a rejected inline update once with the full current tools", async () => { - const original = { - name: "sdk_epoch_original", - description: "Original SDK tool", - parameters: { type: "object", properties: {} }, - defer: "never", - } as const; - const added = { - name: "sdk_epoch_added", - description: "Added SDK tool", - parameters: { type: "object", properties: {} }, - defer: "never", - } as const; - const session = await retryClient.createSession({ - model: "claude-opus-5.5", - toolSearch: { enabled: false }, - onPermissionRequest: approveAll, - provider: { - type: "anthropic", - baseUrl: "https://api.anthropic.com", - apiKey: "synthetic-provider-key", - modelId: "claude-opus-5.5", - wireModel: "claude-opus-5.5", - }, - tools: [ - defineTool(original.name, { - description: original.description, - handler: () => "original", - }), - defineTool(added.name, { description: added.description, handler: () => "added" }), - ], +describe.each(["BYOK", "CAPI"])( + "SDK tool update recovery on %s Anthropic Messages", + async (route) => { + const rejectingHandler = new AnthropicToolUpdateHandler("before-output"); + const { copilotClient: retryClient } = await createSdkTestContext({ + copilotClientOptions: { requestHandler: rejectingHandler }, }); - try { - await session.rpc.tools.initializeAndValidate(); - await session.rpc.tools.set({ tools: [original] }); - const first = await session.sendAndWait({ prompt: "SDK_ANTHROPIC_FIRST" }); - expect(first?.data.content).toContain("SDK_ANTHROPIC_FIRST_OK"); - await session.rpc.tools.set({ tools: [original, added] }); - const recovered = await session.sendAndWait({ - prompt: "SDK_ANTHROPIC_AFTER: add a tool.", + it("retries a rejected inline update once with the full current tools", async () => { + const original = { + name: "sdk_epoch_original", + description: "Original SDK tool", + parameters: { type: "object", properties: {} }, + defer: "never", + } as const; + const added = { + name: "sdk_epoch_added", + description: "Added SDK tool", + parameters: { type: "object", properties: {} }, + defer: "never", + } as const; + const session = await retryClient.createSession({ + model: "claude-opus-5.5", + toolSearch: { enabled: false }, + onPermissionRequest: approveAll, + provider: + route === "BYOK" + ? { + type: "anthropic", + baseUrl: "https://api.anthropic.com", + apiKey: "synthetic-provider-key", + modelId: "claude-opus-5.5", + wireModel: "claude-opus-5.5", + } + : undefined, + tools: [ + defineTool(original.name, { + description: original.description, + handler: () => "original", + }), + defineTool(added.name, { + description: added.description, + handler: () => "added", + }), + ], }); - expect(recovered?.data.content).toContain("SDK_ANTHROPIC_RECOVERED"); - expect(rejectingHandler.requests).toHaveLength(3); - const [before, rejected, retry] = rejectingHandler.requests; - expect(rejected.body.system).toEqual(before.body.system); - expect(rejected.body.tools).toEqual(before.body.tools); - expect(JSON.stringify(rejected.body.messages)).toContain('"type":"tool_addition"'); - expect(rejected.beta).toContain("inline-tools-2026-09-15"); - expect(retry.body.system).toEqual(before.body.system); - expect((retry.body.tools as Array<{ name: string }>).map((tool) => tool.name)).toEqual( - expect.arrayContaining([original.name, added.name]) - ); - expect(JSON.stringify(retry.body.messages)).not.toContain('"type":"tool_addition"'); - expect(retry.beta).not.toContain("inline-tools-2026-09-15"); - } finally { - await session.disconnect(); - } - }); -}); - -describe("SDK tool updates after a streamed Anthropic rejection", async () => { - const handler = new AnthropicToolUpdateHandler("after-output"); - const { copilotClient: client } = await createSdkTestContext({ - copilotClientOptions: { requestHandler: handler }, - }); + try { + await session.rpc.tools.initializeAndValidate(); + await session.rpc.tools.set({ tools: [original] }); + const first = await session.sendAndWait({ prompt: "SDK_ANTHROPIC_FIRST" }); + expect(first?.data.content).toContain("SDK_ANTHROPIC_FIRST_OK"); - it("disables the rejected epoch without replaying output and uses full tools next turn", async () => { - const original = { - name: "sdk_epoch_original", - description: "Original SDK tool", - parameters: { type: "object", properties: {} }, - defer: "never", - } as const; - const added = { - name: "sdk_epoch_added", - description: "Added SDK tool", - parameters: { type: "object", properties: {} }, - defer: "never", - } as const; - const session = await client.createSession({ - model: "claude-opus-5.5", - toolSearch: { enabled: false }, - onPermissionRequest: approveAll, - provider: { - type: "anthropic", - baseUrl: "https://api.anthropic.com", - apiKey: "synthetic-provider-key", - modelId: "claude-opus-5.5", - wireModel: "claude-opus-5.5", - }, - tools: [ - defineTool(original.name, { - description: original.description, - handler: () => "original", - }), - defineTool(added.name, { description: added.description, handler: () => "added" }), - ], - }); - let failedTurnIdle = false; - const unsubscribe = session.on((event) => { - if (event.type === "session.idle" && !event.agentId) { - failedTurnIdle = true; + await session.rpc.tools.set({ tools: [original, added] }); + const recovered = await session.sendAndWait({ + prompt: "SDK_ANTHROPIC_AFTER: add a tool.", + }); + expect(recovered?.data.content).toContain("SDK_ANTHROPIC_RECOVERED"); + expect(rejectingHandler.requests).toHaveLength(3); + const [before, rejected, retry] = rejectingHandler.requests; + expect(rejected.body.system).toEqual(before.body.system); + expect(rejected.body.tools).toEqual(before.body.tools); + expect(JSON.stringify(rejected.body.messages)).toContain('"type":"tool_addition"'); + expect(rejected.beta).toContain("inline-tools-2026-09-15"); + expect(retry.body.system).toEqual(before.body.system); + expect( + (retry.body.tools as Array<{ name: string }>).map((tool) => tool.name) + ).toEqual(expect.arrayContaining([original.name, added.name])); + expect(JSON.stringify(retry.body.messages)).not.toContain('"type":"tool_addition"'); + expect(retry.beta).not.toContain("inline-tools-2026-09-15"); + } finally { + await session.disconnect(); } }); - try { - await session.rpc.tools.initializeAndValidate(); - await session.rpc.tools.set({ tools: [original] }); - const first = await session.sendAndWait({ prompt: "SDK_ANTHROPIC_FIRST" }); - expect(first?.data.content).toContain("SDK_ANTHROPIC_FIRST_OK"); - failedTurnIdle = false; + } +); - await session.rpc.tools.set({ tools: [original, added] }); - await expect( - session.sendAndWait({ prompt: "SDK_ANTHROPIC_AFTER: add a tool." }) - ).rejects.toThrow(/invalid tool_addition/); - await waitForCondition(() => failedTurnIdle, { - timeoutMessage: "Rejected SDK tool update did not reach session.idle", +describe.each(["BYOK", "CAPI"])( + "SDK tool updates after a streamed %s Anthropic rejection", + async (route) => { + const handler = new AnthropicToolUpdateHandler("after-output"); + const { copilotClient: client } = await createSdkTestContext({ + copilotClientOptions: { requestHandler: handler }, + }); + + it("disables the rejected epoch without replaying output and uses full tools next turn", async () => { + const original = { + name: "sdk_epoch_original", + description: "Original SDK tool", + parameters: { type: "object", properties: {} }, + defer: "never", + } as const; + const added = { + name: "sdk_epoch_added", + description: "Added SDK tool", + parameters: { type: "object", properties: {} }, + defer: "never", + } as const; + const session = await client.createSession({ + model: "claude-opus-5.5", + toolSearch: { enabled: false }, + onPermissionRequest: approveAll, + provider: + route === "BYOK" + ? { + type: "anthropic", + baseUrl: "https://api.anthropic.com", + apiKey: "synthetic-provider-key", + modelId: "claude-opus-5.5", + wireModel: "claude-opus-5.5", + } + : undefined, + tools: [ + defineTool(original.name, { + description: original.description, + handler: () => "original", + }), + defineTool(added.name, { + description: added.description, + handler: () => "added", + }), + ], }); - expect(handler.requests).toHaveLength(2); - const [before, rejected] = handler.requests; - expect(rejected.body.system).toEqual(before.body.system); - expect(rejected.body.tools).toEqual(before.body.tools); - expect(JSON.stringify(rejected.body.messages)).toContain('"type":"tool_addition"'); - - const followUp = await session.sendAndWait({ prompt: "SDK_ANTHROPIC_FOLLOW_UP" }); - expect(followUp?.data.content).toContain("SDK_ANTHROPIC_LEGACY_OK"); - expect(handler.requests).toHaveLength(3); - const request = handler.requests[2]; - expect( - (request.body.tools as Array<{ name: string }>).map((tool) => tool.name) - ).toEqual(expect.arrayContaining([original.name, added.name])); - expect(JSON.stringify(request.body.messages)).not.toContain('"type":"tool_addition"'); - expect(request.beta).not.toContain("inline-tools-2026-09-15"); - } finally { - unsubscribe(); - await session.disconnect(); - } - }); -}); + let failedTurnIdle = false; + const unsubscribe = session.on((event) => { + if (event.type === "session.idle" && !event.agentId) { + failedTurnIdle = true; + } + }); + try { + await session.rpc.tools.initializeAndValidate(); + await session.rpc.tools.set({ tools: [original] }); + const first = await session.sendAndWait({ prompt: "SDK_ANTHROPIC_FIRST" }); + expect(first?.data.content).toContain("SDK_ANTHROPIC_FIRST_OK"); + failedTurnIdle = false; + + await session.rpc.tools.set({ tools: [original, added] }); + await expect( + session.sendAndWait({ prompt: "SDK_ANTHROPIC_AFTER: add a tool." }) + ).rejects.toThrow(/invalid tool_addition/); + await waitForCondition(() => failedTurnIdle, { + timeoutMessage: "Rejected SDK tool update did not reach session.idle", + }); + expect(handler.requests).toHaveLength(2); + const [before, rejected] = handler.requests; + expect(rejected.body.system).toEqual(before.body.system); + expect(rejected.body.tools).toEqual(before.body.tools); + expect(JSON.stringify(rejected.body.messages)).toContain('"type":"tool_addition"'); + + const followUp = await session.sendAndWait({ prompt: "SDK_ANTHROPIC_FOLLOW_UP" }); + expect(followUp?.data.content).toContain("SDK_ANTHROPIC_LEGACY_OK"); + expect(handler.requests).toHaveLength(3); + const request = handler.requests[2]; + expect( + (request.body.tools as Array<{ name: string }>).map((tool) => tool.name) + ).toEqual(expect.arrayContaining([original.name, added.name])); + expect(JSON.stringify(request.body.messages)).not.toContain( + '"type":"tool_addition"' + ); + expect(request.beta).not.toContain("inline-tools-2026-09-15"); + } finally { + unsubscribe(); + await session.disconnect(); + } + }); + } +); diff --git a/nodejs/test/e2e/user_settings_edit.e2e.test.ts b/nodejs/test/e2e/user_settings_edit.e2e.test.ts new file mode 100644 index 0000000000..857a1bfdcf --- /dev/null +++ b/nodejs/test/e2e/user_settings_edit.e2e.test.ts @@ -0,0 +1,63 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import { mkdirSync, readFileSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; +import { describe, expect, it } from "vitest"; +import { editUserSettings } from "../../examples/internal-user-settings.js"; +import { createSdkTestContext } from "./harness/sdkTestContext.js"; + +describe("Internal user settings edit contract", async () => { + const { copilotClient: client, workDir, env } = await createSdkTestContext(); + + it("runs the edit example and preserves settings-only reads and safe writes", async () => { + await client.start(); + // These host-only methods deliberately stay off the public SDK surface. + const settings = client["internalRpc"].user.settings; + const home = env.COPILOT_HOME; + writeFileSync(join(home, "config.json"), '{"voice":{"enabled":false}}'); + writeFileSync(join(home, "settings.json"), '{"voice":{"selectedModel":"local"}}'); + + expect(await settings.loadForEdit()).toEqual({ + status: "ok", + settings: { voice: { selectedModel: "local" } }, + }); + + const configDir = join(workDir, "example-config"); + mkdirSync(configDir); + const result = await editUserSettings(settings, configDir); + expect(result).toEqual({ value: { enabled: true, selectedModel: null } }); + expect(JSON.parse(readFileSync(join(configDir, "settings.json"), "utf8"))).toEqual({ + voice: result.value, + }); + console.log("Internal settings example:", JSON.stringify(result)); + + await settings.update({ + key: "voice", + value: { enabled: false }, + configDir, + subDir: "profile", + }); + expect(JSON.parse(readFileSync(join(configDir, "settings/profile.json"), "utf8"))).toEqual({ + voice: { enabled: false }, + }); + await expect( + settings.update({ + key: "voice", + value: { enabled: false }, + configDir, + subDir: "../../outside", + }) + ).rejects.toThrow("`subDir` must be a single path component"); + + const file = join(configDir, "settings.json"); + const original = "{ invalid settings"; + writeFileSync(file, original); + await expect( + settings.update({ key: "voice", value: { enabled: false }, configDir }) + ).rejects.toThrow("refusing to overwrite settings.json"); + expect(readFileSync(file, "utf8")).toBe(original); + expect(await settings.validate({ topKey: "voice", delete: true })).toEqual({ ok: true }); + }); +}); diff --git a/nodejs/test/e2e/workflow.e2e.test.ts b/nodejs/test/e2e/workflow.e2e.test.ts index 349c7b7783..5d2673ea40 100644 --- a/nodejs/test/e2e/workflow.e2e.test.ts +++ b/nodejs/test/e2e/workflow.e2e.test.ts @@ -532,10 +532,15 @@ it("allows a module-level extension watcher to start a workflow while another bo const extensionDir = join(workDir, ".github", "extensions", "workflow-smoke"); await using session = await setupWorkflowExtension(workDir); - const parked = Promise.allSettled([ - session.workflow.run("parked", { notifyOnComplete: false }), - ]); + // Admission must finish before starting the body-entry deadline. + const parked = await session.rpc.workflow.run({ + name: "parked", + args: {}, + options: { notifyOnComplete: false }, + }); + const completion = Promise.allSettled([session.workflow.waitForRun(parked.runId)]); try { + expect(parked.status).toBe("running"); await retry( "wait for the parked workflow to enter its body", async () => { @@ -564,14 +569,14 @@ it("allows a module-level extension watcher to start a workflow while another bo ); } finally { writeFileSync(join(extensionDir, "release"), "release"); - const [outcome] = await parked; + const [outcome] = await completion; if (outcome.status === "rejected") { console.error("Parked workflow failed during cleanup:", outcome.reason); } else if (outcome.value.status !== "completed") { console.error("Parked workflow did not complete during cleanup:", outcome.value); } } - await expect(parked).resolves.toMatchObject([ + await expect(completion).resolves.toMatchObject([ { status: "fulfilled", value: { status: "completed", result: "released" }, diff --git a/nodejs/test/java-codegen.test.ts b/nodejs/test/java-codegen.test.ts index d44fb039a5..62c3027584 100644 --- a/nodejs/test/java-codegen.test.ts +++ b/nodejs/test/java-codegen.test.ts @@ -1,6 +1,11 @@ +import type { JSONSchema7 } from "json-schema"; import { describe, expect, it } from "vitest"; -import { renderRpcTypes, renderRpcWrappers } from "../../java/scripts/codegen/java.ts"; +import { + generateRpcClass, + renderRpcTypes, + renderRpcWrappers, +} from "../../java/scripts/codegen/java.ts"; function rpcSource(files: Map, name: string): string { const source = files.get( @@ -10,6 +15,89 @@ function rpcSource(files: Map, name: string): string { return source!; } +it("preserves boolean-map RPC results without widening them to JsonNode", async () => { + const files = await renderRpcWrappers({ + server: { + sample: { + flags: { + rpcMethod: "sample.flags", + params: null, + result: { type: "object", additionalProperties: { type: "boolean" } }, + }, + document: { + rpcMethod: "sample.document", + params: null, + result: { type: "object", additionalProperties: true }, + }, + }, + }, + }); + const source = rpcSource(files, "ServerSampleApi"); + expect(source).toContain("import java.util.Map;"); + expect(source).toContain("CompletableFuture> flags()"); + expect(source).toContain("constructMapType(Map.class, String.class, Boolean.class)"); + expect(source).toContain("CompletableFuture document()"); +}); + +describe("Java required opaque JSON parameters", () => { + it.each([ + ["user", "applyTopKey"], + ["repo", "writeKey"], + ])("preserves optional value presence in %s.settings.%s", async (namespace, action) => { + const rpcMethod = `${namespace}.settings.${action}`; + const files = await renderRpcWrappers({ + server: { + [namespace]: { + settings: { + [action]: { + rpcMethod, + params: { + type: "object", + properties: { + value: { "x-opaque-json": true } as JSONSchema7, + delete: { type: "boolean" }, + }, + }, + result: null, + }, + }, + }, + }, + }); + const source = rpcSource( + files, + `Server${namespace === "user" ? "User" : "Repo"}SettingsApi` + ); + expect(source).toContain(`return caller.invoke("${rpcMethod}", params, Void.class);`); + expect(source).not.toContain('putNull("value")'); + }); + + it("preserves a required JSON null without emitting absent optional fields", () => { + const opaque = { "x-opaque-json": true } as JSONSchema7; + const { code } = generateRpcClass( + "SettingsUpdateParams", + { + type: "object", + required: ["value"], + properties: { + value: opaque, + optionalValue: opaque, + }, + }, + new Map(), + "com.github.copilot.generated.rpc", + "internal", + true + ); + expect(code).toContain( + '@JsonInclude(JsonInclude.Include.ALWAYS)\n @JsonProperty("value") Object value' + ); + expect(code).not.toContain( + '@JsonInclude(JsonInclude.Include.ALWAYS)\n @JsonProperty("optionalValue")' + ); + }); +}); + describe("java RPC codegen visibility", () => { const schema = { server: { diff --git a/nodejs/test/reasoning-summaries-types.test.ts b/nodejs/test/reasoning-summaries-types.test.ts new file mode 100644 index 0000000000..556b6765b4 --- /dev/null +++ b/nodejs/test/reasoning-summaries-types.test.ts @@ -0,0 +1,19 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import { expectTypeOf, it } from "vitest"; +import type { + CopilotSession, + ModelGetReasoningSummariesRequest, + ModelGetReasoningSummariesResult, +} from "../src/index.js"; + +it("exports reasoning-summary request and result types from the package root", () => { + expectTypeOf().toEqualTypeOf< + Parameters[0] + >(); + expectTypeOf().toEqualTypeOf< + Awaited> + >(); +}); diff --git a/nodejs/test/rust-codegen.test.ts b/nodejs/test/rust-codegen.test.ts index 53c471b104..ce3ee6b426 100644 --- a/nodejs/test/rust-codegen.test.ts +++ b/nodejs/test/rust-codegen.test.ts @@ -821,6 +821,42 @@ pub enum ${name} { }); describe("Rust x-legacy-parameters", () => { + it.each(["server", "session"] as const)( + "serializes unrelated %s requests and options by value", + (scope) => { + const { schema } = legacyRequestSchema(1, scope); + const rpc = generateRpcCode(schema); + expect(rpc.match(/serde_json::to_value\(params\)\?/g)).toHaveLength(2); + expect(rpc).not.toContain("serde_json::to_value(¶ms)"); + } + ); + + it("preserves optional settings value presence without inserting null", () => { + const rpc = generateRpcCode({ + server: { + user: { + settings: { + applyTopKey: { + rpcMethod: "user.settings.applyTopKey", + params: { + type: "object", + properties: { + topKey: { type: "string" }, + value: { "x-opaque-json": true } as JSONSchema7, + delete: { type: "boolean" }, + }, + required: ["topKey"], + }, + result: { type: "object" }, + }, + }, + }, + }, + }); + expect(rpc).toContain("let wire_params = serde_json::to_value(params)?;"); + expect(rpc).not.toContain('_obj.insert("value"'); + }); + const render = (additions: 0 | 1 | 2, scope: "server" | "session" = "server") => { const { schema } = legacyRequestSchema(additions, scope); const types = generateApiTypesCode(schema); diff --git a/nodejs/test/toolSet.test.ts b/nodejs/test/toolSet.test.ts index b77b797072..eba35de989 100644 --- a/nodejs/test/toolSet.test.ts +++ b/nodejs/test/toolSet.test.ts @@ -498,6 +498,27 @@ describe("Empty-mode safe defaults", () => { expect(payload.enableSkills).toBe(true); }); + it("passes the create-time session name through on create", async () => { + const { client, spy } = await setupClient(); + await client.createSession({ + onPermissionRequest: approveAll, + availableTools: new ToolSet().addBuiltIn(BuiltInTools.Isolated), + name: "named at create", + }); + const payload = createPayload(spy); + expect(payload.name).toBe("named at create"); + }); + + it("omits the session name on create when it is not set", async () => { + const { client, spy } = await setupClient(); + await client.createSession({ + onPermissionRequest: approveAll, + availableTools: new ToolSet().addBuiltIn(BuiltInTools.Isolated), + }); + const payload = createPayload(spy); + expect(payload.name).toBeUndefined(); + }); + it("passes organizationCustomInstructions through on create", async () => { const { client, spy } = await setupClient(); await client.createSession({ diff --git a/nodejs/tsconfig.test.json b/nodejs/tsconfig.test.json index 6f8ef72510..f6f04f3548 100644 --- a/nodejs/tsconfig.test.json +++ b/nodejs/tsconfig.test.json @@ -13,6 +13,7 @@ "test/ffiRuntimeHost.test.ts", "test/session-event-types.test.ts", "test/session-config-types.test.ts", + "test/reasoning-summaries-types.test.ts", "test/sandbox-config.test.ts", "test/message-source.test.ts", "test/legacy-request-compatibility.test.ts" diff --git a/nodejs/vitest.config.ts b/nodejs/vitest.config.ts index 9b1badf4ab..d9da632555 100644 --- a/nodejs/vitest.config.ts +++ b/nodejs/vitest.config.ts @@ -52,6 +52,7 @@ const inProcessBlockedE2E = [ "**/test/e2e/system_message_transform.e2e.test.ts", "**/test/e2e/tool_results.e2e.test.ts", "**/test/e2e/tools.e2e.test.ts", + "**/test/e2e/tools_anthropic_updates.e2e.test.ts", ]; // These suites own their provider or CAPI auth/request-handler setup. They run @@ -69,6 +70,7 @@ const selfConfiguredBackendE2E = [ "**/test/e2e/per_session_auth.e2e.test.ts", "**/test/e2e/provider_endpoint.e2e.test.ts", "**/test/e2e/subagent_prompt_resume.e2e.test.ts", + "**/test/e2e/tools_anthropic_updates.e2e.test.ts", "**/test/e2e/websocket_http_fallback.e2e.test.ts", "**/test/e2e/websocket_terminals.e2e.test.ts", ]; diff --git a/python/copilot/client.py b/python/copilot/client.py index 89a9f940f6..b1f7947e0c 100644 --- a/python/copilot/client.py +++ b/python/copilot/client.py @@ -2355,6 +2355,7 @@ async def create_session( on_permission_request: _PermissionHandlerFn | None = None, model: str | None = None, session_id: str | None = None, + name: str | None = None, client_name: str | None = None, reasoning_effort: ReasoningEffort | None = None, reasoning_summary: ReasoningSummary | None = None, @@ -2408,6 +2409,8 @@ async def create_session( included_builtin_skills: list[str] | None = None, skill_directories: list[str] | None = None, skill_provider: SkillProvider | None = None, + agent_directories: list[str] | None = None, + hook_directories: list[str] | None = None, plugin_directories: list[str] | None = None, instruction_directories: list[str] | None = None, disabled_skills: list[str] | None = None, @@ -2454,6 +2457,12 @@ async def create_session( for the consumer to resolve via the pending permission RPC. model: The model to use for the session (e.g. ``"gpt-4"``). session_id: Optional session ID. If not provided, a UUID is generated. + name: Names the session at creation, as ``session.name.set`` would, and + is validated the same way: non-empty, no leading or trailing whitespace, + at most 100 UTF-16 units, no control characters, and no double quotes. + A name also makes the session persist from the start, so it can be listed + and resumed without ever running a turn. Local sessions only: cloud + creation rejects it. client_name: Optional client name for identification. reasoning_effort: Reasoning effort level for the model. reasoning_summary: Reasoning summary mode for supported models. @@ -2554,18 +2563,32 @@ async def create_session( organization_custom_instructions: Organization-level custom instructions. enable_on_demand_instruction_discovery: Enables on-demand instruction file discovery. - enable_file_hooks: Enables file-based hooks from ``.github/hooks/``. + enable_file_hooks: Enables repository-origin file hooks from ``.github/hooks/`` + and trusted repository-configured roots, not explicit hook_directories + or callback hooks. enable_host_git_operations: Enables git operations on the host filesystem. enable_session_store: Enables the cross-session store. enable_skills: Enables skill loading. - skill_directories: Directories to search for skills. + skill_directories: Explicit discovery-only skill roots. No general filesystem + grant. Available without enable_config_discovery, subject to skill/managed + disables. Relative paths resolve once when supplied against the request's + effective working_directory; retained roots do not move on cwd changes. + None and omission are equivalent; [] clears only the explicit SDK roots. skill_provider: **Experimental.** Session-scoped provider for SDK-owned skills. Providers are not persisted; re-supply the provider when resuming the session. Synchronous providers run on the event loop, so keep them fast or make them async. Not supported for cloud sessions. - instruction_directories: Additional directories to search for custom - instruction files. + agent_directories: Explicit discovery-only agent roots, separate from + custom_agents. Same path and clearing rules as skill_directories. Available + without enable_config_discovery, subject to source/managed disables. + hook_directories: Explicit discovery-only file-hook roots, separate from callback + hooks. Same path and clearing rules as skill_directories. Available without + enable_config_discovery or enable_file_hooks (repository-origin hooks only); + hook and managed disables still apply. + instruction_directories: Explicit discovery-only instruction roots using existing + SDK formats. Same path and clearing rules as skill_directories. Available + without enable_config_discovery, subject to instruction/managed disables. disabled_skills: Skills to disable. disabled_mcp_servers: Exact MCP server names to disable only for this session. Disabled servers are not started or authenticated on @@ -2900,8 +2923,12 @@ async def create_session( payload["hasSkillProvider"] = True # Add skill directories configuration if provided - if skill_directories: + if skill_directories is not None: payload["skillDirectories"] = skill_directories + if agent_directories is not None: + payload["agentDirectories"] = agent_directories + if hook_directories is not None: + payload["hookDirectories"] = hook_directories # Add plugin directories configuration if provided if plugin_directories: @@ -2969,6 +2996,8 @@ async def create_session( ) if local_session_id is not None: payload["sessionId"] = local_session_id + if name is not None: + payload["name"] = name github_token_provider_registration_id = self._register_github_token_provider( github_token_provider, local_session_id ) @@ -3292,6 +3321,8 @@ async def resume_session( included_builtin_skills: list[str] | None = None, skill_directories: list[str] | None = None, skill_provider: SkillProvider | None = None, + agent_directories: list[str] | None = None, + hook_directories: list[str] | None = None, plugin_directories: list[str] | None = None, instruction_directories: list[str] | None = None, disabled_skills: list[str] | None = None, @@ -3436,17 +3467,31 @@ async def resume_session( organization_custom_instructions: Organization-level custom instructions. enable_on_demand_instruction_discovery: Enables on-demand instruction file discovery. - enable_file_hooks: Enables file-based hooks from ``.github/hooks/``. + enable_file_hooks: Enables repository-origin file hooks from ``.github/hooks/`` + and trusted repository-configured roots, not explicit hook_directories + or callback hooks. enable_host_git_operations: Enables git operations on the host filesystem. enable_session_store: Enables the cross-session store. enable_skills: Enables skill loading. - skill_directories: Directories to search for skills. + skill_directories: Explicit discovery-only skill roots. No general filesystem + grant. Available without enable_config_discovery, subject to skill/managed + disables. Relative paths resolve once when supplied against the request's + effective working_directory; retained roots do not move on cwd changes. + None and omission are equivalent; [] clears only the explicit SDK roots. skill_provider: **Experimental.** Session-scoped provider for SDK-owned skills. Providers are not persisted; callers must re-supply the provider on resume. Synchronous providers run on the event loop, so keep them fast or make them async. - instruction_directories: Additional directories to search for custom - instruction files. + agent_directories: Explicit discovery-only agent roots, separate from + custom_agents. Same path and clearing rules as skill_directories. Available + without enable_config_discovery, subject to source/managed disables. + hook_directories: Explicit discovery-only file-hook roots, separate from callback + hooks. Same path and clearing rules as skill_directories. Available without + enable_config_discovery or enable_file_hooks (repository-origin hooks only); + hook and managed disables still apply. + instruction_directories: Explicit discovery-only instruction roots using existing + SDK formats. Same path and clearing rules as skill_directories. Available + without enable_config_discovery, subject to instruction/managed disables. disabled_skills: Skills to disable. disabled_mcp_servers: Exact MCP server names to disable only for this session. Disabled servers are not started or authenticated on @@ -3757,8 +3802,12 @@ async def resume_session( if agent: payload["agent"] = agent - if skill_directories: + if skill_directories is not None: payload["skillDirectories"] = skill_directories + if agent_directories is not None: + payload["agentDirectories"] = agent_directories + if hook_directories is not None: + payload["hookDirectories"] = hook_directories if plugin_directories: payload["pluginDirectories"] = plugin_directories if instruction_directories is not None: @@ -4563,6 +4612,8 @@ def _convert_custom_agent_to_wire_format( The custom agent configuration in camelCase wire format. """ wire_agent: dict[str, Any] = {"name": agent.get("name"), "prompt": agent.get("prompt")} + if "hooks" in agent: + wire_agent["hooks"] = agent["hooks"] if "display_name" in agent: wire_agent["displayName"] = agent["display_name"] if "description" in agent: diff --git a/python/copilot/generated/rpc.py b/python/copilot/generated/rpc.py index 605a606bfd..973b275803 100644 --- a/python/copilot/generated/rpc.py +++ b/python/copilot/generated/rpc.py @@ -22,6 +22,7 @@ T = TypeVar("T") EnumT = TypeVar("EnumT", bound=Enum) +UNSET_SENTINEL = object() def from_str(x: Any) -> str: @@ -351,6 +352,31 @@ def to_dict(self) -> dict: class AccountAuthInfoType(Enum): ACCOUNT = "account" +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _AccountDescribeAuthInfoResult: + """The wording the runtime uses for an authentication identity.""" + + description: str + """One-line description of the identity, suitable after a verb such as "Switched to".""" + + message: str + """Sign-in banner announcing the authenticated user.""" + + @staticmethod + def from_dict(obj: Any) -> '_AccountDescribeAuthInfoResult': + assert isinstance(obj, dict) + description = from_str(obj.get("description")) + message = from_str(obj.get("message")) + return _AccountDescribeAuthInfoResult(description, message) + + def to_dict(self) -> dict: + result: dict = {} + result["description"] = from_str(self.description) + result["message"] = from_str(self.message) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class AccountGetCurrentAuthResult: @@ -377,6 +403,38 @@ def to_dict(self) -> dict: result["authInfo"] = from_union([lambda x: (x).to_dict(), from_none], self.auth_info) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _AccountGetGistSupportResult: + """Whether the identity can create gists, and why not when it cannot.""" + + supported: bool + """True when the identity can create gists.""" + + kind: str | None = None + """Machine-readable reason category when unsupported.""" + + reason: str | None = None + """Human-readable explanation to show where the gist action would have been.""" + + @staticmethod + def from_dict(obj: Any) -> '_AccountGetGistSupportResult': + assert isinstance(obj, dict) + supported = from_bool(obj.get("supported")) + kind = from_union([from_str, from_none], obj.get("kind")) + reason = from_union([from_str, from_none], obj.get("reason")) + return _AccountGetGistSupportResult(supported, kind, reason) + + def to_dict(self) -> dict: + result: dict = {} + result["supported"] = from_bool(self.supported) + if self.kind is not None: + result["kind"] = from_union([from_str, from_none], self.kind) + if self.reason is not None: + result["reason"] = from_union([from_str, from_none], self.reason) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class AccountGetQuotaRequest: @@ -460,6 +518,49 @@ def to_dict(self) -> dict: result["resetDate"] = from_union([from_str, from_none], self.reset_date) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _AccountGetTokenEnvVarResult: + """The environment variable supplying a classic personal access token, when one is set.""" + + name: str | None = None + """Variable name, for example `GH_TOKEN`. Absent when no classic token is present in the + environment. + """ + + @staticmethod + def from_dict(obj: Any) -> '_AccountGetTokenEnvVarResult': + assert isinstance(obj, dict) + name = from_union([from_str, from_none], obj.get("name")) + return _AccountGetTokenEnvVarResult(name) + + def to_dict(self) -> dict: + result: dict = {} + if self.name is not None: + result["name"] = from_union([from_str, from_none], self.name) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _AccountGetWebURLResult: + """An absolute URL on the identity's GitHub host.""" + + url: str + """Absolute URL for the requested path.""" + + @staticmethod + def from_dict(obj: Any) -> '_AccountGetWebURLResult': + assert isinstance(obj, dict) + url = from_str(obj.get("url")) + return _AccountGetWebURLResult(url) + + def to_dict(self) -> dict: + result: dict = {} + result["url"] = from_str(self.url) + return result + # Experimental: this type is part of an experimental API and may change or be removed. class AccountKind(Enum): """The provider kind stamped on a signed-in account. @@ -808,6 +909,12 @@ def to_dict(self) -> dict: class AgentsDiscoverRequest: """Optional project paths to include in agent discovery.""" + agent_directories: list[str] | None = field(default=None, kw_only=True) + """Explicit discovery-only agent roots, separate from customAgents and filesystem grants. + Available without ambient discovery, subject to managed/source disables. Relative paths + resolve against the request's effective working directory when supplied. Null and + omission are equivalent; an empty array contributes no explicit roots. + """ exclude_host_agents: bool | None = None """When true, omit the host's agents (the user-level agent directory and all plugin agents), leaving only project and remote agents. For multitenant deployments. @@ -820,12 +927,15 @@ class AgentsDiscoverRequest: @staticmethod def from_dict(obj: Any) -> 'AgentsDiscoverRequest': assert isinstance(obj, dict) + agent_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("agentDirectories")) exclude_host_agents = from_union([from_bool, from_none], obj.get("excludeHostAgents")) project_paths = from_union([lambda x: from_list(from_str, x), from_none], obj.get("projectPaths")) - return AgentsDiscoverRequest(exclude_host_agents, project_paths) + return AgentsDiscoverRequest(exclude_host_agents, project_paths, agent_directories=agent_directories) def to_dict(self) -> dict: result: dict = {} + if self.agent_directories is not None: + result["agentDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.agent_directories) if self.exclude_host_agents is not None: result["excludeHostAgents"] = from_union([from_bool, from_none], self.exclude_host_agents) if self.project_paths is not None: @@ -1026,6 +1136,12 @@ def to_dict(self) -> dict: class AgentsGetDiscoveryPathsRequest: """Optional project paths to include when enumerating agent discovery directories.""" + agent_directories: list[str] | None = field(default=None, kw_only=True) + """Explicit discovery-only agent roots to enumerate, including configured missing + directories. Relative paths resolve against the request's effective working directory + when supplied. These are not filesystem grants or preferred creation targets. Null and + omission are equivalent. + """ exclude_host_agents: bool | None = None """When true, omit the host's user-level agent directory, leaving only project directories. For multitenant deployments (mirrors `discover`'s `excludeHostAgents`). @@ -1038,12 +1154,15 @@ class AgentsGetDiscoveryPathsRequest: @staticmethod def from_dict(obj: Any) -> 'AgentsGetDiscoveryPathsRequest': assert isinstance(obj, dict) + agent_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("agentDirectories")) exclude_host_agents = from_union([from_bool, from_none], obj.get("excludeHostAgents")) project_paths = from_union([lambda x: from_list(from_str, x), from_none], obj.get("projectPaths")) - return AgentsGetDiscoveryPathsRequest(exclude_host_agents, project_paths) + return AgentsGetDiscoveryPathsRequest(exclude_host_agents, project_paths, agent_directories=agent_directories) def to_dict(self) -> dict: result: dict = {} + if self.agent_directories is not None: + result["agentDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.agent_directories) if self.exclude_host_agents is not None: result["excludeHostAgents"] = from_union([from_bool, from_none], self.exclude_host_agents) if self.project_paths is not None: @@ -4142,6 +4261,96 @@ class ExternalToolTextResultForLlmContentTerminalType(Enum): class KindEnum(Enum): TEXT = "text" +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +class _FeatureFlagAvailability(Enum): + """The population a feature flag is declared for, before overrides. + + The population the flag is declared for before any environment or user-settings override + is applied. + """ + EXPERIMENTAL = "experimental" + OFF = "off" + ON = "on" + STAFF = "staff" + STAFF_AND_EXPERIMENTAL = "staff-and-experimental" + STAFF_GITHUB = "staff-github" + STAFF_MICROSOFT = "staff-microsoft" + STAFF_OR_EXPERIMENTAL = "staff-or-experimental" + TEAM = "team" + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _FeatureFlagsResolveRequest: + """Caller population and overrides for static feature-flag resolution, independent of + experiment assignments and active runtime state. + """ + is_experimental: bool + """Whether the caller is in an experimental population.""" + + is_staff: bool + """Whether the caller is GitHub or Microsoft staff.""" + + is_team: bool + """Whether the caller belongs to the team population used by feature availability.""" + + base_flags: dict[str, bool] | None = None + """Resolve against this already-computed flag set rather than each flag's declared + availability. Keyed by flag name. + """ + config: Any = None + """User settings to apply, including `enabledFeatureFlags`, legacy `feature_flags.enabled`, + and supported convenience settings. + """ + environment: dict[str, str] | None = None + """Environment for direct feature-flag overrides and `COPILOT_CLI_ENABLED_FEATURE_FLAGS`. + Does not apply `COPILOT_EXP_*` experiment assignments. Defaults to this runtime process's + own environment. + """ + flag_overrides: dict[str, bool] | None = None + """Flags forced to a value after every other layer, keyed by flag name.""" + + is_staff_github: bool | None = None + """GitHub-staff membership. Omit when it was never recorded: a legacy staff account then + counts as both staff populations and keeps every staff feature. + """ + is_staff_microsoft: bool | None = None + """Microsoft-staff membership. Omitted the same way as `isStaffGitHub`.""" + + @staticmethod + def from_dict(obj: Any) -> '_FeatureFlagsResolveRequest': + assert isinstance(obj, dict) + is_experimental = from_bool(obj.get("isExperimental")) + is_staff = from_bool(obj.get("isStaff")) + is_team = from_bool(obj.get("isTeam")) + base_flags = from_union([lambda x: from_dict(from_bool, x), from_none], obj.get("baseFlags")) + config = obj.get("config") + environment = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("environment")) + flag_overrides = from_union([lambda x: from_dict(from_bool, x), from_none], obj.get("flagOverrides")) + is_staff_github = from_union([from_bool, from_none], obj.get("isStaffGithub")) + is_staff_microsoft = from_union([from_bool, from_none], obj.get("isStaffMicrosoft")) + return _FeatureFlagsResolveRequest(is_experimental, is_staff, is_team, base_flags, config, environment, flag_overrides, is_staff_github, is_staff_microsoft) + + def to_dict(self) -> dict: + result: dict = {} + result["isExperimental"] = from_bool(self.is_experimental) + result["isStaff"] = from_bool(self.is_staff) + result["isTeam"] = from_bool(self.is_team) + if self.base_flags is not None: + result["baseFlags"] = from_union([lambda x: from_dict(from_bool, x), from_none], self.base_flags) + if self.config is not None: + result["config"] = self.config + if self.environment is not None: + result["environment"] = from_union([lambda x: from_dict(from_str, x), from_none], self.environment) + if self.flag_overrides is not None: + result["flagOverrides"] = from_union([lambda x: from_dict(from_bool, x), from_none], self.flag_overrides) + if self.is_staff_github is not None: + result["isStaffGithub"] = from_union([from_bool, from_none], self.is_staff_github) + if self.is_staff_microsoft is not None: + result["isStaffMicrosoft"] = from_union([from_bool, from_none], self.is_staff_microsoft) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class FleetStartRequest: @@ -4412,7 +4621,7 @@ def to_dict(self) -> dict: # Experimental: this type is part of an experimental API and may change or be removed. # Internal: this type is an internal SDK API and is not part of the public surface. @dataclass -class GitHubOwnersRequestIDResult: +class _GitHubOwnersRequestIDResult: """A freshly registered request id. Registering it before the listing starts is what lets a cancel that races the request still find the owner listing slot. The id serves one listing only. Long-abandoned unused ids can be released by later allocations. @@ -4421,10 +4630,10 @@ class GitHubOwnersRequestIDResult: """Request id to pass to `gitHubOwners.list` and, to abandon it, `gitHubOwners.cancel`.""" @staticmethod - def from_dict(obj: Any) -> 'GitHubOwnersRequestIDResult': + def from_dict(obj: Any) -> '_GitHubOwnersRequestIDResult': assert isinstance(obj, dict) request_id = from_int(obj.get("requestId")) - return GitHubOwnersRequestIDResult(request_id) + return _GitHubOwnersRequestIDResult(request_id) def to_dict(self) -> dict: result: dict = {} @@ -5085,6 +5294,13 @@ class HooksDiscoverRequest: still contribute to each remaining row's effective enabled state. This filters sources rather than simulating a host with no settings. """ + hook_directories: list[str] | None = field(default=None, kw_only=True) + """Explicit discovery-only file-hook roots, separate from callback hooks and filesystem + grants. Available without ambient discovery or repository file-hook enablement, subject + to managed/hook disables. Relative paths resolve against the request's effective working + directory when supplied. Null and omission are equivalent; an empty array contributes no + explicit roots. + """ project_paths: list[str] | None = None """Optional project directory paths whose trusted repository and project-expanded plugin hooks should be discovered. When omitted or empty, user, managed-policy, and globally @@ -5095,13 +5311,16 @@ class HooksDiscoverRequest: def from_dict(obj: Any) -> 'HooksDiscoverRequest': assert isinstance(obj, dict) exclude_host_hooks = from_union([from_bool, from_none], obj.get("excludeHostHooks")) + hook_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("hookDirectories")) project_paths = from_union([lambda x: from_list(from_str, x), from_none], obj.get("projectPaths")) - return HooksDiscoverRequest(exclude_host_hooks, project_paths) + return HooksDiscoverRequest(exclude_host_hooks, project_paths, hook_directories=hook_directories) def to_dict(self) -> dict: result: dict = {} if self.exclude_host_hooks is not None: result["excludeHostHooks"] = from_union([from_bool, from_none], self.exclude_host_hooks) + if self.hook_directories is not None: + result["hookDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.hook_directories) if self.project_paths is not None: result["projectPaths"] = from_union([lambda x: from_list(from_str, x), from_none], self.project_paths) return result @@ -5995,6 +6214,63 @@ class InstructionSourceType(Enum): REPO = "repo" VSCODE = "vscode" +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _InstructionsDiscoverRepoSourcesRequest: + """Explicit discovery arguments for one location, supplied by the caller rather than derived + from a session. + """ + location: str + """Repository location to discover. An empty string selects no repository scope; cwdPath can + still supply working-directory sources. + """ + additional_dirs: list[str] | None = None + """Extra directories to scan alongside instruction directories configured in the runtime + environment. + """ + config_dir: str | None = None + """Copilot configuration directory for user-level sources. An omitted or empty value uses + the server's configuration home. + """ + cwd_path: str | None = None + """Working directory whose instruction sources should also be included. Omission adds no + separate working-directory scope. + """ + enable_child_instructions: bool | None = None + """When true, also discover instruction files nested below the location.""" + + is_cli: bool | None = None + """When true, include the sources a command-line host reads. Hosts that are not the CLI omit + it. + """ + + @staticmethod + def from_dict(obj: Any) -> '_InstructionsDiscoverRepoSourcesRequest': + assert isinstance(obj, dict) + location = from_str(obj.get("location")) + additional_dirs = from_union([lambda x: from_list(from_str, x), from_none], obj.get("additionalDirs")) + config_dir = from_union([from_str, from_none], obj.get("configDir")) + cwd_path = from_union([from_str, from_none], obj.get("cwdPath")) + enable_child_instructions = from_union([from_bool, from_none], obj.get("enableChildInstructions")) + is_cli = from_union([from_bool, from_none], obj.get("isCli")) + return _InstructionsDiscoverRepoSourcesRequest(location, additional_dirs, config_dir, cwd_path, enable_child_instructions, is_cli) + + def to_dict(self) -> dict: + result: dict = {} + result["location"] = from_str(self.location) + if self.additional_dirs is not None: + result["additionalDirs"] = from_union([lambda x: from_list(from_str, x), from_none], self.additional_dirs) + if self.config_dir is not None: + result["configDir"] = from_union([from_str, from_none], self.config_dir) + if self.cwd_path is not None: + result["cwdPath"] = from_union([from_str, from_none], self.cwd_path) + if self.enable_child_instructions is not None: + result["enableChildInstructions"] = from_union([from_bool, from_none], self.enable_child_instructions) + if self.is_cli is not None: + result["isCli"] = from_union([from_bool, from_none], self.is_cli) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class InstructionsDiscoverRequest: @@ -6004,6 +6280,12 @@ class InstructionsDiscoverRequest: """When true, omit the host's instruction sources (user/home-level files and plugin rules), leaving only repository and working-directory sources. For multitenant deployments. """ + instruction_directories: list[str] | None = field(default=None, kw_only=True) + """Explicit discovery-only instruction roots using existing SDK instruction formats, not + filesystem grants. Available without ambient discovery, subject to instruction/managed + disables. Relative paths resolve against the request's effective working directory when + supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + """ project_paths: list[str] | None = None """Optional list of project directory paths to scan for repository/working-directory instruction sources. When omitted or empty, only user-level and plugin instruction @@ -6014,13 +6296,16 @@ class InstructionsDiscoverRequest: def from_dict(obj: Any) -> 'InstructionsDiscoverRequest': assert isinstance(obj, dict) exclude_host_instructions = from_union([from_bool, from_none], obj.get("excludeHostInstructions")) + instruction_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("instructionDirectories")) project_paths = from_union([lambda x: from_list(from_str, x), from_none], obj.get("projectPaths")) - return InstructionsDiscoverRequest(exclude_host_instructions, project_paths) + return InstructionsDiscoverRequest(exclude_host_instructions, project_paths, instruction_directories=instruction_directories) def to_dict(self) -> dict: result: dict = {} if self.exclude_host_instructions is not None: result["excludeHostInstructions"] = from_union([from_bool, from_none], self.exclude_host_instructions) + if self.instruction_directories is not None: + result["instructionDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.instruction_directories) if self.project_paths is not None: result["projectPaths"] = from_union([lambda x: from_list(from_str, x), from_none], self.project_paths) return result @@ -6034,6 +6319,12 @@ class InstructionsGetDiscoveryPathsRequest: """When true, omit the host's user-level instruction targets, leaving only repository targets. For multitenant deployments (mirrors `discover`'s `excludeHostInstructions`). """ + instruction_directories: list[str] | None = field(default=None, kw_only=True) + """Explicit discovery-only instruction roots to enumerate, including configured missing + directories. Relative paths resolve against the request's effective working directory + when supplied. These are not filesystem grants or preferred creation targets. Null and + omission are equivalent. + """ project_paths: list[str] | None = None """Optional list of project directory paths. When omitted or empty, only the user-level targets are returned. @@ -6043,17 +6334,40 @@ class InstructionsGetDiscoveryPathsRequest: def from_dict(obj: Any) -> 'InstructionsGetDiscoveryPathsRequest': assert isinstance(obj, dict) exclude_host_instructions = from_union([from_bool, from_none], obj.get("excludeHostInstructions")) + instruction_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("instructionDirectories")) project_paths = from_union([lambda x: from_list(from_str, x), from_none], obj.get("projectPaths")) - return InstructionsGetDiscoveryPathsRequest(exclude_host_instructions, project_paths) + return InstructionsGetDiscoveryPathsRequest(exclude_host_instructions, project_paths, instruction_directories=instruction_directories) def to_dict(self) -> dict: result: dict = {} if self.exclude_host_instructions is not None: result["excludeHostInstructions"] = from_union([from_bool, from_none], self.exclude_host_instructions) + if self.instruction_directories is not None: + result["instructionDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.instruction_directories) if self.project_paths is not None: result["projectPaths"] = from_union([lambda x: from_list(from_str, x), from_none], self.project_paths) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _InstructionsInitPromptResult: + """The prompt the init command runs.""" + + prompt: str + """Prompt text authoring repository instructions.""" + + @staticmethod + def from_dict(obj: Any) -> '_InstructionsInitPromptResult': + assert isinstance(obj, dict) + prompt = from_str(obj.get("prompt")) + return _InstructionsInitPromptResult(prompt) + + def to_dict(self) -> dict: + result: dict = {} + result["prompt"] = from_str(self.prompt) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class InterruptMainTurnRequest: @@ -7332,7 +7646,7 @@ def to_dict(self) -> dict: # Experimental: this type is part of an experimental API and may change or be removed. # Internal: this type is an internal SDK API and is not part of the public surface. @dataclass -class MCPConfigureGitHubRequest: +class _MCPConfigureGitHubRequest: """Credential-free authentication identity used to configure GitHub MCP.""" auth_info: Any @@ -7341,10 +7655,10 @@ class MCPConfigureGitHubRequest: """ @staticmethod - def from_dict(obj: Any) -> 'MCPConfigureGitHubRequest': + def from_dict(obj: Any) -> '_MCPConfigureGitHubRequest': assert isinstance(obj, dict) auth_info = obj.get("authInfo") - return MCPConfigureGitHubRequest(auth_info) + return _MCPConfigureGitHubRequest(auth_info) def to_dict(self) -> dict: result: dict = {} @@ -7754,6 +8068,28 @@ def to_dict(self) -> dict: result["running"] = from_bool(self.running) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _MCPListBuiltinServerNamesResult: + """Names of the MCP servers the runtime supplies itself.""" + + names: list[str] + """Every built-in server name. A host disabling the built-ins wholesale suppresses exactly + this set. + """ + + @staticmethod + def from_dict(obj: Any) -> '_MCPListBuiltinServerNamesResult': + assert isinstance(obj, dict) + names = from_list(from_str, obj.get("names")) + return _MCPListBuiltinServerNamesResult(names) + + def to_dict(self) -> dict: + result: dict = {} + result["names"] = from_list(from_str, self.names) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class MCPListToolsRequest: @@ -8322,17 +8658,17 @@ def to_dict(self) -> dict: # Experimental: this type is part of an experimental API and may change or be removed. # Internal: this type is an internal SDK API and is not part of the public surface. @dataclass -class MCPRegistryCancelRequest: +class _MCPRegistryCancelRequest: """Registry search to abandon.""" request_id: int """Request ID from `mcp.registry.allocateRequestId` that the search uses.""" @staticmethod - def from_dict(obj: Any) -> 'MCPRegistryCancelRequest': + def from_dict(obj: Any) -> '_MCPRegistryCancelRequest': assert isinstance(obj, dict) request_id = from_int(obj.get("requestId")) - return MCPRegistryCancelRequest(request_id) + return _MCPRegistryCancelRequest(request_id) def to_dict(self) -> dict: result: dict = {} @@ -8342,7 +8678,7 @@ def to_dict(self) -> dict: # Experimental: this type is part of an experimental API and may change or be removed. # Internal: this type is an internal SDK API and is not part of the public surface. @dataclass -class MCPRegistryCancelResult: +class _MCPRegistryCancelResult: """Whether the cancel reached a live search.""" canceled: bool @@ -8352,10 +8688,10 @@ class MCPRegistryCancelResult: """ @staticmethod - def from_dict(obj: Any) -> 'MCPRegistryCancelResult': + def from_dict(obj: Any) -> '_MCPRegistryCancelResult': assert isinstance(obj, dict) canceled = from_bool(obj.get("canceled")) - return MCPRegistryCancelResult(canceled) + return _MCPRegistryCancelResult(canceled) def to_dict(self) -> dict: result: dict = {} @@ -8365,7 +8701,7 @@ def to_dict(self) -> dict: # Experimental: this type is part of an experimental API and may change or be removed. # Internal: this type is an internal SDK API and is not part of the public surface. @dataclass -class MCPRegistryRequestIDResult: +class _MCPRegistryRequestIDResult: """Request id naming a cancellable registry search.""" request_id: int @@ -8374,10 +8710,10 @@ class MCPRegistryRequestIDResult: """ @staticmethod - def from_dict(obj: Any) -> 'MCPRegistryRequestIDResult': + def from_dict(obj: Any) -> '_MCPRegistryRequestIDResult': assert isinstance(obj, dict) request_id = from_int(obj.get("requestId")) - return MCPRegistryRequestIDResult(request_id) + return _MCPRegistryRequestIDResult(request_id) def to_dict(self) -> dict: result: dict = {} @@ -8387,7 +8723,7 @@ def to_dict(self) -> dict: # Experimental: this type is part of an experimental API and may change or be removed. # Internal: this type is an internal SDK API and is not part of the public surface. @dataclass -class MCPRegistrySearchResult: +class _MCPRegistrySearchResult: """Servers selected from the registry response.""" servers: Any @@ -8397,10 +8733,10 @@ class MCPRegistrySearchResult: """ @staticmethod - def from_dict(obj: Any) -> 'MCPRegistrySearchResult': + def from_dict(obj: Any) -> '_MCPRegistrySearchResult': assert isinstance(obj, dict) servers = obj.get("servers") - return MCPRegistrySearchResult(servers) + return _MCPRegistrySearchResult(servers) def to_dict(self) -> dict: result: dict = {} @@ -8425,7 +8761,7 @@ class MCPServerConfigType(Enum): # Experimental: this type is part of an experimental API and may change or be removed. # Internal: this type is an internal SDK API and is not part of the public surface. @dataclass -class MCPReloadWithConfigRequest: +class _MCPReloadWithConfigRequest: """Opaque MCP reload configuration.""" config: Any @@ -8434,10 +8770,10 @@ class MCPReloadWithConfigRequest: """ @staticmethod - def from_dict(obj: Any) -> 'MCPReloadWithConfigRequest': + def from_dict(obj: Any) -> '_MCPReloadWithConfigRequest': assert isinstance(obj, dict) config = obj.get("config") - return MCPReloadWithConfigRequest(config) + return _MCPReloadWithConfigRequest(config) def to_dict(self) -> dict: result: dict = {} @@ -8559,7 +8895,7 @@ class MCPServerConfigHTTPType(Enum): # Experimental: this type is part of an experimental API and may change or be removed. # Internal: this type is an internal SDK API and is not part of the public surface. -class MCPServerConfigMemoryType(Enum): +class _MCPServerConfigMemoryType(Enum): """In-process MCP transport type.""" MEMORY = "memory" @@ -8602,7 +8938,7 @@ class OptionsUpdateToolFilterPrecedence(Enum): # Experimental: this type is part of an experimental API and may change or be removed. # Internal: this type is an internal SDK API and is not part of the public surface. @dataclass -class MCPShouldExcludeGitHubToolsResult: +class _MCPShouldExcludeGitHubToolsResult: """Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by the request. """ @@ -8613,10 +8949,10 @@ class MCPShouldExcludeGitHubToolsResult: """ @staticmethod - def from_dict(obj: Any) -> 'MCPShouldExcludeGitHubToolsResult': + def from_dict(obj: Any) -> '_MCPShouldExcludeGitHubToolsResult': assert isinstance(obj, dict) exclude_gh_replaceable_tools = from_bool(obj.get("excludeGhReplaceableTools")) - return MCPShouldExcludeGitHubToolsResult(exclude_gh_replaceable_tools) + return _MCPShouldExcludeGitHubToolsResult(exclude_gh_replaceable_tools) def to_dict(self) -> dict: result: dict = {} @@ -8673,17 +9009,17 @@ def to_dict(self) -> dict: # Experimental: this type is part of an experimental API and may change or be removed. # Internal: this type is an internal SDK API and is not part of the public surface. @dataclass -class MCPUnregisterExternalClientRequest: +class _MCPUnregisterExternalClientRequest: """Server name identifying the external client to remove.""" server_name: str """Server name of the external client to unregister""" @staticmethod - def from_dict(obj: Any) -> 'MCPUnregisterExternalClientRequest': + def from_dict(obj: Any) -> '_MCPUnregisterExternalClientRequest': assert isinstance(obj, dict) server_name = from_str(obj.get("serverName")) - return MCPUnregisterExternalClientRequest(server_name) + return _MCPUnregisterExternalClientRequest(server_name) def to_dict(self) -> dict: result: dict = {} @@ -9480,6 +9816,92 @@ def to_dict(self) -> dict: result["cleared"] = from_bool(self.cleared) return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class ModelGetReasoningSummariesResult: + """Reasoning-summaries presentation policy for the session's current model.""" + + clear_redundant_setting: bool + """Whether the supplied `persistedShowReasoning` setting only restates the model default. + This reports a redundancy, not a standing instruction to delete the setting: it stays + true for as long as the setting and the model default agree, including for a user who + later chose that value deliberately. It exists for a one-time migration of a legacy + setting written before the model default made it redundant, so a host that acts on it + owns the cleanup and must gate it behind its own persisted `done` marker, delete only a + setting whose value still matches the one it read, and never repeat the deletion on a + later launch. Under an off-by-default reasoning-summaries experiment an explicit + `showReasoning: true` opt-in also reads as redundant on a summary-producing model, so an + ungated host would keep deleting that opt-in and hide summaries again on every launch. + """ + experiment_settled: bool + """Whether the session's reasoning-summaries experiment assignment has settled. False means + this read does not wait for a pending assignment and reports the experiment-derived + fields conservatively: `showHiddenHint` is false and `visibility` falls back to + `persistedShowReasoning`, or is omitted when none was supplied. A host that wants the + assigned answer re-reads until this is true. + """ + model_default_shows_summaries: bool + """Whether the selected model shows reasoning summaries by default.""" + + ready: bool + """False until the session has a model catalog and a selected model. This read never + resolves the catalog itself, and the runtime emits no readiness notification, so + repeating this call alone leaves `ready` false indefinitely on a session that has neither + listed models nor run a turn. `session.model.list` is the prerequisite and the signal: it + resolves and caches the catalog for the session, so a successful return means the next + read is ready. The exception is a session that resolves models without a Copilot catalog, + that is a BYOK registry or an alternate provider: `session.model.list` returns an empty + list without caching a catalog, so `ready` stays false and this policy is unavailable + there. While false, every model-policy field is false and `visibility` is omitted; + `experimentSettled` is independent of readiness and still reports the assignment state. + """ + session_shows_summaries: bool + """Whether turns on this session produce reasoning summaries, honouring an explicit session + reasoning-summary override. + """ + show_hidden_hint: bool + """Whether to show the hint that reasoning summaries are hidden. Always false while + `experimentSettled` is false. + """ + show_reasoning_headers: bool + """Whether the selected model emits reasoning headers.""" + + visibility: bool | None = None + """Default reasoning visibility, and only meaningful once `ready` is true: false when the + session produces no summaries, else the persisted setting, else the experiment's default. + While `ready` is true it is omitted only when all three are unavailable, that is when the + session produces summaries, no `persistedShowReasoning` was supplied, and + `experimentSettled` is false. While `ready` is false there is no model policy to report + and this field is always omitted, so an absent value alone does not imply a pending + experiment. + """ + + @staticmethod + def from_dict(obj: Any) -> 'ModelGetReasoningSummariesResult': + assert isinstance(obj, dict) + clear_redundant_setting = from_bool(obj.get("clearRedundantSetting")) + experiment_settled = from_bool(obj.get("experimentSettled")) + model_default_shows_summaries = from_bool(obj.get("modelDefaultShowsSummaries")) + ready = from_bool(obj.get("ready")) + session_shows_summaries = from_bool(obj.get("sessionShowsSummaries")) + show_hidden_hint = from_bool(obj.get("showHiddenHint")) + show_reasoning_headers = from_bool(obj.get("showReasoningHeaders")) + visibility = from_union([from_bool, from_none], obj.get("visibility")) + return ModelGetReasoningSummariesResult(clear_redundant_setting, experiment_settled, model_default_shows_summaries, ready, session_shows_summaries, show_hidden_hint, show_reasoning_headers, visibility) + + def to_dict(self) -> dict: + result: dict = {} + result["clearRedundantSetting"] = from_bool(self.clear_redundant_setting) + result["experimentSettled"] = from_bool(self.experiment_settled) + result["modelDefaultShowsSummaries"] = from_bool(self.model_default_shows_summaries) + result["ready"] = from_bool(self.ready) + result["sessionShowsSummaries"] = from_bool(self.session_shows_summaries) + result["showHiddenHint"] = from_bool(self.show_hidden_hint) + result["showReasoningHeaders"] = from_bool(self.show_reasoning_headers) + if self.visibility is not None: + result["visibility"] = from_union([from_bool, from_none], self.visibility) + return result + # Experimental: this type is part of an experimental API and may change or be removed. class ModelProviderAutomaticDiscoveryMode(Enum): """Whether automatic discovery is allowed, limited to configured providers, or @@ -12616,6 +13038,135 @@ def to_dict(self) -> dict: result["branch"] = from_union([from_str, from_none], self.branch) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _RepoSettingsReadRawRequest: + """Which repository settings file to read.""" + + repo_root: str + """Absolute path of the repository root.""" + + scope: str + """Use repo for shared settings or local for settings.local.json. Other scopes are rejected.""" + + @staticmethod + def from_dict(obj: Any) -> '_RepoSettingsReadRawRequest': + assert isinstance(obj, dict) + repo_root = from_str(obj.get("repoRoot")) + scope = from_str(obj.get("scope")) + return _RepoSettingsReadRawRequest(repo_root, scope) + + def to_dict(self) -> dict: + result: dict = {} + result["repoRoot"] = from_str(self.repo_root) + result["scope"] = from_str(self.scope) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _RepoSettingsReadRawResult: + """Parsed repository settings without normalization or layering.""" + + config: Any + """Stored JSON values after the existing JSONC parser and prototype-safety checks. Empty + when the file is missing, blank, or invalid. + """ + invalid: bool + """True when the file exists but did not parse, so `config` is empty for that reason rather + than because nothing is set. + """ + + @staticmethod + def from_dict(obj: Any) -> '_RepoSettingsReadRawResult': + assert isinstance(obj, dict) + config = obj.get("config") + invalid = from_bool(obj.get("invalid")) + return _RepoSettingsReadRawResult(config, invalid) + + def to_dict(self) -> dict: + result: dict = {} + result["config"] = self.config + result["invalid"] = from_bool(self.invalid) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _RepoSettingsWriteAllRequest: + """The complete set of repository-overridable settings to store.""" + + repo_root: str + """Absolute path of the repository root.""" + + scope: str + """Use repo for shared settings or local for settings.local.json. Other scopes are rejected.""" + + settings: Any + """Object of allowed settings to store. Missing allowlisted keys are removed. Other input + keys are ignored, while unknown stored keys are preserved. + """ + + @staticmethod + def from_dict(obj: Any) -> '_RepoSettingsWriteAllRequest': + assert isinstance(obj, dict) + repo_root = from_str(obj.get("repoRoot")) + scope = from_str(obj.get("scope")) + settings = obj.get("settings") + return _RepoSettingsWriteAllRequest(repo_root, scope, settings) + + def to_dict(self) -> dict: + result: dict = {} + result["repoRoot"] = from_str(self.repo_root) + result["scope"] = from_str(self.scope) + result["settings"] = self.settings + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _RepoSettingsWriteKeyRequest: + """One key to write or remove in a repository settings file.""" + + key: str + """Canonical top-level key permitted by the repository settings allowlist.""" + + repo_root: str + """Absolute path of the repository root.""" + + scope: str + """Use repo for shared settings or local for settings.local.json. Other scopes are rejected.""" + + delete: bool | None = None + """True to remove the key instead of writing it.""" + + value: Any = UNSET_SENTINEL + """Value to validate and write. Required unless delete is true; a null value is validated, + not treated as deletion. + """ + + @staticmethod + def from_dict(obj: Any) -> '_RepoSettingsWriteKeyRequest': + assert isinstance(obj, dict) + key = from_str(obj.get("key")) + repo_root = from_str(obj.get("repoRoot")) + scope = from_str(obj.get("scope")) + delete = from_union([from_bool, from_none], obj.get("delete")) + value = obj["value"] if "value" in obj else UNSET_SENTINEL + return _RepoSettingsWriteKeyRequest(key, repo_root, scope, delete, value) + + def to_dict(self) -> dict: + result: dict = {} + result["key"] = from_str(self.key) + result["repoRoot"] = from_str(self.repo_root) + result["scope"] = from_str(self.scope) + if self.delete is not None: + result["delete"] = from_union([from_bool, from_none], self.delete) + if self.value is not UNSET_SENTINEL: + result["value"] = self.value + return result + class ResponseFormatType(Enum): JSON_SCHEMA = "json_schema" @@ -16364,6 +16915,19 @@ def to_dict(self) -> dict: class SettableTokenAuthInfoType(Enum): TOKEN = "token" +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +class _SettingsEditOperation(Enum): + """One atomic settings mutation. + + Set a scalar, add or remove a string list item, or remove the setting. The handler + rejects a missing or incompatible value. + """ + ADD_ITEM = "add-item" + REMOVE = "remove" + REMOVE_ITEM = "remove-item" + SET = "set" + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class ShellCancelUserRequestedRequest: @@ -16749,7 +17313,11 @@ class SkillsDiscoverRequest: """Optional list of project directory paths to scan for project-scoped skills""" skill_directories: list[str] | None = None - """Optional list of additional skill directory paths to include""" + """Explicit discovery-only skill roots, not filesystem grants. Available without ambient + discovery, subject to skill/managed disables. Relative paths resolve against the + request's effective working directory when supplied. Null and omission are equivalent; an + empty array contributes no explicit roots. + """ @staticmethod def from_dict(obj: Any) -> 'SkillsDiscoverRequest': @@ -16807,6 +17375,12 @@ class SkillsGetDiscoveryPathsRequest: """Optional list of project directory paths. When omitted or empty, only personal and custom directories are returned. """ + skill_directories: list[str] | None = field(default=None, kw_only=True) + """Explicit discovery-only skill roots to enumerate, including configured missing + directories. Relative paths resolve against the request's effective working directory + when supplied. These are not filesystem grants or preferred creation targets. Null and + omission are equivalent. + """ @staticmethod def from_dict(obj: Any) -> 'SkillsGetDiscoveryPathsRequest': @@ -16814,7 +17388,8 @@ def from_dict(obj: Any) -> 'SkillsGetDiscoveryPathsRequest': exclude_host_skills = from_union([from_bool, from_none], obj.get("excludeHostSkills")) ignored_skills_locations = from_union([lambda x: from_list(from_str, x), from_none], obj.get("ignoredSkillsLocations")) project_paths = from_union([lambda x: from_list(from_str, x), from_none], obj.get("projectPaths")) - return SkillsGetDiscoveryPathsRequest(exclude_host_skills, ignored_skills_locations, project_paths) + skill_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("skillDirectories")) + return SkillsGetDiscoveryPathsRequest(exclude_host_skills, ignored_skills_locations, project_paths, skill_directories=skill_directories) def to_dict(self) -> dict: result: dict = {} @@ -16824,6 +17399,8 @@ def to_dict(self) -> dict: result["ignoredSkillsLocations"] = from_union([lambda x: from_list(from_str, x), from_none], self.ignored_skills_locations) if self.project_paths is not None: result["projectPaths"] = from_union([lambda x: from_list(from_str, x), from_none], self.project_paths) + if self.skill_directories is not None: + result["skillDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.skill_directories) return result # Experimental: this type is part of an experimental API and may change or be removed. @@ -18129,6 +18706,302 @@ def to_dict(self) -> dict: result["value"] = self.value return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsApplyTopKeyRequest: + """A single top-level setting subtree to validate and write.""" + + canonical_path: list[str] + """Canonical path of the setting the caller is editing. Currently informational only.""" + + top_key: str + """Top-level setting name to write.""" + + complete_staff_update_channel_migration: bool | None = None + """Records that the user chose an update channel explicitly, so the one-time staff channel + migration stops reapplying. Honored only for the `autoUpdatesChannel` key. + """ + delete: bool | None = None + """True to remove the top-level key instead of writing it.""" + + value: Any = UNSET_SENTINEL + """Value to write for the whole top-level key. Omitted when `delete` is true. Explicit null + is preserved and validated as null. + """ + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsApplyTopKeyRequest': + assert isinstance(obj, dict) + canonical_path = from_list(from_str, obj.get("canonicalPath")) + top_key = from_str(obj.get("topKey")) + complete_staff_update_channel_migration = from_union([from_bool, from_none], obj.get("completeStaffUpdateChannelMigration")) + delete = from_union([from_bool, from_none], obj.get("delete")) + value = obj["value"] if "value" in obj else UNSET_SENTINEL + return UserSettingsApplyTopKeyRequest(canonical_path, top_key, complete_staff_update_channel_migration, delete, value) + + def to_dict(self) -> dict: + result: dict = {} + result["canonicalPath"] = from_list(from_str, self.canonical_path) + result["topKey"] = from_str(self.top_key) + if self.complete_staff_update_channel_migration is not None: + result["completeStaffUpdateChannelMigration"] = from_union([from_bool, from_none], self.complete_staff_update_channel_migration) + if self.delete is not None: + result["delete"] = from_union([from_bool, from_none], self.delete) + if self.value is not UNSET_SENTINEL: + result["value"] = self.value + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsValidationIssue: + """One problem found while validating a setting value.""" + + message: str + """Human-readable description of the problem.""" + + path: list[Any] + """Where in the settings tree the problem sits, as object keys and array indices. The first + element is the top-level key; a whole-value problem is reported as that single key. + """ + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsValidationIssue': + assert isinstance(obj, dict) + message = from_str(obj.get("message")) + path = from_list(lambda x: x, obj.get("path")) + return UserSettingsValidationIssue(message, path) + + def to_dict(self) -> dict: + result: dict = {} + result["message"] = from_str(self.message) + result["path"] = from_list(lambda x: x, self.path) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsGetPathsRequest: + """Selects which settings file paths to resolve.""" + + repo_root: str | None = None + """Absolute path of a repository root. Supply it to also resolve that repository's two + settings file paths; omit it to resolve only the user path. + """ + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsGetPathsRequest': + assert isinstance(obj, dict) + repo_root = from_union([from_str, from_none], obj.get("repoRoot")) + return UserSettingsGetPathsRequest(repo_root) + + def to_dict(self) -> dict: + result: dict = {} + if self.repo_root is not None: + result["repoRoot"] = from_union([from_str, from_none], self.repo_root) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsGetPathsResult: + """On-disk locations of the settings files this runtime reads. A path is reported whether or + not the file exists. + """ + user_settings: str + """The user settings file: `settings.json` under the resolved Copilot home. This is the file + `user.settings.get`, `user.settings.load`, and `user.settings.set` read and write. + """ + repo_local_settings: str | None = None + """The repository's local, untracked settings file, or null when no repository root was + supplied. + """ + repo_settings: str | None = None + """The repository's checked-in settings file, or null when no repository root was supplied.""" + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsGetPathsResult': + assert isinstance(obj, dict) + user_settings = from_str(obj.get("userSettings")) + repo_local_settings = from_union([from_none, from_str], obj.get("repoLocalSettings")) + repo_settings = from_union([from_none, from_str], obj.get("repoSettings")) + return UserSettingsGetPathsResult(user_settings, repo_local_settings, repo_settings) + + def to_dict(self) -> dict: + result: dict = {} + result["userSettings"] = from_str(self.user_settings) + if self.repo_local_settings is not None: + result["repoLocalSettings"] = from_union([from_none, from_str], self.repo_local_settings) + if self.repo_settings is not None: + result["repoSettings"] = from_union([from_none, from_str], self.repo_settings) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsGovernanceKeysResult: + """Top-level user-setting keys grouped by who may govern them.""" + + claude_repo: list[str] + """Top-level keys a repository may override through a Claude-compatible repository config.""" + + managed: list[str] + """Top-level keys an enterprise policy may fix through managed settings.""" + + repo: list[str] + """Top-level keys a repository may override through `.github/copilot/settings.json` or + `.github/copilot/settings.local.json`. + """ + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsGovernanceKeysResult': + assert isinstance(obj, dict) + claude_repo = from_list(from_str, obj.get("claudeRepo")) + managed = from_list(from_str, obj.get("managed")) + repo = from_list(from_str, obj.get("repo")) + return UserSettingsGovernanceKeysResult(claude_repo, managed, repo) + + def to_dict(self) -> dict: + result: dict = {} + result["claudeRepo"] = from_list(from_str, self.claude_repo) + result["managed"] = from_list(from_str, self.managed) + result["repo"] = from_list(from_str, self.repo) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsLoadForEditResult: + """Contents of settings.json as stored, for a caller about to rewrite it.""" + + status: str + """`ok` when the file parsed, `missing` when there is no file yet, `invalid` when the file + exists but will not parse. + """ + settings: Any = None + """Parsed contents, present only when `status` is `ok`.""" + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsLoadForEditResult': + assert isinstance(obj, dict) + status = from_str(obj.get("status")) + settings = obj.get("settings") + return UserSettingsLoadForEditResult(status, settings) + + def to_dict(self) -> dict: + result: dict = {} + result["status"] = from_str(self.status) + if self.settings is not None: + result["settings"] = self.settings + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsNormalizeRequest: + """Settings object whose key names should be canonicalized.""" + + settings: Any + """Free-form settings object, possibly using legacy or snake_case key names.""" + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsNormalizeRequest': + assert isinstance(obj, dict) + settings = obj.get("settings") + return UserSettingsNormalizeRequest(settings) + + def to_dict(self) -> dict: + result: dict = {} + result["settings"] = self.settings + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsNormalizeResult: + """Settings object with canonical key names.""" + + settings: Any + """The same settings with every legacy or snake_case key renamed to its canonical spelling.""" + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsNormalizeResult': + assert isinstance(obj, dict) + settings = obj.get("settings") + return UserSettingsNormalizeResult(settings) + + def to_dict(self) -> dict: + result: dict = {} + result["settings"] = self.settings + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsProblemLocation: + """The settings layer the problem was found in. + + The settings layer a problem was found in. + """ + file_path: str + """Absolute path of the file backing this layer.""" + + kind: str + """Which layer this is: `user`, `repo`, or `local`.""" + + label: str + """The caller-supplied display label for the layer.""" + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsProblemLocation': + assert isinstance(obj, dict) + file_path = from_str(obj.get("filePath")) + kind = from_str(obj.get("kind")) + label = from_str(obj.get("label")) + return UserSettingsProblemLocation(file_path, kind, label) + + def to_dict(self) -> dict: + result: dict = {} + result["filePath"] = from_str(self.file_path) + result["kind"] = from_str(self.kind) + result["label"] = from_str(self.label) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsProblemSource: + """One already-loaded settings layer to diagnose.""" + + file_path: str + """Absolute path of the file backing this layer.""" + + kind: str + """Which layer this is: `user`, `repo`, or `local`.""" + + label: str + """Caller-chosen display label for the layer, echoed back on each problem so a caller can + group by layer without re-deriving its own naming. + """ + config: dict[str, Any] | None = None + """The layer's settings exactly as loaded, unnormalized. Empty when the file is missing or + failed to parse. + """ + invalid: bool | None = None + """True when the file itself failed to parse, so its keys could not be read at all.""" + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsProblemSource': + assert isinstance(obj, dict) + file_path = from_str(obj.get("filePath")) + kind = from_str(obj.get("kind")) + label = from_str(obj.get("label")) + config = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("config")) + invalid = from_union([from_bool, from_none], obj.get("invalid")) + return UserSettingsProblemSource(file_path, kind, label, config, invalid) + + def to_dict(self) -> dict: + result: dict = {} + result["filePath"] = from_str(self.file_path) + result["kind"] = from_str(self.kind) + result["label"] = from_str(self.label) + if self.config is not None: + result["config"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.config) + if self.invalid is not None: + result["invalid"] = from_union([from_bool, from_none], self.invalid) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class UserSettingsSetRequest: @@ -18149,6 +19022,124 @@ def to_dict(self) -> dict: result["settings"] = self.settings return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _UserSettingsUpdateRequest: + """Names the user setting to merge into, and the partial object to merge.""" + + key: str + """Top-level user-setting key to merge into, such as `extensions`.""" + + value: Any + """Value to store for `key`. When both the stored value and this value are objects, their + fields are shallow-merged and fields this object does not name are preserved. Otherwise + this value replaces the stored value. + """ + config_dir: str | None = None + """Copilot configuration directory to write the settings document in, taking precedence over + the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to + use the directory the server resolved for itself. + """ + sub_dir: str | None = None + """Single-component name for the settings document at `/settings/.json`; + path separators, `.` and `..` are rejected. Omit it, or pass an empty string, to use the + main settings document. + """ + + @staticmethod + def from_dict(obj: Any) -> '_UserSettingsUpdateRequest': + assert isinstance(obj, dict) + key = from_str(obj.get("key")) + value = obj.get("value") + config_dir = from_union([from_str, from_none], obj.get("configDir")) + sub_dir = from_union([from_str, from_none], obj.get("subDir")) + return _UserSettingsUpdateRequest(key, value, config_dir, sub_dir) + + def to_dict(self) -> dict: + result: dict = {} + result["key"] = from_str(self.key) + result["value"] = self.value + if self.config_dir is not None: + result["configDir"] = from_union([from_str, from_none], self.config_dir) + if self.sub_dir is not None: + result["subDir"] = from_union([from_str, from_none], self.sub_dir) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _UserSettingsUpdateResult: + """The stored value of the user setting after the merge.""" + + value: Any + """The key's stored value after the write: the merged object when both the stored value and + the supplied value are objects, otherwise the supplied value. + """ + + @staticmethod + def from_dict(obj: Any) -> '_UserSettingsUpdateResult': + assert isinstance(obj, dict) + value = obj.get("value") + return _UserSettingsUpdateResult(value) + + def to_dict(self) -> dict: + result: dict = {} + result["value"] = self.value + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsValidateRequest: + """A single top-level setting subtree to validate.""" + + top_key: str + """Top-level setting name to validate.""" + + delete: bool | None = None + """True to validate a removal of this key. The current settings file is not read.""" + + value: Any = None + """Value to validate. Omitted when `delete` is true.""" + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsValidateRequest': + assert isinstance(obj, dict) + top_key = from_str(obj.get("topKey")) + delete = from_union([from_bool, from_none], obj.get("delete")) + value = obj.get("value") + return UserSettingsValidateRequest(top_key, delete, value) + + def to_dict(self) -> dict: + result: dict = {} + result["topKey"] = from_str(self.top_key) + if self.delete is not None: + result["delete"] = from_union([from_bool, from_none], self.delete) + if self.value is not None: + result["value"] = self.value + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsWriteAllRequest: + """The whole content to store in the user settings file.""" + + settings: Any + """The settings object to store. It replaces the file's entire content, so a key absent here + is removed. + """ + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsWriteAllRequest': + assert isinstance(obj, dict) + settings = obj.get("settings") + return UserSettingsWriteAllRequest(settings) + + def to_dict(self) -> dict: + result: dict = {} + result["settings"] = self.settings + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class WorkflowAbortRequest: @@ -22227,6 +23218,32 @@ def to_dict(self) -> dict: result["callbackUrl"] = from_str(self.callback_url) return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class ModelGetReasoningSummariesRequest: + """Host presentation state the reasoning-summaries policy depends on.""" + + persisted_show_reasoning: bool | None = None + """The host's persisted `showReasoning` user setting, omitted when unset.""" + + summaries_visible: bool | None = None + """Whether the host is currently showing reasoning summaries. Defaults to false.""" + + @staticmethod + def from_dict(obj: Any) -> 'ModelGetReasoningSummariesRequest': + assert isinstance(obj, dict) + persisted_show_reasoning = from_union([from_bool, from_none], obj.get("persistedShowReasoning")) + summaries_visible = from_union([from_bool, from_none], obj.get("summariesVisible")) + return ModelGetReasoningSummariesRequest(persisted_show_reasoning, summaries_visible) + + def to_dict(self) -> dict: + result: dict = {} + if self.persisted_show_reasoning is not None: + result["persistedShowReasoning"] = from_union([from_bool, from_none], self.persisted_show_reasoning) + if self.summaries_visible is not None: + result["summariesVisible"] = from_union([from_bool, from_none], self.summaries_visible) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class ModelSetAllowedModelsRequest: @@ -23494,6 +24511,60 @@ def to_dict(self) -> dict: result["type"] = self.type return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _FeatureFlagMetadata: + """The declared shape of one feature flag, independent of any caller population.""" + + availability: _FeatureFlagAvailability + """The population the flag is declared for before any environment or user-settings override + is applied. + """ + capi_sanity: bool + """Whether the flag participates in the CAPI sanity suite.""" + + name: str + """The flag's name, matching the key it is listed under.""" + + experimental_description: str | None = None + """Text shown to a user choosing whether to turn the flag on in experimental mode. Absent + when the flag is not user-facing. + """ + exp_flag: str | None = None + """The online-experiment (ExP) flag this maps to, when the flag is assigned by an experiment + rather than declared statically. + """ + exp_flag_env_var: str | None = None + """Environment variable that overrides this flag's experiment assignment locally in the + experiment service, not in `featureFlags.resolve`. Present exactly when `expFlag` is, and + derived from it, so a caller reads a local override without reproducing the naming rule. + """ + + @staticmethod + def from_dict(obj: Any) -> '_FeatureFlagMetadata': + assert isinstance(obj, dict) + availability = _FeatureFlagAvailability(obj.get("availability")) + capi_sanity = from_bool(obj.get("capiSanity")) + name = from_str(obj.get("name")) + experimental_description = from_union([from_str, from_none], obj.get("experimentalDescription")) + exp_flag = from_union([from_str, from_none], obj.get("expFlag")) + exp_flag_env_var = from_union([from_str, from_none], obj.get("expFlagEnvVar")) + return _FeatureFlagMetadata(availability, capi_sanity, name, experimental_description, exp_flag, exp_flag_env_var) + + def to_dict(self) -> dict: + result: dict = {} + result["availability"] = to_enum(_FeatureFlagAvailability, self.availability) + result["capiSanity"] = from_bool(self.capi_sanity) + result["name"] = from_str(self.name) + if self.experimental_description is not None: + result["experimentalDescription"] = from_union([from_str, from_none], self.experimental_description) + if self.exp_flag is not None: + result["expFlag"] = from_union([from_str, from_none], self.exp_flag) + if self.exp_flag_env_var is not None: + result["expFlagEnvVar"] = from_union([from_str, from_none], self.exp_flag_env_var) + return result + # Experimental: this type is part of an experimental API and may change or be removed. # Internal: this type is an internal SDK API and is not part of the public surface. @dataclass @@ -26181,7 +27252,7 @@ def to_dict(self) -> dict: # Experimental: this type is part of an experimental API and may change or be removed. # Internal: this type is an internal SDK API and is not part of the public surface. @dataclass -class MCPShouldExcludeGitHubToolsRequest: +class _MCPShouldExcludeGitHubToolsRequest: """The session tool filters that decide whether the session still has a shell to run `gh` with. """ @@ -26200,12 +27271,12 @@ class MCPShouldExcludeGitHubToolsRequest: """ @staticmethod - def from_dict(obj: Any) -> 'MCPShouldExcludeGitHubToolsRequest': + def from_dict(obj: Any) -> '_MCPShouldExcludeGitHubToolsRequest': assert isinstance(obj, dict) available_tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("availableTools")) excluded_tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("excludedTools")) tool_filter_precedence = from_union([from_none, OptionsUpdateToolFilterPrecedence], obj.get("toolFilterPrecedence")) - return MCPShouldExcludeGitHubToolsRequest(available_tools, excluded_tools, tool_filter_precedence) + return _MCPShouldExcludeGitHubToolsRequest(available_tools, excluded_tools, tool_filter_precedence) def to_dict(self) -> dict: result: dict = {} @@ -31380,6 +32451,47 @@ def to_dict(self) -> dict: result["sessionId"] = from_str(self.session_id) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _UserSettingsEditRequest: + """One atomic edit of a canonical setting in settings.json.""" + + canonical_path: list[str] + """Nonempty canonical path segments of the setting to edit, starting with its top-level key.""" + + operation: _SettingsEditOperation + """Set a scalar, add or remove a string list item, or remove the setting. The handler + rejects a missing or incompatible value. + """ + config_dir: str | None = None + """Configuration directory to edit. Omitted or empty resolves the server's own home, as in + `user.settings.loadForConfigDir`. + """ + value: Any = UNSET_SENTINEL + """Required boolean, string or number for set, required string for add-item and remove-item, + and forbidden for remove. The runtime rejects all other JSON values. + """ + + @staticmethod + def from_dict(obj: Any) -> '_UserSettingsEditRequest': + assert isinstance(obj, dict) + canonical_path = from_list(from_str, obj.get("canonicalPath")) + operation = _SettingsEditOperation(obj.get("operation")) + config_dir = from_union([from_str, from_none], obj.get("configDir")) + value = obj["value"] if "value" in obj else UNSET_SENTINEL + return _UserSettingsEditRequest(canonical_path, operation, config_dir, value) + + def to_dict(self) -> dict: + result: dict = {} + result["canonicalPath"] = from_list(from_str, self.canonical_path) + result["operation"] = to_enum(_SettingsEditOperation, self.operation) + if self.config_dir is not None: + result["configDir"] = from_union([from_str, from_none], self.config_dir) + if self.value is not UNSET_SENTINEL: + result["value"] = self.value + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class ShellKillRequest: @@ -31430,6 +32542,9 @@ class AgentInfo: disable_model_invocation: bool | None = None """Whether model-driven invocation is disabled for this agent.""" + hooks: dict[str, list[Any]] | None = None + """Declarative hook actions keyed by event name, executed only while this agent is active.""" + mcp_servers: dict[str, Any] | None = None """MCP server configurations attached to this agent, keyed by server name. Server config shape mirrors the MCP `mcpServers` schema. @@ -31479,6 +32594,7 @@ def from_dict(obj: Any) -> 'AgentInfo': id = from_str(obj.get("id")) name = from_str(obj.get("name")) disable_model_invocation = from_union([from_bool, from_none], obj.get("disableModelInvocation")) + hooks = from_union([lambda x: from_dict(lambda x: from_list(lambda x: x, x), x), from_none], obj.get("hooks")) mcp_servers = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("mcpServers")) model = from_union([from_str, from_none], obj.get("model")) model_policy = from_union([AgentModelPolicy, from_none], obj.get("modelPolicy")) @@ -31490,7 +32606,7 @@ def from_dict(obj: Any) -> 'AgentInfo': source = from_union([AgentInfoSource, from_none], obj.get("source")) tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tools")) user_invocable = from_union([from_bool, from_none], obj.get("userInvocable")) - return AgentInfo(description, display_name, id, name, disable_model_invocation, mcp_servers, model, model_policy, models, path, prompt, reasoning_effort, skills, source, tools, user_invocable) + return AgentInfo(description, display_name, id, name, disable_model_invocation, hooks, mcp_servers, model, model_policy, models, path, prompt, reasoning_effort, skills, source, tools, user_invocable) def to_dict(self) -> dict: result: dict = {} @@ -31500,6 +32616,8 @@ def to_dict(self) -> dict: result["name"] = from_str(self.name) if self.disable_model_invocation is not None: result["disableModelInvocation"] = from_union([from_bool, from_none], self.disable_model_invocation) + if self.hooks is not None: + result["hooks"] = from_union([lambda x: from_dict(lambda x: from_list(lambda x: x, x), x), from_none], self.hooks) if self.mcp_servers is not None: result["mcpServers"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.mcp_servers) if self.model is not None: @@ -33024,6 +34142,133 @@ def to_dict(self) -> dict: result["settings"] = from_dict(lambda x: to_class(UserSettingMetadata, x), self.settings) return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsApplyTopKeyResult: + """Outcome of validating and writing one top-level setting subtree.""" + + status: str + """`ok` when the value was written, `validation-error` when it was rejected before any + write, `write-error` when validation passed but the write failed. + """ + error: str | None = None + """Why the write failed, present only when `status` is `write-error`.""" + + issues: list[UserSettingsValidationIssue] | None = None + """Problems found, present only when `status` is `validation-error`.""" + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsApplyTopKeyResult': + assert isinstance(obj, dict) + status = from_str(obj.get("status")) + error = from_union([from_none, from_str], obj.get("error")) + issues = from_union([lambda x: from_list(UserSettingsValidationIssue.from_dict, x), from_none], obj.get("issues")) + return UserSettingsApplyTopKeyResult(status, error, issues) + + def to_dict(self) -> dict: + result: dict = {} + result["status"] = from_str(self.status) + if self.error is not None: + result["error"] = from_union([from_none, from_str], self.error) + if self.issues is not None: + result["issues"] = from_union([lambda x: from_list(lambda x: to_class(UserSettingsValidationIssue, x), x), from_none], self.issues) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsValidateResult: + """Outcome of validating one top-level setting subtree.""" + + ok: bool + """True when the subtree is valid.""" + + issues: list[UserSettingsValidationIssue] | None = None + """Problems found, empty when `ok` is true.""" + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsValidateResult': + assert isinstance(obj, dict) + ok = from_bool(obj.get("ok")) + issues = from_union([lambda x: from_list(UserSettingsValidationIssue.from_dict, x), from_none], obj.get("issues")) + return UserSettingsValidateResult(ok, issues) + + def to_dict(self) -> dict: + result: dict = {} + result["ok"] = from_bool(self.ok) + if self.issues is not None: + result["issues"] = from_union([lambda x: from_list(lambda x: to_class(UserSettingsValidationIssue, x), x), from_none], self.issues) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsProblem: + """One setting that will not take effect, and why.""" + + category: str + """Coarse grouping for the problem, for a caller that presents problems in sections.""" + + explanation: str + """Why the setting will not take effect. Never contains the setting's value, which may be a + token or another secret. + """ + id: str + """Stable identifier for this problem within the reported set, so a caller can track a + selection across refreshes. + """ + kind: str + """What is wrong in machine-readable form, for a caller that wants to branch rather than + display. + """ + source: UserSettingsProblemLocation + """The settings layer the problem was found in.""" + + raw_key: str | None = None + """The offending key as written in the file, when the problem is attributable to a single + key. Absent when the whole file is at fault. + """ + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsProblem': + assert isinstance(obj, dict) + category = from_str(obj.get("category")) + explanation = from_str(obj.get("explanation")) + id = from_str(obj.get("id")) + kind = from_str(obj.get("kind")) + source = UserSettingsProblemLocation.from_dict(obj.get("source")) + raw_key = from_union([from_str, from_none], obj.get("rawKey")) + return UserSettingsProblem(category, explanation, id, kind, source, raw_key) + + def to_dict(self) -> dict: + result: dict = {} + result["category"] = from_str(self.category) + result["explanation"] = from_str(self.explanation) + result["id"] = from_str(self.id) + result["kind"] = from_str(self.kind) + result["source"] = to_class(UserSettingsProblemLocation, self.source) + if self.raw_key is not None: + result["rawKey"] = from_union([from_str, from_none], self.raw_key) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsProblemsRequest: + """The settings layers to diagnose.""" + + sources: list[UserSettingsProblemSource] | None = None + """Layers to diagnose, in the precedence order the caller applies them.""" + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsProblemsRequest': + assert isinstance(obj, dict) + sources = from_union([lambda x: from_list(UserSettingsProblemSource.from_dict, x), from_none], obj.get("sources")) + return UserSettingsProblemsRequest(sources) + + def to_dict(self) -> dict: + result: dict = {} + if self.sources is not None: + result["sources"] = from_union([lambda x: from_list(lambda x: to_class(UserSettingsProblemSource, x), x), from_none], self.sources) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class WorkflowAgentRequest: @@ -35731,6 +36976,26 @@ def to_dict(self) -> dict: result["title"] = from_union([from_str, from_none], self.title) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _FeatureFlagsMetadataResult: + """Every feature flag this runtime declares, with the shape each one was declared with.""" + + flags: dict[str, _FeatureFlagMetadata] + """Declared feature flags keyed by flag name.""" + + @staticmethod + def from_dict(obj: Any) -> '_FeatureFlagsMetadataResult': + assert isinstance(obj, dict) + flags = from_dict(_FeatureFlagMetadata.from_dict, obj.get("flags")) + return _FeatureFlagsMetadataResult(flags) + + def to_dict(self) -> dict: + result: dict = {} + result["flags"] = from_dict(lambda x: to_class(_FeatureFlagMetadata, x), self.flags) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class MCPOauthHandlePendingRequest: @@ -40037,6 +41302,26 @@ def to_dict(self) -> dict: result["response"] = to_class(UIExitPlanModeResponse, self.response) return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsProblemsResult: + """The settings that will not take effect across the given layers.""" + + problems: list[UserSettingsProblem] | None = None + """Each setting that will not take effect, and why. Empty when every layer is healthy.""" + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsProblemsResult': + assert isinstance(obj, dict) + problems = from_union([lambda x: from_list(UserSettingsProblem.from_dict, x), from_none], obj.get("problems")) + return UserSettingsProblemsResult(problems) + + def to_dict(self) -> dict: + result: dict = {} + if self.problems is not None: + result["problems"] = from_union([lambda x: from_list(lambda x: to_class(UserSettingsProblem, x), x), from_none], self.problems) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class WorkflowLogRequest: @@ -44273,6 +45558,13 @@ class SessionUpdateOptionsParams: agent_context: str | None = None """Runtime context discriminator (e.g., `cli`, `actions`).""" + agent_directories: list[str] | None = None + """Explicit discovery-only agent roots, separate from customAgents and filesystem grants. + Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK + paths resolve once when supplied against the request's effective workingDirectory; + retained roots do not move on cwd changes. Null and omission are equivalent; [] clears + only the explicit SDK contribution. + """ allow_all_mcp_server_instructions: bool | None = None """Whether to include instructions from every MCP server in the system prompt instead of only allowlisted servers. @@ -44313,8 +45605,9 @@ class SessionUpdateOptionsParams: """Skill IDs that should be excluded from this session.""" enable_file_hooks: bool | None = None - """Whether to enable loading of `.github/hooks/` filesystem hooks. Separate from the SDK - callback hook mechanism. + """Whether to enable repository-origin file hooks from `.github/hooks/` and trusted + repository-configured roots. Does not control explicit hookDirectories or SDK callback + hooks. """ enable_host_git_operations: bool | None = None """Whether to enable host git operations (context resolution, child repo scanning, git info @@ -44335,9 +45628,10 @@ class SessionUpdateOptionsParams: """Whether to enable cross-session store writes and reads.""" enable_skills: bool | None = None - """Whether skill loading is enabled. Explicit false disables every source, including a bound - SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, - creation falls back to enableConfigDiscovery unless an SDK skill provider is registered. + """Whether skill loading is enabled. Explicit false disables every source, including + explicit SDK roots and a bound SDK provider; changing the value invalidates the loaded + skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless + explicit SDK skill roots or an SDK skill provider are supplied. """ enable_streaming: bool | None = None """Whether to stream model responses.""" @@ -44364,6 +45658,14 @@ class SessionUpdateOptionsParams: feature_flags: dict[str, bool] | None = None """Map of feature-flag IDs to their boolean enabled state.""" + hook_directories: list[str] | None = None + """Explicit discovery-only file-hook roots, separate from callback hooks and filesystem + grants. Available without enableConfigDiscovery or enableFileHooks, which controls + repository-origin hooks only; hook/managed disables still apply. Relative SDK paths + resolve once when supplied against the request's effective workingDirectory; retained + roots do not move on cwd changes. Null and omission are equivalent; [] clears only the + explicit SDK contribution. + """ ignored_skills_locations: list[str] | None = None """Skill scan directories and descendants excluded from discovery. Supports `~`-relative paths. @@ -44382,6 +45684,13 @@ class SessionUpdateOptionsParams: """Full set of installed plugins for the session. Replaces the existing list; the runtime invalidates the skills cache only when the list materially changes. """ + instruction_directories: list[str] | None = None + """Explicit discovery-only instruction roots using existing SDK instruction formats, not + filesystem grants. Available without enableConfigDiscovery, subject to + instruction/managed disables. Relative SDK paths resolve once when supplied against the + request's effective workingDirectory; retained roots do not move on cwd changes. Null and + omission are equivalent; [] clears only the explicit SDK contribution. + """ integration_id: str | None = None """Stable integration identifier used for analytics and rate-limit attribution.""" @@ -44455,8 +45764,12 @@ class SessionUpdateOptionsParams: """PowerShell process flags applied to built-in and user-requested shell commands.""" skill_directories: list[str] | None = None - """Additional directories to search for skills.""" - + """Explicit discovery-only skill roots, not filesystem grants. Available without + enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once + when supplied against the request's effective workingDirectory; retained roots do not + move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK + contribution. + """ skip_custom_instructions: bool | None = None """Whether to skip loading custom instruction sources.""" @@ -44486,6 +45799,7 @@ def from_dict(obj: Any) -> 'SessionUpdateOptionsParams': assert isinstance(obj, dict) additional_content_exclusion_policies = from_union([lambda x: from_list(OptionsUpdateAdditionalContentExclusionPolicy.from_dict, x), from_none], obj.get("additionalContentExclusionPolicies")) agent_context = from_union([from_str, from_none], obj.get("agentContext")) + agent_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("agentDirectories")) allow_all_mcp_server_instructions = from_union([from_bool, from_none], obj.get("allowAllMcpServerInstructions")) ask_user_disabled = from_union([from_bool, from_none], obj.get("askUserDisabled")) available_tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("availableTools")) @@ -44512,10 +45826,12 @@ def from_dict(obj: Any) -> 'SessionUpdateOptionsParams': excluded_builtin_agents = from_union([lambda x: from_list(from_str, x), from_none], obj.get("excludedBuiltinAgents")) excluded_tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("excludedTools")) feature_flags = from_union([lambda x: from_dict(from_bool, x), from_none], obj.get("featureFlags")) + hook_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("hookDirectories")) ignored_skills_locations = from_union([lambda x: from_list(from_str, x), from_none], obj.get("ignoredSkillsLocations")) included_builtin_agents = from_union([lambda x: from_list(from_str, x), from_none], obj.get("includedBuiltinAgents")) included_builtin_skills = from_union([lambda x: from_list(from_str, x), from_none], obj.get("includedBuiltinSkills")) installed_plugins = from_union([lambda x: from_list(SessionInstalledPlugin.from_dict, x), from_none], obj.get("installedPlugins")) + instruction_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("instructionDirectories")) integration_id = from_union([from_str, from_none], obj.get("integrationId")) is_experimental_mode = from_union([from_bool, from_none], obj.get("isExperimentalMode")) log_interactive_shells = from_union([from_bool, from_none], obj.get("logInteractiveShells")) @@ -44544,7 +45860,7 @@ def from_dict(obj: Any) -> 'SessionUpdateOptionsParams': trajectory_file = from_union([from_str, from_none], obj.get("trajectoryFile")) verbosity = from_union([Verbosity, from_none], obj.get("verbosity")) working_directory = from_union([from_str, from_none], obj.get("workingDirectory")) - return SessionUpdateOptionsParams(additional_content_exclusion_policies, agent_context, allow_all_mcp_server_instructions, ask_user_disabled, available_tools, capi, client_name, coauthor_enabled, context_tier, continue_on_auto_mode, copilot_url, custom_agents_local_only, disabled_instruction_sources, disabled_skills, enable_file_hooks, enable_host_git_operations, enable_on_demand_instruction_discovery, enable_reasoning_summaries, enable_script_safety, enable_session_store, enable_skills, enable_streaming, env_value_mode, events_log_directory, events_log_includes_subagents, excluded_builtin_agents, excluded_tools, feature_flags, ignored_skills_locations, included_builtin_agents, included_builtin_skills, installed_plugins, integration_id, is_experimental_mode, log_interactive_shells, lsp_client_name, manage_schedule_enabled, max_inline_binary_bytes, model, model_capabilities_overrides, organization_custom_instructions, provider, reasoning_effort, reasoning_summary, running_in_interactive_mode, sandbox_config, sandbox_config_source, session_capabilities, session_limits, shell, shell_init_profile, shell_process_flags, skill_directories, skip_custom_instructions, skip_embedding_retrieval, suppress_custom_agent_prompt, tool_filter_precedence, trajectory_file, verbosity, working_directory) + return SessionUpdateOptionsParams(additional_content_exclusion_policies, agent_context, agent_directories, allow_all_mcp_server_instructions, ask_user_disabled, available_tools, capi, client_name, coauthor_enabled, context_tier, continue_on_auto_mode, copilot_url, custom_agents_local_only, disabled_instruction_sources, disabled_skills, enable_file_hooks, enable_host_git_operations, enable_on_demand_instruction_discovery, enable_reasoning_summaries, enable_script_safety, enable_session_store, enable_skills, enable_streaming, env_value_mode, events_log_directory, events_log_includes_subagents, excluded_builtin_agents, excluded_tools, feature_flags, hook_directories, ignored_skills_locations, included_builtin_agents, included_builtin_skills, installed_plugins, instruction_directories, integration_id, is_experimental_mode, log_interactive_shells, lsp_client_name, manage_schedule_enabled, max_inline_binary_bytes, model, model_capabilities_overrides, organization_custom_instructions, provider, reasoning_effort, reasoning_summary, running_in_interactive_mode, sandbox_config, sandbox_config_source, session_capabilities, session_limits, shell, shell_init_profile, shell_process_flags, skill_directories, skip_custom_instructions, skip_embedding_retrieval, suppress_custom_agent_prompt, tool_filter_precedence, trajectory_file, verbosity, working_directory) def to_dict(self) -> dict: result: dict = {} @@ -44552,6 +45868,8 @@ def to_dict(self) -> dict: result["additionalContentExclusionPolicies"] = from_union([lambda x: from_list(lambda x: to_class(OptionsUpdateAdditionalContentExclusionPolicy, x), x), from_none], self.additional_content_exclusion_policies) if self.agent_context is not None: result["agentContext"] = from_union([from_str, from_none], self.agent_context) + if self.agent_directories is not None: + result["agentDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.agent_directories) if self.allow_all_mcp_server_instructions is not None: result["allowAllMcpServerInstructions"] = from_union([from_bool, from_none], self.allow_all_mcp_server_instructions) if self.ask_user_disabled is not None: @@ -44604,6 +45922,8 @@ def to_dict(self) -> dict: result["excludedTools"] = from_union([lambda x: from_list(from_str, x), from_none], self.excluded_tools) if self.feature_flags is not None: result["featureFlags"] = from_union([lambda x: from_dict(from_bool, x), from_none], self.feature_flags) + if self.hook_directories is not None: + result["hookDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.hook_directories) if self.ignored_skills_locations is not None: result["ignoredSkillsLocations"] = from_union([lambda x: from_list(from_str, x), from_none], self.ignored_skills_locations) if self.included_builtin_agents is not None: @@ -44612,6 +45932,8 @@ def to_dict(self) -> dict: result["includedBuiltinSkills"] = from_union([lambda x: from_list(from_str, x), from_none], self.included_builtin_skills) if self.installed_plugins is not None: result["installedPlugins"] = from_union([lambda x: from_list(lambda x: to_class(SessionInstalledPlugin, x), x), from_none], self.installed_plugins) + if self.instruction_directories is not None: + result["instructionDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.instruction_directories) if self.integration_id is not None: result["integrationId"] = from_union([from_str, from_none], self.integration_id) if self.is_experimental_mode is not None: @@ -45555,6 +46877,134 @@ def to_dict(self) -> dict: result["token_based_billing"] = from_union([from_bool, from_none], self.token_based_billing) return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class AuthIdentity: + """Identity to describe. + + Credential-free authentication identity safe to expose to hosts and user interfaces. + + Identity to evaluate. + + Identity whose host the path resolves against. Omit to resolve against the public + github.com host. + + Credential-free identity metadata for the active account, including resolved Copilot user + information when available. + """ + host: str + """Authentication host""" + + type: AuthInfoType + """Authentication type""" + + copilot_user: CopilotUserResponse | None = None + """Snapshot of the authenticated user's Copilot subscription info, if known""" + + env_var: str | None = None + """Name of the environment variable that supplied the credential, when applicable""" + + login: str | None = None + """Authenticated login, when available""" + + registration_id: str | None = None + """Opaque SDK GitHub credential registration backing this identity. Routing metadata only; + never a credential. + """ + + @staticmethod + def from_dict(obj: Any) -> 'AuthIdentity': + assert isinstance(obj, dict) + host = from_str(obj.get("host")) + type = AuthInfoType(obj.get("type")) + copilot_user = from_union([CopilotUserResponse.from_dict, from_none], obj.get("copilotUser")) + env_var = from_union([from_str, from_none], obj.get("envVar")) + login = from_union([from_str, from_none], obj.get("login")) + registration_id = from_union([from_str, from_none], obj.get("registrationId")) + return AuthIdentity(host, type, copilot_user, env_var, login, registration_id) + + def to_dict(self) -> dict: + result: dict = {} + result["host"] = from_str(self.host) + result["type"] = to_enum(AuthInfoType, self.type) + if self.copilot_user is not None: + result["copilotUser"] = from_union([lambda x: to_class(CopilotUserResponse, x), from_none], self.copilot_user) + if self.env_var is not None: + result["envVar"] = from_union([from_str, from_none], self.env_var) + if self.login is not None: + result["login"] = from_union([from_str, from_none], self.login) + if self.registration_id is not None: + result["registrationId"] = from_union([from_str, from_none], self.registration_id) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _AccountDescribeAuthInfoRequest: + """The authentication identity whose shared wording should be rendered.""" + + identity: AuthIdentity + """Identity to describe.""" + + @staticmethod + def from_dict(obj: Any) -> '_AccountDescribeAuthInfoRequest': + assert isinstance(obj, dict) + identity = AuthIdentity.from_dict(obj.get("identity")) + return _AccountDescribeAuthInfoRequest(identity) + + def to_dict(self) -> dict: + result: dict = {} + result["identity"] = to_class(AuthIdentity, self.identity) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _AccountGetGistSupportRequest: + """The authentication identity whose gist support should be reported.""" + + identity: AuthIdentity + """Identity to evaluate.""" + + @staticmethod + def from_dict(obj: Any) -> '_AccountGetGistSupportRequest': + assert isinstance(obj, dict) + identity = AuthIdentity.from_dict(obj.get("identity")) + return _AccountGetGistSupportRequest(identity) + + def to_dict(self) -> dict: + result: dict = {} + result["identity"] = to_class(AuthIdentity, self.identity) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _AccountGetWebURLRequest: + """A path to resolve against the GitHub host an identity is signed in to.""" + + path: str + """Host-relative path, without a leading slash, for example `settings/copilot/features`.""" + + identity: AuthIdentity | None = None + """Identity whose host the path resolves against. Omit to resolve against the public + github.com host. + """ + + @staticmethod + def from_dict(obj: Any) -> '_AccountGetWebURLRequest': + assert isinstance(obj, dict) + path = from_str(obj.get("path")) + identity = from_union([AuthIdentity.from_dict, from_none], obj.get("identity")) + return _AccountGetWebURLRequest(path, identity) + + def to_dict(self) -> dict: + result: dict = {} + result["path"] = from_str(self.path) + if self.identity is not None: + result["identity"] = from_union([lambda x: to_class(AuthIdentity, x), from_none], self.identity) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class AgentRegistryLiveTargetEntry: @@ -45813,59 +47263,6 @@ def to_dict(self) -> dict: result["copilotUser"] = from_union([lambda x: to_class(CopilotUserResponse, x), from_none], self.copilot_user) return result -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class AuthIdentity: - """Credential-free authentication identity safe to expose to hosts and user interfaces. - - Credential-free identity metadata for the active account, including resolved Copilot user - information when available. - """ - host: str - """Authentication host""" - - type: AuthInfoType - """Authentication type""" - - copilot_user: CopilotUserResponse | None = None - """Snapshot of the authenticated user's Copilot subscription info, if known""" - - env_var: str | None = None - """Name of the environment variable that supplied the credential, when applicable""" - - login: str | None = None - """Authenticated login, when available""" - - registration_id: str | None = None - """Opaque SDK GitHub credential registration backing this identity. Routing metadata only; - never a credential. - """ - - @staticmethod - def from_dict(obj: Any) -> 'AuthIdentity': - assert isinstance(obj, dict) - host = from_str(obj.get("host")) - type = AuthInfoType(obj.get("type")) - copilot_user = from_union([CopilotUserResponse.from_dict, from_none], obj.get("copilotUser")) - env_var = from_union([from_str, from_none], obj.get("envVar")) - login = from_union([from_str, from_none], obj.get("login")) - registration_id = from_union([from_str, from_none], obj.get("registrationId")) - return AuthIdentity(host, type, copilot_user, env_var, login, registration_id) - - def to_dict(self) -> dict: - result: dict = {} - result["host"] = from_str(self.host) - result["type"] = to_enum(AuthInfoType, self.type) - if self.copilot_user is not None: - result["copilotUser"] = from_union([lambda x: to_class(CopilotUserResponse, x), from_none], self.copilot_user) - if self.env_var is not None: - result["envVar"] = from_union([from_str, from_none], self.env_var) - if self.login is not None: - result["login"] = from_union([from_str, from_none], self.login) - if self.registration_id is not None: - result["registrationId"] = from_union([from_str, from_none], self.registration_id) - return result - # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class AuthReadValue: @@ -46783,7 +48180,7 @@ def to_dict(self) -> dict: # Experimental: this type is part of an experimental API and may change or be removed. # Internal: this type is an internal SDK API and is not part of the public surface. @dataclass -class MCPRegisterExternalClientRequest: +class _MCPRegisterExternalClientRequest: """Registration parameters for an external MCP client.""" client: Any @@ -46803,13 +48200,13 @@ class MCPRegisterExternalClientRequest: """ @staticmethod - def from_dict(obj: Any) -> 'MCPRegisterExternalClientRequest': + def from_dict(obj: Any) -> '_MCPRegisterExternalClientRequest': assert isinstance(obj, dict) client = obj.get("client") config = obj.get("config") server_name = from_str(obj.get("serverName")) transport = obj.get("transport") - return MCPRegisterExternalClientRequest(client, config, server_name, transport) + return _MCPRegisterExternalClientRequest(client, config, server_name, transport) def to_dict(self) -> dict: result: dict = {} @@ -46822,7 +48219,7 @@ def to_dict(self) -> dict: # Experimental: this type is part of an experimental API and may change or be removed. # Internal: this type is an internal SDK API and is not part of the public surface. @dataclass -class MCPRegistrySearchRequest: +class _MCPRegistrySearchRequest: """Registry search terms, the credential to search under, and the request id that makes the search cancellable. """ @@ -46850,14 +48247,14 @@ class MCPRegistrySearchRequest: """ @staticmethod - def from_dict(obj: Any) -> 'MCPRegistrySearchRequest': + def from_dict(obj: Any) -> '_MCPRegistrySearchRequest': assert isinstance(obj, dict) auth_info = obj.get("authInfo") limit = from_int(obj.get("limit")) request_id = from_int(obj.get("requestId")) query = from_union([from_str, from_none], obj.get("query")) repository = from_union([from_str, from_none], obj.get("repository")) - return MCPRegistrySearchRequest(auth_info, limit, request_id, query, repository) + return _MCPRegistrySearchRequest(auth_info, limit, request_id, query, repository) def to_dict(self) -> dict: result: dict = {} @@ -47119,7 +48516,7 @@ def to_dict(self) -> dict: # Experimental: this type is part of an experimental API and may change or be removed. # Internal: this type is an internal SDK API and is not part of the public surface. @dataclass -class MCPReloadConfig: +class _MCPReloadConfig: """In-process MCP reload configuration.""" mcp_servers: dict[str, MCPServerConfig] @@ -47139,7 +48536,7 @@ class MCPReloadConfig: use_cached_tool_snapshots: bool | None = None @staticmethod - def from_dict(obj: Any) -> 'MCPReloadConfig': + def from_dict(obj: Any) -> '_MCPReloadConfig': assert isinstance(obj, dict) mcp_servers = from_dict(MCPServerConfig.from_dict, obj.get("mcpServers")) active_git_hub_token = from_union([from_str, from_none], obj.get("activeGitHubToken")) @@ -47154,7 +48551,7 @@ def from_dict(obj: Any) -> 'MCPReloadConfig': mcp3_p_enabled = from_union([from_bool, from_none], obj.get("mcp3pEnabled")) secret_store = obj.get("secretStore") use_cached_tool_snapshots = from_union([from_bool, from_none], obj.get("useCachedToolSnapshots")) - return MCPReloadConfig(mcp_servers, active_git_hub_token, cli_enabled_servers, config_filter, disabled_servers, enabled_servers, force_restart, github_mcp_tool_options, github_mcp_user_override, include_workspace_sources, mcp3_p_enabled, secret_store, use_cached_tool_snapshots) + return _MCPReloadConfig(mcp_servers, active_git_hub_token, cli_enabled_servers, config_filter, disabled_servers, enabled_servers, force_restart, github_mcp_tool_options, github_mcp_user_override, include_workspace_sources, mcp3_p_enabled, secret_store, use_cached_tool_snapshots) def to_dict(self) -> dict: result: dict = {} @@ -47423,13 +48820,13 @@ def to_dict(self) -> dict: # Experimental: this type is part of an experimental API and may change or be removed. # Internal: this type is an internal SDK API and is not part of the public surface. @dataclass -class MCPServerConfigMemory: +class _MCPServerConfigMemory: """In-process MCP server configuration used by embedded SDK clients.""" server_instance: Any """In-process MCP server instance. This value cannot cross a JSON-RPC boundary.""" - type: MCPServerConfigMemoryType + type: _MCPServerConfigMemoryType config_warnings: list[str] | None = None """Configuration warnings recorded while loading the server.""" @@ -47493,10 +48890,10 @@ class MCPServerConfigMemory: """Tools to include. Defaults to all tools if not specified.""" @staticmethod - def from_dict(obj: Any) -> 'MCPServerConfigMemory': + def from_dict(obj: Any) -> '_MCPServerConfigMemory': assert isinstance(obj, dict) server_instance = obj.get("serverInstance") - type = MCPServerConfigMemoryType(obj.get("type")) + type = _MCPServerConfigMemoryType(obj.get("type")) config_warnings = from_union([lambda x: from_list(from_str, x), from_none], obj.get("configWarnings")) defer_tools = from_union([MCPServerConfigDeferTools, from_none], obj.get("deferTools")) disable_secret_masking = from_union([from_bool, from_none], obj.get("disableSecretMasking")) @@ -47517,12 +48914,12 @@ def from_dict(obj: Any) -> 'MCPServerConfigMemory': source_plugin_version = from_union([from_str, from_none], obj.get("sourcePluginVersion")) timeout = from_union([from_int, from_none], obj.get("timeout")) tools = from_union([lambda x: from_list(from_str, x), from_none], obj.get("tools")) - return MCPServerConfigMemory(server_instance, type, config_warnings, defer_tools, disable_secret_masking, disable_tool_cache, display_name, events, exclude_tools, filter_mapping, is_default_server, notifications, oidc, safe_for_telemetry, slow_connection_threshold_ms, source, source_path, source_plugin, source_plugin_spec, source_plugin_version, timeout, tools) + return _MCPServerConfigMemory(server_instance, type, config_warnings, defer_tools, disable_secret_masking, disable_tool_cache, display_name, events, exclude_tools, filter_mapping, is_default_server, notifications, oidc, safe_for_telemetry, slow_connection_threshold_ms, source, source_path, source_plugin, source_plugin_spec, source_plugin_version, timeout, tools) def to_dict(self) -> dict: result: dict = {} result["serverInstance"] = self.server_instance - result["type"] = to_enum(MCPServerConfigMemoryType, self.type) + result["type"] = to_enum(_MCPServerConfigMemoryType, self.type) if self.config_warnings is not None: result["configWarnings"] = from_union([lambda x: from_list(from_str, x), from_none], self.config_warnings) if self.defer_tools is not None: @@ -48534,6 +49931,13 @@ class SessionOpenOptions: agent_context: str | None = None """Runtime context discriminator for agent filtering.""" + agent_directories: list[str] | None = None + """Explicit discovery-only agent roots, separate from customAgents and filesystem grants. + Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK + paths resolve once when supplied against the request's effective workingDirectory; + retained roots do not move on cwd changes. Null and omission are equivalent; [] clears + only the explicit SDK contribution. + """ allow_all_mcp_server_instructions: bool | None = None """Whether to include instructions from every MCP server in the system prompt instead of only allowlisted servers. @@ -48634,8 +50038,8 @@ class SessionOpenOptions: """Whether shell-script safety heuristics are enabled.""" enable_skills: bool | None = None - """Whether skill loading is enabled. When omitted, an SDK skill provider enables skills by - default. + """Whether skill loading is enabled. When omitted, explicit SDK skill roots or an SDK skill + provider enable skills independently of enableConfigDiscovery. """ enable_streaming: bool | None = None """Whether model responses stream as delta events.""" @@ -48680,6 +50084,14 @@ class SessionOpenOptions: sessions.open flows reject it because they cannot safely pre-register the callback handler. """ + hook_directories: list[str] | None = None + """Explicit discovery-only file-hook roots, separate from callback hooks and filesystem + grants. Available without enableConfigDiscovery or enableFileHooks, which controls + repository-origin hooks only; hook/managed disables still apply. Relative SDK paths + resolve once when supplied against the request's effective workingDirectory; retained + roots do not move on cwd changes. Null and omission are equivalent; [] clears only the + explicit SDK contribution. + """ ignored_skills_locations: list[str] | None = None """Skill scan directories and descendants excluded from discovery. Supports `~`-relative paths. @@ -48697,6 +50109,13 @@ class SessionOpenOptions: installed_plugins: list[InstalledPlugin] | None = None """Installed plugins visible to the session.""" + instruction_directories: list[str] | None = None + """Explicit discovery-only instruction roots using existing SDK instruction formats, not + filesystem grants. Available without enableConfigDiscovery, subject to + instruction/managed disables. Relative SDK paths resolve once when supplied against the + request's effective workingDirectory; retained roots do not move on cwd changes. Null and + omission are equivalent; [] clears only the explicit SDK contribution. + """ integration_id: str | None = None """Stable integration identifier for analytics.""" @@ -48797,8 +50216,12 @@ class SessionOpenOptions: """PowerShell process flags applied to built-in and user-requested shell commands.""" skill_directories: list[str] | None = None - """Additional directories to search for skills.""" - + """Explicit discovery-only skill roots, not filesystem grants. Available without + enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once + when supplied against the request's effective workingDirectory; retained roots do not + move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK + contribution. + """ skip_custom_instructions: bool | None = None """Whether to skip custom instruction sources.""" @@ -48820,6 +50243,7 @@ def from_dict(obj: Any) -> 'SessionOpenOptions': additional_content_exclusion_policies = from_union([lambda x: from_list(SessionOpenOptionsAdditionalContentExclusionPolicy.from_dict, x), from_none], obj.get("additionalContentExclusionPolicies")) additional_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("additionalDirectories")) agent_context = from_union([from_str, from_none], obj.get("agentContext")) + agent_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("agentDirectories")) allow_all_mcp_server_instructions = from_union([from_bool, from_none], obj.get("allowAllMcpServerInstructions")) ask_user_disabled = from_union([from_bool, from_none], obj.get("askUserDisabled")) auth_client_id_metadata_url = from_union([from_str, from_none], obj.get("authClientIdMetadataUrl")) @@ -48855,10 +50279,12 @@ def from_dict(obj: Any) -> 'SessionOpenOptions': exp_assignments = obj.get("expAssignments") feature_flags = from_union([lambda x: from_dict(from_bool, x), from_none], obj.get("featureFlags")) has_skill_provider = from_union([from_bool, from_none], obj.get("hasSkillProvider")) + hook_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("hookDirectories")) ignored_skills_locations = from_union([lambda x: from_list(from_str, x), from_none], obj.get("ignoredSkillsLocations")) included_builtin_agents = from_union([lambda x: from_list(from_str, x), from_none], obj.get("includedBuiltinAgents")) included_builtin_skills = from_union([lambda x: from_list(from_str, x), from_none], obj.get("includedBuiltinSkills")) installed_plugins = from_union([lambda x: from_list(InstalledPlugin.from_dict, x), from_none], obj.get("installedPlugins")) + instruction_directories = from_union([lambda x: from_list(from_str, x), from_none], obj.get("instructionDirectories")) integration_id = from_union([from_str, from_none], obj.get("integrationId")) is_experimental_mode = from_union([from_bool, from_none], obj.get("isExperimentalMode")) log_interactive_shells = from_union([from_bool, from_none], obj.get("logInteractiveShells")) @@ -48894,7 +50320,7 @@ def from_dict(obj: Any) -> 'SessionOpenOptions': verbosity = from_union([Verbosity, from_none], obj.get("verbosity")) working_directory = from_union([from_str, from_none], obj.get("workingDirectory")) working_directory_context = from_union([SessionContext.from_dict, from_none], obj.get("workingDirectoryContext")) - return SessionOpenOptions(additional_content_exclusion_policies, additional_directories, agent_context, allow_all_mcp_server_instructions, ask_user_disabled, auth_client_id_metadata_url, auth_info, auto_tier_is_explicit, available_tools, capi, client_kind, client_name, coauthor_enabled, config_dir, continue_on_auto_mode, copilot_url, custom_agents_local_only, detached_from_spawning_parent_engagement_id, detached_from_spawning_parent_session_id, disabled_instruction_sources, disabled_mcp_servers, disabled_skills, enable_citations, enable_file_change_tracking, enable_managed_settings, enable_on_demand_instruction_discovery, enable_script_safety, enable_skills, enable_streaming, enforce_managed_model_defaults, env_value_mode, events_log_directory, events_log_includes_subagents, excluded_builtin_agents, excluded_tools, exp_assignments, feature_flags, has_skill_provider, ignored_skills_locations, included_builtin_agents, included_builtin_skills, installed_plugins, integration_id, is_experimental_mode, log_interactive_shells, lsp_client_name, managed_mcp_servers, managed_settings, max_inline_binary_bytes, memory, model, model_capabilities_overrides, models, name, provider, providers, reasoning_effort, reasoning_summary, refresh_custom_instructions, remote_defaulted_on, remote_exporting, remote_steerable, running_in_interactive_mode, sandbox_config, sandbox_config_source, session_capabilities, session_id, session_limits, shell, shell_init_profile, shell_process_flags, skill_directories, skip_custom_instructions, trajectory_file, verbosity, working_directory, working_directory_context) + return SessionOpenOptions(additional_content_exclusion_policies, additional_directories, agent_context, agent_directories, allow_all_mcp_server_instructions, ask_user_disabled, auth_client_id_metadata_url, auth_info, auto_tier_is_explicit, available_tools, capi, client_kind, client_name, coauthor_enabled, config_dir, continue_on_auto_mode, copilot_url, custom_agents_local_only, detached_from_spawning_parent_engagement_id, detached_from_spawning_parent_session_id, disabled_instruction_sources, disabled_mcp_servers, disabled_skills, enable_citations, enable_file_change_tracking, enable_managed_settings, enable_on_demand_instruction_discovery, enable_script_safety, enable_skills, enable_streaming, enforce_managed_model_defaults, env_value_mode, events_log_directory, events_log_includes_subagents, excluded_builtin_agents, excluded_tools, exp_assignments, feature_flags, has_skill_provider, hook_directories, ignored_skills_locations, included_builtin_agents, included_builtin_skills, installed_plugins, instruction_directories, integration_id, is_experimental_mode, log_interactive_shells, lsp_client_name, managed_mcp_servers, managed_settings, max_inline_binary_bytes, memory, model, model_capabilities_overrides, models, name, provider, providers, reasoning_effort, reasoning_summary, refresh_custom_instructions, remote_defaulted_on, remote_exporting, remote_steerable, running_in_interactive_mode, sandbox_config, sandbox_config_source, session_capabilities, session_id, session_limits, shell, shell_init_profile, shell_process_flags, skill_directories, skip_custom_instructions, trajectory_file, verbosity, working_directory, working_directory_context) def to_dict(self) -> dict: result: dict = {} @@ -48904,6 +50330,8 @@ def to_dict(self) -> dict: result["additionalDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.additional_directories) if self.agent_context is not None: result["agentContext"] = from_union([from_str, from_none], self.agent_context) + if self.agent_directories is not None: + result["agentDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.agent_directories) if self.allow_all_mcp_server_instructions is not None: result["allowAllMcpServerInstructions"] = from_union([from_bool, from_none], self.allow_all_mcp_server_instructions) if self.ask_user_disabled is not None: @@ -48974,6 +50402,8 @@ def to_dict(self) -> dict: result["featureFlags"] = from_union([lambda x: from_dict(from_bool, x), from_none], self.feature_flags) if self.has_skill_provider is not None: result["hasSkillProvider"] = from_union([from_bool, from_none], self.has_skill_provider) + if self.hook_directories is not None: + result["hookDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.hook_directories) if self.ignored_skills_locations is not None: result["ignoredSkillsLocations"] = from_union([lambda x: from_list(from_str, x), from_none], self.ignored_skills_locations) if self.included_builtin_agents is not None: @@ -48982,6 +50412,8 @@ def to_dict(self) -> dict: result["includedBuiltinSkills"] = from_union([lambda x: from_list(from_str, x), from_none], self.included_builtin_skills) if self.installed_plugins is not None: result["installedPlugins"] = from_union([lambda x: from_list(lambda x: to_class(InstalledPlugin, x), x), from_none], self.installed_plugins) + if self.instruction_directories is not None: + result["instructionDirectories"] = from_union([lambda x: from_list(from_str, x), from_none], self.instruction_directories) if self.integration_id is not None: result["integrationId"] = from_union([from_str, from_none], self.integration_id) if self.is_experimental_mode is not None: @@ -49497,6 +50929,40 @@ def to_dict(self) -> dict: result["copilotUser"] = from_union([lambda x: to_class(CopilotUserResponse, x), from_none], self.copilot_user) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +class _SettingsEditStatus(Enum): + """Changed, unchanged or invalid existing file. Rejected input, validation failures and I/O + errors remain RPC errors. + + Whether one atomic settings edit changed a file. + """ + CHANGED = "changed" + INVALID = "invalid" + UNCHANGED = "unchanged" + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _SettingsEditResult: + """Outcome of an atomic user or repository settings edit.""" + + status: _SettingsEditStatus + """Changed, unchanged or invalid existing file. Rejected input, validation failures and I/O + errors remain RPC errors. + """ + + @staticmethod + def from_dict(obj: Any) -> '_SettingsEditResult': + assert isinstance(obj, dict) + status = _SettingsEditStatus(obj.get("status")) + return _SettingsEditResult(status) + + def to_dict(self) -> dict: + result: dict = {} + result["status"] = to_enum(_SettingsEditStatus, self.status) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class ShellExecRequest: @@ -50167,10 +51633,17 @@ class RPC: accepted_enqueue_command_result: AcceptedEnqueueCommandResult account_all_users: AccountAllUsers account_auth_info: AccountAuthInfo + account_describe_auth_info_request: _AccountDescribeAuthInfoRequest + account_describe_auth_info_result: _AccountDescribeAuthInfoResult account_get_all_users_result: list[AccountAllUsers] account_get_current_auth_result: AccountGetCurrentAuthResult + account_get_gist_support_request: _AccountGetGistSupportRequest + account_get_gist_support_result: _AccountGetGistSupportResult account_get_quota_request: AccountGetQuotaRequest account_get_quota_result: AccountGetQuotaResult + account_get_token_env_var_result: _AccountGetTokenEnvVarResult + account_get_web_url_request: _AccountGetWebURLRequest + account_get_web_url_result: _AccountGetWebURLResult account_kind: AccountKind account_login_request: AccountLoginRequest account_login_result: AccountLoginResult @@ -50521,6 +51994,11 @@ class RPC: external_tool_text_result_for_llm_content_shell_exit: ExternalToolTextResultForLlmContentShellExit external_tool_text_result_for_llm_content_terminal: ExternalToolTextResultForLlmContentTerminal external_tool_text_result_for_llm_content_text: ExternalToolTextResultForLlmContentText + feature_flag_availability: _FeatureFlagAvailability + feature_flag_metadata: _FeatureFlagMetadata + feature_flags_metadata_result: _FeatureFlagsMetadataResult + feature_flags_resolve_request: _FeatureFlagsResolveRequest + feature_flags_resolve_result: dict[str, bool] filter_mapping: dict[str, ContentFilterMode] | ContentFilterMode fleet_start_request: FleetStartRequest fleet_start_result: FleetStartResult @@ -50536,7 +52014,7 @@ class RPC: git_hub_owners_cancel_result: _GitHubOwnersCancelResult git_hub_owners_list_request: _GitHubOwnersListRequest git_hub_owners_list_result: _GitHubOwnersListResult - git_hub_owners_request_id_result: GitHubOwnersRequestIDResult + git_hub_owners_request_id_result: _GitHubOwnersRequestIDResult git_hub_repository_at_path_request: _GitHubRepositoryAtPathRequest git_hub_repository_at_path_result: _GitHubRepositoryAtPathResult git_hub_repository_identity: GitHubRepositoryIdentity @@ -50622,9 +52100,11 @@ class RPC: instruction_discovery_path_kind: DebugCollectLogsEntryKind instruction_discovery_path_list: InstructionDiscoveryPathList instruction_discovery_path_location: InstructionLocation + instructions_discover_repo_sources_request: _InstructionsDiscoverRepoSourcesRequest instructions_discover_request: InstructionsDiscoverRequest instructions_get_discovery_paths_request: InstructionsGetDiscoveryPathsRequest instructions_get_sources_result: InstructionsGetSourcesResult + instructions_init_prompt_result: _InstructionsInitPromptResult instruction_source: InstructionSource instruction_source_location: InstructionLocation instruction_source_type: InstructionSourceType @@ -50719,7 +52199,7 @@ class RPC: mcp_configured_server: MCPConfiguredServer mcp_configured_server_list: MCPConfiguredServerList mcp_configured_server_state: MCPConfiguredServerState - mcp_configure_git_hub_request: MCPConfigureGitHubRequest + mcp_configure_git_hub_request: _MCPConfigureGitHubRequest mcp_configure_git_hub_result: MCPConfigureGitHubResult mcp_diagnostic_details: MCPDiagnosticDetails mcp_diagnostic_direction: MCPDiagnosticDirection @@ -50757,6 +52237,7 @@ class RPC: mcp_install_plan: MCPInstallPlan mcp_is_server_running_request: MCPIsServerRunningRequest mcp_is_server_running_result: MCPIsServerRunningResult + mcp_list_builtin_server_names_result: _MCPListBuiltinServerNamesResult mcp_list_tools_request: MCPListToolsRequest mcp_list_tools_result: MCPListToolsResult mcp_oauth_authentication_state_changed_request: MCPOauthAuthenticationStateChangedRequest @@ -50823,14 +52304,14 @@ class RPC: mcp_prompts_get_result: MCPPromptsGetResult mcp_prompts_list_request: MCPPromptsListRequest mcp_prompts_list_result: MCPPromptsListResult - mcp_register_external_client_request: MCPRegisterExternalClientRequest - mcp_registry_cancel_request: MCPRegistryCancelRequest - mcp_registry_cancel_result: MCPRegistryCancelResult - mcp_registry_request_id_result: MCPRegistryRequestIDResult - mcp_registry_search_request: MCPRegistrySearchRequest - mcp_registry_search_result: MCPRegistrySearchResult - mcp_reload_config: MCPReloadConfig - mcp_reload_with_config_request: MCPReloadWithConfigRequest + mcp_register_external_client_request: _MCPRegisterExternalClientRequest + mcp_registry_cancel_request: _MCPRegistryCancelRequest + mcp_registry_cancel_result: _MCPRegistryCancelResult + mcp_registry_request_id_result: _MCPRegistryRequestIDResult + mcp_registry_search_request: _MCPRegistrySearchRequest + mcp_registry_search_result: _MCPRegistrySearchResult + mcp_reload_config: _MCPReloadConfig + mcp_reload_with_config_request: _MCPReloadWithConfigRequest mcp_remove_git_hub_result: MCPRemoveGitHubResult mcp_resource: MCPResource mcp_resource_annotations: MCPResourceAnnotations @@ -50863,8 +52344,8 @@ class RPC: mcp_server_config_http: MCPServerConfigHTTP mcp_server_config_http_oauth_grant_type: MCPGrantType mcp_server_config_http_type: MCPServerConfigHTTPType - mcp_server_config_memory: MCPServerConfigMemory - mcp_server_config_memory_type: MCPServerConfigMemoryType + mcp_server_config_memory: _MCPServerConfigMemory + mcp_server_config_memory_type: _MCPServerConfigMemoryType mcp_server_config_stdio: MCPServerConfigStdio mcp_server_config_stdio_type: MCPServerConfigStdioType mcp_server_failure_info: MCPServerFailureInfo @@ -50874,8 +52355,8 @@ class RPC: mcp_set_env_value_mode_details: MCPSetEnvValueModeDetails mcp_set_env_value_mode_params: MCPSetEnvValueModeParams mcp_set_env_value_mode_result: MCPSetEnvValueModeResult - mcp_should_exclude_git_hub_tools_request: MCPShouldExcludeGitHubToolsRequest - mcp_should_exclude_git_hub_tools_result: MCPShouldExcludeGitHubToolsResult + mcp_should_exclude_git_hub_tools_request: _MCPShouldExcludeGitHubToolsRequest + mcp_should_exclude_git_hub_tools_result: _MCPShouldExcludeGitHubToolsResult mcp_source_file: MCPSourceFile mcp_source_plugin: MCPSourcePlugin mcp_source_ref: MCPSourceRef @@ -50887,7 +52368,7 @@ class RPC: mcp_tool_ui: MCPToolUI mcp_tool_ui_visibility: MCPToolUIVisibility mcp_uninstall_plan: MCPUninstallPlan - mcp_unregister_external_client_request: MCPUnregisterExternalClientRequest + mcp_unregister_external_client_request: _MCPUnregisterExternalClientRequest memory_configuration: MemoryConfiguration metadata_context_attribution_result: MetadataContextAttributionResult metadata_context_heaviest_messages_request: MetadataContextHeaviestMessagesRequest @@ -50923,6 +52404,8 @@ class RPC: model_capabilities_supports: ModelCapabilitiesSupports model_clear_startup_seed_request: _ModelClearStartupSeedRequest model_clear_startup_seed_result: _ModelClearStartupSeedResult + model_get_reasoning_summaries_request: ModelGetReasoningSummariesRequest + model_get_reasoning_summaries_result: ModelGetReasoningSummariesResult model_list: ModelList model_list_request: Any model_message: ModelMessage @@ -51238,6 +52721,10 @@ class RPC: remote_session_metadata_value: RemoteSessionMetadataValue remote_session_mode: RemoteSessionMode remote_session_repository: RemoteSessionRepository + repo_settings_read_raw_request: _RepoSettingsReadRawRequest + repo_settings_read_raw_result: _RepoSettingsReadRawResult + repo_settings_write_all_request: _RepoSettingsWriteAllRequest + repo_settings_write_key_request: _RepoSettingsWriteKeyRequest response_format: ResponseFormat sandbox_config: SandboxConfig sandbox_config_auth: SandboxConfigAuth @@ -51494,6 +52981,9 @@ class RPC: session_working_directory_context_with_client: SessionWorkingDirectoryContextWithClient settable_auth_info: SettableAuthInfo settable_token_auth_info: SettableTokenAuthInfo + settings_edit_operation: _SettingsEditOperation + settings_edit_result: _SettingsEditResult + settings_edit_status: _SettingsEditStatus shell_cancel_user_requested_request: ShellCancelUserRequestedRequest shell_credentials: ShellCredentials shell_exec_request: ShellExecRequest @@ -51680,8 +53170,28 @@ class RPC: user_auth_info: UserAuthInfo user_requested_shell_command_result: UserRequestedShellCommandResult user_setting_metadata: UserSettingMetadata + user_settings_apply_top_key_request: UserSettingsApplyTopKeyRequest + user_settings_apply_top_key_result: UserSettingsApplyTopKeyResult + user_settings_edit_request: _UserSettingsEditRequest + user_settings_get_paths_request: UserSettingsGetPathsRequest + user_settings_get_paths_result: UserSettingsGetPathsResult user_settings_get_result: UserSettingsGetResult + user_settings_governance_keys_result: UserSettingsGovernanceKeysResult + user_settings_load_for_edit_result: UserSettingsLoadForEditResult + user_settings_normalize_request: UserSettingsNormalizeRequest + user_settings_normalize_result: UserSettingsNormalizeResult + user_settings_problem: UserSettingsProblem + user_settings_problem_location: UserSettingsProblemLocation + user_settings_problem_source: UserSettingsProblemSource + user_settings_problems_request: UserSettingsProblemsRequest + user_settings_problems_result: UserSettingsProblemsResult user_settings_set_request: UserSettingsSetRequest + user_settings_update_request: _UserSettingsUpdateRequest + user_settings_update_result: _UserSettingsUpdateResult + user_settings_validate_request: UserSettingsValidateRequest + user_settings_validate_result: UserSettingsValidateResult + user_settings_validation_issue: UserSettingsValidationIssue + user_settings_write_all_request: UserSettingsWriteAllRequest visibility_get_result: VisibilityGetResult visibility_set_request: VisibilitySetRequest visibility_set_result: VisibilitySetResult @@ -51782,10 +53292,17 @@ def from_dict(obj: Any) -> 'RPC': accepted_enqueue_command_result = AcceptedEnqueueCommandResult.from_dict(obj.get("AcceptedEnqueueCommandResult")) account_all_users = AccountAllUsers.from_dict(obj.get("AccountAllUsers")) account_auth_info = AccountAuthInfo.from_dict(obj.get("AccountAuthInfo")) + account_describe_auth_info_request = _AccountDescribeAuthInfoRequest.from_dict(obj.get("AccountDescribeAuthInfoRequest")) + account_describe_auth_info_result = _AccountDescribeAuthInfoResult.from_dict(obj.get("AccountDescribeAuthInfoResult")) account_get_all_users_result = from_list(AccountAllUsers.from_dict, obj.get("AccountGetAllUsersResult")) account_get_current_auth_result = AccountGetCurrentAuthResult.from_dict(obj.get("AccountGetCurrentAuthResult")) + account_get_gist_support_request = _AccountGetGistSupportRequest.from_dict(obj.get("AccountGetGistSupportRequest")) + account_get_gist_support_result = _AccountGetGistSupportResult.from_dict(obj.get("AccountGetGistSupportResult")) account_get_quota_request = AccountGetQuotaRequest.from_dict(obj.get("AccountGetQuotaRequest")) account_get_quota_result = AccountGetQuotaResult.from_dict(obj.get("AccountGetQuotaResult")) + account_get_token_env_var_result = _AccountGetTokenEnvVarResult.from_dict(obj.get("AccountGetTokenEnvVarResult")) + account_get_web_url_request = _AccountGetWebURLRequest.from_dict(obj.get("AccountGetWebUrlRequest")) + account_get_web_url_result = _AccountGetWebURLResult.from_dict(obj.get("AccountGetWebUrlResult")) account_kind = AccountKind(obj.get("AccountKind")) account_login_request = AccountLoginRequest.from_dict(obj.get("AccountLoginRequest")) account_login_result = AccountLoginResult.from_dict(obj.get("AccountLoginResult")) @@ -52136,6 +53653,11 @@ def from_dict(obj: Any) -> 'RPC': external_tool_text_result_for_llm_content_shell_exit = ExternalToolTextResultForLlmContentShellExit.from_dict(obj.get("ExternalToolTextResultForLlmContentShellExit")) external_tool_text_result_for_llm_content_terminal = ExternalToolTextResultForLlmContentTerminal.from_dict(obj.get("ExternalToolTextResultForLlmContentTerminal")) external_tool_text_result_for_llm_content_text = ExternalToolTextResultForLlmContentText.from_dict(obj.get("ExternalToolTextResultForLlmContentText")) + feature_flag_availability = _FeatureFlagAvailability(obj.get("FeatureFlagAvailability")) + feature_flag_metadata = _FeatureFlagMetadata.from_dict(obj.get("FeatureFlagMetadata")) + feature_flags_metadata_result = _FeatureFlagsMetadataResult.from_dict(obj.get("FeatureFlagsMetadataResult")) + feature_flags_resolve_request = _FeatureFlagsResolveRequest.from_dict(obj.get("FeatureFlagsResolveRequest")) + feature_flags_resolve_result = from_dict(from_bool, obj.get("FeatureFlagsResolveResult")) filter_mapping = from_union([lambda x: from_dict(ContentFilterMode, x), ContentFilterMode], obj.get("FilterMapping")) fleet_start_request = FleetStartRequest.from_dict(obj.get("FleetStartRequest")) fleet_start_result = FleetStartResult.from_dict(obj.get("FleetStartResult")) @@ -52151,7 +53673,7 @@ def from_dict(obj: Any) -> 'RPC': git_hub_owners_cancel_result = _GitHubOwnersCancelResult.from_dict(obj.get("GitHubOwnersCancelResult")) git_hub_owners_list_request = _GitHubOwnersListRequest.from_dict(obj.get("GitHubOwnersListRequest")) git_hub_owners_list_result = _GitHubOwnersListResult.from_dict(obj.get("GitHubOwnersListResult")) - git_hub_owners_request_id_result = GitHubOwnersRequestIDResult.from_dict(obj.get("GitHubOwnersRequestIdResult")) + git_hub_owners_request_id_result = _GitHubOwnersRequestIDResult.from_dict(obj.get("GitHubOwnersRequestIdResult")) git_hub_repository_at_path_request = _GitHubRepositoryAtPathRequest.from_dict(obj.get("GitHubRepositoryAtPathRequest")) git_hub_repository_at_path_result = _GitHubRepositoryAtPathResult.from_dict(obj.get("GitHubRepositoryAtPathResult")) git_hub_repository_identity = GitHubRepositoryIdentity.from_dict(obj.get("GitHubRepositoryIdentity")) @@ -52237,9 +53759,11 @@ def from_dict(obj: Any) -> 'RPC': instruction_discovery_path_kind = DebugCollectLogsEntryKind(obj.get("InstructionDiscoveryPathKind")) instruction_discovery_path_list = InstructionDiscoveryPathList.from_dict(obj.get("InstructionDiscoveryPathList")) instruction_discovery_path_location = InstructionLocation(obj.get("InstructionDiscoveryPathLocation")) + instructions_discover_repo_sources_request = _InstructionsDiscoverRepoSourcesRequest.from_dict(obj.get("InstructionsDiscoverRepoSourcesRequest")) instructions_discover_request = InstructionsDiscoverRequest.from_dict(obj.get("InstructionsDiscoverRequest")) instructions_get_discovery_paths_request = InstructionsGetDiscoveryPathsRequest.from_dict(obj.get("InstructionsGetDiscoveryPathsRequest")) instructions_get_sources_result = InstructionsGetSourcesResult.from_dict(obj.get("InstructionsGetSourcesResult")) + instructions_init_prompt_result = _InstructionsInitPromptResult.from_dict(obj.get("InstructionsInitPromptResult")) instruction_source = InstructionSource.from_dict(obj.get("InstructionSource")) instruction_source_location = InstructionLocation(obj.get("InstructionSourceLocation")) instruction_source_type = InstructionSourceType(obj.get("InstructionSourceType")) @@ -52334,7 +53858,7 @@ def from_dict(obj: Any) -> 'RPC': mcp_configured_server = MCPConfiguredServer.from_dict(obj.get("McpConfiguredServer")) mcp_configured_server_list = MCPConfiguredServerList.from_dict(obj.get("McpConfiguredServerList")) mcp_configured_server_state = MCPConfiguredServerState.from_dict(obj.get("McpConfiguredServerState")) - mcp_configure_git_hub_request = MCPConfigureGitHubRequest.from_dict(obj.get("McpConfigureGitHubRequest")) + mcp_configure_git_hub_request = _MCPConfigureGitHubRequest.from_dict(obj.get("McpConfigureGitHubRequest")) mcp_configure_git_hub_result = MCPConfigureGitHubResult.from_dict(obj.get("McpConfigureGitHubResult")) mcp_diagnostic_details = MCPDiagnosticDetails.from_dict(obj.get("McpDiagnosticDetails")) mcp_diagnostic_direction = MCPDiagnosticDirection(obj.get("McpDiagnosticDirection")) @@ -52372,6 +53896,7 @@ def from_dict(obj: Any) -> 'RPC': mcp_install_plan = MCPInstallPlan.from_dict(obj.get("McpInstallPlan")) mcp_is_server_running_request = MCPIsServerRunningRequest.from_dict(obj.get("McpIsServerRunningRequest")) mcp_is_server_running_result = MCPIsServerRunningResult.from_dict(obj.get("McpIsServerRunningResult")) + mcp_list_builtin_server_names_result = _MCPListBuiltinServerNamesResult.from_dict(obj.get("McpListBuiltinServerNamesResult")) mcp_list_tools_request = MCPListToolsRequest.from_dict(obj.get("McpListToolsRequest")) mcp_list_tools_result = MCPListToolsResult.from_dict(obj.get("McpListToolsResult")) mcp_oauth_authentication_state_changed_request = MCPOauthAuthenticationStateChangedRequest.from_dict(obj.get("McpOauthAuthenticationStateChangedRequest")) @@ -52438,14 +53963,14 @@ def from_dict(obj: Any) -> 'RPC': mcp_prompts_get_result = MCPPromptsGetResult.from_dict(obj.get("McpPromptsGetResult")) mcp_prompts_list_request = MCPPromptsListRequest.from_dict(obj.get("McpPromptsListRequest")) mcp_prompts_list_result = MCPPromptsListResult.from_dict(obj.get("McpPromptsListResult")) - mcp_register_external_client_request = MCPRegisterExternalClientRequest.from_dict(obj.get("McpRegisterExternalClientRequest")) - mcp_registry_cancel_request = MCPRegistryCancelRequest.from_dict(obj.get("McpRegistryCancelRequest")) - mcp_registry_cancel_result = MCPRegistryCancelResult.from_dict(obj.get("McpRegistryCancelResult")) - mcp_registry_request_id_result = MCPRegistryRequestIDResult.from_dict(obj.get("McpRegistryRequestIdResult")) - mcp_registry_search_request = MCPRegistrySearchRequest.from_dict(obj.get("McpRegistrySearchRequest")) - mcp_registry_search_result = MCPRegistrySearchResult.from_dict(obj.get("McpRegistrySearchResult")) - mcp_reload_config = MCPReloadConfig.from_dict(obj.get("McpReloadConfig")) - mcp_reload_with_config_request = MCPReloadWithConfigRequest.from_dict(obj.get("McpReloadWithConfigRequest")) + mcp_register_external_client_request = _MCPRegisterExternalClientRequest.from_dict(obj.get("McpRegisterExternalClientRequest")) + mcp_registry_cancel_request = _MCPRegistryCancelRequest.from_dict(obj.get("McpRegistryCancelRequest")) + mcp_registry_cancel_result = _MCPRegistryCancelResult.from_dict(obj.get("McpRegistryCancelResult")) + mcp_registry_request_id_result = _MCPRegistryRequestIDResult.from_dict(obj.get("McpRegistryRequestIdResult")) + mcp_registry_search_request = _MCPRegistrySearchRequest.from_dict(obj.get("McpRegistrySearchRequest")) + mcp_registry_search_result = _MCPRegistrySearchResult.from_dict(obj.get("McpRegistrySearchResult")) + mcp_reload_config = _MCPReloadConfig.from_dict(obj.get("McpReloadConfig")) + mcp_reload_with_config_request = _MCPReloadWithConfigRequest.from_dict(obj.get("McpReloadWithConfigRequest")) mcp_remove_git_hub_result = MCPRemoveGitHubResult.from_dict(obj.get("McpRemoveGitHubResult")) mcp_resource = MCPResource.from_dict(obj.get("McpResource")) mcp_resource_annotations = MCPResourceAnnotations.from_dict(obj.get("McpResourceAnnotations")) @@ -52478,8 +54003,8 @@ def from_dict(obj: Any) -> 'RPC': mcp_server_config_http = MCPServerConfigHTTP.from_dict(obj.get("McpServerConfigHttp")) mcp_server_config_http_oauth_grant_type = MCPGrantType(obj.get("McpServerConfigHttpOauthGrantType")) mcp_server_config_http_type = MCPServerConfigHTTPType(obj.get("McpServerConfigHttpType")) - mcp_server_config_memory = MCPServerConfigMemory.from_dict(obj.get("McpServerConfigMemory")) - mcp_server_config_memory_type = MCPServerConfigMemoryType(obj.get("McpServerConfigMemoryType")) + mcp_server_config_memory = _MCPServerConfigMemory.from_dict(obj.get("McpServerConfigMemory")) + mcp_server_config_memory_type = _MCPServerConfigMemoryType(obj.get("McpServerConfigMemoryType")) mcp_server_config_stdio = MCPServerConfigStdio.from_dict(obj.get("McpServerConfigStdio")) mcp_server_config_stdio_type = MCPServerConfigStdioType(obj.get("McpServerConfigStdioType")) mcp_server_failure_info = MCPServerFailureInfo.from_dict(obj.get("McpServerFailureInfo")) @@ -52489,8 +54014,8 @@ def from_dict(obj: Any) -> 'RPC': mcp_set_env_value_mode_details = MCPSetEnvValueModeDetails(obj.get("McpSetEnvValueModeDetails")) mcp_set_env_value_mode_params = MCPSetEnvValueModeParams.from_dict(obj.get("McpSetEnvValueModeParams")) mcp_set_env_value_mode_result = MCPSetEnvValueModeResult.from_dict(obj.get("McpSetEnvValueModeResult")) - mcp_should_exclude_git_hub_tools_request = MCPShouldExcludeGitHubToolsRequest.from_dict(obj.get("McpShouldExcludeGitHubToolsRequest")) - mcp_should_exclude_git_hub_tools_result = MCPShouldExcludeGitHubToolsResult.from_dict(obj.get("McpShouldExcludeGitHubToolsResult")) + mcp_should_exclude_git_hub_tools_request = _MCPShouldExcludeGitHubToolsRequest.from_dict(obj.get("McpShouldExcludeGitHubToolsRequest")) + mcp_should_exclude_git_hub_tools_result = _MCPShouldExcludeGitHubToolsResult.from_dict(obj.get("McpShouldExcludeGitHubToolsResult")) mcp_source_file = MCPSourceFile.from_dict(obj.get("McpSourceFile")) mcp_source_plugin = MCPSourcePlugin.from_dict(obj.get("McpSourcePlugin")) mcp_source_ref = MCPSourceRef.from_dict(obj.get("McpSourceRef")) @@ -52502,7 +54027,7 @@ def from_dict(obj: Any) -> 'RPC': mcp_tool_ui = MCPToolUI.from_dict(obj.get("McpToolUi")) mcp_tool_ui_visibility = MCPToolUIVisibility(obj.get("McpToolUiVisibility")) mcp_uninstall_plan = MCPUninstallPlan.from_dict(obj.get("McpUninstallPlan")) - mcp_unregister_external_client_request = MCPUnregisterExternalClientRequest.from_dict(obj.get("McpUnregisterExternalClientRequest")) + mcp_unregister_external_client_request = _MCPUnregisterExternalClientRequest.from_dict(obj.get("McpUnregisterExternalClientRequest")) memory_configuration = MemoryConfiguration.from_dict(obj.get("MemoryConfiguration")) metadata_context_attribution_result = MetadataContextAttributionResult.from_dict(obj.get("MetadataContextAttributionResult")) metadata_context_heaviest_messages_request = MetadataContextHeaviestMessagesRequest.from_dict(obj.get("MetadataContextHeaviestMessagesRequest")) @@ -52538,6 +54063,8 @@ def from_dict(obj: Any) -> 'RPC': model_capabilities_supports = ModelCapabilitiesSupports.from_dict(obj.get("ModelCapabilitiesSupports")) model_clear_startup_seed_request = _ModelClearStartupSeedRequest.from_dict(obj.get("ModelClearStartupSeedRequest")) model_clear_startup_seed_result = _ModelClearStartupSeedResult.from_dict(obj.get("ModelClearStartupSeedResult")) + model_get_reasoning_summaries_request = ModelGetReasoningSummariesRequest.from_dict(obj.get("ModelGetReasoningSummariesRequest")) + model_get_reasoning_summaries_result = ModelGetReasoningSummariesResult.from_dict(obj.get("ModelGetReasoningSummariesResult")) model_list = ModelList.from_dict(obj.get("ModelList")) model_list_request = obj.get("ModelListRequest") model_message = ModelMessage.from_dict(obj.get("ModelMessage")) @@ -52853,6 +54380,10 @@ def from_dict(obj: Any) -> 'RPC': remote_session_metadata_value = RemoteSessionMetadataValue.from_dict(obj.get("RemoteSessionMetadataValue")) remote_session_mode = RemoteSessionMode(obj.get("RemoteSessionMode")) remote_session_repository = RemoteSessionRepository.from_dict(obj.get("RemoteSessionRepository")) + repo_settings_read_raw_request = _RepoSettingsReadRawRequest.from_dict(obj.get("RepoSettingsReadRawRequest")) + repo_settings_read_raw_result = _RepoSettingsReadRawResult.from_dict(obj.get("RepoSettingsReadRawResult")) + repo_settings_write_all_request = _RepoSettingsWriteAllRequest.from_dict(obj.get("RepoSettingsWriteAllRequest")) + repo_settings_write_key_request = _RepoSettingsWriteKeyRequest.from_dict(obj.get("RepoSettingsWriteKeyRequest")) response_format = ResponseFormat.from_dict(obj.get("ResponseFormat")) sandbox_config = SandboxConfig.from_dict(obj.get("SandboxConfig")) sandbox_config_auth = SandboxConfigAuth.from_dict(obj.get("SandboxConfigAuth")) @@ -53109,6 +54640,9 @@ def from_dict(obj: Any) -> 'RPC': session_working_directory_context_with_client = SessionWorkingDirectoryContextWithClient.from_dict(obj.get("SessionWorkingDirectoryContextWithClient")) settable_auth_info = _load_SettableAuthInfo(obj.get("SettableAuthInfo")) settable_token_auth_info = SettableTokenAuthInfo.from_dict(obj.get("SettableTokenAuthInfo")) + settings_edit_operation = _SettingsEditOperation(obj.get("SettingsEditOperation")) + settings_edit_result = _SettingsEditResult.from_dict(obj.get("SettingsEditResult")) + settings_edit_status = _SettingsEditStatus(obj.get("SettingsEditStatus")) shell_cancel_user_requested_request = ShellCancelUserRequestedRequest.from_dict(obj.get("ShellCancelUserRequestedRequest")) shell_credentials = ShellCredentials.from_dict(obj.get("ShellCredentials")) shell_exec_request = ShellExecRequest.from_dict(obj.get("ShellExecRequest")) @@ -53295,8 +54829,28 @@ def from_dict(obj: Any) -> 'RPC': user_auth_info = UserAuthInfo.from_dict(obj.get("UserAuthInfo")) user_requested_shell_command_result = UserRequestedShellCommandResult.from_dict(obj.get("UserRequestedShellCommandResult")) user_setting_metadata = UserSettingMetadata.from_dict(obj.get("UserSettingMetadata")) + user_settings_apply_top_key_request = UserSettingsApplyTopKeyRequest.from_dict(obj.get("UserSettingsApplyTopKeyRequest")) + user_settings_apply_top_key_result = UserSettingsApplyTopKeyResult.from_dict(obj.get("UserSettingsApplyTopKeyResult")) + user_settings_edit_request = _UserSettingsEditRequest.from_dict(obj.get("UserSettingsEditRequest")) + user_settings_get_paths_request = UserSettingsGetPathsRequest.from_dict(obj.get("UserSettingsGetPathsRequest")) + user_settings_get_paths_result = UserSettingsGetPathsResult.from_dict(obj.get("UserSettingsGetPathsResult")) user_settings_get_result = UserSettingsGetResult.from_dict(obj.get("UserSettingsGetResult")) + user_settings_governance_keys_result = UserSettingsGovernanceKeysResult.from_dict(obj.get("UserSettingsGovernanceKeysResult")) + user_settings_load_for_edit_result = UserSettingsLoadForEditResult.from_dict(obj.get("UserSettingsLoadForEditResult")) + user_settings_normalize_request = UserSettingsNormalizeRequest.from_dict(obj.get("UserSettingsNormalizeRequest")) + user_settings_normalize_result = UserSettingsNormalizeResult.from_dict(obj.get("UserSettingsNormalizeResult")) + user_settings_problem = UserSettingsProblem.from_dict(obj.get("UserSettingsProblem")) + user_settings_problem_location = UserSettingsProblemLocation.from_dict(obj.get("UserSettingsProblemLocation")) + user_settings_problem_source = UserSettingsProblemSource.from_dict(obj.get("UserSettingsProblemSource")) + user_settings_problems_request = UserSettingsProblemsRequest.from_dict(obj.get("UserSettingsProblemsRequest")) + user_settings_problems_result = UserSettingsProblemsResult.from_dict(obj.get("UserSettingsProblemsResult")) user_settings_set_request = UserSettingsSetRequest.from_dict(obj.get("UserSettingsSetRequest")) + user_settings_update_request = _UserSettingsUpdateRequest.from_dict(obj.get("UserSettingsUpdateRequest")) + user_settings_update_result = _UserSettingsUpdateResult.from_dict(obj.get("UserSettingsUpdateResult")) + user_settings_validate_request = UserSettingsValidateRequest.from_dict(obj.get("UserSettingsValidateRequest")) + user_settings_validate_result = UserSettingsValidateResult.from_dict(obj.get("UserSettingsValidateResult")) + user_settings_validation_issue = UserSettingsValidationIssue.from_dict(obj.get("UserSettingsValidationIssue")) + user_settings_write_all_request = UserSettingsWriteAllRequest.from_dict(obj.get("UserSettingsWriteAllRequest")) visibility_get_result = VisibilityGetResult.from_dict(obj.get("VisibilityGetResult")) visibility_set_request = VisibilitySetRequest.from_dict(obj.get("VisibilitySetRequest")) visibility_set_result = VisibilitySetResult.from_dict(obj.get("VisibilitySetResult")) @@ -53388,7 +54942,7 @@ def from_dict(obj: Any) -> 'RPC': subagent_settings = from_union([SubagentSettings.from_dict, from_none], obj.get("SubagentSettings")) task_progress = from_union([TaskProgress.from_dict, from_none], obj.get("TaskProgress")) workspace_summary = from_union([WorkspaceSummary.from_dict, from_none], obj.get("WorkspaceSummary")) - return RPC(abort_request, abort_result, accepted_enqueue_command_result, account_all_users, account_auth_info, account_get_all_users_result, account_get_current_auth_result, account_get_quota_request, account_get_quota_result, account_kind, account_login_request, account_login_result, account_logout_request, account_logout_result, account_quota_snapshot, accounts_enumerate_request, accounts_get_request, accounts_set_request, account_status, adaptive_thinking_support, agent_discovery_path, agent_discovery_path_list, agent_discovery_path_scope, agent_get_current_result, agent_info, agent_info_source, agent_list, agent_list_request, agent_registry_live_target_entry, agent_registry_live_target_entry_attention_kind, agent_registry_live_target_entry_kind, agent_registry_live_target_entry_last_terminal_event, agent_registry_live_target_entry_status, agent_registry_log_capture, agent_registry_log_capture_open_error_reason, agent_registry_spawn_error, agent_registry_spawn_permission_mode, agent_registry_spawn_registry_timeout, agent_registry_spawn_request, agent_registry_spawn_result, agent_registry_spawn_spawned, agent_registry_spawn_validation_error, agent_registry_spawn_validation_error_field, agent_registry_spawn_validation_error_reason, agent_reload_result, agents_custom_agent_initial_model_decision_params, agents_custom_agent_initial_model_decision_result, agents_discover_request, agent_select_request, agent_select_result, agent_set_prompt_request, agents_get_available_builtins_request, agents_get_available_builtins_result, agents_get_builtin_definition_request, agents_get_builtin_definition_result, agents_get_builtin_listing_definition_request, agents_get_builtin_listing_definition_result, agents_get_builtins_result, agents_get_discovery_paths_request, api_key_auth_info, auth_enumerate_query, auth_enumerate_value, auth_identity, auth_identity_metadata, auth_info, auth_info_type, auth_login_account, auth_login_advance_request, auth_login_begin_request, auth_login_begun, auth_login_cancel_request, auth_login_result_dto, auth_login_result_status, auth_login_step, auth_read_query, auth_read_value, auth_status_dto, auth_validation_error, auth_validation_errors, auth_write, auth_write_result, autopilot_objective_credit_limit, autopilot_objective_get_state_result, autopilot_objective_state, autopilot_objective_status, auto_tier_descriptor, auto_tier_metadata, auto_tier_status, builtin_agent_summary, built_in_model_catalog, built_in_model_catalog_entry, builtin_tool_descriptor, builtin_tool_format, builtin_tool_format_type, builtin_tool_input_schema, builtin_tool_input_schema_type, builtin_tool_safe_for_telemetry, builtin_tool_safe_telemetry_fields, cancel_user_requested_shell_command_result, canvas_action, canvas_action_invoke_request, canvas_action_invoke_result, canvas_close_request, canvas_host_context, canvas_host_context_capabilities, canvas_json_schema, canvas_list, canvas_list_open_result, canvas_open_request, canvas_provider_close_request, canvas_provider_invoke_action_request, canvas_provider_open_request, canvas_provider_open_result, canvas_provider_register_request, canvas_provider_unregister_request, canvas_session_context, capi_session_options, card_digest, card_digest_algorithm, card_digest_value, catalog_agent_plugin_candidate, catalog_agent_plugin_candidate_kind, catalog_agent_plugin_candidate_provenance, catalog_agent_plugin_compatibility_tag, catalog_agent_plugin_media_type, catalog_ai_skill_candidate, catalog_ai_skill_candidate_kind, catalog_ai_skill_candidate_provenance, catalog_ai_skill_installability, catalog_ai_skill_media_type, catalog_authentication_required_error, catalog_authentication_required_reason, catalog_candidate, catalog_candidate_kind, catalog_candidate_source, catalog_candidate_source_embedded, catalog_candidate_source_url, catalog_capability, catalog_capability_id, catalog_client_contract, catalog_contract_violation_error, catalog_contract_violation_reason, catalog_handle_rejected_error, catalog_handle_rejection_reason, catalog_handle_type, catalog_invalid_request_error, catalog_invalid_request_field, catalog_malformed_card_error, catalog_malformed_card_reason, catalog_mcp_server_candidate, catalog_mcp_server_candidate_kind, catalog_mcp_server_candidate_provenance, catalog_mcp_server_installability, catalog_media_type, catalog_negotiated_contract, catalog_negotiation_refused_error, catalog_negotiation_refused_reason, catalog_network_failure_error, catalog_network_failure_reason, catalog_not_installable_error, catalog_not_installable_reason, catalog_plugin_repository_source, catalog_policy_rejected_error, catalog_resource_identity, catalog_resource_version, catalog_search_page, catalog_search_pagination, catalog_search_request, catalog_search_result, catalog_search_succeeded, catalog_search_total_count_relation, catalog_selection_cancelled, catalog_selection_decision, catalog_selection_declined, catalog_selection_foreign, catalog_selection_invalid, catalog_selection_replayed, catalog_selection_request, catalog_selection_result, catalog_selection_selected, catalog_selection_stale, catalog_selection_timed_out, catalog_selection_wrong_kind, catalog_trust_eligibility, catalog_trust_provenance, catalog_trust_snapshot, catalog_trust_snapshot_absent, catalog_trust_snapshot_absent_status, catalog_trust_snapshot_current, catalog_trust_snapshot_current_status, catalog_trust_snapshot_downgraded, catalog_trust_snapshot_downgraded_status, catalog_trust_snapshot_malformed, catalog_trust_snapshot_malformed_status, catalog_trust_snapshot_revoked, catalog_trust_snapshot_revoked_status, catalog_trust_snapshot_schema_version, catalog_trust_snapshot_stale, catalog_trust_snapshot_stale_status, catalog_trust_snapshot_unsupported, catalog_trust_snapshot_unsupported_status, catalog_trust_source, catalog_trust_tier, catalog_unavailable_error, catalog_unavailable_reason, catalog_unavailable_transport_error, catalog_unavailable_transport_reason, catalog_unsafe_retrieval_error, catalog_unsafe_retrieval_reason, catalog_unsupported_kind_error, client_metadata, client_task_cancel_reason, client_task_cancel_request, client_task_cancel_result, command_list, commands_finalize_invocation_effect_request, commands_finalize_invocation_effect_result, commands_handle_pending_command_request, commands_handle_pending_command_result, commands_invocation_effect_outcome, commands_invocation_origin, commands_invoke_request, commands_list_request, commands_respond_to_queued_command_request, commands_respond_to_queued_command_result, completions_get_trigger_characters_result, completions_request_request, completions_request_result, configure_session_extensions_params, connect_client_info, connected_remote_session_metadata, connected_remote_session_metadata_kind, connected_remote_session_metadata_repository, connector_account_request, connector_authorization_requirement, connector_authorization_scope, connector_availability, connector_capabilities, connector_catalog_entry, connector_catalog_result, connector_catalog_status, connector_connect_request, connector_connect_result, connector_continue_request, connector_disconnect_result, connector_discovery_account, connector_discovery_account_list, connector_discovery_account_request, connector_discovery_auth_info, connector_discovery_availability, connector_discovery_capabilities, connector_discovery_catalog_entry, connector_discovery_catalog_result, connector_mcp_status, connector_reconcile_request, connector_runtime_status, connector_session_account, connector_status, connect_remote_session_params, connect_request, connect_result, content_exclusion_check_paths_request, content_exclusion_check_paths_result, content_exclusion_path_check, content_filter_mode, context_heaviest_message, copilot_api_token_auth_info, copilot_user_response, copilot_user_response_endpoints, copilot_user_response_quota_snapshots, copilot_user_response_quota_snapshots_chat, copilot_user_response_quota_snapshots_completions, copilot_user_response_quota_snapshots_premium_interactions, current_model, current_tool_metadata, customization_reload_outcome, customization_reload_status, customization_reload_subsystem, customizations_reload_result, debug_collect_logs_collected_entry, debug_collect_logs_destination, debug_collect_logs_entry, debug_collect_logs_entry_kind, debug_collect_logs_include, debug_collect_logs_redaction, debug_collect_logs_request, debug_collect_logs_result, debug_collect_logs_result_kind, debug_collect_logs_skipped_entry, debug_collect_logs_source, diagnostic_cursor_status, diagnostic_entry, diagnostic_log_level, diagnostics_configuration, diagnostics_configure_request, diagnostic_severity, diagnostic_source, diagnostic_sources_configuration, diagnostics_read_request, diagnostics_read_result, discovered_canvas, discovered_extension, discovered_extension_mode, discovered_extension_plugin, discovered_extensions, discovered_extensions_disable_request, discovered_extensions_enable_request, discovered_extension_source, discovered_hook, discovered_mcp_server, discovered_mcp_server_type, discovered_model, discovered_model_list, enqueue_command_params, enqueue_command_result, env_auth_info, environment_capabilities, environment_kind, environments_delete_request, environments_delete_result, environments_get_request, environments_get_result, environments_list_request, environments_list_result, event_log_read_request, event_log_release_interest_result, event_log_tail_result, event_log_types, events_agent_scope, events_cursor_status, events_read_direction, events_read_result, execute_command_params, execute_command_result, extension, extension_context_push_input, extension_launch_profile, extension_launch_provider_resolve_request, extension_launch_provider_resolve_result, extension_list, extensions_disable_request, extensions_enable_request, extension_source, extension_status, external_tool_result, external_tool_text_result_for_llm, external_tool_text_result_for_llm_binary_results_for_llm, external_tool_text_result_for_llm_binary_results_for_llm_type, external_tool_text_result_for_llm_content, external_tool_text_result_for_llm_content_audio, external_tool_text_result_for_llm_content_image, external_tool_text_result_for_llm_content_resource, external_tool_text_result_for_llm_content_resource_details, external_tool_text_result_for_llm_content_resource_link, external_tool_text_result_for_llm_content_resource_link_icon, external_tool_text_result_for_llm_content_resource_link_icon_theme, external_tool_text_result_for_llm_content_shell_exit, external_tool_text_result_for_llm_content_terminal, external_tool_text_result_for_llm_content_text, filter_mapping, fleet_start_request, fleet_start_result, folder_trust_add_params, folder_trust_check_params, folder_trust_check_result, gh_cli_auth_info, git_current_branch_remote_result, git_cwd_request, git_hub_environment, git_hub_owner_option, git_hub_owners_cancel_request, git_hub_owners_cancel_result, git_hub_owners_list_request, git_hub_owners_list_result, git_hub_owners_request_id_result, git_hub_repository_at_path_request, git_hub_repository_at_path_result, git_hub_repository_identity, git_hub_telemetry_client_info, git_hub_telemetry_event, git_hub_telemetry_notification, git_hub_token_acquire_reason, git_hub_token_acquire_request, git_hub_token_acquire_result, git_remote_repository, git_repos_from_remotes_request, git_repos_from_remotes_result, global_state_load_for_config_dir_request, global_state_load_result, global_state_write_key_request, handle_pending_tool_call_request, handle_pending_tool_call_result, history_abort_manual_compaction_result, history_cancel_background_compaction_result, history_clear_context_request, history_clear_context_result, history_compact_context_window, history_compact_request, history_compact_result, history_file_restore_skip_reason, history_list_rewind_points_result, history_preview_rewind_request, history_preview_rewind_result, history_rewind_change_type, history_rewind_file_preview, history_rewind_mode, history_rewind_outcome, history_rewind_point, history_rewind_request, history_rewind_result, history_rewind_unavailable_reason, history_skipped_file_restore, history_summarize_for_handoff_result, history_truncate_request, history_truncate_result, hmac_auth_info, hook_invoke_request, hook_invoke_response, hook_origin, hooks_discover_request, hooks_discover_result, hook_type, host_configuration, host_dispose_request, host_empty_result, host_environment_credentials, host_exited_notification, host_exit_reason, host_git_hub_environment_options, host_list_sessions_request, host_list_sessions_result, host_local_server_configuration, host_local_server_options, host_publish_session_request, host_publish_session_result, host_ready_request, host_register_session_request, host_session_create_callback, host_session_create_request, host_session_create_result, host_session_released_notification, host_session_release_request, host_session_summary, host_start_request, host_start_result, installation_catalogue_identity, installation_confirmation_request, installation_confirmation_response, installation_decision, installation_review, installed_plugin, installed_plugin_info, installed_plugin_source, installed_plugin_source_git_hub, installed_plugin_source_local, installed_plugin_source_url, instruction_discovery_path, instruction_discovery_path_kind, instruction_discovery_path_list, instruction_discovery_path_location, instructions_discover_request, instructions_get_discovery_paths_request, instructions_get_sources_result, instruction_source, instruction_source_location, instruction_source_type, interrupt_main_turn_request, interrupt_main_turn_result, json_schema_response_format, llm_inference_headers, llm_inference_http_request_chunk_request, llm_inference_http_request_chunk_result, llm_inference_http_request_start_request, llm_inference_http_request_start_result, llm_inference_http_request_start_transport, llm_inference_http_response_chunk_error, llm_inference_http_response_chunk_request, llm_inference_http_response_chunk_result, llm_inference_http_response_start_request, llm_inference_http_response_start_result, llm_inference_set_provider_result, local_session_metadata_value, logged_in_user, login_provider_kind, log_request, log_result, lsp_initialize_request, managed_mcp_server_config, managed_permission_evaluation, managed_permission_operation, managed_permission_operation_kind, managed_permissions_evaluate_request, managed_permissions_evaluate_result, managed_permission_verdict, managed_plugin_retry_entry, managed_plugin_retry_status, managed_setting_meta, managed_settings_channel, managed_settings_compose_layer, managed_settings_compose_request, managed_settings_compose_result, managed_settings_diagnostic, managed_settings_diagnostic_severity, managed_settings_layer, managed_settings_meta, managed_settings_read_result, managed_settings_resolved_data, managed_settings_resolve_request, managed_settings_resolve_result, managed_settings_schema_result, managed_settings_validate_request, managed_settings_validate_result, managed_settings_values, marketplace_add_result, marketplace_browse_result, marketplace_info, marketplace_list_result, marketplace_plugin_info, marketplace_refresh_entry, marketplace_refresh_result, marketplace_remove_result, mcp_allowed_server, mcp_apply_install_request, mcp_apply_uninstall_request, mcp_apps_call_tool_request, mcp_apps_diagnose_capability, mcp_apps_diagnose_request, mcp_apps_diagnose_result, mcp_apps_diagnose_server, mcp_apps_host_context, mcp_apps_host_context_details, mcp_apps_host_context_details_available_display_mode, mcp_apps_host_context_details_display_mode, mcp_apps_host_context_details_platform, mcp_apps_host_context_details_theme, mcp_apps_list_tools_request, mcp_apps_list_tools_result, mcp_apps_read_resource_request, mcp_apps_read_resource_result, mcp_apps_resource_content, mcp_apps_set_host_context_details, mcp_apps_set_host_context_details_available_display_mode, mcp_apps_set_host_context_details_display_mode, mcp_apps_set_host_context_details_platform, mcp_apps_set_host_context_details_theme, mcp_apps_set_host_context_request, mcp_cancel_sampling_execution_params, mcp_cancel_sampling_execution_result, mcp_config_add_request, mcp_config_disable_request, mcp_config_enable_request, mcp_config_list, mcp_config_remove_request, mcp_config_update_request, mcp_configured_server, mcp_configured_server_list, mcp_configured_server_state, mcp_configure_git_hub_request, mcp_configure_git_hub_result, mcp_diagnostic_details, mcp_diagnostic_direction, mcp_diagnostic_kind, mcp_diagnostic_source_configuration, mcp_disable_request, mcp_discover_request, mcp_discover_result, mcp_elicitation_form_mode, mcp_enable_request, mcp_execute_sampling_params, mcp_execute_sampling_request, mcp_execute_sampling_result, mcp_failed_server, mcp_filtered_server, mcp_headers_handle_pending_headers_refresh_request, mcp_headers_handle_pending_headers_refresh_request_request, mcp_headers_handle_pending_headers_refresh_request_result, mcp_host_state, mcp_installation_failure_reason, mcp_installation_input, mcp_installation_management_outcome, mcp_installation_management_result, mcp_installation_operation_request, mcp_installation_operation_status, mcp_installation_outcome, mcp_installation_remote_configuration, mcp_installation_result, mcp_installation_review, mcp_installation_secret, mcp_installation_secret_storage, mcp_installations_request, mcp_installation_state, mcp_installation_summary, mcp_install_plan, mcp_is_server_running_request, mcp_is_server_running_result, mcp_list_tools_request, mcp_list_tools_result, mcp_oauth_authentication_state_changed_request, mcp_oauth_cancel_login_request, mcp_oauth_cancel_login_result, mcp_oauth_complete_request, mcp_oauth_handle_pending_request, mcp_oauth_handle_pending_result, mcp_oauth_login_grant_type, mcp_oauth_login_request, mcp_oauth_login_result, mcp_oauth_pending_request_response, mcp_oauth_prepare_login_request, mcp_oauth_prepare_login_result, mcp_oauth_probe_needs_auth_reason, mcp_oauth_probe_request, mcp_oauth_probe_result, mcp_oauth_respond_request, mcp_oauth_respond_result, mcp_owned_oauth_login_status, mcp_plan_configuration_change, mcp_plan_configuration_operation, mcp_plan_enum_value_type, mcp_plan_install_planned, mcp_plan_install_request, mcp_plan_install_result, mcp_plan_install_source, mcp_plan_install_source_candidate, mcp_plan_install_source_candidate_kind, mcp_plan_install_source_card, mcp_plan_install_source_card_kind, mcp_plan_package_install_method, mcp_plan_package_transport, mcp_plan_policy_decision, mcp_plan_policy_result, mcp_plan_policy_source, mcp_plan_provenance, mcp_plan_remote_install_method, mcp_plan_remote_transport, mcp_plan_required_value, mcp_plan_required_value_enum, mcp_plan_required_value_enum_kind, mcp_plan_required_value_scalar, mcp_plan_required_value_scalar_kind, mcp_plan_resource_identity, mcp_plan_scalar_value_type, mcp_plan_scope, mcp_plan_secret_placeholder, mcp_plan_secret_reference, mcp_plan_target, mcp_plan_transport_choice, mcp_plan_transport_choice_package, mcp_plan_transport_choice_remote, mcp_plan_uninstall_request, mcp_plan_value_category, mcp_prepared_install, mcp_prepare_install_request, mcp_prompt, mcp_prompt_argument, mcp_prompt_icon, mcp_prompt_message, mcp_prompt_role, mcp_prompts_get_request, mcp_prompts_get_result, mcp_prompts_list_request, mcp_prompts_list_result, mcp_register_external_client_request, mcp_registry_cancel_request, mcp_registry_cancel_result, mcp_registry_request_id_result, mcp_registry_search_request, mcp_registry_search_result, mcp_reload_config, mcp_reload_with_config_request, mcp_remove_git_hub_result, mcp_resource, mcp_resource_annotations, mcp_resource_content, mcp_resource_icon, mcp_resources_list_request, mcp_resources_list_result, mcp_resources_list_templates_request, mcp_resources_list_templates_result, mcp_resources_read_request, mcp_resources_read_result, mcp_resource_template, mcp_restart_server_request, mcp_safe_for_telemetry, mcp_safe_for_telemetry_fields, mcp_sampling_execution_action, mcp_sampling_execution_result, mcp_serializable_server_config, mcp_server, mcp_server_auth_config, mcp_server_auth_config_redirect_port, mcp_server_card_embedded, mcp_server_card_embedded_kind, mcp_server_card_media_type, mcp_server_card_reference, mcp_server_card_url, mcp_server_card_url_kind, mcp_server_config, mcp_server_config_defer_tools, mcp_server_config_http, mcp_server_config_http_oauth_grant_type, mcp_server_config_http_type, mcp_server_config_memory, mcp_server_config_memory_type, mcp_server_config_stdio, mcp_server_config_stdio_type, mcp_server_failure_info, mcp_server_list, mcp_server_needs_auth_info, mcp_server_ownership, mcp_set_env_value_mode_details, mcp_set_env_value_mode_params, mcp_set_env_value_mode_result, mcp_should_exclude_git_hub_tools_request, mcp_should_exclude_git_hub_tools_result, mcp_source_file, mcp_source_plugin, mcp_source_ref, mcp_start_server_request, mcp_start_servers_result, mcp_stop_server_request, mcp_task_metadata, mcp_tools, mcp_tool_ui, mcp_tool_ui_visibility, mcp_uninstall_plan, mcp_unregister_external_client_request, memory_configuration, metadata_context_attribution_result, metadata_context_heaviest_messages_request, metadata_context_heaviest_messages_result, metadata_context_info_request, metadata_context_info_result, metadata_is_processing_result, metadata_recompute_context_tokens_request, metadata_recompute_context_tokens_result, metadata_record_context_change_request, metadata_record_context_change_result, metadata_set_working_directory_request, metadata_set_working_directory_result, metadata_snapshot_current_mode, metadata_snapshot_remote_metadata, metadata_snapshot_remote_metadata_repository, metadata_snapshot_remote_metadata_task_type, metadata_update_client_metadata_request, model, model_apply_startup_overlay_request, model_artifact_details, model_billing, model_billing_promo, model_billing_token_prices, model_billing_token_prices_long_context, model_capabilities, model_capabilities_limits, model_capabilities_limits_vision, model_capabilities_override, model_capabilities_override_limits, model_capabilities_override_limits_vision, model_capabilities_override_supports, model_capabilities_supports, model_clear_startup_seed_request, model_clear_startup_seed_result, model_list, model_list_request, model_message, model_picker_category, model_picker_persistence_request, model_picker_price_category, model_picker_settings_context, model_policy, model_policy_state, model_provider_adapter_catalog, model_provider_adapter_descriptor, model_provider_adapter_operation_descriptor, model_provider_attribution, model_provider_automatic_discovery_mode, model_provider_automatic_discovery_policy, model_provider_configuration_disposition, model_provider_configuration_plan, model_provider_descriptor, model_provider_discover_request, model_provider_discover_result, model_provider_discovery_network_scope, model_provider_get_status_request, model_provider_instance, model_provider_instance_reference, model_provider_models_list_request, model_provider_operation_outcome, model_provider_operation_outcome_code, model_provider_prepare_configuration_request, model_provider_provenance, model_provider_provenance_source, model_provider_status, model_provider_warning, model_set_allowed_models_request, model_set_allowed_models_result, model_set_reasoning_effort_request, model_set_reasoning_effort_result, models_list_request, model_switch_auto_tier_request, model_switch_auto_tier_result, model_switch_auto_tier_status, model_switch_confirmation, model_switch_to_request, model_switch_to_result, model_warning_text, mode_set_request, mode_set_result, move_mcp_loading_to_background_result, named_provider_config, name_get_result, name_set_auto_request, name_set_auto_result, name_set_request, open_canvas_instance, options_update_additional_content_exclusion_policy, options_update_additional_content_exclusion_policy_rule, options_update_additional_content_exclusion_policy_rule_source, options_update_additional_content_exclusion_policy_scope, options_update_context_tier, options_update_env_value_mode, options_update_reasoning_summary, options_update_tool_filter_precedence, pending_external_tool_request, pending_external_tool_request_list, pending_permission_request, pending_permission_request_list, permission_decision, permission_decision_approved, permission_decision_approved_for_location, permission_decision_approved_for_session, permission_decision_approve_for_location, permission_decision_approve_for_location_approval, permission_decision_approve_for_location_approval_commands, permission_decision_approve_for_location_approval_custom_tool, permission_decision_approve_for_location_approval_extension_env_access, permission_decision_approve_for_location_approval_extension_management, permission_decision_approve_for_location_approval_extension_permission_access, permission_decision_approve_for_location_approval_mcp, permission_decision_approve_for_location_approval_mcp_sampling, permission_decision_approve_for_location_approval_memory, permission_decision_approve_for_location_approval_read, permission_decision_approve_for_location_approval_workflow, permission_decision_approve_for_location_approval_write, permission_decision_approve_for_session, permission_decision_approve_for_session_approval, permission_decision_approve_for_session_approval_commands, permission_decision_approve_for_session_approval_custom_tool, permission_decision_approve_for_session_approval_extension_env_access, permission_decision_approve_for_session_approval_extension_management, permission_decision_approve_for_session_approval_extension_permission_access, permission_decision_approve_for_session_approval_mcp, permission_decision_approve_for_session_approval_mcp_sampling, permission_decision_approve_for_session_approval_memory, permission_decision_approve_for_session_approval_read, permission_decision_approve_for_session_approval_workflow, permission_decision_approve_for_session_approval_write, permission_decision_approve_once, permission_decision_approve_permanently, permission_decision_approve_read_only_for_session, permission_decision_cancelled, permission_decision_context, permission_decision_denied_by_content_exclusion_policy, permission_decision_denied_by_permission_request_hook, permission_decision_denied_by_rules, permission_decision_denied_interactively_by_user, permission_decision_denied_no_approval_rule_and_could_not_request_from_user, permission_decision_outcome, permission_decision_reject, permission_decision_request, permission_decision_surface, permission_decision_user_not_available, permission_location_add_tool_approval_params, permission_location_apply_params, permission_location_apply_result, permission_location_resolve_params, permission_location_resolve_result, permission_location_type, permission_mode_source, permission_paths_add_params, permission_paths_allowed_check_params, permission_paths_allowed_check_result, permission_paths_config, permission_paths_list, permission_paths_update_primary_params, permission_paths_workspace_check_params, permission_paths_workspace_check_result, permission_prompt_shown_notification, permission_request_result, permission_response_capability, permission_rules_set, permissions_configure_additional_content_exclusion_policy, permissions_configure_additional_content_exclusion_policy_rule, permissions_configure_additional_content_exclusion_policy_rule_source, permissions_configure_additional_content_exclusion_policy_scope, permissions_configure_params, permissions_configure_result, permissions_folder_trust_add_trusted_result, permissions_get_mode_request, permissions_get_mode_result, permissions_locations_add_tool_approval_details, permissions_locations_add_tool_approval_details_commands, permissions_locations_add_tool_approval_details_custom_tool, permissions_locations_add_tool_approval_details_extension_env_access, permissions_locations_add_tool_approval_details_extension_management, permissions_locations_add_tool_approval_details_extension_permission_access, permissions_locations_add_tool_approval_details_mcp, permissions_locations_add_tool_approval_details_mcp_sampling, permissions_locations_add_tool_approval_details_memory, permissions_locations_add_tool_approval_details_read, permissions_locations_add_tool_approval_details_workflow, permissions_locations_add_tool_approval_details_write, permissions_locations_add_tool_approval_result, permissions_modify_rules_params, permissions_modify_rules_result, permissions_modify_rules_scope, permissions_notify_prompt_shown_result, permissions_paths_add_result, permissions_paths_list_request, permissions_paths_update_primary_result, permissions_pending_requests_request, permissions_reset_session_approvals_request, permissions_reset_session_approvals_result, permissions_set_approve_all_request, permissions_set_approve_all_result, permissions_set_approve_all_source, permissions_set_mode_request, permissions_set_mode_result, permissions_set_required_request, permissions_set_required_result, permissions_urls_set_unrestricted_mode_result, permission_urls_config, permission_urls_set_unrestricted_mode_params, ping_request, ping_result, plan_read_result, plan_read_sql_todos_result, plan_read_sql_todos_with_dependencies_result, plan_sql_todo_dependency, plan_sql_todos_row, plan_update_request, plugin, plugin_install_result, plugin_install_staging_mode, plugin_list, plugin_list_result, plugins_builtin_set_request, plugins_disable_request, plugins_enable_request, plugins_install_request, plugins_marketplaces_add_request, plugins_marketplaces_browse_request, plugins_marketplaces_refresh_request, plugins_marketplaces_remove_request, plugins_reload_request, plugins_uninstall_request, plugins_update_request, plugin_update_all_entry, plugin_update_all_result, plugin_update_result, protocol_append_mode, protocol_customize_mode, protocol_external_tool_defer, protocol_external_tool_definition, protocol_marker_section_override, protocol_replace_mode, protocol_section_override, protocol_static_section_action, protocol_static_section_override, protocol_system_message_append_config, protocol_system_message_config, protocol_system_message_customize_config, protocol_system_message_replace_config, provider_add_request, provider_add_result, provider_config, provider_config_azure, provider_config_model_provider, provider_config_transport, provider_config_type, provider_config_wire_api, provider_descriptor, provider_endpoint, provider_endpoint_transport, provider_endpoint_type, provider_endpoint_wire_api, provider_get_endpoint_request, provider_model_config, provider_session_token, provider_sync_request, provider_sync_result, provider_token_acquire_request, provider_token_acquire_result, provider_withdraw_request, provider_withdraw_result, push_attachment, push_attachment_blob, push_attachment_directory, push_attachment_file, push_attachment_file_line_range, push_attachment_git_hub_actions_job, push_attachment_git_hub_commit, push_attachment_git_hub_file, push_attachment_git_hub_file_diff, push_attachment_git_hub_file_diff_side, push_attachment_git_hub_reference, push_attachment_git_hub_reference_type, push_attachment_git_hub_release, push_attachment_git_hub_repository, push_attachment_git_hub_snippet, push_attachment_git_hub_tree_comparison, push_attachment_git_hub_tree_comparison_side, push_attachment_git_hub_url, push_attachment_selection, push_attachment_selection_details, push_attachment_selection_details_end, push_attachment_selection_details_start, push_git_hub_repo_ref, queue_append_steering_request, queue_begin_deferred_idle_drain_request, queue_begin_deferred_idle_drain_result, queue_consume_system_notifications_request, queued_command_handled, queued_command_not_handled, queued_command_result, queue_defer_session_idle_request, queue_duplicate_at_request, queue_duplicate_at_result, queue_enqueue_resume_pending_result, queue_finish_deferred_idle_drain_request, queue_finish_deferred_idle_drain_result, queue_has_pending_result, queue_insert_at_request, queue_insert_at_result, queue_insert_message, queue_move_item_request, queue_move_item_result, queue_pending_items, queue_pending_items_kind, queue_pending_items_result, queue_remove_at_request, queue_remove_at_result, queue_remove_most_recent_result, queue_send_now_request, queue_send_now_result, queue_set_drain_paused_request, queue_snapshot_result, queue_update_text_request, queue_update_text_result, queue_withdraw_message_request, queue_withdraw_message_result, quota_take_warnings_result, quota_warning_projection, register_event_interest_params, register_event_interest_result, release_event_interest_params, remote_control_config, remote_control_config_existing_mc_session, remote_control_status, remote_control_status_active, remote_control_status_connecting, remote_control_status_error, remote_control_status_off, remote_control_status_result, remote_control_stop_result, remote_control_transfer_result, remote_enable_request, remote_enable_result, remote_notify_steerable_changed_request, remote_notify_steerable_changed_result, remote_session_connection_result, remote_session_host_status, remote_session_metadata_repository, remote_session_metadata_task_type, remote_session_metadata_value, remote_session_mode, remote_session_repository, response_format, sandbox_config, sandbox_config_auth, sandbox_config_source, sandbox_config_user_policy, sandbox_config_user_policy_experimental, sandbox_config_user_policy_experimental_seatbelt, sandbox_config_user_policy_filesystem, sandbox_config_user_policy_network, sandbox_config_user_policy_network_proxy, sandbox_config_user_policy_seatbelt, sandbox_credentials_config, sandbox_credential_suggestion, sandbox_credential_suggestions_result, sandbox_disable_for_session_request, sandbox_disable_for_session_result, sandbox_enforcement_status, sandbox_grant_path_for_request_request, sandbox_grant_path_for_request_result, sandbox_host_capability, sandbox_host_capability_name, sandbox_host_support, sandbox_masked_env_var, sandbox_proxy_ca_create_result, sandbox_proxy_ca_request, sandbox_proxy_ca_state, sandbox_proxy_ca_status, sandbox_session_change, schedule_add_at_request, schedule_add_cron_request, schedule_add_request, schedule_add_result, schedule_add_self_paced_request, schedule_entry, schedule_has_self_paced_result, schedule_list, schedule_rearm_self_paced_request, schedule_stop_request, schedule_stop_result, secrets_add_filter_values_request, secrets_add_filter_values_result, send_agent_mode, send_attachments_to_message_params, send_message_item, send_messages_request, send_messages_result, send_mode, send_request, send_result, send_system_notification_request, server_agent_list, server_instruction_source_list, server_skill, server_skill_list, session_activity, session_agent_list_request, session_auth_login_request, session_auth_logout_user_request, session_auth_status, session_auth_switch_request, session_bulk_delete_result, session_cancel_all_background_agents_result, session_capability, session_commands_list_request, session_completion_item, session_connected_ide_info, session_context, session_context_host_type, session_enrich_metadata_result, session_fs_append_file_request, session_fs_error, session_fs_error_code, session_fs_exists_request, session_fs_exists_result, session_fs_mkdir_request, session_fs_readdir_request, session_fs_readdir_result, session_fs_readdir_with_types_entry, session_fs_readdir_with_types_entry_type, session_fs_readdir_with_types_request, session_fs_readdir_with_types_result, session_fs_read_file_bytes_request, session_fs_read_file_bytes_result, session_fs_read_file_request, session_fs_read_file_result, session_fs_rename_request, session_fs_rm_request, session_fs_set_provider_capabilities, session_fs_set_provider_conventions, session_fs_set_provider_request, session_fs_set_provider_result, session_fs_sqlite_exists_request, session_fs_sqlite_exists_result, session_fs_sqlite_query_request, session_fs_sqlite_query_result, session_fs_sqlite_query_type, session_fs_sqlite_transaction_error, session_fs_sqlite_transaction_error_class, session_fs_sqlite_transaction_request, session_fs_sqlite_transaction_result, session_fs_sqlite_transaction_statement, session_fs_stat_request, session_fs_stat_result, session_fs_write_file_bytes_request, session_fs_write_file_request, session_git_hub_auth_get_all_auth_available_result, session_git_hub_auth_logout_result, session_git_hub_auth_logout_user_result, session_history_compact_request, session_installed_plugin, session_installed_plugin_source, session_installed_plugin_source_git_hub, session_installed_plugin_source_local, session_installed_plugin_source_url, session_limit_prediction_baseline_data, session_limit_prediction_client_type, session_limit_prediction_details, session_limit_prediction_predict_request, session_limit_prediction_request, session_limit_prediction_result, session_limit_prediction_source, session_limit_prediction_tier, session_limit_prediction_tier_option, session_limit_prediction_unavailable_reason, session_list, session_list_entry, session_list_filter, session_load_deferred_repo_hooks_result, session_log_level, session_managed_permissions, session_managed_settings, session_mcp_apps_call_tool_result, session_mcp_oauth_cancel_login_request, session_mcp_oauth_cancel_login_result, session_mcp_oauth_prepare_login_request, session_mcp_oauth_prepare_login_result, session_mcp_set_connected_ide_info_params, session_metadata_snapshot, session_mode, session_model_clear_startup_seed_request, session_model_clear_startup_seed_result, session_model_list, session_model_list_request, session_model_price_category, session_open_options, session_open_options_additional_content_exclusion_policy, session_open_options_additional_content_exclusion_policy_rule, session_open_options_additional_content_exclusion_policy_rule_source, session_open_options_additional_content_exclusion_policy_scope, session_open_options_env_value_mode, session_open_options_reasoning_summary, session_open_params, session_open_result, session_plugins_disable_request, session_plugins_enable_request, session_plugins_install_request, session_plugins_marketplaces_refresh_request, session_plugins_reload_request, session_plugins_retry_managed_request, session_plugins_retry_managed_result, session_provider_get_endpoint_request, session_prune_result, session_quota_delegate_warning, session_quota_get_result, session_quota_plan_tier, session_quota_projection, session_quota_refresh_result, session_quota_snapshot, session_quota_take_warnings_result, sessions_bulk_delete_request, sessions_check_in_use_request, sessions_check_in_use_result, sessions_client_metadata_entry, sessions_close_request, sessions_close_result, sessions_create_workspace_request, sessions_create_workspace_result, sessions_delete_request, sessions_enrich_metadata_request, session_set_credentials_params, session_set_credentials_result, session_settings_built_in_tool_availability_snapshot, session_settings_evaluate_predicate_request, session_settings_evaluate_predicate_result, session_settings_job_snapshot, session_settings_model_snapshot, session_settings_online_evaluation_snapshot, session_settings_predicate_name, session_settings_repo_snapshot, session_settings_snapshot, session_settings_validation_snapshot, sessions_find_by_prefix_request, sessions_find_by_prefix_result, sessions_find_by_task_id_request, sessions_find_by_task_id_result, sessions_fork_request, sessions_fork_result, sessions_get_board_entry_count_request, sessions_get_board_entry_count_result, sessions_get_client_metadata_request, sessions_get_client_metadata_result, sessions_get_event_file_path_request, sessions_get_event_file_path_result, sessions_get_last_for_context_request, sessions_get_last_for_context_result, sessions_get_metadata_request, sessions_get_metadata_result, sessions_get_persisted_remote_steerable_request, sessions_get_persisted_remote_steerable_result, session_sizes, sessions_list_non_empty_session_ids_request, sessions_list_non_empty_session_ids_result, sessions_list_request, sessions_load_deferred_repo_hooks_request, sessions_load_workspace_request, sessions_load_workspace_result, sessions_open_attach, sessions_open_cloud, sessions_open_create, sessions_open_handoff, sessions_open_handoff_task_type, sessions_open_progress, sessions_open_progress_status, sessions_open_progress_step, sessions_open_remote, sessions_open_resume, sessions_open_resume_last, sessions_open_status, session_source, sessions_prune_old_request, sessions_read_persisted_events_request, sessions_release_lock_request, sessions_release_lock_result, sessions_reload_plugin_hooks_request, sessions_reload_plugin_hooks_result, sessions_save_request, sessions_save_result, sessions_set_additional_plugins_request, sessions_set_additional_plugins_result, sessions_set_remote_control_steering_request, sessions_start_remote_control_request, sessions_stop_remote_control_request, sessions_transfer_remote_control_request, sessions_update_workspace_fields_request, sessions_update_workspace_fields_result, session_telemetry_engagement, session_update_options_params, session_update_options_result, session_usage_set_code_changes_request, session_visibility_status, session_workflow_pause_at_checkpoint_result, session_working_directory_context, session_working_directory_context_host_type, session_working_directory_context_with_client, settable_auth_info, settable_token_auth_info, shell_cancel_user_requested_request, shell_credentials, shell_exec_request, shell_exec_result, shell_execute_user_requested_request, shell_init_profile, shell_init_script, shell_init_script_shell, shell_kill_request, shell_kill_result, shell_kill_signal, shell_options, shutdown_request, skill, skill_apply_install_request, skill_apply_uninstall_request, skill_discovery_path, skill_discovery_path_list, skill_discovery_scope, skill_installation_failure_reason, skill_installation_file_review, skill_installation_location, skill_installation_management_outcome, skill_installation_management_result, skill_installation_operation_request, skill_installation_operation_status, skill_installation_outcome, skill_installation_ownership_state, skill_installation_result, skill_installation_review, skill_installation_scope, skill_installation_session_state, skill_installation_source, skill_installations_request, skill_installation_summary, skill_install_plan, skill_list, skill_plan_install_request, skill_plan_uninstall_request, skill_provider_descriptor, skill_provider_list_request, skill_provider_list_result, skill_provider_read_request, skill_provider_read_result, skills_config_set_disabled_skills_request, skills_config_set_skill_disabled_request, skills_disable_request, skills_discover_request, skills_enable_request, skill_set_enabled_request, skills_get_discovery_paths_request, skills_get_invoked_result, skills_invoked_skill, skills_load_diagnostics, skill_uninstall_plan, slash_command_add_timeline_entry_result, slash_command_agent_prompt_result, slash_command_completed_result, slash_command_info, slash_command_input, slash_command_input_choice, slash_command_input_completion, slash_command_invocation_result, slash_command_kind, slash_command_model_picker_dialog, slash_command_select_subcommand_option, slash_command_select_subcommand_result, slash_command_set_model_result, slash_command_set_plan_model_result, slash_command_show_dialog_result, slash_command_text_result, slash_command_timeline_entry, subagent_settings_entry, subagent_settings_entry_context_tier, system_message_block, task_agent_info, task_agent_progress, task_client_active_status, task_client_execution_mode, task_client_info, task_client_owner, task_client_owner_kind, task_client_owner_presence, task_client_progress, task_client_status, task_client_type, task_client_update, task_complete_data, task_completion_decision, task_execution_mode, task_info, task_kind, task_list, task_progress_line, tasks_cancel_request, tasks_cancel_result, tasks_get_current_promotable_result, tasks_get_progress_request, tasks_get_progress_result, task_shell_info, task_shell_info_attachment_mode, task_shell_progress, tasks_promote_current_to_background_result, tasks_promote_to_background_request, tasks_promote_to_background_result, tasks_refresh_result, tasks_register_request, tasks_register_result, tasks_remove_request, tasks_remove_result, tasks_send_message_request, tasks_send_message_result, tasks_start_agent_request, tasks_start_agent_result, task_status, tasks_update_request, tasks_update_result, tasks_wait_for_pending_result, telemetry_set_feature_overrides_request, token_auth_info, token_provider_auth_info, tool, tool_list, tool_result, tool_result_expanded, tool_result_new_message, tool_result_type, tools_execute_request, tools_get_builtin_descriptors_request, tools_get_builtin_descriptors_result, tools_get_current_metadata_result, tools_initialize_and_validate_result, tools_list_pending_requests_request, tools_list_request, tools_set_request, tools_set_result, tools_shell_descriptor_config, tools_task_complete_event_data_request, tools_update_subagent_settings_result, ui_auto_mode_switch_response, ui_elicitation_array_any_of_field, ui_elicitation_array_any_of_field_items, ui_elicitation_array_any_of_field_items_any_of, ui_elicitation_array_enum_field, ui_elicitation_array_enum_field_items, ui_elicitation_field_value, ui_elicitation_request, ui_elicitation_response, ui_elicitation_response_action, ui_elicitation_response_content, ui_elicitation_result, ui_elicitation_schema, ui_elicitation_schema_property, ui_elicitation_schema_property_boolean, ui_elicitation_schema_property_number, ui_elicitation_schema_property_number_type, ui_elicitation_schema_property_string, ui_elicitation_schema_property_string_format, ui_elicitation_string_enum_field, ui_elicitation_string_one_of_field, ui_elicitation_string_one_of_field_one_of, ui_ephemeral_query_request, ui_ephemeral_query_result, ui_exit_plan_mode_action, ui_exit_plan_mode_response, ui_handle_pending_auto_mode_switch_request, ui_handle_pending_elicitation_request, ui_handle_pending_exit_plan_mode_request, ui_handle_pending_result, ui_handle_pending_sampling_request, ui_handle_pending_sampling_response, ui_handle_pending_session_limits_exhausted_request, ui_handle_pending_user_input_request, ui_register_direct_auto_mode_switch_handler_result, ui_session_limits_exhausted_response, ui_session_limits_exhausted_response_action, ui_unregister_direct_auto_mode_switch_handler_request, ui_unregister_direct_auto_mode_switch_handler_result, ui_user_input_response, unsupported_enqueue_command_result, update_subagent_settings_request, usage_get_metrics_result, usage_set_code_changes_request, user_auth_info, user_requested_shell_command_result, user_setting_metadata, user_settings_get_result, user_settings_set_request, visibility_get_result, visibility_set_request, visibility_set_result, workflow_abort_request, workflow_ack_result, workflow_agent_options, workflow_agent_request, workflow_agent_result, workflow_agent_summary, workflow_cancel_request, workflow_current_phase, workflow_declared_limits, workflow_durable_operation, workflow_execute_request, workflow_execute_result, workflow_get_run_progress_request, workflow_get_run_request, workflow_journal_get_request, workflow_journal_get_result, workflow_journal_put_request, workflow_list_runs_request, workflow_list_runs_result, workflow_log_line, workflow_log_line_kind, workflow_log_request, workflow_pause_checkpoint_action, workflow_pause_checkpoint_request, workflow_pause_checkpoint_result, workflow_pause_info, workflow_pause_request, workflow_phase_observation, workflow_phase_status, workflow_progress_line, workflow_progress_page, workflow_resume_request, workflow_resume_result, workflow_run_consumed, workflow_run_detail, workflow_run_failure, workflow_run_failure_kind, workflow_run_limits, workflow_run_options, workflow_run_request, workflow_run_result, workflow_run_status, workflow_run_summary, workflow_run_terminal, workflow_tool_resume_request, workflow_tool_run_options, workflow_tool_run_request, workspace_diff_contents, workspace_diff_file_change, workspace_diff_file_change_type, workspace_diff_mode, workspace_diff_result, workspaces_add_summary_request, workspaces_add_summary_result, workspaces_autopilot_objective_exists_result, workspaces_checkpoints, workspaces_create_directory_request, workspaces_create_file_request, workspaces_delete_autopilot_objective_result, workspaces_diff_request, workspaces_ensure_request, workspaces_get_workspace_result, workspaces_list_checkpoints_result, workspaces_list_files_result, workspaces_read_autopilot_objective_result, workspaces_read_checkpoint_request, workspaces_read_checkpoint_result, workspaces_read_file_request, workspaces_read_file_result, workspaces_remove_path_request, workspaces_rename_path_request, workspaces_save_large_paste_request, workspaces_save_large_paste_result, workspaces_stat_file_request, workspaces_stat_file_result, workspaces_truncate_summaries_request, workspace_summary_host_type, workspaces_update_metadata_request, workspaces_workspace_details_host_type, workspaces_write_autopilot_objective_request, workspaces_write_autopilot_objective_result, connector_session_account_result, session_auth_info_result, session_context_attribution, session_context_info, subagent_settings, task_progress, workspace_summary) + return RPC(abort_request, abort_result, accepted_enqueue_command_result, account_all_users, account_auth_info, account_describe_auth_info_request, account_describe_auth_info_result, account_get_all_users_result, account_get_current_auth_result, account_get_gist_support_request, account_get_gist_support_result, account_get_quota_request, account_get_quota_result, account_get_token_env_var_result, account_get_web_url_request, account_get_web_url_result, account_kind, account_login_request, account_login_result, account_logout_request, account_logout_result, account_quota_snapshot, accounts_enumerate_request, accounts_get_request, accounts_set_request, account_status, adaptive_thinking_support, agent_discovery_path, agent_discovery_path_list, agent_discovery_path_scope, agent_get_current_result, agent_info, agent_info_source, agent_list, agent_list_request, agent_registry_live_target_entry, agent_registry_live_target_entry_attention_kind, agent_registry_live_target_entry_kind, agent_registry_live_target_entry_last_terminal_event, agent_registry_live_target_entry_status, agent_registry_log_capture, agent_registry_log_capture_open_error_reason, agent_registry_spawn_error, agent_registry_spawn_permission_mode, agent_registry_spawn_registry_timeout, agent_registry_spawn_request, agent_registry_spawn_result, agent_registry_spawn_spawned, agent_registry_spawn_validation_error, agent_registry_spawn_validation_error_field, agent_registry_spawn_validation_error_reason, agent_reload_result, agents_custom_agent_initial_model_decision_params, agents_custom_agent_initial_model_decision_result, agents_discover_request, agent_select_request, agent_select_result, agent_set_prompt_request, agents_get_available_builtins_request, agents_get_available_builtins_result, agents_get_builtin_definition_request, agents_get_builtin_definition_result, agents_get_builtin_listing_definition_request, agents_get_builtin_listing_definition_result, agents_get_builtins_result, agents_get_discovery_paths_request, api_key_auth_info, auth_enumerate_query, auth_enumerate_value, auth_identity, auth_identity_metadata, auth_info, auth_info_type, auth_login_account, auth_login_advance_request, auth_login_begin_request, auth_login_begun, auth_login_cancel_request, auth_login_result_dto, auth_login_result_status, auth_login_step, auth_read_query, auth_read_value, auth_status_dto, auth_validation_error, auth_validation_errors, auth_write, auth_write_result, autopilot_objective_credit_limit, autopilot_objective_get_state_result, autopilot_objective_state, autopilot_objective_status, auto_tier_descriptor, auto_tier_metadata, auto_tier_status, builtin_agent_summary, built_in_model_catalog, built_in_model_catalog_entry, builtin_tool_descriptor, builtin_tool_format, builtin_tool_format_type, builtin_tool_input_schema, builtin_tool_input_schema_type, builtin_tool_safe_for_telemetry, builtin_tool_safe_telemetry_fields, cancel_user_requested_shell_command_result, canvas_action, canvas_action_invoke_request, canvas_action_invoke_result, canvas_close_request, canvas_host_context, canvas_host_context_capabilities, canvas_json_schema, canvas_list, canvas_list_open_result, canvas_open_request, canvas_provider_close_request, canvas_provider_invoke_action_request, canvas_provider_open_request, canvas_provider_open_result, canvas_provider_register_request, canvas_provider_unregister_request, canvas_session_context, capi_session_options, card_digest, card_digest_algorithm, card_digest_value, catalog_agent_plugin_candidate, catalog_agent_plugin_candidate_kind, catalog_agent_plugin_candidate_provenance, catalog_agent_plugin_compatibility_tag, catalog_agent_plugin_media_type, catalog_ai_skill_candidate, catalog_ai_skill_candidate_kind, catalog_ai_skill_candidate_provenance, catalog_ai_skill_installability, catalog_ai_skill_media_type, catalog_authentication_required_error, catalog_authentication_required_reason, catalog_candidate, catalog_candidate_kind, catalog_candidate_source, catalog_candidate_source_embedded, catalog_candidate_source_url, catalog_capability, catalog_capability_id, catalog_client_contract, catalog_contract_violation_error, catalog_contract_violation_reason, catalog_handle_rejected_error, catalog_handle_rejection_reason, catalog_handle_type, catalog_invalid_request_error, catalog_invalid_request_field, catalog_malformed_card_error, catalog_malformed_card_reason, catalog_mcp_server_candidate, catalog_mcp_server_candidate_kind, catalog_mcp_server_candidate_provenance, catalog_mcp_server_installability, catalog_media_type, catalog_negotiated_contract, catalog_negotiation_refused_error, catalog_negotiation_refused_reason, catalog_network_failure_error, catalog_network_failure_reason, catalog_not_installable_error, catalog_not_installable_reason, catalog_plugin_repository_source, catalog_policy_rejected_error, catalog_resource_identity, catalog_resource_version, catalog_search_page, catalog_search_pagination, catalog_search_request, catalog_search_result, catalog_search_succeeded, catalog_search_total_count_relation, catalog_selection_cancelled, catalog_selection_decision, catalog_selection_declined, catalog_selection_foreign, catalog_selection_invalid, catalog_selection_replayed, catalog_selection_request, catalog_selection_result, catalog_selection_selected, catalog_selection_stale, catalog_selection_timed_out, catalog_selection_wrong_kind, catalog_trust_eligibility, catalog_trust_provenance, catalog_trust_snapshot, catalog_trust_snapshot_absent, catalog_trust_snapshot_absent_status, catalog_trust_snapshot_current, catalog_trust_snapshot_current_status, catalog_trust_snapshot_downgraded, catalog_trust_snapshot_downgraded_status, catalog_trust_snapshot_malformed, catalog_trust_snapshot_malformed_status, catalog_trust_snapshot_revoked, catalog_trust_snapshot_revoked_status, catalog_trust_snapshot_schema_version, catalog_trust_snapshot_stale, catalog_trust_snapshot_stale_status, catalog_trust_snapshot_unsupported, catalog_trust_snapshot_unsupported_status, catalog_trust_source, catalog_trust_tier, catalog_unavailable_error, catalog_unavailable_reason, catalog_unavailable_transport_error, catalog_unavailable_transport_reason, catalog_unsafe_retrieval_error, catalog_unsafe_retrieval_reason, catalog_unsupported_kind_error, client_metadata, client_task_cancel_reason, client_task_cancel_request, client_task_cancel_result, command_list, commands_finalize_invocation_effect_request, commands_finalize_invocation_effect_result, commands_handle_pending_command_request, commands_handle_pending_command_result, commands_invocation_effect_outcome, commands_invocation_origin, commands_invoke_request, commands_list_request, commands_respond_to_queued_command_request, commands_respond_to_queued_command_result, completions_get_trigger_characters_result, completions_request_request, completions_request_result, configure_session_extensions_params, connect_client_info, connected_remote_session_metadata, connected_remote_session_metadata_kind, connected_remote_session_metadata_repository, connector_account_request, connector_authorization_requirement, connector_authorization_scope, connector_availability, connector_capabilities, connector_catalog_entry, connector_catalog_result, connector_catalog_status, connector_connect_request, connector_connect_result, connector_continue_request, connector_disconnect_result, connector_discovery_account, connector_discovery_account_list, connector_discovery_account_request, connector_discovery_auth_info, connector_discovery_availability, connector_discovery_capabilities, connector_discovery_catalog_entry, connector_discovery_catalog_result, connector_mcp_status, connector_reconcile_request, connector_runtime_status, connector_session_account, connector_status, connect_remote_session_params, connect_request, connect_result, content_exclusion_check_paths_request, content_exclusion_check_paths_result, content_exclusion_path_check, content_filter_mode, context_heaviest_message, copilot_api_token_auth_info, copilot_user_response, copilot_user_response_endpoints, copilot_user_response_quota_snapshots, copilot_user_response_quota_snapshots_chat, copilot_user_response_quota_snapshots_completions, copilot_user_response_quota_snapshots_premium_interactions, current_model, current_tool_metadata, customization_reload_outcome, customization_reload_status, customization_reload_subsystem, customizations_reload_result, debug_collect_logs_collected_entry, debug_collect_logs_destination, debug_collect_logs_entry, debug_collect_logs_entry_kind, debug_collect_logs_include, debug_collect_logs_redaction, debug_collect_logs_request, debug_collect_logs_result, debug_collect_logs_result_kind, debug_collect_logs_skipped_entry, debug_collect_logs_source, diagnostic_cursor_status, diagnostic_entry, diagnostic_log_level, diagnostics_configuration, diagnostics_configure_request, diagnostic_severity, diagnostic_source, diagnostic_sources_configuration, diagnostics_read_request, diagnostics_read_result, discovered_canvas, discovered_extension, discovered_extension_mode, discovered_extension_plugin, discovered_extensions, discovered_extensions_disable_request, discovered_extensions_enable_request, discovered_extension_source, discovered_hook, discovered_mcp_server, discovered_mcp_server_type, discovered_model, discovered_model_list, enqueue_command_params, enqueue_command_result, env_auth_info, environment_capabilities, environment_kind, environments_delete_request, environments_delete_result, environments_get_request, environments_get_result, environments_list_request, environments_list_result, event_log_read_request, event_log_release_interest_result, event_log_tail_result, event_log_types, events_agent_scope, events_cursor_status, events_read_direction, events_read_result, execute_command_params, execute_command_result, extension, extension_context_push_input, extension_launch_profile, extension_launch_provider_resolve_request, extension_launch_provider_resolve_result, extension_list, extensions_disable_request, extensions_enable_request, extension_source, extension_status, external_tool_result, external_tool_text_result_for_llm, external_tool_text_result_for_llm_binary_results_for_llm, external_tool_text_result_for_llm_binary_results_for_llm_type, external_tool_text_result_for_llm_content, external_tool_text_result_for_llm_content_audio, external_tool_text_result_for_llm_content_image, external_tool_text_result_for_llm_content_resource, external_tool_text_result_for_llm_content_resource_details, external_tool_text_result_for_llm_content_resource_link, external_tool_text_result_for_llm_content_resource_link_icon, external_tool_text_result_for_llm_content_resource_link_icon_theme, external_tool_text_result_for_llm_content_shell_exit, external_tool_text_result_for_llm_content_terminal, external_tool_text_result_for_llm_content_text, feature_flag_availability, feature_flag_metadata, feature_flags_metadata_result, feature_flags_resolve_request, feature_flags_resolve_result, filter_mapping, fleet_start_request, fleet_start_result, folder_trust_add_params, folder_trust_check_params, folder_trust_check_result, gh_cli_auth_info, git_current_branch_remote_result, git_cwd_request, git_hub_environment, git_hub_owner_option, git_hub_owners_cancel_request, git_hub_owners_cancel_result, git_hub_owners_list_request, git_hub_owners_list_result, git_hub_owners_request_id_result, git_hub_repository_at_path_request, git_hub_repository_at_path_result, git_hub_repository_identity, git_hub_telemetry_client_info, git_hub_telemetry_event, git_hub_telemetry_notification, git_hub_token_acquire_reason, git_hub_token_acquire_request, git_hub_token_acquire_result, git_remote_repository, git_repos_from_remotes_request, git_repos_from_remotes_result, global_state_load_for_config_dir_request, global_state_load_result, global_state_write_key_request, handle_pending_tool_call_request, handle_pending_tool_call_result, history_abort_manual_compaction_result, history_cancel_background_compaction_result, history_clear_context_request, history_clear_context_result, history_compact_context_window, history_compact_request, history_compact_result, history_file_restore_skip_reason, history_list_rewind_points_result, history_preview_rewind_request, history_preview_rewind_result, history_rewind_change_type, history_rewind_file_preview, history_rewind_mode, history_rewind_outcome, history_rewind_point, history_rewind_request, history_rewind_result, history_rewind_unavailable_reason, history_skipped_file_restore, history_summarize_for_handoff_result, history_truncate_request, history_truncate_result, hmac_auth_info, hook_invoke_request, hook_invoke_response, hook_origin, hooks_discover_request, hooks_discover_result, hook_type, host_configuration, host_dispose_request, host_empty_result, host_environment_credentials, host_exited_notification, host_exit_reason, host_git_hub_environment_options, host_list_sessions_request, host_list_sessions_result, host_local_server_configuration, host_local_server_options, host_publish_session_request, host_publish_session_result, host_ready_request, host_register_session_request, host_session_create_callback, host_session_create_request, host_session_create_result, host_session_released_notification, host_session_release_request, host_session_summary, host_start_request, host_start_result, installation_catalogue_identity, installation_confirmation_request, installation_confirmation_response, installation_decision, installation_review, installed_plugin, installed_plugin_info, installed_plugin_source, installed_plugin_source_git_hub, installed_plugin_source_local, installed_plugin_source_url, instruction_discovery_path, instruction_discovery_path_kind, instruction_discovery_path_list, instruction_discovery_path_location, instructions_discover_repo_sources_request, instructions_discover_request, instructions_get_discovery_paths_request, instructions_get_sources_result, instructions_init_prompt_result, instruction_source, instruction_source_location, instruction_source_type, interrupt_main_turn_request, interrupt_main_turn_result, json_schema_response_format, llm_inference_headers, llm_inference_http_request_chunk_request, llm_inference_http_request_chunk_result, llm_inference_http_request_start_request, llm_inference_http_request_start_result, llm_inference_http_request_start_transport, llm_inference_http_response_chunk_error, llm_inference_http_response_chunk_request, llm_inference_http_response_chunk_result, llm_inference_http_response_start_request, llm_inference_http_response_start_result, llm_inference_set_provider_result, local_session_metadata_value, logged_in_user, login_provider_kind, log_request, log_result, lsp_initialize_request, managed_mcp_server_config, managed_permission_evaluation, managed_permission_operation, managed_permission_operation_kind, managed_permissions_evaluate_request, managed_permissions_evaluate_result, managed_permission_verdict, managed_plugin_retry_entry, managed_plugin_retry_status, managed_setting_meta, managed_settings_channel, managed_settings_compose_layer, managed_settings_compose_request, managed_settings_compose_result, managed_settings_diagnostic, managed_settings_diagnostic_severity, managed_settings_layer, managed_settings_meta, managed_settings_read_result, managed_settings_resolved_data, managed_settings_resolve_request, managed_settings_resolve_result, managed_settings_schema_result, managed_settings_validate_request, managed_settings_validate_result, managed_settings_values, marketplace_add_result, marketplace_browse_result, marketplace_info, marketplace_list_result, marketplace_plugin_info, marketplace_refresh_entry, marketplace_refresh_result, marketplace_remove_result, mcp_allowed_server, mcp_apply_install_request, mcp_apply_uninstall_request, mcp_apps_call_tool_request, mcp_apps_diagnose_capability, mcp_apps_diagnose_request, mcp_apps_diagnose_result, mcp_apps_diagnose_server, mcp_apps_host_context, mcp_apps_host_context_details, mcp_apps_host_context_details_available_display_mode, mcp_apps_host_context_details_display_mode, mcp_apps_host_context_details_platform, mcp_apps_host_context_details_theme, mcp_apps_list_tools_request, mcp_apps_list_tools_result, mcp_apps_read_resource_request, mcp_apps_read_resource_result, mcp_apps_resource_content, mcp_apps_set_host_context_details, mcp_apps_set_host_context_details_available_display_mode, mcp_apps_set_host_context_details_display_mode, mcp_apps_set_host_context_details_platform, mcp_apps_set_host_context_details_theme, mcp_apps_set_host_context_request, mcp_cancel_sampling_execution_params, mcp_cancel_sampling_execution_result, mcp_config_add_request, mcp_config_disable_request, mcp_config_enable_request, mcp_config_list, mcp_config_remove_request, mcp_config_update_request, mcp_configured_server, mcp_configured_server_list, mcp_configured_server_state, mcp_configure_git_hub_request, mcp_configure_git_hub_result, mcp_diagnostic_details, mcp_diagnostic_direction, mcp_diagnostic_kind, mcp_diagnostic_source_configuration, mcp_disable_request, mcp_discover_request, mcp_discover_result, mcp_elicitation_form_mode, mcp_enable_request, mcp_execute_sampling_params, mcp_execute_sampling_request, mcp_execute_sampling_result, mcp_failed_server, mcp_filtered_server, mcp_headers_handle_pending_headers_refresh_request, mcp_headers_handle_pending_headers_refresh_request_request, mcp_headers_handle_pending_headers_refresh_request_result, mcp_host_state, mcp_installation_failure_reason, mcp_installation_input, mcp_installation_management_outcome, mcp_installation_management_result, mcp_installation_operation_request, mcp_installation_operation_status, mcp_installation_outcome, mcp_installation_remote_configuration, mcp_installation_result, mcp_installation_review, mcp_installation_secret, mcp_installation_secret_storage, mcp_installations_request, mcp_installation_state, mcp_installation_summary, mcp_install_plan, mcp_is_server_running_request, mcp_is_server_running_result, mcp_list_builtin_server_names_result, mcp_list_tools_request, mcp_list_tools_result, mcp_oauth_authentication_state_changed_request, mcp_oauth_cancel_login_request, mcp_oauth_cancel_login_result, mcp_oauth_complete_request, mcp_oauth_handle_pending_request, mcp_oauth_handle_pending_result, mcp_oauth_login_grant_type, mcp_oauth_login_request, mcp_oauth_login_result, mcp_oauth_pending_request_response, mcp_oauth_prepare_login_request, mcp_oauth_prepare_login_result, mcp_oauth_probe_needs_auth_reason, mcp_oauth_probe_request, mcp_oauth_probe_result, mcp_oauth_respond_request, mcp_oauth_respond_result, mcp_owned_oauth_login_status, mcp_plan_configuration_change, mcp_plan_configuration_operation, mcp_plan_enum_value_type, mcp_plan_install_planned, mcp_plan_install_request, mcp_plan_install_result, mcp_plan_install_source, mcp_plan_install_source_candidate, mcp_plan_install_source_candidate_kind, mcp_plan_install_source_card, mcp_plan_install_source_card_kind, mcp_plan_package_install_method, mcp_plan_package_transport, mcp_plan_policy_decision, mcp_plan_policy_result, mcp_plan_policy_source, mcp_plan_provenance, mcp_plan_remote_install_method, mcp_plan_remote_transport, mcp_plan_required_value, mcp_plan_required_value_enum, mcp_plan_required_value_enum_kind, mcp_plan_required_value_scalar, mcp_plan_required_value_scalar_kind, mcp_plan_resource_identity, mcp_plan_scalar_value_type, mcp_plan_scope, mcp_plan_secret_placeholder, mcp_plan_secret_reference, mcp_plan_target, mcp_plan_transport_choice, mcp_plan_transport_choice_package, mcp_plan_transport_choice_remote, mcp_plan_uninstall_request, mcp_plan_value_category, mcp_prepared_install, mcp_prepare_install_request, mcp_prompt, mcp_prompt_argument, mcp_prompt_icon, mcp_prompt_message, mcp_prompt_role, mcp_prompts_get_request, mcp_prompts_get_result, mcp_prompts_list_request, mcp_prompts_list_result, mcp_register_external_client_request, mcp_registry_cancel_request, mcp_registry_cancel_result, mcp_registry_request_id_result, mcp_registry_search_request, mcp_registry_search_result, mcp_reload_config, mcp_reload_with_config_request, mcp_remove_git_hub_result, mcp_resource, mcp_resource_annotations, mcp_resource_content, mcp_resource_icon, mcp_resources_list_request, mcp_resources_list_result, mcp_resources_list_templates_request, mcp_resources_list_templates_result, mcp_resources_read_request, mcp_resources_read_result, mcp_resource_template, mcp_restart_server_request, mcp_safe_for_telemetry, mcp_safe_for_telemetry_fields, mcp_sampling_execution_action, mcp_sampling_execution_result, mcp_serializable_server_config, mcp_server, mcp_server_auth_config, mcp_server_auth_config_redirect_port, mcp_server_card_embedded, mcp_server_card_embedded_kind, mcp_server_card_media_type, mcp_server_card_reference, mcp_server_card_url, mcp_server_card_url_kind, mcp_server_config, mcp_server_config_defer_tools, mcp_server_config_http, mcp_server_config_http_oauth_grant_type, mcp_server_config_http_type, mcp_server_config_memory, mcp_server_config_memory_type, mcp_server_config_stdio, mcp_server_config_stdio_type, mcp_server_failure_info, mcp_server_list, mcp_server_needs_auth_info, mcp_server_ownership, mcp_set_env_value_mode_details, mcp_set_env_value_mode_params, mcp_set_env_value_mode_result, mcp_should_exclude_git_hub_tools_request, mcp_should_exclude_git_hub_tools_result, mcp_source_file, mcp_source_plugin, mcp_source_ref, mcp_start_server_request, mcp_start_servers_result, mcp_stop_server_request, mcp_task_metadata, mcp_tools, mcp_tool_ui, mcp_tool_ui_visibility, mcp_uninstall_plan, mcp_unregister_external_client_request, memory_configuration, metadata_context_attribution_result, metadata_context_heaviest_messages_request, metadata_context_heaviest_messages_result, metadata_context_info_request, metadata_context_info_result, metadata_is_processing_result, metadata_recompute_context_tokens_request, metadata_recompute_context_tokens_result, metadata_record_context_change_request, metadata_record_context_change_result, metadata_set_working_directory_request, metadata_set_working_directory_result, metadata_snapshot_current_mode, metadata_snapshot_remote_metadata, metadata_snapshot_remote_metadata_repository, metadata_snapshot_remote_metadata_task_type, metadata_update_client_metadata_request, model, model_apply_startup_overlay_request, model_artifact_details, model_billing, model_billing_promo, model_billing_token_prices, model_billing_token_prices_long_context, model_capabilities, model_capabilities_limits, model_capabilities_limits_vision, model_capabilities_override, model_capabilities_override_limits, model_capabilities_override_limits_vision, model_capabilities_override_supports, model_capabilities_supports, model_clear_startup_seed_request, model_clear_startup_seed_result, model_get_reasoning_summaries_request, model_get_reasoning_summaries_result, model_list, model_list_request, model_message, model_picker_category, model_picker_persistence_request, model_picker_price_category, model_picker_settings_context, model_policy, model_policy_state, model_provider_adapter_catalog, model_provider_adapter_descriptor, model_provider_adapter_operation_descriptor, model_provider_attribution, model_provider_automatic_discovery_mode, model_provider_automatic_discovery_policy, model_provider_configuration_disposition, model_provider_configuration_plan, model_provider_descriptor, model_provider_discover_request, model_provider_discover_result, model_provider_discovery_network_scope, model_provider_get_status_request, model_provider_instance, model_provider_instance_reference, model_provider_models_list_request, model_provider_operation_outcome, model_provider_operation_outcome_code, model_provider_prepare_configuration_request, model_provider_provenance, model_provider_provenance_source, model_provider_status, model_provider_warning, model_set_allowed_models_request, model_set_allowed_models_result, model_set_reasoning_effort_request, model_set_reasoning_effort_result, models_list_request, model_switch_auto_tier_request, model_switch_auto_tier_result, model_switch_auto_tier_status, model_switch_confirmation, model_switch_to_request, model_switch_to_result, model_warning_text, mode_set_request, mode_set_result, move_mcp_loading_to_background_result, named_provider_config, name_get_result, name_set_auto_request, name_set_auto_result, name_set_request, open_canvas_instance, options_update_additional_content_exclusion_policy, options_update_additional_content_exclusion_policy_rule, options_update_additional_content_exclusion_policy_rule_source, options_update_additional_content_exclusion_policy_scope, options_update_context_tier, options_update_env_value_mode, options_update_reasoning_summary, options_update_tool_filter_precedence, pending_external_tool_request, pending_external_tool_request_list, pending_permission_request, pending_permission_request_list, permission_decision, permission_decision_approved, permission_decision_approved_for_location, permission_decision_approved_for_session, permission_decision_approve_for_location, permission_decision_approve_for_location_approval, permission_decision_approve_for_location_approval_commands, permission_decision_approve_for_location_approval_custom_tool, permission_decision_approve_for_location_approval_extension_env_access, permission_decision_approve_for_location_approval_extension_management, permission_decision_approve_for_location_approval_extension_permission_access, permission_decision_approve_for_location_approval_mcp, permission_decision_approve_for_location_approval_mcp_sampling, permission_decision_approve_for_location_approval_memory, permission_decision_approve_for_location_approval_read, permission_decision_approve_for_location_approval_workflow, permission_decision_approve_for_location_approval_write, permission_decision_approve_for_session, permission_decision_approve_for_session_approval, permission_decision_approve_for_session_approval_commands, permission_decision_approve_for_session_approval_custom_tool, permission_decision_approve_for_session_approval_extension_env_access, permission_decision_approve_for_session_approval_extension_management, permission_decision_approve_for_session_approval_extension_permission_access, permission_decision_approve_for_session_approval_mcp, permission_decision_approve_for_session_approval_mcp_sampling, permission_decision_approve_for_session_approval_memory, permission_decision_approve_for_session_approval_read, permission_decision_approve_for_session_approval_workflow, permission_decision_approve_for_session_approval_write, permission_decision_approve_once, permission_decision_approve_permanently, permission_decision_approve_read_only_for_session, permission_decision_cancelled, permission_decision_context, permission_decision_denied_by_content_exclusion_policy, permission_decision_denied_by_permission_request_hook, permission_decision_denied_by_rules, permission_decision_denied_interactively_by_user, permission_decision_denied_no_approval_rule_and_could_not_request_from_user, permission_decision_outcome, permission_decision_reject, permission_decision_request, permission_decision_surface, permission_decision_user_not_available, permission_location_add_tool_approval_params, permission_location_apply_params, permission_location_apply_result, permission_location_resolve_params, permission_location_resolve_result, permission_location_type, permission_mode_source, permission_paths_add_params, permission_paths_allowed_check_params, permission_paths_allowed_check_result, permission_paths_config, permission_paths_list, permission_paths_update_primary_params, permission_paths_workspace_check_params, permission_paths_workspace_check_result, permission_prompt_shown_notification, permission_request_result, permission_response_capability, permission_rules_set, permissions_configure_additional_content_exclusion_policy, permissions_configure_additional_content_exclusion_policy_rule, permissions_configure_additional_content_exclusion_policy_rule_source, permissions_configure_additional_content_exclusion_policy_scope, permissions_configure_params, permissions_configure_result, permissions_folder_trust_add_trusted_result, permissions_get_mode_request, permissions_get_mode_result, permissions_locations_add_tool_approval_details, permissions_locations_add_tool_approval_details_commands, permissions_locations_add_tool_approval_details_custom_tool, permissions_locations_add_tool_approval_details_extension_env_access, permissions_locations_add_tool_approval_details_extension_management, permissions_locations_add_tool_approval_details_extension_permission_access, permissions_locations_add_tool_approval_details_mcp, permissions_locations_add_tool_approval_details_mcp_sampling, permissions_locations_add_tool_approval_details_memory, permissions_locations_add_tool_approval_details_read, permissions_locations_add_tool_approval_details_workflow, permissions_locations_add_tool_approval_details_write, permissions_locations_add_tool_approval_result, permissions_modify_rules_params, permissions_modify_rules_result, permissions_modify_rules_scope, permissions_notify_prompt_shown_result, permissions_paths_add_result, permissions_paths_list_request, permissions_paths_update_primary_result, permissions_pending_requests_request, permissions_reset_session_approvals_request, permissions_reset_session_approvals_result, permissions_set_approve_all_request, permissions_set_approve_all_result, permissions_set_approve_all_source, permissions_set_mode_request, permissions_set_mode_result, permissions_set_required_request, permissions_set_required_result, permissions_urls_set_unrestricted_mode_result, permission_urls_config, permission_urls_set_unrestricted_mode_params, ping_request, ping_result, plan_read_result, plan_read_sql_todos_result, plan_read_sql_todos_with_dependencies_result, plan_sql_todo_dependency, plan_sql_todos_row, plan_update_request, plugin, plugin_install_result, plugin_install_staging_mode, plugin_list, plugin_list_result, plugins_builtin_set_request, plugins_disable_request, plugins_enable_request, plugins_install_request, plugins_marketplaces_add_request, plugins_marketplaces_browse_request, plugins_marketplaces_refresh_request, plugins_marketplaces_remove_request, plugins_reload_request, plugins_uninstall_request, plugins_update_request, plugin_update_all_entry, plugin_update_all_result, plugin_update_result, protocol_append_mode, protocol_customize_mode, protocol_external_tool_defer, protocol_external_tool_definition, protocol_marker_section_override, protocol_replace_mode, protocol_section_override, protocol_static_section_action, protocol_static_section_override, protocol_system_message_append_config, protocol_system_message_config, protocol_system_message_customize_config, protocol_system_message_replace_config, provider_add_request, provider_add_result, provider_config, provider_config_azure, provider_config_model_provider, provider_config_transport, provider_config_type, provider_config_wire_api, provider_descriptor, provider_endpoint, provider_endpoint_transport, provider_endpoint_type, provider_endpoint_wire_api, provider_get_endpoint_request, provider_model_config, provider_session_token, provider_sync_request, provider_sync_result, provider_token_acquire_request, provider_token_acquire_result, provider_withdraw_request, provider_withdraw_result, push_attachment, push_attachment_blob, push_attachment_directory, push_attachment_file, push_attachment_file_line_range, push_attachment_git_hub_actions_job, push_attachment_git_hub_commit, push_attachment_git_hub_file, push_attachment_git_hub_file_diff, push_attachment_git_hub_file_diff_side, push_attachment_git_hub_reference, push_attachment_git_hub_reference_type, push_attachment_git_hub_release, push_attachment_git_hub_repository, push_attachment_git_hub_snippet, push_attachment_git_hub_tree_comparison, push_attachment_git_hub_tree_comparison_side, push_attachment_git_hub_url, push_attachment_selection, push_attachment_selection_details, push_attachment_selection_details_end, push_attachment_selection_details_start, push_git_hub_repo_ref, queue_append_steering_request, queue_begin_deferred_idle_drain_request, queue_begin_deferred_idle_drain_result, queue_consume_system_notifications_request, queued_command_handled, queued_command_not_handled, queued_command_result, queue_defer_session_idle_request, queue_duplicate_at_request, queue_duplicate_at_result, queue_enqueue_resume_pending_result, queue_finish_deferred_idle_drain_request, queue_finish_deferred_idle_drain_result, queue_has_pending_result, queue_insert_at_request, queue_insert_at_result, queue_insert_message, queue_move_item_request, queue_move_item_result, queue_pending_items, queue_pending_items_kind, queue_pending_items_result, queue_remove_at_request, queue_remove_at_result, queue_remove_most_recent_result, queue_send_now_request, queue_send_now_result, queue_set_drain_paused_request, queue_snapshot_result, queue_update_text_request, queue_update_text_result, queue_withdraw_message_request, queue_withdraw_message_result, quota_take_warnings_result, quota_warning_projection, register_event_interest_params, register_event_interest_result, release_event_interest_params, remote_control_config, remote_control_config_existing_mc_session, remote_control_status, remote_control_status_active, remote_control_status_connecting, remote_control_status_error, remote_control_status_off, remote_control_status_result, remote_control_stop_result, remote_control_transfer_result, remote_enable_request, remote_enable_result, remote_notify_steerable_changed_request, remote_notify_steerable_changed_result, remote_session_connection_result, remote_session_host_status, remote_session_metadata_repository, remote_session_metadata_task_type, remote_session_metadata_value, remote_session_mode, remote_session_repository, repo_settings_read_raw_request, repo_settings_read_raw_result, repo_settings_write_all_request, repo_settings_write_key_request, response_format, sandbox_config, sandbox_config_auth, sandbox_config_source, sandbox_config_user_policy, sandbox_config_user_policy_experimental, sandbox_config_user_policy_experimental_seatbelt, sandbox_config_user_policy_filesystem, sandbox_config_user_policy_network, sandbox_config_user_policy_network_proxy, sandbox_config_user_policy_seatbelt, sandbox_credentials_config, sandbox_credential_suggestion, sandbox_credential_suggestions_result, sandbox_disable_for_session_request, sandbox_disable_for_session_result, sandbox_enforcement_status, sandbox_grant_path_for_request_request, sandbox_grant_path_for_request_result, sandbox_host_capability, sandbox_host_capability_name, sandbox_host_support, sandbox_masked_env_var, sandbox_proxy_ca_create_result, sandbox_proxy_ca_request, sandbox_proxy_ca_state, sandbox_proxy_ca_status, sandbox_session_change, schedule_add_at_request, schedule_add_cron_request, schedule_add_request, schedule_add_result, schedule_add_self_paced_request, schedule_entry, schedule_has_self_paced_result, schedule_list, schedule_rearm_self_paced_request, schedule_stop_request, schedule_stop_result, secrets_add_filter_values_request, secrets_add_filter_values_result, send_agent_mode, send_attachments_to_message_params, send_message_item, send_messages_request, send_messages_result, send_mode, send_request, send_result, send_system_notification_request, server_agent_list, server_instruction_source_list, server_skill, server_skill_list, session_activity, session_agent_list_request, session_auth_login_request, session_auth_logout_user_request, session_auth_status, session_auth_switch_request, session_bulk_delete_result, session_cancel_all_background_agents_result, session_capability, session_commands_list_request, session_completion_item, session_connected_ide_info, session_context, session_context_host_type, session_enrich_metadata_result, session_fs_append_file_request, session_fs_error, session_fs_error_code, session_fs_exists_request, session_fs_exists_result, session_fs_mkdir_request, session_fs_readdir_request, session_fs_readdir_result, session_fs_readdir_with_types_entry, session_fs_readdir_with_types_entry_type, session_fs_readdir_with_types_request, session_fs_readdir_with_types_result, session_fs_read_file_bytes_request, session_fs_read_file_bytes_result, session_fs_read_file_request, session_fs_read_file_result, session_fs_rename_request, session_fs_rm_request, session_fs_set_provider_capabilities, session_fs_set_provider_conventions, session_fs_set_provider_request, session_fs_set_provider_result, session_fs_sqlite_exists_request, session_fs_sqlite_exists_result, session_fs_sqlite_query_request, session_fs_sqlite_query_result, session_fs_sqlite_query_type, session_fs_sqlite_transaction_error, session_fs_sqlite_transaction_error_class, session_fs_sqlite_transaction_request, session_fs_sqlite_transaction_result, session_fs_sqlite_transaction_statement, session_fs_stat_request, session_fs_stat_result, session_fs_write_file_bytes_request, session_fs_write_file_request, session_git_hub_auth_get_all_auth_available_result, session_git_hub_auth_logout_result, session_git_hub_auth_logout_user_result, session_history_compact_request, session_installed_plugin, session_installed_plugin_source, session_installed_plugin_source_git_hub, session_installed_plugin_source_local, session_installed_plugin_source_url, session_limit_prediction_baseline_data, session_limit_prediction_client_type, session_limit_prediction_details, session_limit_prediction_predict_request, session_limit_prediction_request, session_limit_prediction_result, session_limit_prediction_source, session_limit_prediction_tier, session_limit_prediction_tier_option, session_limit_prediction_unavailable_reason, session_list, session_list_entry, session_list_filter, session_load_deferred_repo_hooks_result, session_log_level, session_managed_permissions, session_managed_settings, session_mcp_apps_call_tool_result, session_mcp_oauth_cancel_login_request, session_mcp_oauth_cancel_login_result, session_mcp_oauth_prepare_login_request, session_mcp_oauth_prepare_login_result, session_mcp_set_connected_ide_info_params, session_metadata_snapshot, session_mode, session_model_clear_startup_seed_request, session_model_clear_startup_seed_result, session_model_list, session_model_list_request, session_model_price_category, session_open_options, session_open_options_additional_content_exclusion_policy, session_open_options_additional_content_exclusion_policy_rule, session_open_options_additional_content_exclusion_policy_rule_source, session_open_options_additional_content_exclusion_policy_scope, session_open_options_env_value_mode, session_open_options_reasoning_summary, session_open_params, session_open_result, session_plugins_disable_request, session_plugins_enable_request, session_plugins_install_request, session_plugins_marketplaces_refresh_request, session_plugins_reload_request, session_plugins_retry_managed_request, session_plugins_retry_managed_result, session_provider_get_endpoint_request, session_prune_result, session_quota_delegate_warning, session_quota_get_result, session_quota_plan_tier, session_quota_projection, session_quota_refresh_result, session_quota_snapshot, session_quota_take_warnings_result, sessions_bulk_delete_request, sessions_check_in_use_request, sessions_check_in_use_result, sessions_client_metadata_entry, sessions_close_request, sessions_close_result, sessions_create_workspace_request, sessions_create_workspace_result, sessions_delete_request, sessions_enrich_metadata_request, session_set_credentials_params, session_set_credentials_result, session_settings_built_in_tool_availability_snapshot, session_settings_evaluate_predicate_request, session_settings_evaluate_predicate_result, session_settings_job_snapshot, session_settings_model_snapshot, session_settings_online_evaluation_snapshot, session_settings_predicate_name, session_settings_repo_snapshot, session_settings_snapshot, session_settings_validation_snapshot, sessions_find_by_prefix_request, sessions_find_by_prefix_result, sessions_find_by_task_id_request, sessions_find_by_task_id_result, sessions_fork_request, sessions_fork_result, sessions_get_board_entry_count_request, sessions_get_board_entry_count_result, sessions_get_client_metadata_request, sessions_get_client_metadata_result, sessions_get_event_file_path_request, sessions_get_event_file_path_result, sessions_get_last_for_context_request, sessions_get_last_for_context_result, sessions_get_metadata_request, sessions_get_metadata_result, sessions_get_persisted_remote_steerable_request, sessions_get_persisted_remote_steerable_result, session_sizes, sessions_list_non_empty_session_ids_request, sessions_list_non_empty_session_ids_result, sessions_list_request, sessions_load_deferred_repo_hooks_request, sessions_load_workspace_request, sessions_load_workspace_result, sessions_open_attach, sessions_open_cloud, sessions_open_create, sessions_open_handoff, sessions_open_handoff_task_type, sessions_open_progress, sessions_open_progress_status, sessions_open_progress_step, sessions_open_remote, sessions_open_resume, sessions_open_resume_last, sessions_open_status, session_source, sessions_prune_old_request, sessions_read_persisted_events_request, sessions_release_lock_request, sessions_release_lock_result, sessions_reload_plugin_hooks_request, sessions_reload_plugin_hooks_result, sessions_save_request, sessions_save_result, sessions_set_additional_plugins_request, sessions_set_additional_plugins_result, sessions_set_remote_control_steering_request, sessions_start_remote_control_request, sessions_stop_remote_control_request, sessions_transfer_remote_control_request, sessions_update_workspace_fields_request, sessions_update_workspace_fields_result, session_telemetry_engagement, session_update_options_params, session_update_options_result, session_usage_set_code_changes_request, session_visibility_status, session_workflow_pause_at_checkpoint_result, session_working_directory_context, session_working_directory_context_host_type, session_working_directory_context_with_client, settable_auth_info, settable_token_auth_info, settings_edit_operation, settings_edit_result, settings_edit_status, shell_cancel_user_requested_request, shell_credentials, shell_exec_request, shell_exec_result, shell_execute_user_requested_request, shell_init_profile, shell_init_script, shell_init_script_shell, shell_kill_request, shell_kill_result, shell_kill_signal, shell_options, shutdown_request, skill, skill_apply_install_request, skill_apply_uninstall_request, skill_discovery_path, skill_discovery_path_list, skill_discovery_scope, skill_installation_failure_reason, skill_installation_file_review, skill_installation_location, skill_installation_management_outcome, skill_installation_management_result, skill_installation_operation_request, skill_installation_operation_status, skill_installation_outcome, skill_installation_ownership_state, skill_installation_result, skill_installation_review, skill_installation_scope, skill_installation_session_state, skill_installation_source, skill_installations_request, skill_installation_summary, skill_install_plan, skill_list, skill_plan_install_request, skill_plan_uninstall_request, skill_provider_descriptor, skill_provider_list_request, skill_provider_list_result, skill_provider_read_request, skill_provider_read_result, skills_config_set_disabled_skills_request, skills_config_set_skill_disabled_request, skills_disable_request, skills_discover_request, skills_enable_request, skill_set_enabled_request, skills_get_discovery_paths_request, skills_get_invoked_result, skills_invoked_skill, skills_load_diagnostics, skill_uninstall_plan, slash_command_add_timeline_entry_result, slash_command_agent_prompt_result, slash_command_completed_result, slash_command_info, slash_command_input, slash_command_input_choice, slash_command_input_completion, slash_command_invocation_result, slash_command_kind, slash_command_model_picker_dialog, slash_command_select_subcommand_option, slash_command_select_subcommand_result, slash_command_set_model_result, slash_command_set_plan_model_result, slash_command_show_dialog_result, slash_command_text_result, slash_command_timeline_entry, subagent_settings_entry, subagent_settings_entry_context_tier, system_message_block, task_agent_info, task_agent_progress, task_client_active_status, task_client_execution_mode, task_client_info, task_client_owner, task_client_owner_kind, task_client_owner_presence, task_client_progress, task_client_status, task_client_type, task_client_update, task_complete_data, task_completion_decision, task_execution_mode, task_info, task_kind, task_list, task_progress_line, tasks_cancel_request, tasks_cancel_result, tasks_get_current_promotable_result, tasks_get_progress_request, tasks_get_progress_result, task_shell_info, task_shell_info_attachment_mode, task_shell_progress, tasks_promote_current_to_background_result, tasks_promote_to_background_request, tasks_promote_to_background_result, tasks_refresh_result, tasks_register_request, tasks_register_result, tasks_remove_request, tasks_remove_result, tasks_send_message_request, tasks_send_message_result, tasks_start_agent_request, tasks_start_agent_result, task_status, tasks_update_request, tasks_update_result, tasks_wait_for_pending_result, telemetry_set_feature_overrides_request, token_auth_info, token_provider_auth_info, tool, tool_list, tool_result, tool_result_expanded, tool_result_new_message, tool_result_type, tools_execute_request, tools_get_builtin_descriptors_request, tools_get_builtin_descriptors_result, tools_get_current_metadata_result, tools_initialize_and_validate_result, tools_list_pending_requests_request, tools_list_request, tools_set_request, tools_set_result, tools_shell_descriptor_config, tools_task_complete_event_data_request, tools_update_subagent_settings_result, ui_auto_mode_switch_response, ui_elicitation_array_any_of_field, ui_elicitation_array_any_of_field_items, ui_elicitation_array_any_of_field_items_any_of, ui_elicitation_array_enum_field, ui_elicitation_array_enum_field_items, ui_elicitation_field_value, ui_elicitation_request, ui_elicitation_response, ui_elicitation_response_action, ui_elicitation_response_content, ui_elicitation_result, ui_elicitation_schema, ui_elicitation_schema_property, ui_elicitation_schema_property_boolean, ui_elicitation_schema_property_number, ui_elicitation_schema_property_number_type, ui_elicitation_schema_property_string, ui_elicitation_schema_property_string_format, ui_elicitation_string_enum_field, ui_elicitation_string_one_of_field, ui_elicitation_string_one_of_field_one_of, ui_ephemeral_query_request, ui_ephemeral_query_result, ui_exit_plan_mode_action, ui_exit_plan_mode_response, ui_handle_pending_auto_mode_switch_request, ui_handle_pending_elicitation_request, ui_handle_pending_exit_plan_mode_request, ui_handle_pending_result, ui_handle_pending_sampling_request, ui_handle_pending_sampling_response, ui_handle_pending_session_limits_exhausted_request, ui_handle_pending_user_input_request, ui_register_direct_auto_mode_switch_handler_result, ui_session_limits_exhausted_response, ui_session_limits_exhausted_response_action, ui_unregister_direct_auto_mode_switch_handler_request, ui_unregister_direct_auto_mode_switch_handler_result, ui_user_input_response, unsupported_enqueue_command_result, update_subagent_settings_request, usage_get_metrics_result, usage_set_code_changes_request, user_auth_info, user_requested_shell_command_result, user_setting_metadata, user_settings_apply_top_key_request, user_settings_apply_top_key_result, user_settings_edit_request, user_settings_get_paths_request, user_settings_get_paths_result, user_settings_get_result, user_settings_governance_keys_result, user_settings_load_for_edit_result, user_settings_normalize_request, user_settings_normalize_result, user_settings_problem, user_settings_problem_location, user_settings_problem_source, user_settings_problems_request, user_settings_problems_result, user_settings_set_request, user_settings_update_request, user_settings_update_result, user_settings_validate_request, user_settings_validate_result, user_settings_validation_issue, user_settings_write_all_request, visibility_get_result, visibility_set_request, visibility_set_result, workflow_abort_request, workflow_ack_result, workflow_agent_options, workflow_agent_request, workflow_agent_result, workflow_agent_summary, workflow_cancel_request, workflow_current_phase, workflow_declared_limits, workflow_durable_operation, workflow_execute_request, workflow_execute_result, workflow_get_run_progress_request, workflow_get_run_request, workflow_journal_get_request, workflow_journal_get_result, workflow_journal_put_request, workflow_list_runs_request, workflow_list_runs_result, workflow_log_line, workflow_log_line_kind, workflow_log_request, workflow_pause_checkpoint_action, workflow_pause_checkpoint_request, workflow_pause_checkpoint_result, workflow_pause_info, workflow_pause_request, workflow_phase_observation, workflow_phase_status, workflow_progress_line, workflow_progress_page, workflow_resume_request, workflow_resume_result, workflow_run_consumed, workflow_run_detail, workflow_run_failure, workflow_run_failure_kind, workflow_run_limits, workflow_run_options, workflow_run_request, workflow_run_result, workflow_run_status, workflow_run_summary, workflow_run_terminal, workflow_tool_resume_request, workflow_tool_run_options, workflow_tool_run_request, workspace_diff_contents, workspace_diff_file_change, workspace_diff_file_change_type, workspace_diff_mode, workspace_diff_result, workspaces_add_summary_request, workspaces_add_summary_result, workspaces_autopilot_objective_exists_result, workspaces_checkpoints, workspaces_create_directory_request, workspaces_create_file_request, workspaces_delete_autopilot_objective_result, workspaces_diff_request, workspaces_ensure_request, workspaces_get_workspace_result, workspaces_list_checkpoints_result, workspaces_list_files_result, workspaces_read_autopilot_objective_result, workspaces_read_checkpoint_request, workspaces_read_checkpoint_result, workspaces_read_file_request, workspaces_read_file_result, workspaces_remove_path_request, workspaces_rename_path_request, workspaces_save_large_paste_request, workspaces_save_large_paste_result, workspaces_stat_file_request, workspaces_stat_file_result, workspaces_truncate_summaries_request, workspace_summary_host_type, workspaces_update_metadata_request, workspaces_workspace_details_host_type, workspaces_write_autopilot_objective_request, workspaces_write_autopilot_objective_result, connector_session_account_result, session_auth_info_result, session_context_attribution, session_context_info, subagent_settings, task_progress, workspace_summary) def to_dict(self) -> dict: result: dict = {} @@ -53397,10 +54951,17 @@ def to_dict(self) -> dict: result["AcceptedEnqueueCommandResult"] = to_class(AcceptedEnqueueCommandResult, self.accepted_enqueue_command_result) result["AccountAllUsers"] = to_class(AccountAllUsers, self.account_all_users) result["AccountAuthInfo"] = to_class(AccountAuthInfo, self.account_auth_info) + result["AccountDescribeAuthInfoRequest"] = to_class(_AccountDescribeAuthInfoRequest, self.account_describe_auth_info_request) + result["AccountDescribeAuthInfoResult"] = to_class(_AccountDescribeAuthInfoResult, self.account_describe_auth_info_result) result["AccountGetAllUsersResult"] = from_list(lambda x: to_class(AccountAllUsers, x), self.account_get_all_users_result) result["AccountGetCurrentAuthResult"] = to_class(AccountGetCurrentAuthResult, self.account_get_current_auth_result) + result["AccountGetGistSupportRequest"] = to_class(_AccountGetGistSupportRequest, self.account_get_gist_support_request) + result["AccountGetGistSupportResult"] = to_class(_AccountGetGistSupportResult, self.account_get_gist_support_result) result["AccountGetQuotaRequest"] = to_class(AccountGetQuotaRequest, self.account_get_quota_request) result["AccountGetQuotaResult"] = to_class(AccountGetQuotaResult, self.account_get_quota_result) + result["AccountGetTokenEnvVarResult"] = to_class(_AccountGetTokenEnvVarResult, self.account_get_token_env_var_result) + result["AccountGetWebUrlRequest"] = to_class(_AccountGetWebURLRequest, self.account_get_web_url_request) + result["AccountGetWebUrlResult"] = to_class(_AccountGetWebURLResult, self.account_get_web_url_result) result["AccountKind"] = to_enum(AccountKind, self.account_kind) result["AccountLoginRequest"] = to_class(AccountLoginRequest, self.account_login_request) result["AccountLoginResult"] = to_class(AccountLoginResult, self.account_login_result) @@ -53751,6 +55312,11 @@ def to_dict(self) -> dict: result["ExternalToolTextResultForLlmContentShellExit"] = to_class(ExternalToolTextResultForLlmContentShellExit, self.external_tool_text_result_for_llm_content_shell_exit) result["ExternalToolTextResultForLlmContentTerminal"] = to_class(ExternalToolTextResultForLlmContentTerminal, self.external_tool_text_result_for_llm_content_terminal) result["ExternalToolTextResultForLlmContentText"] = to_class(ExternalToolTextResultForLlmContentText, self.external_tool_text_result_for_llm_content_text) + result["FeatureFlagAvailability"] = to_enum(_FeatureFlagAvailability, self.feature_flag_availability) + result["FeatureFlagMetadata"] = to_class(_FeatureFlagMetadata, self.feature_flag_metadata) + result["FeatureFlagsMetadataResult"] = to_class(_FeatureFlagsMetadataResult, self.feature_flags_metadata_result) + result["FeatureFlagsResolveRequest"] = to_class(_FeatureFlagsResolveRequest, self.feature_flags_resolve_request) + result["FeatureFlagsResolveResult"] = from_dict(from_bool, self.feature_flags_resolve_result) result["FilterMapping"] = from_union([lambda x: from_dict(lambda x: to_enum(ContentFilterMode, x), x), lambda x: to_enum(ContentFilterMode, x)], self.filter_mapping) result["FleetStartRequest"] = to_class(FleetStartRequest, self.fleet_start_request) result["FleetStartResult"] = to_class(FleetStartResult, self.fleet_start_result) @@ -53766,7 +55332,7 @@ def to_dict(self) -> dict: result["GitHubOwnersCancelResult"] = to_class(_GitHubOwnersCancelResult, self.git_hub_owners_cancel_result) result["GitHubOwnersListRequest"] = to_class(_GitHubOwnersListRequest, self.git_hub_owners_list_request) result["GitHubOwnersListResult"] = to_class(_GitHubOwnersListResult, self.git_hub_owners_list_result) - result["GitHubOwnersRequestIdResult"] = to_class(GitHubOwnersRequestIDResult, self.git_hub_owners_request_id_result) + result["GitHubOwnersRequestIdResult"] = to_class(_GitHubOwnersRequestIDResult, self.git_hub_owners_request_id_result) result["GitHubRepositoryAtPathRequest"] = to_class(_GitHubRepositoryAtPathRequest, self.git_hub_repository_at_path_request) result["GitHubRepositoryAtPathResult"] = to_class(_GitHubRepositoryAtPathResult, self.git_hub_repository_at_path_result) result["GitHubRepositoryIdentity"] = to_class(GitHubRepositoryIdentity, self.git_hub_repository_identity) @@ -53852,9 +55418,11 @@ def to_dict(self) -> dict: result["InstructionDiscoveryPathKind"] = to_enum(DebugCollectLogsEntryKind, self.instruction_discovery_path_kind) result["InstructionDiscoveryPathList"] = to_class(InstructionDiscoveryPathList, self.instruction_discovery_path_list) result["InstructionDiscoveryPathLocation"] = to_enum(InstructionLocation, self.instruction_discovery_path_location) + result["InstructionsDiscoverRepoSourcesRequest"] = to_class(_InstructionsDiscoverRepoSourcesRequest, self.instructions_discover_repo_sources_request) result["InstructionsDiscoverRequest"] = to_class(InstructionsDiscoverRequest, self.instructions_discover_request) result["InstructionsGetDiscoveryPathsRequest"] = to_class(InstructionsGetDiscoveryPathsRequest, self.instructions_get_discovery_paths_request) result["InstructionsGetSourcesResult"] = to_class(InstructionsGetSourcesResult, self.instructions_get_sources_result) + result["InstructionsInitPromptResult"] = to_class(_InstructionsInitPromptResult, self.instructions_init_prompt_result) result["InstructionSource"] = to_class(InstructionSource, self.instruction_source) result["InstructionSourceLocation"] = to_enum(InstructionLocation, self.instruction_source_location) result["InstructionSourceType"] = to_enum(InstructionSourceType, self.instruction_source_type) @@ -53949,7 +55517,7 @@ def to_dict(self) -> dict: result["McpConfiguredServer"] = to_class(MCPConfiguredServer, self.mcp_configured_server) result["McpConfiguredServerList"] = to_class(MCPConfiguredServerList, self.mcp_configured_server_list) result["McpConfiguredServerState"] = to_class(MCPConfiguredServerState, self.mcp_configured_server_state) - result["McpConfigureGitHubRequest"] = to_class(MCPConfigureGitHubRequest, self.mcp_configure_git_hub_request) + result["McpConfigureGitHubRequest"] = to_class(_MCPConfigureGitHubRequest, self.mcp_configure_git_hub_request) result["McpConfigureGitHubResult"] = to_class(MCPConfigureGitHubResult, self.mcp_configure_git_hub_result) result["McpDiagnosticDetails"] = to_class(MCPDiagnosticDetails, self.mcp_diagnostic_details) result["McpDiagnosticDirection"] = to_enum(MCPDiagnosticDirection, self.mcp_diagnostic_direction) @@ -53987,6 +55555,7 @@ def to_dict(self) -> dict: result["McpInstallPlan"] = to_class(MCPInstallPlan, self.mcp_install_plan) result["McpIsServerRunningRequest"] = to_class(MCPIsServerRunningRequest, self.mcp_is_server_running_request) result["McpIsServerRunningResult"] = to_class(MCPIsServerRunningResult, self.mcp_is_server_running_result) + result["McpListBuiltinServerNamesResult"] = to_class(_MCPListBuiltinServerNamesResult, self.mcp_list_builtin_server_names_result) result["McpListToolsRequest"] = to_class(MCPListToolsRequest, self.mcp_list_tools_request) result["McpListToolsResult"] = to_class(MCPListToolsResult, self.mcp_list_tools_result) result["McpOauthAuthenticationStateChangedRequest"] = to_class(MCPOauthAuthenticationStateChangedRequest, self.mcp_oauth_authentication_state_changed_request) @@ -54053,14 +55622,14 @@ def to_dict(self) -> dict: result["McpPromptsGetResult"] = to_class(MCPPromptsGetResult, self.mcp_prompts_get_result) result["McpPromptsListRequest"] = to_class(MCPPromptsListRequest, self.mcp_prompts_list_request) result["McpPromptsListResult"] = to_class(MCPPromptsListResult, self.mcp_prompts_list_result) - result["McpRegisterExternalClientRequest"] = to_class(MCPRegisterExternalClientRequest, self.mcp_register_external_client_request) - result["McpRegistryCancelRequest"] = to_class(MCPRegistryCancelRequest, self.mcp_registry_cancel_request) - result["McpRegistryCancelResult"] = to_class(MCPRegistryCancelResult, self.mcp_registry_cancel_result) - result["McpRegistryRequestIdResult"] = to_class(MCPRegistryRequestIDResult, self.mcp_registry_request_id_result) - result["McpRegistrySearchRequest"] = to_class(MCPRegistrySearchRequest, self.mcp_registry_search_request) - result["McpRegistrySearchResult"] = to_class(MCPRegistrySearchResult, self.mcp_registry_search_result) - result["McpReloadConfig"] = to_class(MCPReloadConfig, self.mcp_reload_config) - result["McpReloadWithConfigRequest"] = to_class(MCPReloadWithConfigRequest, self.mcp_reload_with_config_request) + result["McpRegisterExternalClientRequest"] = to_class(_MCPRegisterExternalClientRequest, self.mcp_register_external_client_request) + result["McpRegistryCancelRequest"] = to_class(_MCPRegistryCancelRequest, self.mcp_registry_cancel_request) + result["McpRegistryCancelResult"] = to_class(_MCPRegistryCancelResult, self.mcp_registry_cancel_result) + result["McpRegistryRequestIdResult"] = to_class(_MCPRegistryRequestIDResult, self.mcp_registry_request_id_result) + result["McpRegistrySearchRequest"] = to_class(_MCPRegistrySearchRequest, self.mcp_registry_search_request) + result["McpRegistrySearchResult"] = to_class(_MCPRegistrySearchResult, self.mcp_registry_search_result) + result["McpReloadConfig"] = to_class(_MCPReloadConfig, self.mcp_reload_config) + result["McpReloadWithConfigRequest"] = to_class(_MCPReloadWithConfigRequest, self.mcp_reload_with_config_request) result["McpRemoveGitHubResult"] = to_class(MCPRemoveGitHubResult, self.mcp_remove_git_hub_result) result["McpResource"] = to_class(MCPResource, self.mcp_resource) result["McpResourceAnnotations"] = to_class(MCPResourceAnnotations, self.mcp_resource_annotations) @@ -54093,8 +55662,8 @@ def to_dict(self) -> dict: result["McpServerConfigHttp"] = to_class(MCPServerConfigHTTP, self.mcp_server_config_http) result["McpServerConfigHttpOauthGrantType"] = to_enum(MCPGrantType, self.mcp_server_config_http_oauth_grant_type) result["McpServerConfigHttpType"] = to_enum(MCPServerConfigHTTPType, self.mcp_server_config_http_type) - result["McpServerConfigMemory"] = to_class(MCPServerConfigMemory, self.mcp_server_config_memory) - result["McpServerConfigMemoryType"] = to_enum(MCPServerConfigMemoryType, self.mcp_server_config_memory_type) + result["McpServerConfigMemory"] = to_class(_MCPServerConfigMemory, self.mcp_server_config_memory) + result["McpServerConfigMemoryType"] = to_enum(_MCPServerConfigMemoryType, self.mcp_server_config_memory_type) result["McpServerConfigStdio"] = to_class(MCPServerConfigStdio, self.mcp_server_config_stdio) result["McpServerConfigStdioType"] = to_enum(MCPServerConfigStdioType, self.mcp_server_config_stdio_type) result["McpServerFailureInfo"] = to_class(MCPServerFailureInfo, self.mcp_server_failure_info) @@ -54104,8 +55673,8 @@ def to_dict(self) -> dict: result["McpSetEnvValueModeDetails"] = to_enum(MCPSetEnvValueModeDetails, self.mcp_set_env_value_mode_details) result["McpSetEnvValueModeParams"] = to_class(MCPSetEnvValueModeParams, self.mcp_set_env_value_mode_params) result["McpSetEnvValueModeResult"] = to_class(MCPSetEnvValueModeResult, self.mcp_set_env_value_mode_result) - result["McpShouldExcludeGitHubToolsRequest"] = to_class(MCPShouldExcludeGitHubToolsRequest, self.mcp_should_exclude_git_hub_tools_request) - result["McpShouldExcludeGitHubToolsResult"] = to_class(MCPShouldExcludeGitHubToolsResult, self.mcp_should_exclude_git_hub_tools_result) + result["McpShouldExcludeGitHubToolsRequest"] = to_class(_MCPShouldExcludeGitHubToolsRequest, self.mcp_should_exclude_git_hub_tools_request) + result["McpShouldExcludeGitHubToolsResult"] = to_class(_MCPShouldExcludeGitHubToolsResult, self.mcp_should_exclude_git_hub_tools_result) result["McpSourceFile"] = to_class(MCPSourceFile, self.mcp_source_file) result["McpSourcePlugin"] = to_class(MCPSourcePlugin, self.mcp_source_plugin) result["McpSourceRef"] = to_class(MCPSourceRef, self.mcp_source_ref) @@ -54117,7 +55686,7 @@ def to_dict(self) -> dict: result["McpToolUi"] = to_class(MCPToolUI, self.mcp_tool_ui) result["McpToolUiVisibility"] = to_enum(MCPToolUIVisibility, self.mcp_tool_ui_visibility) result["McpUninstallPlan"] = to_class(MCPUninstallPlan, self.mcp_uninstall_plan) - result["McpUnregisterExternalClientRequest"] = to_class(MCPUnregisterExternalClientRequest, self.mcp_unregister_external_client_request) + result["McpUnregisterExternalClientRequest"] = to_class(_MCPUnregisterExternalClientRequest, self.mcp_unregister_external_client_request) result["MemoryConfiguration"] = to_class(MemoryConfiguration, self.memory_configuration) result["MetadataContextAttributionResult"] = to_class(MetadataContextAttributionResult, self.metadata_context_attribution_result) result["MetadataContextHeaviestMessagesRequest"] = to_class(MetadataContextHeaviestMessagesRequest, self.metadata_context_heaviest_messages_request) @@ -54153,6 +55722,8 @@ def to_dict(self) -> dict: result["ModelCapabilitiesSupports"] = to_class(ModelCapabilitiesSupports, self.model_capabilities_supports) result["ModelClearStartupSeedRequest"] = to_class(_ModelClearStartupSeedRequest, self.model_clear_startup_seed_request) result["ModelClearStartupSeedResult"] = to_class(_ModelClearStartupSeedResult, self.model_clear_startup_seed_result) + result["ModelGetReasoningSummariesRequest"] = to_class(ModelGetReasoningSummariesRequest, self.model_get_reasoning_summaries_request) + result["ModelGetReasoningSummariesResult"] = to_class(ModelGetReasoningSummariesResult, self.model_get_reasoning_summaries_result) result["ModelList"] = to_class(ModelList, self.model_list) result["ModelListRequest"] = self.model_list_request result["ModelMessage"] = to_class(ModelMessage, self.model_message) @@ -54468,6 +56039,10 @@ def to_dict(self) -> dict: result["RemoteSessionMetadataValue"] = to_class(RemoteSessionMetadataValue, self.remote_session_metadata_value) result["RemoteSessionMode"] = to_enum(RemoteSessionMode, self.remote_session_mode) result["RemoteSessionRepository"] = to_class(RemoteSessionRepository, self.remote_session_repository) + result["RepoSettingsReadRawRequest"] = to_class(_RepoSettingsReadRawRequest, self.repo_settings_read_raw_request) + result["RepoSettingsReadRawResult"] = to_class(_RepoSettingsReadRawResult, self.repo_settings_read_raw_result) + result["RepoSettingsWriteAllRequest"] = to_class(_RepoSettingsWriteAllRequest, self.repo_settings_write_all_request) + result["RepoSettingsWriteKeyRequest"] = to_class(_RepoSettingsWriteKeyRequest, self.repo_settings_write_key_request) result["ResponseFormat"] = to_class(ResponseFormat, self.response_format) result["SandboxConfig"] = to_class(SandboxConfig, self.sandbox_config) result["SandboxConfigAuth"] = to_class(SandboxConfigAuth, self.sandbox_config_auth) @@ -54724,6 +56299,9 @@ def to_dict(self) -> dict: result["SessionWorkingDirectoryContextWithClient"] = to_class(SessionWorkingDirectoryContextWithClient, self.session_working_directory_context_with_client) result["SettableAuthInfo"] = (self.settable_auth_info).to_dict() result["SettableTokenAuthInfo"] = to_class(SettableTokenAuthInfo, self.settable_token_auth_info) + result["SettingsEditOperation"] = to_enum(_SettingsEditOperation, self.settings_edit_operation) + result["SettingsEditResult"] = to_class(_SettingsEditResult, self.settings_edit_result) + result["SettingsEditStatus"] = to_enum(_SettingsEditStatus, self.settings_edit_status) result["ShellCancelUserRequestedRequest"] = to_class(ShellCancelUserRequestedRequest, self.shell_cancel_user_requested_request) result["ShellCredentials"] = to_class(ShellCredentials, self.shell_credentials) result["ShellExecRequest"] = to_class(ShellExecRequest, self.shell_exec_request) @@ -54910,8 +56488,28 @@ def to_dict(self) -> dict: result["UserAuthInfo"] = to_class(UserAuthInfo, self.user_auth_info) result["UserRequestedShellCommandResult"] = to_class(UserRequestedShellCommandResult, self.user_requested_shell_command_result) result["UserSettingMetadata"] = to_class(UserSettingMetadata, self.user_setting_metadata) + result["UserSettingsApplyTopKeyRequest"] = to_class(UserSettingsApplyTopKeyRequest, self.user_settings_apply_top_key_request) + result["UserSettingsApplyTopKeyResult"] = to_class(UserSettingsApplyTopKeyResult, self.user_settings_apply_top_key_result) + result["UserSettingsEditRequest"] = to_class(_UserSettingsEditRequest, self.user_settings_edit_request) + result["UserSettingsGetPathsRequest"] = to_class(UserSettingsGetPathsRequest, self.user_settings_get_paths_request) + result["UserSettingsGetPathsResult"] = to_class(UserSettingsGetPathsResult, self.user_settings_get_paths_result) result["UserSettingsGetResult"] = to_class(UserSettingsGetResult, self.user_settings_get_result) + result["UserSettingsGovernanceKeysResult"] = to_class(UserSettingsGovernanceKeysResult, self.user_settings_governance_keys_result) + result["UserSettingsLoadForEditResult"] = to_class(UserSettingsLoadForEditResult, self.user_settings_load_for_edit_result) + result["UserSettingsNormalizeRequest"] = to_class(UserSettingsNormalizeRequest, self.user_settings_normalize_request) + result["UserSettingsNormalizeResult"] = to_class(UserSettingsNormalizeResult, self.user_settings_normalize_result) + result["UserSettingsProblem"] = to_class(UserSettingsProblem, self.user_settings_problem) + result["UserSettingsProblemLocation"] = to_class(UserSettingsProblemLocation, self.user_settings_problem_location) + result["UserSettingsProblemSource"] = to_class(UserSettingsProblemSource, self.user_settings_problem_source) + result["UserSettingsProblemsRequest"] = to_class(UserSettingsProblemsRequest, self.user_settings_problems_request) + result["UserSettingsProblemsResult"] = to_class(UserSettingsProblemsResult, self.user_settings_problems_result) result["UserSettingsSetRequest"] = to_class(UserSettingsSetRequest, self.user_settings_set_request) + result["UserSettingsUpdateRequest"] = to_class(_UserSettingsUpdateRequest, self.user_settings_update_request) + result["UserSettingsUpdateResult"] = to_class(_UserSettingsUpdateResult, self.user_settings_update_result) + result["UserSettingsValidateRequest"] = to_class(UserSettingsValidateRequest, self.user_settings_validate_request) + result["UserSettingsValidateResult"] = to_class(UserSettingsValidateResult, self.user_settings_validate_result) + result["UserSettingsValidationIssue"] = to_class(UserSettingsValidationIssue, self.user_settings_validation_issue) + result["UserSettingsWriteAllRequest"] = to_class(UserSettingsWriteAllRequest, self.user_settings_write_all_request) result["VisibilityGetResult"] = to_class(VisibilityGetResult, self.visibility_get_result) result["VisibilitySetRequest"] = to_class(VisibilitySetRequest, self.visibility_set_request) result["VisibilitySetResult"] = to_class(VisibilitySetResult, self.visibility_set_result) @@ -55426,6 +57024,7 @@ def _load_TaskInfo(obj: Any) -> "TaskInfo": EventsCursorStatus = CursorStatus ExternalToolResult = ExternalToolTextResultForLlm ExternalToolTextResultForLlmContentResourceLinkIconTheme = Theme +FeatureFlagsResolveResult = dict FilterMapping = dict HistoryCompactRequest = Any InstructionDiscoveryPathKind = DebugCollectLogsEntryKind @@ -55810,6 +57409,22 @@ async def disable(self, params: DiscoveredExtensionsDisableRequest, *, timeout: await self._client.request("extensions.disable", params_dict, **_timeout_kwargs(timeout)) +# Experimental: this API group is experimental and may change or be removed. +class ServerInstructionsApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def discover(self, params: InstructionsDiscoverRequest, *, timeout: float | None = None) -> ServerInstructionSourceList: + "Discovers instruction sources across user, repository, and plugin sources.\n\nArgs:\n params: Optional project paths to include in instruction discovery.\n\nReturns:\n Instruction sources discovered across user, repository, and plugin sources." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return ServerInstructionSourceList.from_dict(await self._client.request("instructions.discover", params_dict, **_timeout_kwargs(timeout))) + + async def get_discovery_paths(self, params: InstructionsGetDiscoveryPathsRequest, *, timeout: float | None = None) -> InstructionDiscoveryPathList: + "Returns the canonical files and directories where a client may create custom instructions that the runtime will recognize, including ones that do not exist yet. Repository targets become active once created.\n\nArgs:\n params: Optional project paths to include when enumerating instruction discovery targets.\n\nReturns:\n Canonical files and directories where custom instructions can be created so the runtime will recognize them." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return InstructionDiscoveryPathList.from_dict(await self._client.request("instructions.getDiscoveryPaths", params_dict, **_timeout_kwargs(timeout))) + + # Experimental: this API group is experimental and may change or be removed. class ServerSkillsInstallationsApi: def __init__(self, client: "JsonRpcClient"): @@ -56009,22 +57624,6 @@ async def get_discovery_paths(self, params: AgentsGetDiscoveryPathsRequest, *, t return AgentDiscoveryPathList.from_dict(await self._client.request("agents.getDiscoveryPaths", params_dict, **_timeout_kwargs(timeout))) -# Experimental: this API group is experimental and may change or be removed. -class ServerInstructionsApi: - def __init__(self, client: "JsonRpcClient"): - self._client = client - - async def discover(self, params: InstructionsDiscoverRequest, *, timeout: float | None = None) -> ServerInstructionSourceList: - "Discovers instruction sources across user, repository, and plugin sources.\n\nArgs:\n params: Optional project paths to include in instruction discovery.\n\nReturns:\n Instruction sources discovered across user, repository, and plugin sources." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return ServerInstructionSourceList.from_dict(await self._client.request("instructions.discover", params_dict, **_timeout_kwargs(timeout))) - - async def get_discovery_paths(self, params: InstructionsGetDiscoveryPathsRequest, *, timeout: float | None = None) -> InstructionDiscoveryPathList: - "Returns the canonical files and directories where a client may create custom instructions that the runtime will recognize, including ones that do not exist yet. Repository targets become active once created.\n\nArgs:\n params: Optional project paths to include when enumerating instruction discovery targets.\n\nReturns:\n Canonical files and directories where custom instructions can be created so the runtime will recognize them." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return InstructionDiscoveryPathList.from_dict(await self._client.request("instructions.getDiscoveryPaths", params_dict, **_timeout_kwargs(timeout))) - - # Experimental: this API group is experimental and may change or be removed. class ServerCommandsApi: def __init__(self, client: "JsonRpcClient"): @@ -56321,11 +57920,11 @@ def __init__(self, client: "JsonRpcClient"): self.secrets = ServerSecretsApi(client) self.mcp = ServerMcpApi(client) self.extensions = ServerExtensionsApi(client) + self.instructions = ServerInstructionsApi(client) self.skills = ServerSkillsApi(client) self.catalog = ServerCatalogApi(client) self.plugins = ServerPluginsApi(client) self.agents = ServerAgentsApi(client) - self.instructions = ServerInstructionsApi(client) self.commands = ServerCommandsApi(client) self.user = ServerUserApi(client) self.managed_settings = ServerManagedSettingsApi(client) @@ -56375,24 +57974,49 @@ async def _ready(self, params: HostReadyRequest, *, timeout: float | None = None return HostEmptyResult.from_dict(await self._client.request("host.ready", params_dict, **_timeout_kwargs(timeout))) +# Experimental: this API group is experimental and may change or be removed. +class _InternalServerAccountApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def _describe_auth_info(self, params: _AccountDescribeAuthInfoRequest, *, timeout: float | None = None) -> _AccountDescribeAuthInfoResult: + "Renders the sign-in banner and the one-line account description the runtime uses for an authentication identity. The runtime words these in several places for its own callers, so a host that announces a sign-in or an account switch should render them from here rather than composing its own, which would let the two spellings drift apart.\n\nArgs:\n params: The authentication identity whose shared wording should be rendered.\n\nReturns:\n The wording the runtime uses for an authentication identity.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _AccountDescribeAuthInfoResult.from_dict(await self._client.request("account.describeAuthInfo", params_dict, **_timeout_kwargs(timeout))) + + async def _get_gist_support(self, params: _AccountGetGistSupportRequest, *, timeout: float | None = None) -> _AccountGetGistSupportResult: + "Reports whether the supplied identity can create gists. Gists are unavailable on GitHub Enterprise Cloud with data residency, and to Enterprise Managed Users on github.com, so a host that offers gist actions should hide or disable them when this reports no support.\n\nArgs:\n params: The authentication identity whose gist support should be reported.\n\nReturns:\n Whether the identity can create gists, and why not when it cannot.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _AccountGetGistSupportResult.from_dict(await self._client.request("account.getGistSupport", params_dict, **_timeout_kwargs(timeout))) + + async def _get_web_url(self, params: _AccountGetWebURLRequest, *, timeout: float | None = None) -> _AccountGetWebURLResult: + "Resolves a path on the identity's GitHub host into an absolute URL, so a host can link to settings or documentation on the enterprise instance the user is signed in to rather than to github.com. Falls back to the public host when no identity is supplied.\n\nArgs:\n params: A path to resolve against the GitHub host an identity is signed in to.\n\nReturns:\n An absolute URL on the identity's GitHub host.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _AccountGetWebURLResult.from_dict(await self._client.request("account.getWebUrl", params_dict, **_timeout_kwargs(timeout))) + + async def _get_token_env_var(self, *, timeout: float | None = None) -> _AccountGetTokenEnvVarResult: + "Names the environment variable supplying a classic personal access token, if one is set. A classic token cannot be upgraded in place, so a host that finds one should tell the user which variable to unset rather than starting an interactive sign-in that the variable would override.\n\nReturns:\n The environment variable supplying a classic personal access token, when one is set.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + return _AccountGetTokenEnvVarResult.from_dict(await self._client.request("account.getTokenEnvVar", {}, **_timeout_kwargs(timeout))) + + # Experimental: this API group is experimental and may change or be removed. class _InternalServerMcpRegistryApi: def __init__(self, client: "JsonRpcClient"): self._client = client - async def _allocate_request_id(self, *, timeout: float | None = None) -> MCPRegistryRequestIDResult: + async def _allocate_request_id(self, *, timeout: float | None = None) -> _MCPRegistryRequestIDResult: "Allocates an ID for one cancellable MCP registry search. The ID exists before the search starts, so callers can cancel before it starts. The networking stack supplies the cancellation namespace. The runtime retains at most 1,024 unused IDs. At capacity, another allocation can reclaim an unused ID. Active searches retain their IDs until they finish.\n\nReturns:\n Request id naming a cancellable registry search.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." - return MCPRegistryRequestIDResult.from_dict(await self._client.request("mcp.registry.allocateRequestId", {}, **_timeout_kwargs(timeout))) + return _MCPRegistryRequestIDResult.from_dict(await self._client.request("mcp.registry.allocateRequestId", {}, **_timeout_kwargs(timeout))) - async def _search(self, params: MCPRegistrySearchRequest, *, timeout: float | None = None) -> MCPRegistrySearchResult: + async def _search(self, params: _MCPRegistrySearchRequest, *, timeout: float | None = None) -> _MCPRegistrySearchResult: "Searches the MCP registry the supplied credential may read, resolving the registry endpoint from policy first. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. The runtime follows registry pages, keeps the newest entry per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub stars. Each server object is carried opaquely.\n\nArgs:\n params: Registry search terms, the credential to search under, and the request id that makes the search cancellable.\n\nReturns:\n Servers selected from the registry response.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return MCPRegistrySearchResult.from_dict(await self._client.request("mcp.registry.search", params_dict, **_timeout_kwargs(timeout))) + return _MCPRegistrySearchResult.from_dict(await self._client.request("mcp.registry.search", params_dict, **_timeout_kwargs(timeout))) - async def _cancel(self, params: MCPRegistryCancelRequest, *, timeout: float | None = None) -> MCPRegistryCancelResult: + async def _cancel(self, params: _MCPRegistryCancelRequest, *, timeout: float | None = None) -> _MCPRegistryCancelResult: "Abandons the registry search that uses the given request ID. It acts only on IDs from `mcp.registry.allocateRequestId`, so it never cancels another component's request. Answers `canceled: true` when it stops a running search. Answers `canceled: false` for unknown or reclaimed IDs, completed or canceled searches, and unused reservations. It releases an unused reservation, so a later search with that ID is refused.\n\nArgs:\n params: Registry search to abandon.\n\nReturns:\n Whether the cancel reached a live search.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return MCPRegistryCancelResult.from_dict(await self._client.request("mcp.registry.cancel", params_dict, **_timeout_kwargs(timeout))) + return _MCPRegistryCancelResult.from_dict(await self._client.request("mcp.registry.cancel", params_dict, **_timeout_kwargs(timeout))) # Experimental: this API group is experimental and may change or be removed. @@ -56401,10 +58025,33 @@ def __init__(self, client: "JsonRpcClient"): self._client = client self.registry = _InternalServerMcpRegistryApi(client) - async def _should_exclude_git_hub_tools(self, params: MCPShouldExcludeGitHubToolsRequest, *, timeout: float | None = None) -> MCPShouldExcludeGitHubToolsResult: + async def _list_builtin_server_names(self, *, timeout: float | None = None) -> _MCPListBuiltinServerNamesResult: + "Lists the MCP servers the runtime supplies itself, so a host that disables the built-ins wholesale suppresses exactly the set the runtime would otherwise add. The names are fixed for a build and depend on no configuration, session or account.\n\nReturns:\n Names of the MCP servers the runtime supplies itself.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + return _MCPListBuiltinServerNamesResult.from_dict(await self._client.request("mcp.listBuiltinServerNames", {}, **_timeout_kwargs(timeout))) + + async def _should_exclude_git_hub_tools(self, params: _MCPShouldExcludeGitHubToolsRequest, *, timeout: float | None = None) -> _MCPShouldExcludeGitHubToolsResult: "Reports whether the gh-replaceable GitHub MCP tools may be clipped for a session, which a host feeds back as the `excludeGhReplaceableTools` build option. The tools are redundant only when the session can reach a shell *and* the host has the `gh` that would replace them, so both halves are decided here. The shell half runs the platform shell tool through the runtime's own tool-filter matcher, so entry forms like `builtin:bash` and `builtin:*` behave exactly as they do when a session builds its tool catalog. The host half probes for `gh`, and is skipped entirely when the filters already rule the shell out. Host presence alone is not enough: a session restricted to, say, `view` would otherwise lose the built-in issue-read fallback while having no shell to replace it with. The answer describes the host the runtime runs on, so it is never forwarded to a remote engine.\n\nArgs:\n params: The session tool filters that decide whether the session still has a shell to run `gh` with.\n\nReturns:\n Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by the request.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return MCPShouldExcludeGitHubToolsResult.from_dict(await self._client.request("mcp.shouldExcludeGitHubTools", params_dict, **_timeout_kwargs(timeout))) + return _MCPShouldExcludeGitHubToolsResult.from_dict(await self._client.request("mcp.shouldExcludeGitHubTools", params_dict, **_timeout_kwargs(timeout))) + + +# Experimental: this API group is experimental and may change or be removed. +class _InternalServerInstructionsApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def _get_init_prompt(self, *, timeout: float | None = None) -> _InstructionsInitPromptResult: + "Returns the prompt the `init` command runs to author repository instructions. A host offering its own initialize action sends this text so the instructions it produces match the ones the CLI produces. The text is fixed for a build and depends on no configuration, session or repository.\n\nReturns:\n The prompt the init command runs.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + return _InstructionsInitPromptResult.from_dict(await self._client.request("instructions.getInitPrompt", {}, **_timeout_kwargs(timeout))) + + async def _discover_repo_sources(self, params: _InstructionsDiscoverRepoSourcesRequest, *, timeout: float | None = None) -> ServerInstructionSourceList: + "Discovers the instruction sources for one caller-named location and returns them in the order the runtime applies them. `discover` answers for a set of project paths and derives the rest of its scope itself; this one instead takes every argument from the caller — the extra directories to scan and whether to descend into nested instruction files — and honors them as given. It also includes instruction directories from trusted repository settings, matching native repository discovery. Use it when the caller knows its own scope and no session exists to derive that scope from, such as a host reporting how many instruction files a directory contributes before any session starts. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on.\n\nArgs:\n params: Explicit discovery arguments for one location, supplied by the caller rather than derived from a session.\n\nReturns:\n Instruction sources discovered across user, repository, and plugin sources.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return ServerInstructionSourceList.from_dict(await self._client.request("instructions.discoverRepoSources", params_dict, **_timeout_kwargs(timeout))) + + async def _clear_cache(self, *, timeout: float | None = None) -> None: + "Drops the runtime's in-memory cache of discovered custom instructions so the next discovery reads them from disk again. A host calls this after it changes instruction files, or after it trusts a folder whose instructions an earlier discovery skipped, so that a session started afterwards sees the current files instead of a cached earlier answer. The call performs no I/O of its own and removes nothing from disk; it only invalidates, so the cost lands on the next discovery. Returns once the cache is clear, which is what lets a caller order a session start after it. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + await self._client.request("instructions.clearCache", {}, **_timeout_kwargs(timeout)) # Experimental: this API group is experimental and may change or be removed. @@ -56457,6 +58104,110 @@ async def _write_key(self, params: _GlobalStateWriteKeyRequest, *, timeout: floa await self._client.request("globalState.writeKey", params_dict, **_timeout_kwargs(timeout)) +# Experimental: this API group is experimental and may change or be removed. +class _InternalServerUserSettingsApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def _get_paths(self, params: UserSettingsGetPathsRequest, *, timeout: float | None = None) -> UserSettingsGetPathsResult: + "Resolves the on-disk locations of the settings files this runtime reads, so a consumer can show or open them. The user path is the same file `user.settings.get`, `user.settings.load`, and `user.settings.set` operate on. Supply `repoRoot` to also resolve that repository's checked-in and local settings paths. A path is reported whether or not the file exists.\n\nArgs:\n params: Selects which settings file paths to resolve.\n\nReturns:\n On-disk locations of the settings files this runtime reads. A path is reported whether or not the file exists.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return UserSettingsGetPathsResult.from_dict(await self._client.request("user.settings.getPaths", params_dict, **_timeout_kwargs(timeout))) + + async def _list_governance_keys(self, *, timeout: float | None = None) -> UserSettingsGovernanceKeysResult: + "Lists the top-level user-setting keys by who is allowed to govern them: `repo` keys a repository may override through `.github/copilot/settings.json`, `claudeRepo` keys a repository may override through a Claude-compatible config, and `managed` keys an enterprise policy may fix. The lists are static for a given runtime build and fail closed: a key absent from a list cannot be governed that way.\n\nReturns:\n Top-level user-setting keys grouped by who may govern them.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + return UserSettingsGovernanceKeysResult.from_dict(await self._client.request("user.settings.listGovernanceKeys", {}, **_timeout_kwargs(timeout))) + + async def _edit(self, params: _UserSettingsEditRequest, *, timeout: float | None = None) -> _SettingsEditResult: + "Atomically edits one canonical user setting inside its settings-file lock. Reads, canonicalizes touched aliases, applies the edit, validates the resulting top-level setting and writes before releasing the lock. An explicit autoUpdatesChannel set completes the staff migration in the same transaction. Only a malformed existing file returns `invalid`; refused keys, invalid values and I/O errors reject the call.\n\nArgs:\n params: One atomic edit of a canonical setting in settings.json.\n\nReturns:\n Outcome of an atomic user or repository settings edit.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = params.to_dict() + return _SettingsEditResult.from_dict(await self._client.request("user.settings.edit", params_dict, **_timeout_kwargs(timeout))) + + async def _normalize(self, params: UserSettingsNormalizeRequest, *, timeout: float | None = None) -> UserSettingsNormalizeResult: + "Rewrites legacy and snake_case setting names in a settings object to their canonical spelling. A caller editing settings.json must normalize before writing: a legacy key left in place survives the write, is re-normalized on the next load, and silently shadows the canonical value the write just stored.\n\nArgs:\n params: Settings object whose key names should be canonicalized.\n\nReturns:\n Settings object with canonical key names.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return UserSettingsNormalizeResult.from_dict(await self._client.request("user.settings.normalize", params_dict, **_timeout_kwargs(timeout))) + + async def _diagnose_problems(self, params: UserSettingsProblemsRequest, *, timeout: float | None = None) -> UserSettingsProblemsResult: + "Diagnoses a set of already-loaded settings layers, reporting each key that will not take effect and why. Settings load tolerantly so that one bad key does not stop a session from starting; this method surfaces what was dropped so a caller can report it instead of silently ignoring the user's intent. Takes the layers as given rather than reading them, so a caller can diagnose exactly the content it is showing, including unsaved edits. Never echoes a setting's value, because a value may be a token or another secret. Marked internal because it exists to carry a CLI call site off the native addon, not to serve a consumer-facing need; it becomes public once an SDK consumer needs to inspect settings health itself.\n\nArgs:\n params: The settings layers to diagnose.\n\nReturns:\n The settings that will not take effect across the given layers.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return UserSettingsProblemsResult.from_dict(await self._client.request("user.settings.diagnoseProblems", params_dict, **_timeout_kwargs(timeout))) + + async def _apply_top_key(self, params: UserSettingsApplyTopKeyRequest, *, timeout: float | None = None) -> UserSettingsApplyTopKeyResult: + "Validates one top-level setting subtree and writes just that key to settings.json as a single step. Doing both here closes the race a caller cannot close itself: between a separate preflight read and the write, the file may change. Rewriting only the touched key keeps legacy siblings out of settings.json. Answers a status rather than failing, so a validation problem and a write problem stay distinguishable.\n\nArgs:\n params: A single top-level setting subtree to validate and write.\n\nReturns:\n Outcome of validating and writing one top-level setting subtree.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = params.to_dict() + return UserSettingsApplyTopKeyResult.from_dict(await self._client.request("user.settings.applyTopKey", params_dict, **_timeout_kwargs(timeout))) + + async def _write_all(self, params: UserSettingsWriteAllRequest, *, timeout: float | None = None) -> None: + "Replaces the user settings file's entire content in one write. A key absent from `settings` is removed, which is what distinguishes this from `user.settings.set`: that one merges, so it can never clear a key the caller has dropped. For a caller saving the result of a raw edit, a merge would silently resurrect every key the user deleted. Records the same one-time mutation marks a per-key write records, so a setting the user has now chosen explicitly stops being migrated for them.\n\nArgs:\n params: The whole content to store in the user settings file.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + await self._client.request("user.settings.writeAll", params_dict, **_timeout_kwargs(timeout)) + + async def _update(self, params: _UserSettingsUpdateRequest, *, timeout: float | None = None) -> _UserSettingsUpdateResult: + "Merges a partial object into one top-level user setting, re-reading the stored value inside this runtime process's settings.json write lock so that concurrent writers in this process to different sub-fields of the same key do not clobber each other. Unlike `user.settings.set`, which replaces a key's whole value with what the caller last read, this keeps sub-fields the caller did not name when both the stored value and supplied value are objects; otherwise the supplied value replaces the stored value. Use it whenever two independent surfaces own different sub-fields of one setting. Returns the key's stored value after the write, in `value`.\n\nArgs:\n params: Names the user setting to merge into, and the partial object to merge.\n\nReturns:\n The stored value of the user setting after the merge.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _UserSettingsUpdateResult.from_dict(await self._client.request("user.settings.update", params_dict, **_timeout_kwargs(timeout))) + + async def _load_for_edit(self, *, timeout: float | None = None) -> UserSettingsLoadForEditResult: + "Reads settings.json as stored for a caller that is about to edit it. Unlike `user.settings.get`, this returns file values rather than per-key metadata and defaults. Reports `missing` for an absent file and `invalid` when the existing file will not parse. Retired config.json and extensionless files are not read.\n\nReturns:\n Contents of settings.json as stored, for a caller about to rewrite it.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + return UserSettingsLoadForEditResult.from_dict(await self._client.request("user.settings.loadForEdit", {}, **_timeout_kwargs(timeout))) + + async def _validate(self, params: UserSettingsValidateRequest, *, timeout: float | None = None) -> UserSettingsValidateResult: + "Validates one top-level setting subtree without writing it, reporting each problem with the path it applies to. Scoped to a single top-level key on purpose: validating the whole file would reject an edit whenever an unrelated pre-existing field is malformed, locking the user out of the very tool that could fix it.\n\nArgs:\n params: A single top-level setting subtree to validate.\n\nReturns:\n Outcome of validating one top-level setting subtree.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return UserSettingsValidateResult.from_dict(await self._client.request("user.settings.validate", params_dict, **_timeout_kwargs(timeout))) + + +# Experimental: this API group is experimental and may change or be removed. +class _InternalServerUserApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + self.settings = _InternalServerUserSettingsApi(client) + + +# Experimental: this API group is experimental and may change or be removed. +class _InternalServerFeatureFlagsApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def _list_metadata(self, *, timeout: float | None = None) -> _FeatureFlagsMetadataResult: + "Lists every feature flag this runtime declares, with the population each one is declared for, its experimental description, and the online-experiment flag it maps to. This is the static catalog: it describes how each flag is defined, not whether it is on for anyone. Use `featureFlags.resolve` for static values with caller overrides, not active runtime values or experiment assignments.\n\nReturns:\n Every feature flag this runtime declares, with the shape each one was declared with.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + return _FeatureFlagsMetadataResult.from_dict(await self._client.request("featureFlags.listMetadata", {}, **_timeout_kwargs(timeout))) + + async def _resolve(self, params: _FeatureFlagsResolveRequest, *, timeout: float | None = None) -> dict: + "Computes static feature flags from the supplied population and overrides without changing runtime state or verifying audience membership. Starts from declared availability, then applies direct feature-flag environment values, user settings, and explicit `flagOverrides`. It does not apply `COPILOT_EXP_*` experiment assignments, authenticated startup gates, or active runtime state. Settings include `enabledFeatureFlags`, the legacy `feature_flags.enabled` list, and supported convenience settings. Supply `baseFlags` to use an existing flag set instead of declared availability. Omit `isStaffGitHub` or `isStaffMicrosoft` when membership was never recorded: a legacy staff account then counts as both populations.\n\nArgs:\n params: Caller population and overrides for static feature-flag resolution, independent of experiment assignments and active runtime state.\n\nReturns:\n The resolved feature flags, keyed by flag name.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return dict(await self._client.request("featureFlags.resolve", params_dict, **_timeout_kwargs(timeout))) + + +# Experimental: this API group is experimental and may change or be removed. +class _InternalServerRepoSettingsApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def _read_raw(self, params: _RepoSettingsReadRawRequest, *, timeout: float | None = None) -> _RepoSettingsReadRawResult: + "Reads one repository settings file without settings normalization or layering. The existing JSONC parser accepts comments and trailing commas and applies its prototype-safety rules. Missing or blank files return an empty valid config. Invalid files return an empty config with invalid=true; other read failures reject.\n\nArgs:\n params: Which repository settings file to read.\n\nReturns:\n Parsed repository settings without normalization or layering.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _RepoSettingsReadRawResult.from_dict(await self._client.request("repo.settings.readRaw", params_dict, **_timeout_kwargs(timeout))) + + async def _write_key(self, params: _RepoSettingsWriteKeyRequest, *, timeout: float | None = None) -> None: + "Writes or removes one allowed top-level repository setting through the existing validator and file lock. Preserves unrelated stored keys. Invalid keys, values, existing documents, and I/O errors reject without replacing the file. Deletion requires delete=true; otherwise value must be present.\n\nArgs:\n params: One key to write or remove in a repository settings file.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = params.to_dict() + await self._client.request("repo.settings.writeKey", params_dict, **_timeout_kwargs(timeout)) + + async def _write_all(self, params: _RepoSettingsWriteAllRequest, *, timeout: float | None = None) -> None: + "Replaces the repository-overridable settings in one locked write. Allowed keys present in settings are validated and written; allowed keys absent from settings are removed. Other input keys are ignored, and unknown keys already stored in the file remain unchanged. Invalid values or an invalid existing file reject without a partial write.\n\nArgs:\n params: The complete set of repository-overridable settings to store.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + await self._client.request("repo.settings.writeAll", params_dict, **_timeout_kwargs(timeout)) + + +# Experimental: this API group is experimental and may change or be removed. +class _InternalServerRepoApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + self.settings = _InternalServerRepoSettingsApi(client) + + # Experimental: this API group is experimental and may change or be removed. class _InternalServerGitHubRepositoryApi: def __init__(self, client: "JsonRpcClient"): @@ -56473,9 +58224,9 @@ class _InternalServerGitHubOwnersApi: def __init__(self, client: "JsonRpcClient"): self._client = client - async def _next_request_id(self, *, timeout: float | None = None) -> GitHubOwnersRequestIDResult: + async def _next_request_id(self, *, timeout: float | None = None) -> _GitHubOwnersRequestIDResult: "Registers a cancellable owner listing and returns its request id. Separate from `gitHubOwners.list` so the id exists before the listing starts: a caller that abandons the listing the moment it begins would otherwise have nothing to name in `gitHubOwners.cancel`. The id serves one listing only. Long-abandoned unused ids can be released by later allocations.\n\nReturns:\n A freshly registered request id. Registering it before the listing starts is what lets a cancel that races the request still find the owner listing slot. The id serves one listing only. Long-abandoned unused ids can be released by later allocations.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." - return GitHubOwnersRequestIDResult.from_dict(await self._client.request("gitHubOwners.nextRequestId", {}, **_timeout_kwargs(timeout))) + return _GitHubOwnersRequestIDResult.from_dict(await self._client.request("gitHubOwners.nextRequestId", {}, **_timeout_kwargs(timeout))) async def _list(self, params: _GitHubOwnersListRequest, *, timeout: float | None = None) -> _GitHubOwnersListResult: "Lists the logins the authenticated user may act as — their own account first, then the organizations they belong to — by asking the GitHub API under the supplied credential. No credential travels in the request: `authInfo` selects one the runtime already holds, and the runtime resolves the token and the GitHub host from it. A failure the caller should render arrives as `message`; one it should raise arrives as `throwError`.\n\nArgs:\n params: Credential to list owners under, and the request id that makes the listing cancellable.\n\nReturns:\n Outcome of an owner listing. Exactly one of `owners` and `message` is present, except that `throwError` reports a failure the caller is expected to raise rather than render.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." @@ -56570,9 +58321,14 @@ class _InternalServerRpc: def __init__(self, client: "JsonRpcClient"): self._client = client self.host = _InternalServerHostApi(client) + self.account = _InternalServerAccountApi(client) self.mcp = _InternalServerMcpApi(client) + self.instructions = _InternalServerInstructionsApi(client) self.agents = _InternalServerAgentsApi(client) self.global_state = _InternalServerGlobalStateApi(client) + self.user = _InternalServerUserApi(client) + self.feature_flags = _InternalServerFeatureFlagsApi(client) + self.repo = _InternalServerRepoApi(client) self.git_hub_repository = _InternalServerGitHubRepositoryApi(client) self.git_hub_owners = _InternalServerGitHubOwnersApi(client) self.git = _InternalServerGitApi(client) @@ -56897,6 +58653,12 @@ async def set_reasoning_effort(self, params: ModelSetReasoningEffortRequest, *, params_dict["sessionId"] = self._session_id return ModelSetReasoningEffortResult.from_dict(await self._client.request("session.model.setReasoningEffort", params_dict, **_timeout_kwargs(timeout))) + async def get_reasoning_summaries(self, params: ModelGetReasoningSummariesRequest, *, timeout: float | None = None) -> ModelGetReasoningSummariesResult: + "Computes whether the session's current model shows reasoning summaries and how a host should present them: the default Ctrl+T visibility, reasoning headers, the hidden-summaries hint, and whether a persisted `showReasoning` setting is redundant. The runtime folds in the session's model catalog, selection and reasoning-summaries experiment assignment; the host supplies only its own persisted setting and current visibility. This method reads the session's resolved model catalog rather than resolving it, so call `session.model.list` first on a session that has not listed models or run a turn; until then the result is `ready: false`. A session that resolves models without a Copilot catalog, that is a BYOK registry or an alternate provider, never caches one and stays `ready: false`.\n\nArgs:\n params: Host presentation state the reasoning-summaries policy depends on.\n\nReturns:\n Reasoning-summaries presentation policy for the session's current model." + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + return ModelGetReasoningSummariesResult.from_dict(await self._client.request("session.model.getReasoningSummaries", params_dict, **_timeout_kwargs(timeout))) + async def list(self, params: SessionModelListRequest | None = None, *, timeout: float | None = None) -> SessionModelList: "Lists models available to this session using its own auth and integration context. Connected hosts (CLI TUI, GitHub App) should call this through the session client so remote sessions return the remote CLI's available models rather than the caller's.\n\nArgs:\n params: Optional listing options.\n\nReturns:\n The list of models available to this session." params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} @@ -58750,25 +60512,25 @@ async def _set_connected_ide_info(self, params: SessionMCPSetConnectedIDEInfoPar params_dict["sessionId"] = self._session_id await self._client.request("session.mcp.setConnectedIdeInfo", params_dict, **_timeout_kwargs(timeout)) - async def _reload_with_config(self, params: MCPReloadWithConfigRequest, *, timeout: float | None = None) -> MCPStartServersResult: + async def _reload_with_config(self, params: _MCPReloadWithConfigRequest, *, timeout: float | None = None) -> MCPStartServersResult: "Reloads MCP server connections for the session with an explicit host-provided configuration.\n\nArgs:\n params: Opaque MCP reload configuration.\n\nReturns:\n MCP server startup filtering result.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id return MCPStartServersResult.from_dict(await self._client.request("session.mcp.reloadWithConfig", params_dict, **_timeout_kwargs(timeout))) - async def _configure_git_hub(self, params: MCPConfigureGitHubRequest, *, timeout: float | None = None) -> MCPConfigureGitHubResult: + async def _configure_git_hub(self, params: _MCPConfigureGitHubRequest, *, timeout: float | None = None) -> MCPConfigureGitHubResult: "Configures the built-in GitHub MCP server for the session's current auth context.\n\nArgs:\n params: Credential-free authentication identity used to configure GitHub MCP.\n\nReturns:\n Result of configuring GitHub MCP.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id return MCPConfigureGitHubResult.from_dict(await self._client.request("session.mcp.configureGitHub", params_dict, **_timeout_kwargs(timeout))) - async def _register_external_client(self, params: MCPRegisterExternalClientRequest, *, timeout: float | None = None) -> None: + async def _register_external_client(self, params: _MCPRegisterExternalClientRequest, *, timeout: float | None = None) -> None: "Registers a pre-connected external MCP client (e.g. IDE) on the session's host. The caller retains lifecycle ownership of the client and transport. Marked internal because the `client` and `transport` arguments are in-process MCP SDK instances that cannot be serialized across the JSON-RPC boundary; once the CLI moves on top of the SDK, external clients will be expressed as transport configs the runtime can construct itself.\n\nArgs:\n params: Registration parameters for an external MCP client.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id await self._client.request("session.mcp.registerExternalClient", params_dict, **_timeout_kwargs(timeout)) - async def _unregister_external_client(self, params: MCPUnregisterExternalClientRequest, *, timeout: float | None = None) -> None: + async def _unregister_external_client(self, params: _MCPUnregisterExternalClientRequest, *, timeout: float | None = None) -> None: "Unregisters a previously registered external MCP client by server name. Marked internal as the paired companion of `registerExternalClient`: only in-process callers that registered a client this way can meaningfully unregister it. Disappears alongside `registerExternalClient`: once external clients are described to the runtime as config rather than handed in as instances, lifecycle (including deregistration) is owned entirely by the runtime.\n\nArgs:\n params: Server name identifying the external client to remove.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id @@ -59822,6 +61584,7 @@ async def handle_installations_confirm(params: dict) -> dict | None: "ExternalToolTextResultForLlmContentTerminalType", "ExternalToolTextResultForLlmContentText", "ExternalToolTextResultForLlmContentType", + "FeatureFlagsResolveResult", "FilterMapping", "FleetApi", "FleetStartRequest", @@ -59834,7 +61597,6 @@ async def handle_installations_confirm(params: dict) -> dict | None: "GhCLIAuthInfoType", "GitHubAuthApi", "GitHubEnvironment", - "GitHubOwnersRequestIDResult", "GitHubRepositoryIdentity", "GitHubTelemetryClientInfo", "GitHubTelemetryEvent", @@ -59982,7 +61744,6 @@ async def handle_installations_confirm(params: dict) -> dict | None: "MCPConfigList", "MCPConfigRemoveRequest", "MCPConfigUpdateRequest", - "MCPConfigureGitHubRequest", "MCPConfigureGitHubResult", "MCPConfiguredServer", "MCPConfiguredServerList", @@ -60099,14 +61860,6 @@ async def handle_installations_confirm(params: dict) -> dict | None: "MCPPromptsGetResult", "MCPPromptsListRequest", "MCPPromptsListResult", - "MCPRegisterExternalClientRequest", - "MCPRegistryCancelRequest", - "MCPRegistryCancelResult", - "MCPRegistryRequestIDResult", - "MCPRegistrySearchRequest", - "MCPRegistrySearchResult", - "MCPReloadConfig", - "MCPReloadWithConfigRequest", "MCPRemoveGitHubResult", "MCPResource", "MCPResourceAnnotations", @@ -60137,8 +61890,6 @@ async def handle_installations_confirm(params: dict) -> dict | None: "MCPServerConfigDeferTools", "MCPServerConfigHTTP", "MCPServerConfigHTTPType", - "MCPServerConfigMemory", - "MCPServerConfigMemoryType", "MCPServerConfigStdio", "MCPServerConfigStdioType", "MCPServerConfigType", @@ -60149,8 +61900,6 @@ async def handle_installations_confirm(params: dict) -> dict | None: "MCPSetEnvValueModeDetails", "MCPSetEnvValueModeParams", "MCPSetEnvValueModeResult", - "MCPShouldExcludeGitHubToolsRequest", - "MCPShouldExcludeGitHubToolsResult", "MCPSourceFile", "MCPSourcePlugin", "MCPSourceRef", @@ -60162,7 +61911,6 @@ async def handle_installations_confirm(params: dict) -> dict | None: "MCPToolUIVisibility", "MCPTools", "MCPUninstallPlan", - "MCPUnregisterExternalClientRequest", "ManagedMCPServerConfig", "ManagedPermissionEvaluation", "ManagedPermissionOperation", @@ -60264,6 +62012,8 @@ async def handle_installations_confirm(params: dict) -> dict | None: "ModelCapabilitiesOverrideLimitsVision", "ModelCapabilitiesOverrideSupports", "ModelCapabilitiesSupports", + "ModelGetReasoningSummariesRequest", + "ModelGetReasoningSummariesResult", "ModelList", "ModelListRequest", "ModelMessage", @@ -61168,6 +62918,7 @@ async def handle_installations_confirm(params: dict) -> dict | None: "UIUnregisterDirectAutoModeSwitchHandlerRequest", "UIUnregisterDirectAutoModeSwitchHandlerResult", "UIUserInputResponse", + "UNSET_SENTINEL", "UiApi", "UnsupportedEnqueueCommandResult", "UpdateSubagentSettingsRequest", @@ -61175,8 +62926,25 @@ async def handle_installations_confirm(params: dict) -> dict | None: "UserAuthInfo", "UserRequestedShellCommandResult", "UserSettingMetadata", + "UserSettingsApplyTopKeyRequest", + "UserSettingsApplyTopKeyResult", + "UserSettingsGetPathsRequest", + "UserSettingsGetPathsResult", "UserSettingsGetResult", + "UserSettingsGovernanceKeysResult", + "UserSettingsLoadForEditResult", + "UserSettingsNormalizeRequest", + "UserSettingsNormalizeResult", + "UserSettingsProblem", + "UserSettingsProblemLocation", + "UserSettingsProblemSource", + "UserSettingsProblemsRequest", + "UserSettingsProblemsResult", "UserSettingsSetRequest", + "UserSettingsValidateRequest", + "UserSettingsValidateResult", + "UserSettingsValidationIssue", + "UserSettingsWriteAllRequest", "VisibilityApi", "VisibilityGetResult", "VisibilitySetRequest", diff --git a/python/copilot/generated/session_events.py b/python/copilot/generated/session_events.py index 3ef3b61685..9291f489a5 100644 --- a/python/copilot/generated/session_events.py +++ b/python/copilot/generated/session_events.py @@ -5021,6 +5021,7 @@ class CompactionCompleteCompactionTokensUsed: model_display_name: str | None = None output_tokens: int | None = None provider: ModelProviderRef | None = None + request_count: int | None = None @staticmethod def from_dict(obj: Any) -> "CompactionCompleteCompactionTokensUsed": @@ -5035,6 +5036,7 @@ def from_dict(obj: Any) -> "CompactionCompleteCompactionTokensUsed": model_display_name = from_union([from_none, from_str], obj.get("modelDisplayName")) output_tokens = from_union([from_none, from_int], obj.get("outputTokens")) provider = from_union([from_none, ModelProviderRef.from_dict], obj.get("provider")) + request_count = from_union([from_none, from_int], obj.get("requestCount")) return CompactionCompleteCompactionTokensUsed( ai_credits_status=ai_credits_status, cache_read_tokens=cache_read_tokens, @@ -5046,6 +5048,7 @@ def from_dict(obj: Any) -> "CompactionCompleteCompactionTokensUsed": model_display_name=model_display_name, output_tokens=output_tokens, provider=provider, + request_count=request_count, ) def to_dict(self) -> dict: @@ -5070,6 +5073,8 @@ def to_dict(self) -> dict: result["outputTokens"] = from_union([from_none, to_int], self.output_tokens) if self.provider is not None: result["provider"] = from_union([from_none, lambda x: to_class(ModelProviderRef, x)], self.provider) + if self.request_count is not None: + result["requestCount"] = from_union([from_none, to_int], self.request_count) return result @@ -7925,6 +7930,8 @@ class PermissionRecoveryData: on_blocked: PermissionRecoveryOnBlocked reason: PermissionRecoveryReason status: PermissionRecoveryStatus + owner_agent_id: str | None = None + owner_session_id: str | None = None @staticmethod def from_dict(obj: Any) -> "PermissionRecoveryData": @@ -7935,6 +7942,8 @@ def from_dict(obj: Any) -> "PermissionRecoveryData": on_blocked = parse_enum(PermissionRecoveryOnBlocked, obj.get("onBlocked")) reason = parse_enum(PermissionRecoveryReason, obj.get("reason")) status = parse_enum(PermissionRecoveryStatus, obj.get("status")) + owner_agent_id = from_union([from_none, from_str], obj.get("ownerAgentId")) + owner_session_id = from_union([from_none, from_str], obj.get("ownerSessionId")) return PermissionRecoveryData( attempts=attempts, episode_id=episode_id, @@ -7942,6 +7951,8 @@ def from_dict(obj: Any) -> "PermissionRecoveryData": on_blocked=on_blocked, reason=reason, status=status, + owner_agent_id=owner_agent_id, + owner_session_id=owner_session_id, ) def to_dict(self) -> dict: @@ -7952,6 +7963,10 @@ def to_dict(self) -> dict: result["onBlocked"] = to_enum(PermissionRecoveryOnBlocked, self.on_blocked) result["reason"] = to_enum(PermissionRecoveryReason, self.reason) result["status"] = to_enum(PermissionRecoveryStatus, self.status) + if self.owner_agent_id is not None: + result["ownerAgentId"] = from_union([from_none, from_str], self.owner_agent_id) + if self.owner_session_id is not None: + result["ownerSessionId"] = from_union([from_none, from_str], self.owner_session_id) return result @@ -8715,6 +8730,8 @@ class PermissionRequestedData: permission_request: PermissionRequest request_id: str agent_mode: SessionMode | None = None + owner_agent_id: str | None = None + owner_session_id: str | None = None permission_mode: PermissionMode | None = None prompt_request: PermissionPromptRequest | None = None recovery_episode_id: str | None = None @@ -8727,6 +8744,8 @@ def from_dict(obj: Any) -> "PermissionRequestedData": permission_request = _load_PermissionRequest(obj.get("permissionRequest")) request_id = from_str(obj.get("requestId")) agent_mode = from_union([from_none, lambda x: parse_enum(SessionMode, x)], obj.get("agentMode")) + owner_agent_id = from_union([from_none, from_str], obj.get("ownerAgentId")) + owner_session_id = from_union([from_none, from_str], obj.get("ownerSessionId")) permission_mode = from_union([from_none, lambda x: parse_enum(PermissionMode, x)], obj.get("permissionMode")) prompt_request = from_union([from_none, _load_PermissionPromptRequest], obj.get("promptRequest")) recovery_episode_id = from_union([from_none, from_str], obj.get("recoveryEpisodeId")) @@ -8736,6 +8755,8 @@ def from_dict(obj: Any) -> "PermissionRequestedData": permission_request=permission_request, request_id=request_id, agent_mode=agent_mode, + owner_agent_id=owner_agent_id, + owner_session_id=owner_session_id, permission_mode=permission_mode, prompt_request=prompt_request, recovery_episode_id=recovery_episode_id, @@ -8749,6 +8770,10 @@ def to_dict(self) -> dict: result["requestId"] = from_str(self.request_id) if self.agent_mode is not None: result["agentMode"] = from_union([from_none, lambda x: to_enum(SessionMode, x)], self.agent_mode) + if self.owner_agent_id is not None: + result["ownerAgentId"] = from_union([from_none, from_str], self.owner_agent_id) + if self.owner_session_id is not None: + result["ownerSessionId"] = from_union([from_none, from_str], self.owner_session_id) if self.permission_mode is not None: result["permissionMode"] = from_union([from_none, lambda x: to_enum(PermissionMode, x)], self.permission_mode) if self.prompt_request is not None: @@ -9795,6 +9820,8 @@ class SessionErrorData: eligible_for_auto_switch: bool | None = None error_code: str | None = None provider_call_id: str | None = None + provider_error_param: str | None = None + provider_error_type: str | None = None remediation: RemediationAction | None = None service_request_id: str | None = None stack: str | None = None @@ -9809,6 +9836,8 @@ def from_dict(obj: Any) -> "SessionErrorData": eligible_for_auto_switch = from_union([from_none, from_bool], obj.get("eligibleForAutoSwitch")) error_code = from_union([from_none, from_str], obj.get("errorCode")) provider_call_id = from_union([from_none, from_str], obj.get("providerCallId")) + provider_error_param = from_union([from_none, from_str], obj.get("providerErrorParam")) + provider_error_type = from_union([from_none, from_str], obj.get("providerErrorType")) remediation = from_union([from_none, lambda x: parse_enum(RemediationAction, x)], obj.get("remediation")) service_request_id = from_union([from_none, from_str], obj.get("serviceRequestId")) stack = from_union([from_none, from_str], obj.get("stack")) @@ -9820,6 +9849,8 @@ def from_dict(obj: Any) -> "SessionErrorData": eligible_for_auto_switch=eligible_for_auto_switch, error_code=error_code, provider_call_id=provider_call_id, + provider_error_param=provider_error_param, + provider_error_type=provider_error_type, remediation=remediation, service_request_id=service_request_id, stack=stack, @@ -9837,6 +9868,10 @@ def to_dict(self) -> dict: result["errorCode"] = from_union([from_none, from_str], self.error_code) if self.provider_call_id is not None: result["providerCallId"] = from_union([from_none, from_str], self.provider_call_id) + if self.provider_error_param is not None: + result["providerErrorParam"] = from_union([from_none, from_str], self.provider_error_param) + if self.provider_error_type is not None: + result["providerErrorType"] = from_union([from_none, from_str], self.provider_error_type) if self.remediation is not None: result["remediation"] = from_union([from_none, lambda x: to_enum(RemediationAction, x)], self.remediation) if self.service_request_id is not None: @@ -10490,6 +10525,8 @@ class SessionPermissionRecoveryData: on_blocked: PermissionRecoveryOnBlocked reason: PermissionRecoveryReason status: PermissionRecoveryStatus + owner_agent_id: str | None = None + owner_session_id: str | None = None @staticmethod def from_dict(obj: Any) -> "SessionPermissionRecoveryData": @@ -10500,6 +10537,8 @@ def from_dict(obj: Any) -> "SessionPermissionRecoveryData": on_blocked = parse_enum(PermissionRecoveryOnBlocked, obj.get("onBlocked")) reason = parse_enum(PermissionRecoveryReason, obj.get("reason")) status = parse_enum(PermissionRecoveryStatus, obj.get("status")) + owner_agent_id = from_union([from_none, from_str], obj.get("ownerAgentId")) + owner_session_id = from_union([from_none, from_str], obj.get("ownerSessionId")) return SessionPermissionRecoveryData( attempts=attempts, episode_id=episode_id, @@ -10507,6 +10546,8 @@ def from_dict(obj: Any) -> "SessionPermissionRecoveryData": on_blocked=on_blocked, reason=reason, status=status, + owner_agent_id=owner_agent_id, + owner_session_id=owner_session_id, ) def to_dict(self) -> dict: @@ -10517,6 +10558,10 @@ def to_dict(self) -> dict: result["onBlocked"] = to_enum(PermissionRecoveryOnBlocked, self.on_blocked) result["reason"] = to_enum(PermissionRecoveryReason, self.reason) result["status"] = to_enum(PermissionRecoveryStatus, self.status) + if self.owner_agent_id is not None: + result["ownerAgentId"] = from_union([from_none, from_str], self.owner_agent_id) + if self.owner_session_id is not None: + result["ownerSessionId"] = from_union([from_none, from_str], self.owner_session_id) return result @@ -15870,6 +15915,8 @@ class RemediationAction(Enum): REVIEW_SANDBOX_POLICY = "review_sandbox_policy" # Permit outbound network access in the sandbox policy. ALLOW_SANDBOX_OUTBOUND = "allow_sandbox_outbound" + # Discard conversation history back through the blocked request before continuing. + REWIND_CONVERSATION = "rewind_conversation" class SandboxAttestation(Enum): diff --git a/python/copilot/session.py b/python/copilot/session.py index b61d753956..572f5e187a 100644 --- a/python/copilot/session.py +++ b/python/copilot/session.py @@ -1373,6 +1373,7 @@ class GitHubMcpToolConfig(TypedDict, total=False): class CustomAgentConfig(TypedDict, total=False): """Configuration for a custom agent.""" + hooks: NotRequired[dict[str, list[dict[str, Any]]]] name: str # Unique name of the custom agent display_name: NotRequired[str] # Display name for UI purposes description: NotRequired[str] # Description of what the agent does diff --git a/python/e2e/test_client_options_e2e.py b/python/e2e/test_client_options_e2e.py index 1267bf6d57..701ddddd42 100644 --- a/python/e2e/test_client_options_e2e.py +++ b/python/e2e/test_client_options_e2e.py @@ -499,6 +499,7 @@ async def test_should_forward_advanced_session_options_in_create_wire_request( try: await client.start() session = await client.create_session( + name="python named at create", client_name="advanced-create-client", model="claude-sonnet-5", reasoning_effort="medium", @@ -585,6 +586,7 @@ async def test_should_forward_advanced_session_options_in_create_wire_request( ) try: params = _get_captured_request(capture_path, "session.create") + assert params["name"] == "python named at create" assert params["clientName"] == "advanced-create-client" assert params["model"] == "claude-sonnet-5" assert params["reasoningEffort"] == "medium" diff --git a/python/test_customization_directories.py b/python/test_customization_directories.py new file mode 100644 index 0000000000..254025a34f --- /dev/null +++ b/python/test_customization_directories.py @@ -0,0 +1,71 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. + +from unittest.mock import AsyncMock + +import pytest + +from copilot import CopilotClient, RuntimeConnection +from copilot._jsonrpc import JsonRpcClient + + +@pytest.mark.asyncio +@pytest.mark.parametrize("roots", [None, [], ["relative-root", "other-root"]]) +async def test_customization_roots_preserved_on_create_and_resume(monkeypatch, roots): + client = CopilotClient(connection=RuntimeConnection.for_uri("localhost:1234")) + rpc = AsyncMock(spec=JsonRpcClient) + requests = {} + + async def request(method, params, **kwargs): + requests[method] = params + if method in ("session.create", "session.resume"): + response = {"sessionId": params["sessionId"]} + if callback := kwargs.get("on_response_inline"): + callback(response) + return response + return {} + + rpc.request.side_effect = request + monkeypatch.setattr(client, "_client", rpc) + skills = None if roots is None else [f"{root}-skills" for root in roots] + agents = None if roots is None else [f"{root}-agents" for root in roots] + instructions = None if roots is None else [f"{root}-instructions" for root in roots] + hooks = None if roots is None else [f"{root}-hooks" for root in roots] + try: + session = await client.create_session( + working_directory="request-cwd", + enable_config_discovery=False, + enable_file_hooks=False, + skill_directories=skills, + agent_directories=agents, + instruction_directories=instructions, + hook_directories=hooks, + ) + await client.resume_session( + session.session_id, + working_directory="resume-cwd", + enable_config_discovery=False, + enable_file_hooks=False, + skill_directories=skills, + agent_directories=agents, + instruction_directories=instructions, + hook_directories=hooks, + ) + for method in ("session.create", "session.resume"): + payload = requests[method] + for key, expected in ( + ("skillDirectories", skills), + ("agentDirectories", agents), + ("instructionDirectories", instructions), + ("hookDirectories", hooks), + ): + if expected is None: + assert key not in payload + else: + assert payload[key] == expected + assert payload["enableConfigDiscovery"] is False + assert payload["enableFileHooks"] is False + assert "additionalDirectories" not in payload + assert "customAgents" not in payload + assert "hooks" not in payload + finally: + await client.force_stop() diff --git a/rust/Cargo.toml b/rust/Cargo.toml index b82e322b02..46b818bb61 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -81,8 +81,10 @@ tokio-tungstenite = { version = "0.28.0", default-features = false, features = [ zip = { version = "7.2.0", default-features = false, features = ["deflate"], optional = true } windows-sys = { version = "0.61", default-features = false, features = [ "Win32_Foundation", - "Win32_System_Diagnostics_ToolHelp", + "Win32_System_Diagnostics_Debug", + "Win32_System_Diagnostics_ProcessSnapshotting", "Win32_System_JobObjects", + "Win32_System_Kernel", "Win32_System_Threading", ] } diff --git a/rust/README.md b/rust/README.md index 87484defec..f233c8b14e 100644 --- a/rust/README.md +++ b/rust/README.md @@ -124,6 +124,12 @@ Transport-specific phases are optional. For example, `port_wait_ms` is present only for TCP and `process_spawn_ms` is absent for external and in-process transports. +On Windows, SDK-spawned CLI processes start suspended and are assigned to a +private kill-on-close Job Object before their initial thread resumes. Thread +lookup captures only that child's process snapshot, rather than enumerating +machine-wide threads. The Job owns the CLI and its descendants until client +shutdown or final-client drop, including abrupt termination of the SDK host. + **`ClientOptions`:** | Field | Type | Description | diff --git a/rust/bazel/crates/BUILD.windows-sys-0.61.2.bazel b/rust/bazel/crates/BUILD.windows-sys-0.61.2.bazel index f964882760..87b0fb6806 100644 --- a/rust/bazel/crates/BUILD.windows-sys-0.61.2.bazel +++ b/rust/bazel/crates/BUILD.windows-sys-0.61.2.bazel @@ -54,9 +54,11 @@ rust_library( "Win32_Storage_FileSystem", "Win32_System", "Win32_System_Diagnostics", - "Win32_System_Diagnostics_ToolHelp", + "Win32_System_Diagnostics_Debug", + "Win32_System_Diagnostics_ProcessSnapshotting", "Win32_System_IO", "Win32_System_JobObjects", + "Win32_System_Kernel", "Win32_System_LibraryLoader", "Win32_System_Memory", "Win32_System_Pipes", diff --git a/rust/src/ahp_host.rs b/rust/src/ahp_host.rs index 7ae2f1ca4e..5c906f605c 100644 --- a/rust/src/ahp_host.rs +++ b/rust/src/ahp_host.rs @@ -936,6 +936,8 @@ macro_rules! host_settings { "memory" => memory, "pluginDirectories" => plugin_directories, "skillDirectories" => skill_directories, + "agentDirectories" => agent_directories, + "hookDirectories" => hook_directories, "instructionDirectories" => instruction_directories, "enableMcpApps" => enable_mcp_apps, "model" => model, diff --git a/rust/src/ahp_host/factory_tests.rs b/rust/src/ahp_host/factory_tests.rs index bb328c7acd..a4b9cf3751 100644 --- a/rust/src/ahp_host/factory_tests.rs +++ b/rust/src/ahp_host/factory_tests.rs @@ -629,6 +629,7 @@ fn host_settings_round_trip_without_callbacks_or_losing_constraints() { "customAgentsLocalOnly": true, "coauthorEnabled": false, "manageScheduleEnabled": false, "memory": {"enabled":false}, "pluginDirectories": ["/plugins"], "skillDirectories": ["/skills"], "instructionDirectories": ["/instructions"], + "agentDirectories": ["relative-agents"], "hookDirectories": [], "enableMcpApps": true, "model":"model", "reasoningEffort":"high", "contextTier":"long_context" }); let config = config_from_host(&serde_json::from_value(value.clone()).unwrap()).unwrap(); diff --git a/rust/src/copilot_request_handler.rs b/rust/src/copilot_request_handler.rs index 381acac0d2..c0dec20a97 100644 --- a/rust/src/copilot_request_handler.rs +++ b/rust/src/copilot_request_handler.rs @@ -718,7 +718,13 @@ impl CopilotRequestExchange { let mut buf = Vec::new(); let mut rx = self.body_rx.lock().await; while let Some(frame) = rx.recv().await { - buf.extend_from_slice(&frame); + // The first frame becomes the buffer, so a body sent as one chunk (the runtime sends + // every HTTP request body so) reaches the handler without a copy. + if buf.is_empty() { + buf = frame; + } else { + buf.extend_from_slice(&frame); + } } buf } @@ -1114,7 +1120,8 @@ impl CopilotRequestDispatcher { async fn handle_start(self: &Arc, request: JsonRpcRequest) { let id = request.id; - let Some(params) = parse_params::(&request) else { + let Some(params) = parse_params::(request.params) + else { self.send_error(id, "invalid llmInference.httpRequestStart params") .await; return; @@ -1140,7 +1147,8 @@ impl CopilotRequestDispatcher { async fn handle_chunk(&self, request: JsonRpcRequest) { let id = request.id; - let Some(params) = parse_params::(&request) else { + let Some(params) = parse_params::(request.params) + else { self.send_error(id, "invalid llmInference.httpRequestChunk params") .await; return; @@ -1149,7 +1157,7 @@ impl CopilotRequestDispatcher { // May arrive before the matching start frame; get-or-create so the body // is buffered, never lost. let exchange = self.get_or_create_exchange(params.request_id.to_string()); - apply_chunk(&exchange, ¶ms); + apply_chunk(&exchange, params); self.ack(id).await; } @@ -1193,7 +1201,7 @@ impl CopilotRequestDispatcher { /// Apply one body chunk to a pending request: route data into the body stream, /// or terminate it on `end` / `cancel`. -fn apply_chunk(exchange: &CopilotRequestExchange, params: &LlmInferenceHttpRequestChunkRequest) { +fn apply_chunk(exchange: &CopilotRequestExchange, params: LlmInferenceHttpRequestChunkRequest) { if params.cancel == Some(true) { exchange.push_cancel(); return; @@ -1209,7 +1217,7 @@ fn apply_chunk(exchange: &CopilotRequestExchange, params: &LlmInferenceHttpReque } } } else { - params.data.clone().into_bytes() + params.data.into_bytes() }; exchange.push_chunk(decoded); } @@ -1219,11 +1227,10 @@ fn apply_chunk(exchange: &CopilotRequestExchange, params: &LlmInferenceHttpReque } } -fn parse_params(request: &JsonRpcRequest) -> Option { - request - .params - .as_ref() - .and_then(|p| serde_json::from_value(p.clone()).ok()) +/// Deserialize a request's params by value, so their strings (the request body among them) move +/// into `T`: deserializing from a borrow deep-clones the whole `Value` first. +fn parse_params(params: Option) -> Option { + params.and_then(|p| serde_json::from_value(p).ok()) } /// Convert a wire header map into an [`http::HeaderMap`], skipping any entry the diff --git a/rust/src/generated/api_types.rs b/rust/src/generated/api_types.rs index 577940cb1e..6c28002b9a 100644 --- a/rust/src/generated/api_types.rs +++ b/rust/src/generated/api_types.rs @@ -81,6 +81,14 @@ pub mod rpc_methods { pub const ACCOUNT_LOGIN: &str = "account.login"; /// `account.logout` pub const ACCOUNT_LOGOUT: &str = "account.logout"; + /// `account.describeAuthInfo` + pub const ACCOUNT_DESCRIBEAUTHINFO: &str = "account.describeAuthInfo"; + /// `account.getGistSupport` + pub const ACCOUNT_GETGISTSUPPORT: &str = "account.getGistSupport"; + /// `account.getWebUrl` + pub const ACCOUNT_GETWEBURL: &str = "account.getWebUrl"; + /// `account.getTokenEnvVar` + pub const ACCOUNT_GETTOKENENVVAR: &str = "account.getTokenEnvVar"; /// `secrets.addFilterValues` pub const SECRETS_ADDFILTERVALUES: &str = "secrets.addFilterValues"; /// `mcp.config.list` @@ -105,6 +113,8 @@ pub mod rpc_methods { pub const MCP_REGISTRY_CANCEL: &str = "mcp.registry.cancel"; /// `mcp.discover` pub const MCP_DISCOVER: &str = "mcp.discover"; + /// `mcp.listBuiltinServerNames` + pub const MCP_LISTBUILTINSERVERNAMES: &str = "mcp.listBuiltinServerNames"; /// `mcp.shouldExcludeGitHubTools` pub const MCP_SHOULDEXCLUDEGITHUBTOOLS: &str = "mcp.shouldExcludeGitHubTools"; /// `mcp.planInstall` @@ -131,6 +141,16 @@ pub mod rpc_methods { pub const EXTENSIONS_ENABLE: &str = "extensions.enable"; /// `extensions.disable` pub const EXTENSIONS_DISABLE: &str = "extensions.disable"; + /// `instructions.getInitPrompt` + pub const INSTRUCTIONS_GETINITPROMPT: &str = "instructions.getInitPrompt"; + /// `instructions.discover` + pub const INSTRUCTIONS_DISCOVER: &str = "instructions.discover"; + /// `instructions.discoverRepoSources` + pub const INSTRUCTIONS_DISCOVERREPOSOURCES: &str = "instructions.discoverRepoSources"; + /// `instructions.getDiscoveryPaths` + pub const INSTRUCTIONS_GETDISCOVERYPATHS: &str = "instructions.getDiscoveryPaths"; + /// `instructions.clearCache` + pub const INSTRUCTIONS_CLEARCACHE: &str = "instructions.clearCache"; /// `skills.planInstall` pub const SKILLS_PLANINSTALL: &str = "skills.planInstall"; /// `skills.applyInstall` @@ -204,10 +224,6 @@ pub mod rpc_methods { /// `agents.customAgentInitialModelDecision` pub const AGENTS_CUSTOMAGENTINITIALMODELDECISION: &str = "agents.customAgentInitialModelDecision"; - /// `instructions.discover` - pub const INSTRUCTIONS_DISCOVER: &str = "instructions.discover"; - /// `instructions.getDiscoveryPaths` - pub const INSTRUCTIONS_GETDISCOVERYPATHS: &str = "instructions.getDiscoveryPaths"; /// `globalState.load` pub const GLOBALSTATE_LOAD: &str = "globalState.load"; /// `globalState.loadForConfigDir` @@ -218,8 +234,38 @@ pub mod rpc_methods { pub const COMMANDS_LIST: &str = "commands.list"; /// `user.settings.get` pub const USER_SETTINGS_GET: &str = "user.settings.get"; + /// `user.settings.getPaths` + pub const USER_SETTINGS_GETPATHS: &str = "user.settings.getPaths"; /// `user.settings.set` pub const USER_SETTINGS_SET: &str = "user.settings.set"; + /// `user.settings.listGovernanceKeys` + pub const USER_SETTINGS_LISTGOVERNANCEKEYS: &str = "user.settings.listGovernanceKeys"; + /// `user.settings.edit` + pub const USER_SETTINGS_EDIT: &str = "user.settings.edit"; + /// `user.settings.normalize` + pub const USER_SETTINGS_NORMALIZE: &str = "user.settings.normalize"; + /// `user.settings.diagnoseProblems` + pub const USER_SETTINGS_DIAGNOSEPROBLEMS: &str = "user.settings.diagnoseProblems"; + /// `user.settings.applyTopKey` + pub const USER_SETTINGS_APPLYTOPKEY: &str = "user.settings.applyTopKey"; + /// `user.settings.writeAll` + pub const USER_SETTINGS_WRITEALL: &str = "user.settings.writeAll"; + /// `user.settings.update` + pub const USER_SETTINGS_UPDATE: &str = "user.settings.update"; + /// `user.settings.loadForEdit` + pub const USER_SETTINGS_LOADFOREDIT: &str = "user.settings.loadForEdit"; + /// `user.settings.validate` + pub const USER_SETTINGS_VALIDATE: &str = "user.settings.validate"; + /// `featureFlags.listMetadata` + pub const FEATUREFLAGS_LISTMETADATA: &str = "featureFlags.listMetadata"; + /// `featureFlags.resolve` + pub const FEATUREFLAGS_RESOLVE: &str = "featureFlags.resolve"; + /// `repo.settings.readRaw` + pub const REPO_SETTINGS_READRAW: &str = "repo.settings.readRaw"; + /// `repo.settings.writeKey` + pub const REPO_SETTINGS_WRITEKEY: &str = "repo.settings.writeKey"; + /// `repo.settings.writeAll` + pub const REPO_SETTINGS_WRITEALL: &str = "repo.settings.writeAll"; /// `gitHubRepository.atPath` pub const GITHUBREPOSITORY_ATPATH: &str = "gitHubRepository.atPath"; /// `gitHubOwners.nextRequestId` @@ -467,6 +513,8 @@ pub mod rpc_methods { pub const SESSION_MODEL_SETALLOWEDMODELS: &str = "session.model.setAllowedModels"; /// `session.model.setReasoningEffort` pub const SESSION_MODEL_SETREASONINGEFFORT: &str = "session.model.setReasoningEffort"; + /// `session.model.getReasoningSummaries` + pub const SESSION_MODEL_GETREASONINGSUMMARIES: &str = "session.model.getReasoningSummaries"; /// `session.model.list` pub const SESSION_MODEL_LIST: &str = "session.model.list"; /// `session.mode.get` @@ -1775,6 +1823,67 @@ pub struct AccountAllUsers { pub token: Option, } +/// Credential-free authentication identity safe to expose to hosts and user interfaces. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct AuthIdentity { + /// Snapshot of the authenticated user's Copilot subscription info, if known + #[serde(skip_serializing_if = "Option::is_none")] + pub copilot_user: Option, + /// Name of the environment variable that supplied the credential, when applicable + #[serde(skip_serializing_if = "Option::is_none")] + pub env_var: Option, + /// Authentication host + pub host: String, + /// Authenticated login, when available + #[serde(skip_serializing_if = "Option::is_none")] + pub login: Option, + /// Opaque SDK GitHub credential registration backing this identity. Routing metadata only; never a credential. + #[serde(skip_serializing_if = "Option::is_none")] + pub registration_id: Option, + /// Authentication type + pub r#type: AuthInfoType, +} + +/// The authentication identity whose shared wording should be rendered. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct AccountDescribeAuthInfoRequest { + /// Identity to describe. + pub identity: AuthIdentity, +} + +/// The wording the runtime uses for an authentication identity. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct AccountDescribeAuthInfoResult { + /// One-line description of the identity, suitable after a verb such as "Switched to". + pub description: String, + /// Sign-in banner announcing the authenticated user. + pub message: String, +} + /// Current authentication state /// ///
@@ -1794,6 +1903,42 @@ pub struct AccountGetCurrentAuthResult { pub auth_info: Option, } +/// The authentication identity whose gist support should be reported. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct AccountGetGistSupportRequest { + /// Identity to evaluate. + pub identity: AuthIdentity, +} + +/// Whether the identity can create gists, and why not when it cannot. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct AccountGetGistSupportResult { + /// Machine-readable reason category when unsupported. + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, + /// Human-readable explanation to show where the gist action would have been. + #[serde(skip_serializing_if = "Option::is_none")] + pub reason: Option, + /// True when the identity can create gists. + pub supported: bool, +} + /// Optional opaque account selection or compatibility GitHub token used to look up quota. /// ///
@@ -1858,6 +2003,55 @@ pub struct AccountGetQuotaResult { pub quota_snapshots: HashMap, } +/// The environment variable supplying a classic personal access token, when one is set. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct AccountGetTokenEnvVarResult { + /// Variable name, for example `GH_TOKEN`. Absent when no classic token is present in the environment. + #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option, +} + +/// A path to resolve against the GitHub host an identity is signed in to. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct AccountGetWebUrlRequest { + /// Identity whose host the path resolves against. Omit to resolve against the public github.com host. + #[serde(skip_serializing_if = "Option::is_none")] + pub identity: Option, + /// Host-relative path, without a leading slash, for example `settings/copilot/features`. + pub path: String, +} + +/// An absolute URL on the identity's GitHub host. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct AccountGetWebUrlResult { + /// Absolute URL for the requested path. + pub url: String, +} + /// Credentials to validate and store. Omit login to resolve the authenticated user from the token. /// ///
@@ -2126,6 +2320,9 @@ pub struct AgentInfo { pub disable_model_invocation: Option, /// Human-readable display name pub display_name: String, + /// Declarative hook actions keyed by event name, executed only while this agent is active. + #[serde(skip_serializing_if = "Option::is_none")] + pub hooks: Option>>, /// Stable identifier for selection. For most agents this is the same as `name`; for plugin/builtin agents it may differ. Always populated; defaults to `name` when no distinct id was assigned. pub id: String, /// MCP server configurations attached to this agent, keyed by server name. Server config shape mirrors the MCP `mcpServers` schema. @@ -2496,6 +2693,63 @@ pub struct AgentsDiscoverRequest { pub project_paths: Option>, } +/// Extensible [`AgentsDiscoverRequest`], including inputs added after it was published. +/// +/// Required inputs are [`AgentsDiscoverOptions::new`] arguments; optional inputs have fluent setters. +/// Input-only: it serialises to the flat wire request and is not deserialisable. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct AgentsDiscoverOptions { + #[serde(flatten)] + legacy: AgentsDiscoverRequest, + #[serde(skip_serializing_if = "Option::is_none")] + agent_directories: Option>, +} + +impl AgentsDiscoverOptions { + /// Creates options with the required inputs. + pub fn new() -> Self { + Self { + legacy: AgentsDiscoverRequest { + project_paths: None, + exclude_host_agents: None, + }, + agent_directories: None, + } + } + + /// Optional list of project directory paths to scan for project-scoped agents. When omitted or empty, only user/plugin/remote-independent agents are returned (no project scan). + pub fn project_paths(mut self, value: Vec) -> Self { + self.legacy.project_paths = Some(value); + self + } + + /// When true, omit the host's agents (the user-level agent directory and all plugin agents), leaving only project and remote agents. For multitenant deployments. + pub fn exclude_host_agents(mut self, value: bool) -> Self { + self.legacy.exclude_host_agents = Some(value); + self + } + + /// Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without ambient discovery, subject to managed/source disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + pub fn agent_directories(mut self, value: Vec) -> Self { + self.agent_directories = Some(value); + self + } +} + +impl Default for AgentsDiscoverOptions { + fn default() -> Self { + Self::new() + } +} + /// Name of the custom agent to select for subsequent turns. /// ///
@@ -2696,6 +2950,63 @@ pub struct AgentsGetDiscoveryPathsRequest { pub project_paths: Option>, } +/// Extensible [`AgentsGetDiscoveryPathsRequest`], including inputs added after it was published. +/// +/// Required inputs are [`AgentsGetDiscoveryPathsOptions::new`] arguments; optional inputs have fluent setters. +/// Input-only: it serialises to the flat wire request and is not deserialisable. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct AgentsGetDiscoveryPathsOptions { + #[serde(flatten)] + legacy: AgentsGetDiscoveryPathsRequest, + #[serde(skip_serializing_if = "Option::is_none")] + agent_directories: Option>, +} + +impl AgentsGetDiscoveryPathsOptions { + /// Creates options with the required inputs. + pub fn new() -> Self { + Self { + legacy: AgentsGetDiscoveryPathsRequest { + project_paths: None, + exclude_host_agents: None, + }, + agent_directories: None, + } + } + + /// Optional list of project directory paths. When omitted or empty, only the user-level directory is returned. + pub fn project_paths(mut self, value: Vec) -> Self { + self.legacy.project_paths = Some(value); + self + } + + /// When true, omit the host's user-level agent directory, leaving only project directories. For multitenant deployments (mirrors `discover`'s `excludeHostAgents`). + pub fn exclude_host_agents(mut self, value: bool) -> Self { + self.legacy.exclude_host_agents = Some(value); + self + } + + /// Explicit discovery-only agent roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + pub fn agent_directories(mut self, value: Vec) -> Self { + self.agent_directories = Some(value); + self + } +} + +impl Default for AgentsGetDiscoveryPathsOptions { + fn default() -> Self { + Self::new() + } +} + /// Blob attachment with inline base64-encoded data /// ///
@@ -3234,35 +3545,6 @@ pub struct AuthEnumerateValueProviders { pub kind: AuthEnumerateValueProvidersKind, } -/// Credential-free authentication identity safe to expose to hosts and user interfaces. -/// -///
-/// -/// **Experimental.** This type is part of an experimental wire-protocol surface -/// and may change or be removed in future SDK or CLI releases. -/// -///
-#[derive(Debug, Clone, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct AuthIdentity { - /// Snapshot of the authenticated user's Copilot subscription info, if known - #[serde(skip_serializing_if = "Option::is_none")] - pub copilot_user: Option, - /// Name of the environment variable that supplied the credential, when applicable - #[serde(skip_serializing_if = "Option::is_none")] - pub env_var: Option, - /// Authentication host - pub host: String, - /// Authenticated login, when available - #[serde(skip_serializing_if = "Option::is_none")] - pub login: Option, - /// Opaque SDK GitHub credential registration backing this identity. Routing metadata only; never a credential. - #[serde(skip_serializing_if = "Option::is_none")] - pub registration_id: Option, - /// Authentication type - pub r#type: AuthInfoType, -} - /// Credential-free identity metadata. /// ///
@@ -8219,6 +8501,88 @@ pub struct ExternalToolTextResultForLlmContentText { pub r#type: ExternalToolTextResultForLlmContentTextType, } +/// The declared shape of one feature flag, independent of any caller population. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct FeatureFlagMetadata { + /// The population the flag is declared for before any environment or user-settings override is applied. + #[doc(hidden)] + pub(crate) availability: FeatureFlagAvailability, + /// Whether the flag participates in the CAPI sanity suite. + pub capi_sanity: bool, + /// Text shown to a user choosing whether to turn the flag on in experimental mode. Absent when the flag is not user-facing. + #[serde(skip_serializing_if = "Option::is_none")] + pub experimental_description: Option, + /// The online-experiment (ExP) flag this maps to, when the flag is assigned by an experiment rather than declared statically. + #[serde(skip_serializing_if = "Option::is_none")] + pub exp_flag: Option, + /// Environment variable that overrides this flag's experiment assignment locally in the experiment service, not in `featureFlags.resolve`. Present exactly when `expFlag` is, and derived from it, so a caller reads a local override without reproducing the naming rule. + #[serde(skip_serializing_if = "Option::is_none")] + pub exp_flag_env_var: Option, + /// The flag's name, matching the key it is listed under. + pub name: String, +} + +/// Every feature flag this runtime declares, with the shape each one was declared with. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct FeatureFlagsMetadataResult { + /// Declared feature flags keyed by flag name. + #[doc(hidden)] + pub(crate) flags: HashMap, +} + +/// Caller population and overrides for static feature-flag resolution, independent of experiment assignments and active runtime state. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct FeatureFlagsResolveRequest { + /// Resolve against this already-computed flag set rather than each flag's declared availability. Keyed by flag name. + #[serde(skip_serializing_if = "Option::is_none")] + pub base_flags: Option>, + /// User settings to apply, including `enabledFeatureFlags`, legacy `feature_flags.enabled`, and supported convenience settings. + #[serde(skip_serializing_if = "Option::is_none")] + pub config: Option, + /// Environment for direct feature-flag overrides and `COPILOT_CLI_ENABLED_FEATURE_FLAGS`. Does not apply `COPILOT_EXP_*` experiment assignments. Defaults to this runtime process's own environment. + #[serde(skip_serializing_if = "Option::is_none")] + pub environment: Option>, + /// Flags forced to a value after every other layer, keyed by flag name. + #[serde(skip_serializing_if = "Option::is_none")] + pub flag_overrides: Option>, + /// Whether the caller is in an experimental population. + pub is_experimental: bool, + /// Whether the caller is GitHub or Microsoft staff. + pub is_staff: bool, + /// GitHub-staff membership. Omit when it was never recorded: a legacy staff account then counts as both staff populations and keeps every staff feature. + #[serde(skip_serializing_if = "Option::is_none")] + pub is_staff_github: Option, + /// Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. + #[serde(skip_serializing_if = "Option::is_none")] + pub is_staff_microsoft: Option, + /// Whether the caller belongs to the team population used by feature availability. + pub is_team: bool, +} + /// Parameters for starting fleet orchestration: an optional user prompt combined with the fleet instructions, plus the send options forwarded to the resulting turn. /// ///
@@ -9295,6 +9659,63 @@ pub struct HooksDiscoverRequest { pub project_paths: Option>, } +/// Extensible [`HooksDiscoverRequest`], including inputs added after it was published. +/// +/// Required inputs are [`HooksDiscoverOptions::new`] arguments; optional inputs have fluent setters. +/// Input-only: it serialises to the flat wire request and is not deserialisable. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct HooksDiscoverOptions { + #[serde(flatten)] + legacy: HooksDiscoverRequest, + #[serde(skip_serializing_if = "Option::is_none")] + hook_directories: Option>, +} + +impl HooksDiscoverOptions { + /// Creates options with the required inputs. + pub fn new() -> Self { + Self { + legacy: HooksDiscoverRequest { + project_paths: None, + exclude_host_hooks: None, + }, + hook_directories: None, + } + } + + /// Optional project directory paths whose trusted repository and project-expanded plugin hooks should be discovered. When omitted or empty, user, managed-policy, and globally enabled installed or explicit plugin hooks are returned without project expansion. + pub fn project_paths(mut self, value: Vec) -> Self { + self.legacy.project_paths = Some(value); + self + } + + /// When true, omit host-owned user and plugin hook rows and their diagnostics. Managed-policy hooks and trusted repository hooks remain visible, and host disabledHooks still contribute to each remaining row's effective enabled state. This filters sources rather than simulating a host with no settings. + pub fn exclude_host_hooks(mut self, value: bool) -> Self { + self.legacy.exclude_host_hooks = Some(value); + self + } + + /// Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without ambient discovery or repository file-hook enablement, subject to managed/hook disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + pub fn hook_directories(mut self, value: Vec) -> Self { + self.hook_directories = Some(value); + self + } +} + +impl Default for HooksDiscoverOptions { + fn default() -> Self { + Self::new() + } +} + /// Server-discovered hook actions and partial-load diagnostics from user, repository, plugin, and managed-policy sources. Concrete sessions may include additional session-specific hook sources. /// ///
@@ -10643,6 +11064,36 @@ pub struct InstructionDiscoveryPathList { pub paths: Vec, } +/// Explicit discovery arguments for one location, supplied by the caller rather than derived from a session. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct InstructionsDiscoverRepoSourcesRequest { + /// Extra directories to scan alongside instruction directories configured in the runtime environment. + #[serde(skip_serializing_if = "Option::is_none")] + pub additional_dirs: Option>, + /// Copilot configuration directory for user-level sources. An omitted or empty value uses the server's configuration home. + #[serde(skip_serializing_if = "Option::is_none")] + pub config_dir: Option, + /// Working directory whose instruction sources should also be included. Omission adds no separate working-directory scope. + #[serde(skip_serializing_if = "Option::is_none")] + pub cwd_path: Option, + /// When true, also discover instruction files nested below the location. + #[serde(skip_serializing_if = "Option::is_none")] + pub enable_child_instructions: Option, + /// When true, include the sources a command-line host reads. Hosts that are not the CLI omit it. + #[serde(skip_serializing_if = "Option::is_none")] + pub is_cli: Option, + /// Repository location to discover. An empty string selects no repository scope; cwdPath can still supply working-directory sources. + pub location: String, +} + /// Optional project paths to include in instruction discovery. /// ///
@@ -10662,6 +11113,63 @@ pub struct InstructionsDiscoverRequest { pub project_paths: Option>, } +/// Extensible [`InstructionsDiscoverRequest`], including inputs added after it was published. +/// +/// Required inputs are [`InstructionsDiscoverOptions::new`] arguments; optional inputs have fluent setters. +/// Input-only: it serialises to the flat wire request and is not deserialisable. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InstructionsDiscoverOptions { + #[serde(flatten)] + legacy: InstructionsDiscoverRequest, + #[serde(skip_serializing_if = "Option::is_none")] + instruction_directories: Option>, +} + +impl InstructionsDiscoverOptions { + /// Creates options with the required inputs. + pub fn new() -> Self { + Self { + legacy: InstructionsDiscoverRequest { + project_paths: None, + exclude_host_instructions: None, + }, + instruction_directories: None, + } + } + + /// Optional list of project directory paths to scan for repository/working-directory instruction sources. When omitted or empty, only user-level and plugin instruction sources are returned (no project scan). + pub fn project_paths(mut self, value: Vec) -> Self { + self.legacy.project_paths = Some(value); + self + } + + /// When true, omit the host's instruction sources (user/home-level files and plugin rules), leaving only repository and working-directory sources. For multitenant deployments. + pub fn exclude_host_instructions(mut self, value: bool) -> Self { + self.legacy.exclude_host_instructions = Some(value); + self + } + + /// Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without ambient discovery, subject to instruction/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + pub fn instruction_directories(mut self, value: Vec) -> Self { + self.instruction_directories = Some(value); + self + } +} + +impl Default for InstructionsDiscoverOptions { + fn default() -> Self { + Self::new() + } +} + /// Optional project paths to include when enumerating instruction discovery targets. /// ///
@@ -10681,6 +11189,63 @@ pub struct InstructionsGetDiscoveryPathsRequest { pub project_paths: Option>, } +/// Extensible [`InstructionsGetDiscoveryPathsRequest`], including inputs added after it was published. +/// +/// Required inputs are [`InstructionsGetDiscoveryPathsOptions::new`] arguments; optional inputs have fluent setters. +/// Input-only: it serialises to the flat wire request and is not deserialisable. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InstructionsGetDiscoveryPathsOptions { + #[serde(flatten)] + legacy: InstructionsGetDiscoveryPathsRequest, + #[serde(skip_serializing_if = "Option::is_none")] + instruction_directories: Option>, +} + +impl InstructionsGetDiscoveryPathsOptions { + /// Creates options with the required inputs. + pub fn new() -> Self { + Self { + legacy: InstructionsGetDiscoveryPathsRequest { + project_paths: None, + exclude_host_instructions: None, + }, + instruction_directories: None, + } + } + + /// Optional list of project directory paths. When omitted or empty, only the user-level targets are returned. + pub fn project_paths(mut self, value: Vec) -> Self { + self.legacy.project_paths = Some(value); + self + } + + /// When true, omit the host's user-level instruction targets, leaving only repository targets. For multitenant deployments (mirrors `discover`'s `excludeHostInstructions`). + pub fn exclude_host_instructions(mut self, value: bool) -> Self { + self.legacy.exclude_host_instructions = Some(value); + self + } + + /// Explicit discovery-only instruction roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + pub fn instruction_directories(mut self, value: Vec) -> Self { + self.instruction_directories = Some(value); + self + } +} + +impl Default for InstructionsGetDiscoveryPathsOptions { + fn default() -> Self { + Self::new() + } +} + /// Loaded instruction source for a session, including path, content, category, location, applicability, and optional description. /// ///
@@ -10733,6 +11298,21 @@ pub struct InstructionsGetSourcesResult { pub sources: Vec, } +/// The prompt the init command runs. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct InstructionsInitPromptResult { + /// Prompt text authoring repository instructions. + pub prompt: String, +} + /// Parameters for interrupting the main agent turn. /// ///
@@ -13010,6 +13590,21 @@ pub struct McpIsServerRunningResult { pub running: bool, } +/// Names of the MCP servers the runtime supplies itself. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct McpListBuiltinServerNamesResult { + /// Every built-in server name. A host disabling the built-ins wholesale suppresses exactly this set. + pub names: Vec, +} + /// Server name whose tool list should be returned. /// ///
@@ -15988,6 +16583,55 @@ pub(crate) struct ModelClearStartupSeedResult { pub cleared: bool, } +/// Host presentation state the reasoning-summaries policy depends on. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ModelGetReasoningSummariesRequest { + /// The host's persisted `showReasoning` user setting, omitted when unset. + #[serde(skip_serializing_if = "Option::is_none")] + pub persisted_show_reasoning: Option, + /// Whether the host is currently showing reasoning summaries. Defaults to false. + #[serde(skip_serializing_if = "Option::is_none")] + pub summaries_visible: Option, +} + +/// Reasoning-summaries presentation policy for the session's current model. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ModelGetReasoningSummariesResult { + /// Whether the supplied `persistedShowReasoning` setting only restates the model default. This reports a redundancy, not a standing instruction to delete the setting: it stays true for as long as the setting and the model default agree, including for a user who later chose that value deliberately. It exists for a one-time migration of a legacy setting written before the model default made it redundant, so a host that acts on it owns the cleanup and must gate it behind its own persisted `done` marker, delete only a setting whose value still matches the one it read, and never repeat the deletion on a later launch. Under an off-by-default reasoning-summaries experiment an explicit `showReasoning: true` opt-in also reads as redundant on a summary-producing model, so an ungated host would keep deleting that opt-in and hide summaries again on every launch. + pub clear_redundant_setting: bool, + /// Whether the session's reasoning-summaries experiment assignment has settled. False means this read does not wait for a pending assignment and reports the experiment-derived fields conservatively: `showHiddenHint` is false and `visibility` falls back to `persistedShowReasoning`, or is omitted when none was supplied. A host that wants the assigned answer re-reads until this is true. + pub experiment_settled: bool, + /// Whether the selected model shows reasoning summaries by default. + pub model_default_shows_summaries: bool, + /// False until the session has a model catalog and a selected model. This read never resolves the catalog itself, and the runtime emits no readiness notification, so repeating this call alone leaves `ready` false indefinitely on a session that has neither listed models nor run a turn. `session.model.list` is the prerequisite and the signal: it resolves and caches the catalog for the session, so a successful return means the next read is ready. The exception is a session that resolves models without a Copilot catalog, that is a BYOK registry or an alternate provider: `session.model.list` returns an empty list without caching a catalog, so `ready` stays false and this policy is unavailable there. While false, every model-policy field is false and `visibility` is omitted; `experimentSettled` is independent of readiness and still reports the assignment state. + pub ready: bool, + /// Whether turns on this session produce reasoning summaries, honouring an explicit session reasoning-summary override. + pub session_shows_summaries: bool, + /// Whether to show the hint that reasoning summaries are hidden. Always false while `experimentSettled` is false. + pub show_hidden_hint: bool, + /// Whether the selected model emits reasoning headers. + pub show_reasoning_headers: bool, + /// Default reasoning visibility, and only meaningful once `ready` is true: false when the session produces no summaries, else the persisted setting, else the experiment's default. While `ready` is true it is omitted only when all three are unavailable, that is when the session produces summaries, no `persistedShowReasoning` was supplied, and `experimentSettled` is false. While `ready` is false there is no model policy to report and this field is always omitted, so an absent value alone does not imply a pending experiment. + #[serde(skip_serializing_if = "Option::is_none")] + pub visibility: Option, +} + /// List of Copilot models available to the resolved user, including capabilities and billing metadata. /// ///
@@ -21095,6 +21739,84 @@ pub struct RemoteSessionRepository { pub owner: String, } +/// Which repository settings file to read. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct RepoSettingsReadRawRequest { + /// Absolute path of the repository root. + pub repo_root: String, + /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + pub scope: String, +} + +/// Parsed repository settings without normalization or layering. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct RepoSettingsReadRawResult { + /// Stored JSON values after the existing JSONC parser and prototype-safety checks. Empty when the file is missing, blank, or invalid. + pub config: serde_json::Value, + /// True when the file exists but did not parse, so `config` is empty for that reason rather than because nothing is set. + pub invalid: bool, +} + +/// The complete set of repository-overridable settings to store. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct RepoSettingsWriteAllRequest { + /// Absolute path of the repository root. + pub repo_root: String, + /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + pub scope: String, + /// Object of allowed settings to store. Missing allowlisted keys are removed. Other input keys are ignored, while unknown stored keys are preserved. + pub settings: serde_json::Value, +} + +/// One key to write or remove in a repository settings file. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct RepoSettingsWriteKeyRequest { + /// True to remove the key instead of writing it. + #[serde(skip_serializing_if = "Option::is_none")] + pub delete: Option, + /// Canonical top-level key permitted by the repository settings allowlist. + pub key: String, + /// Absolute path of the repository root. + pub repo_root: String, + /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + pub scope: String, + /// Value to validate and write. Required unless delete is true; a null value is validated, not treated as deletion. + #[serde(skip_serializing_if = "Option::is_none")] + pub value: Option, +} + /// Provider-native structured output format. JSON Schema is forwarded without rewriting or validating the schema or the generated output. /// ///
@@ -23606,6 +24328,9 @@ pub struct SessionOpenOptions { /// Runtime context discriminator for agent filtering. #[serde(skip_serializing_if = "Option::is_none")] pub agent_context: Option, + /// Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + #[serde(skip_serializing_if = "Option::is_none")] + pub agent_directories: Option>, /// Whether to include instructions from every MCP server in the system prompt instead of only allowlisted servers. #[serde(skip_serializing_if = "Option::is_none")] pub allow_all_mcp_server_instructions: Option, @@ -23686,7 +24411,7 @@ pub struct SessionOpenOptions { /// Whether shell-script safety heuristics are enabled. #[serde(skip_serializing_if = "Option::is_none")] pub enable_script_safety: Option, - /// Whether skill loading is enabled. When omitted, an SDK skill provider enables skills by default. + /// Whether skill loading is enabled. When omitted, explicit SDK skill roots or an SDK skill provider enable skills independently of enableConfigDiscovery. #[serde(skip_serializing_if = "Option::is_none")] pub enable_skills: Option, /// Whether model responses stream as delta events. @@ -23728,6 +24453,9 @@ pub struct SessionOpenOptions { #[doc(hidden)] #[serde(skip_serializing_if = "Option::is_none")] pub(crate) has_skill_provider: Option, + /// Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without enableConfigDiscovery or enableFileHooks, which controls repository-origin hooks only; hook/managed disables still apply. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + #[serde(skip_serializing_if = "Option::is_none")] + pub hook_directories: Option>, /// Skill scan directories and descendants excluded from discovery. Supports `~`-relative paths. #[serde(skip_serializing_if = "Option::is_none")] pub ignored_skills_locations: Option>, @@ -23740,6 +24468,9 @@ pub struct SessionOpenOptions { /// Installed plugins visible to the session. #[serde(skip_serializing_if = "Option::is_none")] pub installed_plugins: Option>, + /// Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without enableConfigDiscovery, subject to instruction/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + #[serde(skip_serializing_if = "Option::is_none")] + pub instruction_directories: Option>, /// Stable integration identifier for analytics. #[serde(skip_serializing_if = "Option::is_none")] pub integration_id: Option, @@ -23857,7 +24588,7 @@ pub struct SessionOpenOptions { /// PowerShell process flags applied to built-in and user-requested shell commands. #[serde(skip_serializing_if = "Option::is_none")] pub shell_process_flags: Option>, - /// Additional directories to search for skills. + /// Explicit discovery-only skill roots, not filesystem grants. Available without enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. #[serde(skip_serializing_if = "Option::is_none")] pub skill_directories: Option>, /// Whether to skip custom instruction sources. @@ -25479,6 +26210,9 @@ pub struct SessionUpdateOptionsParams { /// Runtime context discriminator (e.g., `cli`, `actions`). #[serde(skip_serializing_if = "Option::is_none")] pub agent_context: Option, + /// Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + #[serde(skip_serializing_if = "Option::is_none")] + pub agent_directories: Option>, /// Whether to include instructions from every MCP server in the system prompt instead of only allowlisted servers. #[serde(skip_serializing_if = "Option::is_none")] pub allow_all_mcp_server_instructions: Option, @@ -25515,7 +26249,7 @@ pub struct SessionUpdateOptionsParams { /// Skill IDs that should be excluded from this session. #[serde(skip_serializing_if = "Option::is_none")] pub disabled_skills: Option>, - /// Whether to enable loading of `.github/hooks/` filesystem hooks. Separate from the SDK callback hook mechanism. + /// Whether to enable repository-origin file hooks from `.github/hooks/` and trusted repository-configured roots. Does not control explicit hookDirectories or SDK callback hooks. #[serde(skip_serializing_if = "Option::is_none")] pub enable_file_hooks: Option, /// Whether to enable host git operations (context resolution, child repo scanning, git info in system prompt). @@ -25533,7 +26267,7 @@ pub struct SessionUpdateOptionsParams { /// Whether to enable cross-session store writes and reads. #[serde(skip_serializing_if = "Option::is_none")] pub enable_session_store: Option, - /// Whether skill loading is enabled. Explicit false disables every source, including a bound SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless an SDK skill provider is registered. + /// Whether skill loading is enabled. Explicit false disables every source, including explicit SDK roots and a bound SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless explicit SDK skill roots or an SDK skill provider are supplied. #[serde(skip_serializing_if = "Option::is_none")] pub enable_skills: Option, /// Whether to stream model responses. @@ -25557,6 +26291,9 @@ pub struct SessionUpdateOptionsParams { /// Map of feature-flag IDs to their boolean enabled state. #[serde(skip_serializing_if = "Option::is_none")] pub feature_flags: Option>, + /// Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without enableConfigDiscovery or enableFileHooks, which controls repository-origin hooks only; hook/managed disables still apply. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + #[serde(skip_serializing_if = "Option::is_none")] + pub hook_directories: Option>, /// Skill scan directories and descendants excluded from discovery. Supports `~`-relative paths. #[serde(skip_serializing_if = "Option::is_none")] pub ignored_skills_locations: Option>, @@ -25569,6 +26306,9 @@ pub struct SessionUpdateOptionsParams { /// Full set of installed plugins for the session. Replaces the existing list; the runtime invalidates the skills cache only when the list materially changes. #[serde(skip_serializing_if = "Option::is_none")] pub installed_plugins: Option>, + /// Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without enableConfigDiscovery, subject to instruction/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + #[serde(skip_serializing_if = "Option::is_none")] + pub instruction_directories: Option>, /// Stable integration identifier used for analytics and rate-limit attribution. #[serde(skip_serializing_if = "Option::is_none")] pub integration_id: Option, @@ -25638,7 +26378,7 @@ pub struct SessionUpdateOptionsParams { /// PowerShell process flags applied to built-in and user-requested shell commands. #[serde(skip_serializing_if = "Option::is_none")] pub shell_process_flags: Option>, - /// Additional directories to search for skills. + /// Explicit discovery-only skill roots, not filesystem grants. Available without enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. #[serde(skip_serializing_if = "Option::is_none")] pub skill_directories: Option>, /// Whether to skip loading custom instruction sources. @@ -25682,6 +26422,22 @@ pub struct SessionUpdateOptionsResult { pub success: bool, } +/// Outcome of an atomic user or repository settings edit. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct SettingsEditResult { + /// Changed, unchanged or invalid existing file. Rejected input, validation failures and I/O errors remain RPC errors. + #[doc(hidden)] + pub(crate) status: SettingsEditStatus, +} + /// User-requested shell execution cancellation handle. /// ///
@@ -26446,7 +27202,7 @@ pub struct SkillsDiscoverRequest { /// Optional list of project directory paths to scan for project-scoped skills #[serde(skip_serializing_if = "Option::is_none")] pub project_paths: Option>, - /// Optional list of additional skill directory paths to include + /// Explicit discovery-only skill roots, not filesystem grants. Available without ambient discovery, subject to skill/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. #[serde(skip_serializing_if = "Option::is_none")] pub skill_directories: Option>, } @@ -26509,6 +27265,70 @@ pub struct SkillsGetDiscoveryPathsRequest { pub project_paths: Option>, } +/// Extensible [`SkillsGetDiscoveryPathsRequest`], including inputs added after it was published. +/// +/// Required inputs are [`SkillsGetDiscoveryPathsOptions::new`] arguments; optional inputs have fluent setters. +/// Input-only: it serialises to the flat wire request and is not deserialisable. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SkillsGetDiscoveryPathsOptions { + #[serde(flatten)] + legacy: SkillsGetDiscoveryPathsRequest, + #[serde(skip_serializing_if = "Option::is_none")] + skill_directories: Option>, +} + +impl SkillsGetDiscoveryPathsOptions { + /// Creates options with the required inputs. + pub fn new() -> Self { + Self { + legacy: SkillsGetDiscoveryPathsRequest { + project_paths: None, + ignored_skills_locations: None, + exclude_host_skills: None, + }, + skill_directories: None, + } + } + + /// Optional list of project directory paths. When omitted or empty, only personal and custom directories are returned. + pub fn project_paths(mut self, value: Vec) -> Self { + self.legacy.project_paths = Some(value); + self + } + + /// Optional skill scan paths to exclude from discovery. + pub fn ignored_skills_locations(mut self, value: Vec) -> Self { + self.legacy.ignored_skills_locations = Some(value); + self + } + + /// When true, omit the host's personal and custom skill directories, leaving only project directories. For multitenant deployments. + pub fn exclude_host_skills(mut self, value: bool) -> Self { + self.legacy.exclude_host_skills = Some(value); + self + } + + /// Explicit discovery-only skill roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + pub fn skill_directories(mut self, value: Vec) -> Self { + self.skill_directories = Some(value); + self + } +} + +impl Default for SkillsGetDiscoveryPathsOptions { + fn default() -> Self { + Self::new() + } +} + /// Skill invocation record with name, path, content, allowed tools, and turn number. /// ///
@@ -28787,6 +29607,131 @@ pub struct UserSettingMetadata { pub value: serde_json::Value, } +/// A single top-level setting subtree to validate and write. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsApplyTopKeyRequest { + /// Canonical path of the setting the caller is editing. Currently informational only. + pub canonical_path: Vec, + /// Records that the user chose an update channel explicitly, so the one-time staff channel migration stops reapplying. Honored only for the `autoUpdatesChannel` key. + #[serde(skip_serializing_if = "Option::is_none")] + pub complete_staff_update_channel_migration: Option, + /// True to remove the top-level key instead of writing it. + #[serde(skip_serializing_if = "Option::is_none")] + pub delete: Option, + /// Top-level setting name to write. + pub top_key: String, + /// Value to write for the whole top-level key. Omitted when `delete` is true. Explicit null is preserved and validated as null. + #[serde(skip_serializing_if = "Option::is_none")] + pub value: Option, +} + +/// One problem found while validating a setting value. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsValidationIssue { + /// Human-readable description of the problem. + pub message: String, + /// Where in the settings tree the problem sits, as object keys and array indices. The first element is the top-level key; a whole-value problem is reported as that single key. + pub path: Vec, +} + +/// Outcome of validating and writing one top-level setting subtree. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsApplyTopKeyResult { + /// Why the write failed, present only when `status` is `write-error`. + #[serde(skip_serializing_if = "Option::is_none")] + pub error: Option, + /// Problems found, present only when `status` is `validation-error`. + #[serde(skip_serializing_if = "Option::is_none")] + pub issues: Option>, + /// `ok` when the value was written, `validation-error` when it was rejected before any write, `write-error` when validation passed but the write failed. + pub status: String, +} + +/// One atomic edit of a canonical setting in settings.json. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsEditRequest { + /// Nonempty canonical path segments of the setting to edit, starting with its top-level key. + pub canonical_path: Vec, + /// Configuration directory to edit. Omitted or empty resolves the server's own home, as in `user.settings.loadForConfigDir`. + #[serde(skip_serializing_if = "Option::is_none")] + pub config_dir: Option, + /// Set a scalar, add or remove a string list item, or remove the setting. The handler rejects a missing or incompatible value. + #[doc(hidden)] + pub(crate) operation: SettingsEditOperation, + /// Required boolean, string or number for set, required string for add-item and remove-item, and forbidden for remove. The runtime rejects all other JSON values. + #[serde(skip_serializing_if = "Option::is_none")] + pub value: Option, +} + +/// Selects which settings file paths to resolve. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsGetPathsRequest { + /// Absolute path of a repository root. Supply it to also resolve that repository's two settings file paths; omit it to resolve only the user path. + #[serde(skip_serializing_if = "Option::is_none")] + pub repo_root: Option, +} + +/// On-disk locations of the settings files this runtime reads. A path is reported whether or not the file exists. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsGetPathsResult { + /// The repository's local, untracked settings file, or null when no repository root was supplied. + #[serde(skip_serializing_if = "Option::is_none")] + pub repo_local_settings: Option, + /// The repository's checked-in settings file, or null when no repository root was supplied. + #[serde(skip_serializing_if = "Option::is_none")] + pub repo_settings: Option, + /// The user settings file: `settings.json` under the resolved Copilot home. This is the file `user.settings.get`, `user.settings.load`, and `user.settings.set` read and write. + pub user_settings: String, +} + /// Per-key metadata for every known user setting in settings.json, including settings left at their default. Excludes repository- and enterprise-managed overrides. /// ///
@@ -28802,6 +29747,175 @@ pub struct UserSettingsGetResult { pub settings: HashMap, } +/// Top-level user-setting keys grouped by who may govern them. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsGovernanceKeysResult { + /// Top-level keys a repository may override through a Claude-compatible repository config. + pub claude_repo: Vec, + /// Top-level keys an enterprise policy may fix through managed settings. + pub managed: Vec, + /// Top-level keys a repository may override through `.github/copilot/settings.json` or `.github/copilot/settings.local.json`. + pub repo: Vec, +} + +/// Contents of settings.json as stored, for a caller about to rewrite it. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsLoadForEditResult { + /// Parsed contents, present only when `status` is `ok`. + #[serde(skip_serializing_if = "Option::is_none")] + pub settings: Option, + /// `ok` when the file parsed, `missing` when there is no file yet, `invalid` when the file exists but will not parse. + pub status: String, +} + +/// Settings object whose key names should be canonicalized. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsNormalizeRequest { + /// Free-form settings object, possibly using legacy or snake_case key names. + pub settings: serde_json::Value, +} + +/// Settings object with canonical key names. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsNormalizeResult { + /// The same settings with every legacy or snake_case key renamed to its canonical spelling. + pub settings: serde_json::Value, +} + +/// The settings layer a problem was found in. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsProblemLocation { + /// Absolute path of the file backing this layer. + pub file_path: String, + /// Which layer this is: `user`, `repo`, or `local`. + pub kind: String, + /// The caller-supplied display label for the layer. + pub label: String, +} + +/// One setting that will not take effect, and why. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsProblem { + /// Coarse grouping for the problem, for a caller that presents problems in sections. + pub category: String, + /// Why the setting will not take effect. Never contains the setting's value, which may be a token or another secret. + pub explanation: String, + /// Stable identifier for this problem within the reported set, so a caller can track a selection across refreshes. + pub id: String, + /// What is wrong in machine-readable form, for a caller that wants to branch rather than display. + pub kind: String, + /// The offending key as written in the file, when the problem is attributable to a single key. Absent when the whole file is at fault. + #[serde(skip_serializing_if = "Option::is_none")] + pub raw_key: Option, + /// The settings layer the problem was found in. + pub source: UserSettingsProblemLocation, +} + +/// One already-loaded settings layer to diagnose. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsProblemSource { + /// The layer's settings exactly as loaded, unnormalized. Empty when the file is missing or failed to parse. + #[serde(skip_serializing_if = "Option::is_none")] + pub config: Option>, + /// Absolute path of the file backing this layer. + pub file_path: String, + /// True when the file itself failed to parse, so its keys could not be read at all. + #[serde(skip_serializing_if = "Option::is_none")] + pub invalid: Option, + /// Which layer this is: `user`, `repo`, or `local`. + pub kind: String, + /// Caller-chosen display label for the layer, echoed back on each problem so a caller can group by layer without re-deriving its own naming. + pub label: String, +} + +/// The settings layers to diagnose. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsProblemsRequest { + /// Layers to diagnose, in the precedence order the caller applies them. + #[serde(skip_serializing_if = "Option::is_none")] + pub sources: Option>, +} + +/// The settings that will not take effect across the given layers. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsProblemsResult { + /// Each setting that will not take effect, and why. Empty when every layer is healthy. + #[serde(skip_serializing_if = "Option::is_none")] + pub problems: Option>, +} + /// Partial user settings to write to settings.json. Each top-level key is written individually, replacing the existing value; a key whose value is null is removed. /// ///
@@ -28817,6 +29931,98 @@ pub struct UserSettingsSetRequest { pub settings: serde_json::Value, } +/// Names the user setting to merge into, and the partial object to merge. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsUpdateRequest { + /// Copilot configuration directory to write the settings document in, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to use the directory the server resolved for itself. + #[serde(skip_serializing_if = "Option::is_none")] + pub config_dir: Option, + /// Top-level user-setting key to merge into, such as `extensions`. + pub key: String, + /// Single-component name for the settings document at `/settings/.json`; path separators, `.` and `..` are rejected. Omit it, or pass an empty string, to use the main settings document. + #[serde(skip_serializing_if = "Option::is_none")] + pub sub_dir: Option, + /// Value to store for `key`. When both the stored value and this value are objects, their fields are shallow-merged and fields this object does not name are preserved. Otherwise this value replaces the stored value. + pub value: serde_json::Value, +} + +/// The stored value of the user setting after the merge. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsUpdateResult { + /// The key's stored value after the write: the merged object when both the stored value and the supplied value are objects, otherwise the supplied value. + pub value: serde_json::Value, +} + +/// A single top-level setting subtree to validate. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsValidateRequest { + /// True to validate a removal of this key. The current settings file is not read. + #[serde(skip_serializing_if = "Option::is_none")] + pub delete: Option, + /// Top-level setting name to validate. + pub top_key: String, + /// Value to validate. Omitted when `delete` is true. + #[serde(skip_serializing_if = "Option::is_none")] + pub value: Option, +} + +/// Outcome of validating one top-level setting subtree. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsValidateResult { + /// Problems found, empty when `ok` is true. + #[serde(skip_serializing_if = "Option::is_none")] + pub issues: Option>, + /// True when the subtree is valid. + pub ok: bool, +} + +/// The whole content to store in the user settings file. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsWriteAllRequest { + /// The settings object to store. It replaces the file's entire content, so a key absent here is removed. + pub settings: serde_json::Value, +} + /// Current sharing status and shareable GitHub URL for a session. /// ///
@@ -30778,6 +31984,66 @@ pub struct ExtensionsDiscoverResult { pub mode: DiscoveredExtensionMode, } +/// The prompt the init command runs. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct InstructionsGetInitPromptResult { + /// Prompt text authoring repository instructions. + pub prompt: String, +} + +/// Instruction sources discovered across user, repository, and plugin sources. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct InstructionsDiscoverResult { + /// All discovered instruction sources + pub sources: Vec, +} + +/// Instruction sources discovered across user, repository, and plugin sources. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct InstructionsDiscoverRepoSourcesResult { + /// All discovered instruction sources + pub sources: Vec, +} + +/// Canonical files and directories where custom instructions can be created so the runtime will recognize them. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct InstructionsGetDiscoveryPathsResult { + /// Canonical instruction create/discovery files and directories, in priority order + pub paths: Vec, +} + /// Skills discovered across global and project sources. /// ///
@@ -30996,36 +32262,6 @@ pub struct AgentsGetDiscoveryPathsResult { pub paths: Vec, } -/// Instruction sources discovered across user, repository, and plugin sources. -/// -///
-/// -/// **Experimental.** This type is part of an experimental wire-protocol surface -/// and may change or be removed in future SDK or CLI releases. -/// -///
-#[derive(Debug, Clone, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct InstructionsDiscoverResult { - /// All discovered instruction sources - pub sources: Vec, -} - -/// Canonical files and directories where custom instructions can be created so the runtime will recognize them. -/// -///
-/// -/// **Experimental.** This type is part of an experimental wire-protocol surface -/// and may change or be removed in future SDK or CLI releases. -/// -///
-#[derive(Debug, Clone, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct InstructionsGetDiscoveryPathsResult { - /// Canonical instruction create/discovery files and directories, in priority order - pub paths: Vec, -} - /// The host's machine-wide state. Every field is optional because a fresh install has recorded nothing yet, so a reader must treat an absent field as `not yet`, never as a negative answer. Stored credentials are deliberately absent from this shape. /// ///
@@ -31113,6 +32349,73 @@ pub struct CommandsListResult { pub commands: Vec, } +/// Top-level user-setting keys grouped by who may govern them. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsListGovernanceKeysResult { + /// Top-level keys a repository may override through a Claude-compatible repository config. + pub claude_repo: Vec, + /// Top-level keys an enterprise policy may fix through managed settings. + pub managed: Vec, + /// Top-level keys a repository may override through `.github/copilot/settings.json` or `.github/copilot/settings.local.json`. + pub repo: Vec, +} + +/// Outcome of an atomic user or repository settings edit. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsEditResult { + /// Changed, unchanged or invalid existing file. Rejected input, validation failures and I/O errors remain RPC errors. + #[doc(hidden)] + pub(crate) status: SettingsEditStatus, +} + +/// The settings that will not take effect across the given layers. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsDiagnoseProblemsResult { + /// Each setting that will not take effect, and why. Empty when every layer is healthy. + #[serde(skip_serializing_if = "Option::is_none")] + pub problems: Option>, +} + +/// Every feature flag this runtime declares, with the shape each one was declared with. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct FeatureFlagsListMetadataResult { + /// Declared feature flags keyed by flag name. + #[doc(hidden)] + pub(crate) flags: HashMap, +} + /// A freshly registered request id. Registering it before the listing starts is what lets a cancel that races the request still find the owner listing slot. The id serves one listing only. Long-abandoned unused ids can be released by later allocations. /// ///
@@ -32781,6 +34084,36 @@ pub struct SessionModelSetReasoningEffortResult { pub reasoning_effort: String, } +/// Reasoning-summaries presentation policy for the session's current model. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SessionModelGetReasoningSummariesResult { + /// Whether the supplied `persistedShowReasoning` setting only restates the model default. This reports a redundancy, not a standing instruction to delete the setting: it stays true for as long as the setting and the model default agree, including for a user who later chose that value deliberately. It exists for a one-time migration of a legacy setting written before the model default made it redundant, so a host that acts on it owns the cleanup and must gate it behind its own persisted `done` marker, delete only a setting whose value still matches the one it read, and never repeat the deletion on a later launch. Under an off-by-default reasoning-summaries experiment an explicit `showReasoning: true` opt-in also reads as redundant on a summary-producing model, so an ungated host would keep deleting that opt-in and hide summaries again on every launch. + pub clear_redundant_setting: bool, + /// Whether the session's reasoning-summaries experiment assignment has settled. False means this read does not wait for a pending assignment and reports the experiment-derived fields conservatively: `showHiddenHint` is false and `visibility` falls back to `persistedShowReasoning`, or is omitted when none was supplied. A host that wants the assigned answer re-reads until this is true. + pub experiment_settled: bool, + /// Whether the selected model shows reasoning summaries by default. + pub model_default_shows_summaries: bool, + /// False until the session has a model catalog and a selected model. This read never resolves the catalog itself, and the runtime emits no readiness notification, so repeating this call alone leaves `ready` false indefinitely on a session that has neither listed models nor run a turn. `session.model.list` is the prerequisite and the signal: it resolves and caches the catalog for the session, so a successful return means the next read is ready. The exception is a session that resolves models without a Copilot catalog, that is a BYOK registry or an alternate provider: `session.model.list` returns an empty list without caching a catalog, so `ready` stays false and this policy is unavailable there. While false, every model-policy field is false and `visibility` is omitted; `experimentSettled` is independent of readiness and still reports the assignment state. + pub ready: bool, + /// Whether turns on this session produce reasoning summaries, honouring an explicit session reasoning-summary override. + pub session_shows_summaries: bool, + /// Whether to show the hint that reasoning summaries are hidden. Always false while `experimentSettled` is false. + pub show_hidden_hint: bool, + /// Whether the selected model emits reasoning headers. + pub show_reasoning_headers: bool, + /// Default reasoning visibility, and only meaningful once `ready` is true: false when the session produces no summaries, else the persisted setting, else the experiment's default. While `ready` is true it is omitted only when all three are unavailable, that is when the session produces summaries, no `persistedShowReasoning` was supplied, and `experimentSettled` is false. While `ready` is false there is no model policy to report and this field is always omitted, so an absent value alone does not imply a pending experiment. + #[serde(skip_serializing_if = "Option::is_none")] + pub visibility: Option, +} + /// The list of models available to this session. /// ///
@@ -38312,6 +39645,16 @@ pub type UIElicitationResponseContent = HashMap; ///
pub type AccountGetAllUsersResult = Vec; +/// The resolved feature flags, keyed by flag name. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+pub type FeatureFlagsResolveResult = HashMap; + /// The number of running background agents (task-registry agents) that were cancelled. /// ///
@@ -38527,6 +39870,49 @@ pub enum AuthInfo { ApiKey(ApiKeyAuthInfo), } +/// Authentication type +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum AuthInfoType { + /// Authentication provided by a GitHub App HMAC credential. + #[serde(rename = "hmac")] + Hmac, + /// Authentication resolved from environment-provided credentials. + #[serde(rename = "env")] + Env, + /// Authentication from an interactive user sign-in. + #[serde(rename = "user")] + User, + /// Authentication from a selected provider-owned account, without a GitHub credential. + #[serde(rename = "account")] + Account, + /// Authentication delegated to the GitHub CLI. + #[serde(rename = "gh-cli")] + GhCli, + /// Authentication from an API key credential. + #[serde(rename = "api-key")] + ApiKey, + /// Authentication from a GitHub token. + #[serde(rename = "token")] + Token, + /// Authentication from an SDK GitHub token callback. + #[serde(rename = "token-provider")] + TokenProvider, + /// Authentication from a Copilot API token. + #[serde(rename = "copilot-api-token")] + CopilotApiToken, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + /// The provider kind stamped on a signed-in account. /// ///
@@ -39210,49 +40596,6 @@ pub enum AuthEnumerateValue { Providers(AuthEnumerateValueProviders), } -/// Authentication type -/// -///
-/// -/// **Experimental.** This type is part of an experimental wire-protocol surface -/// and may change or be removed in future SDK or CLI releases. -/// -///
-#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] -pub enum AuthInfoType { - /// Authentication provided by a GitHub App HMAC credential. - #[serde(rename = "hmac")] - Hmac, - /// Authentication resolved from environment-provided credentials. - #[serde(rename = "env")] - Env, - /// Authentication from an interactive user sign-in. - #[serde(rename = "user")] - User, - /// Authentication from a selected provider-owned account, without a GitHub credential. - #[serde(rename = "account")] - Account, - /// Authentication delegated to the GitHub CLI. - #[serde(rename = "gh-cli")] - GhCli, - /// Authentication from an API key credential. - #[serde(rename = "api-key")] - ApiKey, - /// Authentication from a GitHub token. - #[serde(rename = "token")] - Token, - /// Authentication from an SDK GitHub token callback. - #[serde(rename = "token-provider")] - TokenProvider, - /// Authentication from a Copilot API token. - #[serde(rename = "copilot-api-token")] - CopilotApiToken, - /// Unknown variant for forward compatibility. - #[default] - #[serde(other)] - Unknown, -} - /// Login flow step variant discriminator. #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] pub enum AuthLoginStepOpenUrlKind { @@ -41989,6 +43332,49 @@ pub enum ExternalToolTextResultForLlmContentTextType { Text, } +/// The population a feature flag is declared for, before overrides. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum FeatureFlagAvailability { + /// Enabled for everyone, before any override. + #[serde(rename = "on")] + On, + /// Enabled only for accounts on the owning team. + #[serde(rename = "team")] + Team, + /// Enabled only for staff accounts that have also opted into experimental features. + #[serde(rename = "staff-and-experimental")] + StaffAndExperimental, + /// Enabled for staff accounts and for accounts that opted into experimental features. + #[serde(rename = "staff-or-experimental")] + StaffOrExperimental, + /// Enabled for any staff account, GitHub or Microsoft. + #[serde(rename = "staff")] + Staff, + /// Enabled for GitHub staff accounts only. + #[serde(rename = "staff-github")] + StaffGitHub, + /// Enabled for Microsoft staff accounts only. + #[serde(rename = "staff-microsoft")] + StaffMicrosoft, + /// Enabled only for accounts that opted into experimental features. + #[serde(rename = "experimental")] + Experimental, + /// Disabled for everyone, before any override. + #[serde(rename = "off")] + Off, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + /// Why the runtime is requesting a GitHub credential. #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] pub enum GitHubTokenAcquireReason { @@ -46749,6 +48135,59 @@ pub enum SessionVisibilityStatus { Unknown, } +/// One atomic settings mutation. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum SettingsEditOperation { + /// Set one scalar value. + #[serde(rename = "set")] + Set, + /// Add one string to a list, unless present. + #[serde(rename = "add-item")] + AddItem, + /// Remove one string from a list, unless absent. + #[serde(rename = "remove-item")] + RemoveItem, + /// Remove the setting without supplying a value. + #[serde(rename = "remove")] + Remove, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + +/// Whether one atomic settings edit changed a file. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum SettingsEditStatus { + /// The edit changed the setting and was stored. + #[serde(rename = "changed")] + Changed, + /// The setting already had the requested state. + #[serde(rename = "unchanged")] + Unchanged, + /// The existing settings file could not be edited safely; nothing was written. + #[serde(rename = "invalid")] + Invalid, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + /// Signal to send (default: SIGTERM) /// ///
diff --git a/rust/src/generated/rpc.rs b/rust/src/generated/rpc.rs index e2b69d3933..fccafc3749 100644 --- a/rust/src/generated/rpc.rs +++ b/rust/src/generated/rpc.rs @@ -78,6 +78,13 @@ impl<'a> ClientRpc<'a> { } } + /// `featureFlags.*` sub-namespace. + pub fn feature_flags(&self) -> ClientRpcFeatureFlags<'a> { + ClientRpcFeatureFlags { + client: self.client, + } + } + /// `git.*` sub-namespace. pub fn git(&self) -> ClientRpcGit<'a> { ClientRpcGit { @@ -162,6 +169,13 @@ impl<'a> ClientRpc<'a> { } } + /// `repo.*` sub-namespace. + pub fn repo(&self) -> ClientRpcRepo<'a> { + ClientRpcRepo { + client: self.client, + } + } + /// `runtime.*` sub-namespace. pub fn runtime(&self) -> ClientRpcRuntime<'a> { ClientRpcRuntime { @@ -463,6 +477,123 @@ impl<'a> ClientRpcAccount<'a> { .await?; Ok(serde_json::from_value(_value)?) } + + /// Renders the sign-in banner and the one-line account description the runtime uses for an authentication identity. The runtime words these in several places for its own callers, so a host that announces a sign-in or an account switch should render them from here rather than composing its own, which would let the two spellings drift apart. + /// + /// Wire method: `account.describeAuthInfo`. + /// + /// # Parameters + /// + /// * `params` - The authentication identity whose shared wording should be rendered. + /// + /// # Returns + /// + /// The wording the runtime uses for an authentication identity. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn describe_auth_info( + &self, + params: AccountDescribeAuthInfoRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::ACCOUNT_DESCRIBEAUTHINFO, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Reports whether the supplied identity can create gists. Gists are unavailable on GitHub Enterprise Cloud with data residency, and to Enterprise Managed Users on github.com, so a host that offers gist actions should hide or disable them when this reports no support. + /// + /// Wire method: `account.getGistSupport`. + /// + /// # Parameters + /// + /// * `params` - The authentication identity whose gist support should be reported. + /// + /// # Returns + /// + /// Whether the identity can create gists, and why not when it cannot. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn get_gist_support( + &self, + params: AccountGetGistSupportRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::ACCOUNT_GETGISTSUPPORT, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Resolves a path on the identity's GitHub host into an absolute URL, so a host can link to settings or documentation on the enterprise instance the user is signed in to rather than to github.com. Falls back to the public host when no identity is supplied. + /// + /// Wire method: `account.getWebUrl`. + /// + /// # Parameters + /// + /// * `params` - A path to resolve against the GitHub host an identity is signed in to. + /// + /// # Returns + /// + /// An absolute URL on the identity's GitHub host. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn get_web_url( + &self, + params: AccountGetWebUrlRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::ACCOUNT_GETWEBURL, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Names the environment variable supplying a classic personal access token, if one is set. A classic token cannot be upgraded in place, so a host that finds one should tell the user which variable to unset rather than starting an interactive sign-in that the variable would override. + /// + /// Wire method: `account.getTokenEnvVar`. + /// + /// # Returns + /// + /// The environment variable supplying a classic personal access token, when one is set. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn get_token_env_var(&self) -> Result { + let wire_params = serde_json::json!({}); + let _value = self + .client + .call(rpc_methods::ACCOUNT_GETTOKENENVVAR, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } } /// `agentRegistry.*` RPCs. @@ -539,6 +670,39 @@ impl<'a> ClientRpcAgents<'a> { Ok(serde_json::from_value(_value)?) } + /// Discovers custom agents across user, project, plugin, and remote sources. + /// + /// Wire method: `agents.discover`. + /// + /// # Parameters + /// + /// * `params` - Optional project paths to include in agent discovery. + /// + /// # Returns + /// + /// Agents discovered across user, project, plugin, and remote sources. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ /// + /// Accepts [`AgentsDiscoverOptions`], including inputs added after [`AgentsDiscoverRequest`]. + pub async fn discover_with_options( + &self, + params: AgentsDiscoverOptions, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::AGENTS_DISCOVER, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + /// Returns the canonical directories where a client may create custom agents that the runtime will recognize, including ones that do not exist yet. Project directories become active once created. /// /// Wire method: `agents.getDiscoveryPaths`. @@ -570,6 +734,39 @@ impl<'a> ClientRpcAgents<'a> { Ok(serde_json::from_value(_value)?) } + /// Returns the canonical directories where a client may create custom agents that the runtime will recognize, including ones that do not exist yet. Project directories become active once created. + /// + /// Wire method: `agents.getDiscoveryPaths`. + /// + /// # Parameters + /// + /// * `params` - Optional project paths to include when enumerating agent discovery directories. + /// + /// # Returns + /// + /// Canonical locations where custom agents can be created so the runtime will recognize them. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ /// + /// Accepts [`AgentsGetDiscoveryPathsOptions`], including inputs added after [`AgentsGetDiscoveryPathsRequest`]. + pub async fn get_discovery_paths_with_options( + &self, + params: AgentsGetDiscoveryPathsOptions, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::AGENTS_GETDISCOVERYPATHS, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + /// Lists the agents this runtime ships, by name. A consumer separating shipped agents from ones the user or a plugin authored should compare against these names rather than against `AgentInfo.source`: an authored agent may carry the `builtin` source while not being one of these, and the runtime treats the two as separate questions. `disableableNames` is the subset a user may turn off, which a client needs to decide whether to offer a toggle. `yamlBasedNames` is the subset backed by a shipped YAML definition, which a client needs before asking the runtime to load one. /// /// Wire method: `agents.getBuiltins`. @@ -1156,6 +1353,69 @@ impl<'a> ClientRpcExtensions<'a> { } } +/// `featureFlags.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcFeatureFlags<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcFeatureFlags<'a> { + /// Lists every feature flag this runtime declares, with the population each one is declared for, its experimental description, and the online-experiment flag it maps to. This is the static catalog: it describes how each flag is defined, not whether it is on for anyone. Use `featureFlags.resolve` for static values with caller overrides, not active runtime values or experiment assignments. + /// + /// Wire method: `featureFlags.listMetadata`. + /// + /// # Returns + /// + /// Every feature flag this runtime declares, with the shape each one was declared with. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn list_metadata(&self) -> Result { + let wire_params = serde_json::json!({}); + let _value = self + .client + .call(rpc_methods::FEATUREFLAGS_LISTMETADATA, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Computes static feature flags from the supplied population and overrides without changing runtime state or verifying audience membership. Starts from declared availability, then applies direct feature-flag environment values, user settings, and explicit `flagOverrides`. It does not apply `COPILOT_EXP_*` experiment assignments, authenticated startup gates, or active runtime state. Settings include `enabledFeatureFlags`, the legacy `feature_flags.enabled` list, and supported convenience settings. Supply `baseFlags` to use an existing flag set instead of declared availability. Omit `isStaffGitHub` or `isStaffMicrosoft` when membership was never recorded: a legacy staff account then counts as both populations. + /// + /// Wire method: `featureFlags.resolve`. + /// + /// # Parameters + /// + /// * `params` - Caller population and overrides for static feature-flag resolution, independent of experiment assignments and active runtime state. + /// + /// # Returns + /// + /// The resolved feature flags, keyed by flag name. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn resolve( + &self, + params: FeatureFlagsResolveRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::FEATUREFLAGS_RESOLVE, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } +} + /// `git.*` RPCs. #[derive(Clone, Copy)] pub struct ClientRpcGit<'a> { @@ -1514,6 +1774,39 @@ impl<'a> ClientRpcHooks<'a> { .await?; Ok(serde_json::from_value(_value)?) } + + /// Discovers hook actions enabled under server-side discovery settings from user, repository, plugin, and managed-policy sources. + /// + /// Wire method: `hooks.discover`. + /// + /// # Parameters + /// + /// * `params` - Optional project paths and host-exclusion behavior for server-scoped hook discovery. + /// + /// # Returns + /// + /// Server-discovered hook actions and partial-load diagnostics from user, repository, plugin, and managed-policy sources. Concrete sessions may include additional session-specific hook sources. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ /// + /// Accepts [`HooksDiscoverOptions`], including inputs added after [`HooksDiscoverRequest`]. + pub async fn discover_with_options( + &self, + params: HooksDiscoverOptions, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::HOOKS_DISCOVER, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } } /// `host.*` RPCs. @@ -1825,6 +2118,30 @@ pub struct ClientRpcInstructions<'a> { } impl<'a> ClientRpcInstructions<'a> { + /// Returns the prompt the `init` command runs to author repository instructions. A host offering its own initialize action sends this text so the instructions it produces match the ones the CLI produces. The text is fixed for a build and depends on no configuration, session or repository. + /// + /// Wire method: `instructions.getInitPrompt`. + /// + /// # Returns + /// + /// The prompt the init command runs. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn get_init_prompt(&self) -> Result { + let wire_params = serde_json::json!({}); + let _value = self + .client + .call(rpc_methods::INSTRUCTIONS_GETINITPROMPT, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + /// Discovers instruction sources across user, repository, and plugin sources. /// /// Wire method: `instructions.discover`. @@ -1856,6 +2173,73 @@ impl<'a> ClientRpcInstructions<'a> { Ok(serde_json::from_value(_value)?) } + /// Discovers instruction sources across user, repository, and plugin sources. + /// + /// Wire method: `instructions.discover`. + /// + /// # Parameters + /// + /// * `params` - Optional project paths to include in instruction discovery. + /// + /// # Returns + /// + /// Instruction sources discovered across user, repository, and plugin sources. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ /// + /// Accepts [`InstructionsDiscoverOptions`], including inputs added after [`InstructionsDiscoverRequest`]. + pub async fn discover_with_options( + &self, + params: InstructionsDiscoverOptions, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::INSTRUCTIONS_DISCOVER, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Discovers the instruction sources for one caller-named location and returns them in the order the runtime applies them. `discover` answers for a set of project paths and derives the rest of its scope itself; this one instead takes every argument from the caller — the extra directories to scan and whether to descend into nested instruction files — and honors them as given. It also includes instruction directories from trusted repository settings, matching native repository discovery. Use it when the caller knows its own scope and no session exists to derive that scope from, such as a host reporting how many instruction files a directory contributes before any session starts. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. + /// + /// Wire method: `instructions.discoverRepoSources`. + /// + /// # Parameters + /// + /// * `params` - Explicit discovery arguments for one location, supplied by the caller rather than derived from a session. + /// + /// # Returns + /// + /// Instruction sources discovered across user, repository, and plugin sources. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn discover_repo_sources( + &self, + params: InstructionsDiscoverRepoSourcesRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call( + rpc_methods::INSTRUCTIONS_DISCOVERREPOSOURCES, + Some(wire_params), + ) + .await?; + Ok(serde_json::from_value(_value)?) + } + /// Returns the canonical files and directories where a client may create custom instructions that the runtime will recognize, including ones that do not exist yet. Repository targets become active once created. /// /// Wire method: `instructions.getDiscoveryPaths`. @@ -1889,6 +2273,62 @@ impl<'a> ClientRpcInstructions<'a> { .await?; Ok(serde_json::from_value(_value)?) } + + /// Returns the canonical files and directories where a client may create custom instructions that the runtime will recognize, including ones that do not exist yet. Repository targets become active once created. + /// + /// Wire method: `instructions.getDiscoveryPaths`. + /// + /// # Parameters + /// + /// * `params` - Optional project paths to include when enumerating instruction discovery targets. + /// + /// # Returns + /// + /// Canonical files and directories where custom instructions can be created so the runtime will recognize them. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ /// + /// Accepts [`InstructionsGetDiscoveryPathsOptions`], including inputs added after [`InstructionsGetDiscoveryPathsRequest`]. + pub async fn get_discovery_paths_with_options( + &self, + params: InstructionsGetDiscoveryPathsOptions, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call( + rpc_methods::INSTRUCTIONS_GETDISCOVERYPATHS, + Some(wire_params), + ) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Drops the runtime's in-memory cache of discovered custom instructions so the next discovery reads them from disk again. A host calls this after it changes instruction files, or after it trusts a folder whose instructions an earlier discovery skipped, so that a session started afterwards sees the current files instead of a cached earlier answer. The call performs no I/O of its own and removes nothing from disk; it only invalidates, so the cost lands on the next discovery. Returns once the cache is clear, which is what lets a caller order a session start after it. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. + /// + /// Wire method: `instructions.clearCache`. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn clear_cache(&self) -> Result<(), Error> { + let wire_params = serde_json::json!({}); + let _value = self + .client + .call(rpc_methods::INSTRUCTIONS_CLEARCACHE, Some(wire_params)) + .await?; + Ok(()) + } } /// `llmInference.*` RPCs. @@ -2289,6 +2729,32 @@ impl<'a> ClientRpcMcp<'a> { Ok(serde_json::from_value(_value)?) } + /// Lists the MCP servers the runtime supplies itself, so a host that disables the built-ins wholesale suppresses exactly the set the runtime would otherwise add. The names are fixed for a build and depend on no configuration, session or account. + /// + /// Wire method: `mcp.listBuiltinServerNames`. + /// + /// # Returns + /// + /// Names of the MCP servers the runtime supplies itself. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn list_builtin_server_names( + &self, + ) -> Result { + let wire_params = serde_json::json!({}); + let _value = self + .client + .call(rpc_methods::MCP_LISTBUILTINSERVERNAMES, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + /// Reports whether the gh-replaceable GitHub MCP tools may be clipped for a session, which a host feeds back as the `excludeGhReplaceableTools` build option. The tools are redundant only when the session can reach a shell *and* the host has the `gh` that would replace them, so both halves are decided here. The shell half runs the platform shell tool through the runtime's own tool-filter matcher, so entry forms like `builtin:bash` and `builtin:*` behave exactly as they do when a session builds its tool catalog. The host half probes for `gh`, and is skipped entirely when the filters already rule the shell out. Host presence alone is not enough: a session restricted to, say, `view` would otherwise lose the built-in issue-read fallback while having no shell to replace it with. The answer describes the host the runtime runs on, so it is never forwarded to a remote engine. /// /// Wire method: `mcp.shouldExcludeGitHubTools`. @@ -3407,6 +3873,108 @@ impl<'a> ClientRpcPluginsMarketplaces<'a> { } } +/// `repo.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcRepo<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcRepo<'a> { + /// `repo.settings.*` sub-namespace. + pub fn settings(&self) -> ClientRpcRepoSettings<'a> { + ClientRpcRepoSettings { + client: self.client, + } + } +} + +/// `repo.settings.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcRepoSettings<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcRepoSettings<'a> { + /// Reads one repository settings file without settings normalization or layering. The existing JSONC parser accepts comments and trailing commas and applies its prototype-safety rules. Missing or blank files return an empty valid config. Invalid files return an empty config with invalid=true; other read failures reject. + /// + /// Wire method: `repo.settings.readRaw`. + /// + /// # Parameters + /// + /// * `params` - Which repository settings file to read. + /// + /// # Returns + /// + /// Parsed repository settings without normalization or layering. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn read_raw( + &self, + params: RepoSettingsReadRawRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::REPO_SETTINGS_READRAW, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Writes or removes one allowed top-level repository setting through the existing validator and file lock. Preserves unrelated stored keys. Invalid keys, values, existing documents, and I/O errors reject without replacing the file. Deletion requires delete=true; otherwise value must be present. + /// + /// Wire method: `repo.settings.writeKey`. + /// + /// # Parameters + /// + /// * `params` - One key to write or remove in a repository settings file. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn write_key(&self, params: RepoSettingsWriteKeyRequest) -> Result<(), Error> { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::REPO_SETTINGS_WRITEKEY, Some(wire_params)) + .await?; + Ok(()) + } + + /// Replaces the repository-overridable settings in one locked write. Allowed keys present in settings are validated and written; allowed keys absent from settings are removed. Other input keys are ignored, and unknown keys already stored in the file remain unchanged. Invalid values or an invalid existing file reject without a partial write. + /// + /// Wire method: `repo.settings.writeAll`. + /// + /// # Parameters + /// + /// * `params` - The complete set of repository-overridable settings to store. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn write_all(&self, params: RepoSettingsWriteAllRequest) -> Result<(), Error> { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::REPO_SETTINGS_WRITEALL, Some(wire_params)) + .await?; + Ok(()) + } +} + /// `runtime.*` RPCs. #[derive(Clone, Copy)] pub struct ClientRpcRuntime<'a> { @@ -5027,9 +5595,42 @@ impl<'a> ClientRpcSkills<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn get_discovery_paths( + pub async fn get_discovery_paths( + &self, + params: SkillsGetDiscoveryPathsRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::SKILLS_GETDISCOVERYPATHS, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Returns the canonical directories where a client may create skills that the runtime will recognize, including ones that do not exist yet. Project directories become active once created. + /// + /// Wire method: `skills.getDiscoveryPaths`. + /// + /// # Parameters + /// + /// * `params` - Optional project paths to enumerate. + /// + /// # Returns + /// + /// Canonical locations where skills can be created so the runtime will recognize them. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ /// + /// Accepts [`SkillsGetDiscoveryPathsOptions`], including inputs added after [`SkillsGetDiscoveryPathsRequest`]. + pub async fn get_discovery_paths_with_options( &self, - params: SkillsGetDiscoveryPathsRequest, + params: SkillsGetDiscoveryPathsOptions, ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self @@ -5356,6 +5957,37 @@ impl<'a> ClientRpcUserSettings<'a> { Ok(serde_json::from_value(_value)?) } + /// Resolves the on-disk locations of the settings files this runtime reads, so a consumer can show or open them. The user path is the same file `user.settings.get`, `user.settings.load`, and `user.settings.set` operate on. Supply `repoRoot` to also resolve that repository's checked-in and local settings paths. A path is reported whether or not the file exists. + /// + /// Wire method: `user.settings.getPaths`. + /// + /// # Parameters + /// + /// * `params` - Selects which settings file paths to resolve. + /// + /// # Returns + /// + /// On-disk locations of the settings files this runtime reads. A path is reported whether or not the file exists. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn get_paths( + &self, + params: UserSettingsGetPathsRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::USER_SETTINGS_GETPATHS, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + /// Writes one or more user settings to settings.json, replacing each provided top-level key. A key whose value is null is removed. /// /// Wire method: `user.settings.set`. @@ -5379,6 +6011,272 @@ impl<'a> ClientRpcUserSettings<'a> { .await?; Ok(()) } + + /// Lists the top-level user-setting keys by who is allowed to govern them: `repo` keys a repository may override through `.github/copilot/settings.json`, `claudeRepo` keys a repository may override through a Claude-compatible config, and `managed` keys an enterprise policy may fix. The lists are static for a given runtime build and fail closed: a key absent from a list cannot be governed that way. + /// + /// Wire method: `user.settings.listGovernanceKeys`. + /// + /// # Returns + /// + /// Top-level user-setting keys grouped by who may govern them. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn list_governance_keys( + &self, + ) -> Result { + let wire_params = serde_json::json!({}); + let _value = self + .client + .call( + rpc_methods::USER_SETTINGS_LISTGOVERNANCEKEYS, + Some(wire_params), + ) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Atomically edits one canonical user setting inside its settings-file lock. Reads, canonicalizes touched aliases, applies the edit, validates the resulting top-level setting and writes before releasing the lock. An explicit autoUpdatesChannel set completes the staff migration in the same transaction. Only a malformed existing file returns `invalid`; refused keys, invalid values and I/O errors reject the call. + /// + /// Wire method: `user.settings.edit`. + /// + /// # Parameters + /// + /// * `params` - One atomic edit of a canonical setting in settings.json. + /// + /// # Returns + /// + /// Outcome of an atomic user or repository settings edit. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn edit( + &self, + params: UserSettingsEditRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::USER_SETTINGS_EDIT, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Rewrites legacy and snake_case setting names in a settings object to their canonical spelling. A caller editing settings.json must normalize before writing: a legacy key left in place survives the write, is re-normalized on the next load, and silently shadows the canonical value the write just stored. + /// + /// Wire method: `user.settings.normalize`. + /// + /// # Parameters + /// + /// * `params` - Settings object whose key names should be canonicalized. + /// + /// # Returns + /// + /// Settings object with canonical key names. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn normalize( + &self, + params: UserSettingsNormalizeRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::USER_SETTINGS_NORMALIZE, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Diagnoses a set of already-loaded settings layers, reporting each key that will not take effect and why. Settings load tolerantly so that one bad key does not stop a session from starting; this method surfaces what was dropped so a caller can report it instead of silently ignoring the user's intent. Takes the layers as given rather than reading them, so a caller can diagnose exactly the content it is showing, including unsaved edits. Never echoes a setting's value, because a value may be a token or another secret. Marked internal because it exists to carry a CLI call site off the native addon, not to serve a consumer-facing need; it becomes public once an SDK consumer needs to inspect settings health itself. + /// + /// Wire method: `user.settings.diagnoseProblems`. + /// + /// # Parameters + /// + /// * `params` - The settings layers to diagnose. + /// + /// # Returns + /// + /// The settings that will not take effect across the given layers. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn diagnose_problems( + &self, + params: UserSettingsProblemsRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call( + rpc_methods::USER_SETTINGS_DIAGNOSEPROBLEMS, + Some(wire_params), + ) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Validates one top-level setting subtree and writes just that key to settings.json as a single step. Doing both here closes the race a caller cannot close itself: between a separate preflight read and the write, the file may change. Rewriting only the touched key keeps legacy siblings out of settings.json. Answers a status rather than failing, so a validation problem and a write problem stay distinguishable. + /// + /// Wire method: `user.settings.applyTopKey`. + /// + /// # Parameters + /// + /// * `params` - A single top-level setting subtree to validate and write. + /// + /// # Returns + /// + /// Outcome of validating and writing one top-level setting subtree. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn apply_top_key( + &self, + params: UserSettingsApplyTopKeyRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::USER_SETTINGS_APPLYTOPKEY, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Replaces the user settings file's entire content in one write. A key absent from `settings` is removed, which is what distinguishes this from `user.settings.set`: that one merges, so it can never clear a key the caller has dropped. For a caller saving the result of a raw edit, a merge would silently resurrect every key the user deleted. Records the same one-time mutation marks a per-key write records, so a setting the user has now chosen explicitly stops being migrated for them. + /// + /// Wire method: `user.settings.writeAll`. + /// + /// # Parameters + /// + /// * `params` - The whole content to store in the user settings file. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn write_all(&self, params: UserSettingsWriteAllRequest) -> Result<(), Error> { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::USER_SETTINGS_WRITEALL, Some(wire_params)) + .await?; + Ok(()) + } + + /// Merges a partial object into one top-level user setting, re-reading the stored value inside this runtime process's settings.json write lock so that concurrent writers in this process to different sub-fields of the same key do not clobber each other. Unlike `user.settings.set`, which replaces a key's whole value with what the caller last read, this keeps sub-fields the caller did not name when both the stored value and supplied value are objects; otherwise the supplied value replaces the stored value. Use it whenever two independent surfaces own different sub-fields of one setting. Returns the key's stored value after the write, in `value`. + /// + /// Wire method: `user.settings.update`. + /// + /// # Parameters + /// + /// * `params` - Names the user setting to merge into, and the partial object to merge. + /// + /// # Returns + /// + /// The stored value of the user setting after the merge. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn update( + &self, + params: UserSettingsUpdateRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::USER_SETTINGS_UPDATE, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Reads settings.json as stored for a caller that is about to edit it. Unlike `user.settings.get`, this returns file values rather than per-key metadata and defaults. Reports `missing` for an absent file and `invalid` when the existing file will not parse. Retired config.json and extensionless files are not read. + /// + /// Wire method: `user.settings.loadForEdit`. + /// + /// # Returns + /// + /// Contents of settings.json as stored, for a caller about to rewrite it. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn load_for_edit(&self) -> Result { + let wire_params = serde_json::json!({}); + let _value = self + .client + .call(rpc_methods::USER_SETTINGS_LOADFOREDIT, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Validates one top-level setting subtree without writing it, reporting each problem with the path it applies to. Scoped to a single top-level key on purpose: validating the whole file would reject an edit whenever an unrelated pre-existing field is malformed, locking the user out of the very tool that could fix it. + /// + /// Wire method: `user.settings.validate`. + /// + /// # Parameters + /// + /// * `params` - A single top-level setting subtree to validate. + /// + /// # Returns + /// + /// Outcome of validating one top-level setting subtree. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn validate( + &self, + params: UserSettingsValidateRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::USER_SETTINGS_VALIDATE, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } } /// Typed view over a [`Session`]'s RPC namespace. @@ -11008,6 +11906,42 @@ impl<'a> SessionRpcModel<'a> { Ok(serde_json::from_value(_value)?) } + /// Computes whether the session's current model shows reasoning summaries and how a host should present them: the default Ctrl+T visibility, reasoning headers, the hidden-summaries hint, and whether a persisted `showReasoning` setting is redundant. The runtime folds in the session's model catalog, selection and reasoning-summaries experiment assignment; the host supplies only its own persisted setting and current visibility. This method reads the session's resolved model catalog rather than resolving it, so call `session.model.list` first on a session that has not listed models or run a turn; until then the result is `ready: false`. A session that resolves models without a Copilot catalog, that is a BYOK registry or an alternate provider, never caches one and stays `ready: false`. + /// + /// Wire method: `session.model.getReasoningSummaries`. + /// + /// # Parameters + /// + /// * `params` - Host presentation state the reasoning-summaries policy depends on. + /// + /// # Returns + /// + /// Reasoning-summaries presentation policy for the session's current model. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn get_reasoning_summaries( + &self, + params: ModelGetReasoningSummariesRequest, + ) -> Result { + let mut wire_params = serde_json::to_value(params)?; + wire_params["sessionId"] = serde_json::Value::String(self.session.id().to_string()); + let _value = self + .session + .client() + .call( + rpc_methods::SESSION_MODEL_GETREASONINGSUMMARIES, + Some(wire_params), + ) + .await?; + Ok(serde_json::from_value(_value)?) + } + /// Lists models available to this session using its own auth and integration context. Connected hosts (CLI TUI, GitHub App) should call this through the session client so remote sessions return the remote CLI's available models rather than the caller's. /// /// Wire method: `session.model.list`. diff --git a/rust/src/generated/session_events.rs b/rust/src/generated/session_events.rs index 8d0e4d9b65..13b80797dd 100644 --- a/rust/src/generated/session_events.rs +++ b/rust/src/generated/session_events.rs @@ -1356,13 +1356,19 @@ pub struct SessionErrorData { /// Fine-grained error code from the upstream provider, when available. For `errorType: "rate_limit"`, this is one of the `RateLimitErrorCode` values (e.g., `"user_weekly_rate_limited"`, `"user_global_rate_limited"`, `"rate_limited"`, `"user_model_rate_limited"`, `"integration_rate_limited"`). For `errorType: "quota"`, this is the CAPI quota error code (e.g., `"quota_exceeded"`, `"session_quota_exceeded"`, `"billing_not_configured"`). #[serde(skip_serializing_if = "Option::is_none")] pub error_code: Option, - /// Category of error (e.g., "authentication", "authorization", "quota", "rate_limit", "context_limit", "query") + /// Category of error (e.g., "authentication", "authorization", "policy", "quota", "rate_limit", "context_limit", "query") pub error_type: String, /// Human-readable error message pub message: String, /// GitHub request tracing ID (x-github-request-id header) for correlating with server-side logs #[serde(skip_serializing_if = "Option::is_none")] pub provider_call_id: Option, + /// Sanitized provider-defined error parameter preserved from a structured upstream error envelope, when available. + #[serde(skip_serializing_if = "Option::is_none")] + pub provider_error_param: Option, + /// Provider-defined error type preserved from a structured upstream error envelope, when available (for example, `invalid_request_error`). + #[serde(skip_serializing_if = "Option::is_none")] + pub provider_error_type: Option, /// What the user must do to recover, when the runtime knows of an action. The `message` never names a client affordance, so a client that offers one — a slash command, a settings pane, a link — renders it from this value. #[serde(skip_serializing_if = "Option::is_none")] pub remediation: Option, @@ -2550,6 +2556,9 @@ pub struct CompactionCompleteCompactionTokensUsed { /// Provider captured for the compaction call; absent when attribution is unknown. #[serde(skip_serializing_if = "Option::is_none")] pub provider: Option, + /// Number of model requests represented by this aggregated compaction usage + #[serde(skip_serializing_if = "Option::is_none")] + pub request_count: Option, } /// Original request-level and effective conversation reasoning effort for a provider history boundary; the historical type name is retained for compatibility @@ -2677,6 +2686,12 @@ pub struct PermissionRecoveryData { pub max_attempts: i64, /// Policy selected from the current client's response capability; mode or client changes may update it during recovery pub on_blocked: PermissionRecoveryOnBlocked, + /// Subagent identifier that owns this recovery episode when the request was delegated through a parent permission service + #[serde(skip_serializing_if = "Option::is_none")] + pub owner_agent_id: Option, + /// Root or child execution-session identifier that owns this recovery episode; omitted for legacy snapshots + #[serde(skip_serializing_if = "Option::is_none")] + pub owner_session_id: Option, /// Controlled reason for the latest episode transition pub reason: PermissionRecoveryReason, /// Current lifecycle state of the recovery episode @@ -3110,6 +3125,12 @@ pub struct SessionPermissionRecoveryData { pub max_attempts: i64, /// Policy selected from the current client's response capability; mode or client changes may update it during recovery pub on_blocked: PermissionRecoveryOnBlocked, + /// Subagent identifier that owns this recovery episode when the request was delegated through a parent permission service + #[serde(skip_serializing_if = "Option::is_none")] + pub owner_agent_id: Option, + /// Root or child execution-session identifier that owns this recovery episode; omitted for legacy snapshots + #[serde(skip_serializing_if = "Option::is_none")] + pub owner_session_id: Option, /// Controlled reason for the latest episode transition pub reason: PermissionRecoveryReason, /// Current lifecycle state of the recovery episode @@ -7029,6 +7050,12 @@ pub struct PermissionRequestedData { /// Agent mode captured from the owning turn when permission evaluation began. #[serde(skip_serializing_if = "Option::is_none")] pub agent_mode: Option, + /// Delegated agent that owns permission recovery when the owner session multiplexes remote agents. Absent otherwise. + #[serde(skip_serializing_if = "Option::is_none")] + pub owner_agent_id: Option, + /// Execution session that owns permission recovery for this request. Absent on historical events. + #[serde(skip_serializing_if = "Option::is_none")] + pub owner_session_id: Option, /// Permission mode captured when evaluation began. Absent on historical events. #[serde(skip_serializing_if = "Option::is_none")] pub permission_mode: Option, @@ -8977,6 +9004,9 @@ pub enum RemediationAction { /// Permit outbound network access in the sandbox policy. #[serde(rename = "allow_sandbox_outbound")] AllowSandboxOutbound, + /// Discard conversation history back through the blocked request before continuing. + #[serde(rename = "rewind_conversation")] + RewindConversation, /// Unknown variant for forward compatibility. #[default] #[serde(other)] diff --git a/rust/src/process_tree.rs b/rust/src/process_tree.rs index ef9d3fc62e..238854bcf9 100644 --- a/rust/src/process_tree.rs +++ b/rust/src/process_tree.rs @@ -56,9 +56,11 @@ mod platform { use std::{io, ptr}; use tokio::process::{Child, Command}; - use windows_sys::Win32::Foundation::{CloseHandle, HANDLE, INVALID_HANDLE_VALUE}; - use windows_sys::Win32::System::Diagnostics::ToolHelp::{ - CreateToolhelp32Snapshot, TH32CS_SNAPTHREAD, THREADENTRY32, Thread32First, Thread32Next, + use windows_sys::Win32::Foundation::{CloseHandle, ERROR_NO_MORE_ITEMS, HANDLE}; + use windows_sys::Win32::System::Diagnostics::ProcessSnapshotting::{ + HPSS, HPSSWALK, PSS_CAPTURE_THREADS, PSS_THREAD_ENTRY, PSS_WALK_THREADS, + PssCaptureSnapshot, PssFreeSnapshot, PssWalkMarkerCreate, PssWalkMarkerFree, + PssWalkSnapshot, }; use windows_sys::Win32::System::JobObjects::{ AssignProcessToJobObject, CreateJobObjectW, JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, @@ -66,9 +68,48 @@ mod platform { SetInformationJobObject, TerminateJobObject, }; use windows_sys::Win32::System::Threading::{ - CREATE_NO_WINDOW, CREATE_SUSPENDED, OpenThread, ResumeThread, THREAD_SUSPEND_RESUME, + CREATE_NO_WINDOW, CREATE_SUSPENDED, GetCurrentProcess, GetProcessIdOfThread, OpenThread, + ResumeThread, THREAD_QUERY_LIMITED_INFORMATION, THREAD_SUSPEND_RESUME, }; + #[cfg(test)] + use super::tests::{ + BEFORE_ASSIGNMENT, BEFORE_RESUME, FailurePoint, MARKERS, RESUME_ELAPSED, SNAPSHOTS, + THREADS_EXAMINED, fail_at, + }; + + struct ThreadSnapshot(HPSS); + + impl Drop for ThreadSnapshot { + fn drop(&mut self) { + // SAFETY: this process uniquely owns the local snapshot descriptor. + let status = unsafe { PssFreeSnapshot(GetCurrentProcess(), self.0) }; + if let Err(error) = check_status(status) { + tracing::warn!(%error, "failed to free CLI thread snapshot"); + } + #[cfg(test)] + if status == 0 { + SNAPSHOTS.set((SNAPSHOTS.get().0, SNAPSHOTS.get().1 + 1)); + } + } + } + + struct WalkMarker(HPSSWALK); + + impl Drop for WalkMarker { + fn drop(&mut self) { + // SAFETY: this value uniquely owns a valid walk marker. + let status = unsafe { PssWalkMarkerFree(self.0) }; + if let Err(error) = check_status(status) { + tracing::warn!(%error, "failed to free CLI thread walk marker"); + } + #[cfg(test)] + if status == 0 { + MARKERS.set((MARKERS.get().0, MARKERS.get().1 + 1)); + } + } + } + struct OwnedHandle(HANDLE); // SAFETY: Win32 handles may be used and closed from any thread. @@ -97,13 +138,19 @@ mod platform { match attach_and_resume(&child) { Ok(tree) => Ok((child, tree)), Err(error) => { - let _ = child.start_kill(); + if let Err(kill_error) = child.start_kill() { + tracing::warn!(%kill_error, "failed to terminate suspended CLI child"); + } Err(error) } } } fn attach_and_resume(child: &Child) -> io::Result { + #[cfg(test)] + if let Some(hook) = BEFORE_ASSIGNMENT.with_borrow_mut(Option::take) { + hook(child)?; + } // SAFETY: null security attributes and name create a private, // non-inheritable Job Object. let raw_job = unsafe { CreateJobObjectW(ptr::null(), ptr::null()) }; @@ -138,50 +185,122 @@ mod platform { return Err(io::Error::last_os_error()); } - resume_initial_thread(child.id().ok_or_else(|| { - io::Error::new(io::ErrorKind::NotFound, "CLI exited before thread resume") - })?)?; + #[cfg(test)] + if let Some(hook) = BEFORE_RESUME.with_borrow_mut(Option::take) { + hook(child, job.0)?; + } + #[cfg(test)] + let resume_start = std::time::Instant::now(); + let result = resume_initial_thread( + process.cast(), + child.id().ok_or_else(|| { + io::Error::new(io::ErrorKind::NotFound, "CLI exited before thread resume") + })?, + ); + #[cfg(test)] + RESUME_ELAPSED.set(resume_start.elapsed()); + result?; Ok(Tree { job }) } - fn resume_initial_thread(pid: u32) -> io::Result<()> { - // SAFETY: the returned snapshot handle is owned and closed below. - let snapshot = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0) }; - if snapshot == INVALID_HANDLE_VALUE { - return Err(io::Error::last_os_error()); + pub(super) fn check_status(status: u32) -> io::Result<()> { + if status == 0 { + Ok(()) + } else { + Err(io::Error::from_raw_os_error(status as i32)) } - let snapshot = OwnedHandle(snapshot); - let mut entry = THREADENTRY32 { - dwSize: size_of::() as u32, - ..Default::default() - }; - - // SAFETY: `entry` has the documented size and remains live throughout - // enumeration. - let mut found = unsafe { Thread32First(snapshot.0, &mut entry) } != 0; - while found { - if entry.th32OwnerProcessID == pid { - // SAFETY: the thread id came from the live system snapshot. - let raw_thread = - unsafe { OpenThread(THREAD_SUSPEND_RESUME, 0, entry.th32ThreadID) }; + } + + pub(super) fn resume_initial_thread(process: HANDLE, pid: u32) -> io::Result<()> { + #[cfg(test)] + THREADS_EXAMINED.set(0); + #[cfg(test)] + fail_at(FailurePoint::Capture)?; + let mut snapshot = ptr::null_mut(); + // SAFETY: the suspended child owns the live process handle throughout + // capture and resume. Only its thread information is captured. + check_status(unsafe { + PssCaptureSnapshot(process, PSS_CAPTURE_THREADS, 0, &mut snapshot) + })?; + let snapshot = ThreadSnapshot(snapshot); + #[cfg(test)] + SNAPSHOTS.set((SNAPSHOTS.get().0 + 1, SNAPSHOTS.get().1)); + + #[cfg(test)] + fail_at(FailurePoint::Marker)?; + let mut marker = ptr::null_mut(); + // SAFETY: Windows initializes the marker with its default allocator. + check_status(unsafe { PssWalkMarkerCreate(ptr::null(), &mut marker) })?; + let marker = WalkMarker(marker); + #[cfg(test)] + MARKERS.set((MARKERS.get().0 + 1, MARKERS.get().1)); + + loop { + #[cfg(test)] + fail_at(FailurePoint::Walk)?; + let mut entry = PSS_THREAD_ENTRY::default(); + // SAFETY: the aligned entry has the layout and size required by + // PSS_WALK_THREADS; both snapshot and marker remain owned. + let status = unsafe { + PssWalkSnapshot( + snapshot.0, + PSS_WALK_THREADS, + marker.0, + ptr::from_mut(&mut entry).cast(), + size_of::() as u32, + ) + }; + if status == ERROR_NO_MORE_ITEMS { + return Err(io::Error::new( + io::ErrorKind::NotFound, + "CLI initial thread was not found in its process snapshot", + )); + } + check_status(status)?; + #[cfg(test)] + THREADS_EXAMINED.set(THREADS_EXAMINED.get() + 1); + if entry.ProcessId == pid { + #[cfg(test)] + fail_at(FailurePoint::OpenThread)?; + // SAFETY: the thread id came from the child's process snapshot. + let raw_thread = unsafe { + OpenThread( + THREAD_SUSPEND_RESUME | THREAD_QUERY_LIMITED_INFORMATION, + 0, + entry.ThreadId, + ) + }; if raw_thread.is_null() { return Err(io::Error::last_os_error()); } let thread = OwnedHandle(raw_thread); - // SAFETY: this is the root's suspended initial thread. - if unsafe { ResumeThread(thread.0) } == u32::MAX { - return Err(io::Error::last_os_error()); - } - return Ok(()); + return resume_owned_thread(thread.0, pid); } - // SAFETY: same valid snapshot and initialized entry as above. - found = unsafe { Thread32Next(snapshot.0, &mut entry) } != 0; } + } - Err(io::Error::new( - io::ErrorKind::NotFound, - "CLI initial thread was not found", - )) + pub(super) fn resume_owned_thread(thread: HANDLE, pid: u32) -> io::Result<()> { + #[cfg(test)] + fail_at(FailurePoint::QueryThread)?; + // SAFETY: the caller owns this thread handle with limited-query rights. + let owner = unsafe { GetProcessIdOfThread(thread) }; + if owner == 0 { + return Err(io::Error::last_os_error()); + } + if owner != pid { + return Err(io::Error::new( + io::ErrorKind::PermissionDenied, + "CLI initial thread no longer belongs to the spawned process", + )); + } + #[cfg(test)] + fail_at(FailurePoint::Resume)?; + // SAFETY: the open handle's ownership was verified, and the root's + // initial thread remains suspended until Job assignment completes. + if unsafe { ResumeThread(thread) } == u32::MAX { + return Err(io::Error::last_os_error()); + } + Ok(()) } impl Tree { @@ -195,3 +314,6 @@ mod platform { } } } + +#[cfg(all(test, windows, feature = "runtime"))] +mod tests; diff --git a/rust/src/process_tree/tests.rs b/rust/src/process_tree/tests.rs new file mode 100644 index 0000000000..5106081dac --- /dev/null +++ b/rust/src/process_tree/tests.rs @@ -0,0 +1,318 @@ +#![cfg(test)] + +use std::os::windows::io::{AsRawHandle, FromRawHandle, OwnedHandle}; +use std::os::windows::process::CommandExt; +use std::path::{Path, PathBuf}; +use std::sync::Arc; +use std::time::{Duration, Instant}; +use std::{io, ptr}; + +use tokio::process::{Child, Command}; +use windows_sys::Win32::Foundation::{ + DUPLICATE_SAME_ACCESS, DuplicateHandle, ERROR_ACCESS_DENIED, HANDLE, +}; +use windows_sys::Win32::System::JobObjects::IsProcessInJob; +use windows_sys::Win32::System::Threading::{ + GetCurrentProcess, GetCurrentProcessId, GetCurrentThreadId, OpenThread, + THREAD_QUERY_LIMITED_INFORMATION, THREAD_SUSPEND_RESUME, WaitForSingleObject, +}; + +use super::platform::{check_status, resume_initial_thread, resume_owned_thread}; + +#[derive(Clone, Copy, PartialEq)] +pub(super) enum FailurePoint { + Capture, + Marker, + Walk, + OpenThread, + QueryThread, + Resume, +} + +type BeforeAssignment = Box io::Result<()>>; +type BeforeResume = Box io::Result<()>>; + +thread_local! { + pub(super) static THREADS_EXAMINED: std::cell::Cell = const { std::cell::Cell::new(0) }; + pub(super) static RESUME_ELAPSED: std::cell::Cell = + const { std::cell::Cell::new(Duration::ZERO) }; + pub(super) static BEFORE_ASSIGNMENT: std::cell::RefCell> = + const { std::cell::RefCell::new(None) }; + pub(super) static BEFORE_RESUME: std::cell::RefCell> = + const { std::cell::RefCell::new(None) }; + static FAILURE: std::cell::Cell> = + const { std::cell::Cell::new(None) }; + pub(super) static SNAPSHOTS: std::cell::Cell<(u32, u32)> = + const { std::cell::Cell::new((0, 0)) }; + pub(super) static MARKERS: std::cell::Cell<(u32, u32)> = + const { std::cell::Cell::new((0, 0)) }; +} + +pub(super) fn fail_at(point: FailurePoint) -> io::Result<()> { + if FAILURE.get() == Some(point) { + Err(io::Error::from_raw_os_error(ERROR_ACCESS_DENIED as i32)) + } else { + Ok(()) + } +} + +struct ResetHooks; + +impl Drop for ResetHooks { + fn drop(&mut self) { + FAILURE.set(None); + BEFORE_ASSIGNMENT.with_borrow_mut(|hook| *hook = None); + BEFORE_RESUME.with_borrow_mut(|hook| *hook = None); + } +} + +fn command() -> Command { + let mut command = Command::new( + PathBuf::from(std::env::var_os("SystemRoot").expect("SystemRoot")) + .join("System32") + .join("cmd.exe"), + ); + command.args(["/d", "/c"]).kill_on_drop(true); + command +} + +fn marker_command(marker: &Path) -> Command { + let mut command = command(); + command + .as_std_mut() + .raw_arg(format!("echo ready>\"{}\"", marker.display())); + command +} + +fn retain_process(child: &Child) -> OwnedHandle { + let mut handle = ptr::null_mut(); + // SAFETY: the child owns its live process handle; the duplicate is independently owned. + let result = unsafe { + DuplicateHandle( + GetCurrentProcess(), + child.raw_handle().expect("live child").cast(), + GetCurrentProcess(), + &mut handle, + 0, + 0, + DUPLICATE_SAME_ACCESS, + ) + }; + assert_ne!(result, 0, "{}", io::Error::last_os_error()); + // SAFETY: DuplicateHandle returned a new uniquely owned process handle. + unsafe { OwnedHandle::from_raw_handle(handle) } +} + +fn assert_exited(handle: &OwnedHandle) { + // SAFETY: the independently owned process handle remains valid. + assert_eq!( + unsafe { WaitForSingleObject(handle.as_raw_handle().cast(), 5000) }, + 0, + "owned suspended root must terminate" + ); +} + +#[tokio::test] +async fn initial_thread_lookup_is_process_scoped() { + let mut command = command(); + command.args(["exit", "/b", "0"]); + let start = Instant::now(); + let (mut child, tree) = super::spawn(&mut command).expect("spawn owned suspended child"); + let spawn_elapsed = start.elapsed(); + let status = tokio::time::timeout(Duration::from_secs(5), child.wait()) + .await + .expect("initial thread must execute") + .expect("reap child"); + drop(tree); + assert!(status.success()); + eprintln!( + "owned lookup: spawn_ms={:.3} resume_ms={:.3} entries={}", + spawn_elapsed.as_secs_f64() * 1000.0, + RESUME_ELAPSED.get().as_secs_f64() * 1000.0, + THREADS_EXAMINED.get() + ); + assert_eq!( + THREADS_EXAMINED.get(), + 1, + "lookup must not walk unrelated machine-wide threads" + ); +} + +#[tokio::test] +async fn initial_thread_executes_only_after_private_job_assignment() { + let _reset = ResetHooks; + let dir = tempfile::tempdir().expect("fixture directory"); + let marker = dir.path().join("executed.txt"); + BEFORE_ASSIGNMENT.with_borrow_mut(|hook| { + let marker = marker.clone(); + *hook = Some(Box::new(move |_| { + assert!( + !marker.exists(), + "suspended root cannot execute before assignment" + ); + Ok(()) + })); + }); + BEFORE_RESUME.with_borrow_mut(|hook| { + let marker = marker.clone(); + *hook = Some(Box::new(move |child, job| { + assert!( + !marker.exists(), + "suspended initial thread must not have executed" + ); + let mut assigned = 0; + // SAFETY: both handles remain owned throughout the hook. + assert_ne!( + unsafe { + IsProcessInJob( + child.raw_handle().expect("live child").cast(), + job, + &mut assigned, + ) + }, + 0, + "{}", + io::Error::last_os_error() + ); + assert_ne!( + assigned, 0, + "root must belong to its private Job before resume" + ); + Ok(()) + })); + }); + let (mut child, tree) = super::spawn(&mut marker_command(&marker)).expect("owned spawn"); + let status = tokio::time::timeout(Duration::from_secs(5), child.wait()) + .await + .expect("fixture must execute its initial thread") + .expect("reap fixture"); + assert!(status.success()); + assert_eq!( + std::fs::read_to_string(marker) + .expect("executed marker") + .trim(), + "ready" + ); + drop(tree); +} + +#[tokio::test] +async fn lookup_failures_reap_suspended_root_and_release_pss_resources() { + let _reset = ResetHooks; + for point in [ + FailurePoint::Capture, + FailurePoint::Marker, + FailurePoint::Walk, + FailurePoint::OpenThread, + FailurePoint::QueryThread, + FailurePoint::Resume, + ] { + let dir = tempfile::tempdir().expect("fixture directory"); + let marker = dir.path().join("must-not-execute.txt"); + let retained = Arc::new(parking_lot::Mutex::new(None)); + BEFORE_ASSIGNMENT.with_borrow_mut(|hook| { + let retained = retained.clone(); + *hook = Some(Box::new(move |child| { + *retained.lock() = Some(retain_process(child)); + Ok(()) + })); + }); + SNAPSHOTS.set((0, 0)); + MARKERS.set((0, 0)); + FAILURE.set(Some(point)); + let result = super::spawn(&mut marker_command(&marker)); + let error = result.err().expect("injected launch failure"); + assert_eq!(error.raw_os_error(), Some(ERROR_ACCESS_DENIED as i32)); + assert_exited(retained.lock().as_ref().expect("retained suspended root")); + assert!( + !marker.exists(), + "failed lookup must never execute the root" + ); + let snapshots = u32::from(point != FailurePoint::Capture); + let markers = u32::from(point != FailurePoint::Capture && point != FailurePoint::Marker); + assert_eq!(SNAPSHOTS.get(), (snapshots, snapshots)); + assert_eq!(MARKERS.get(), (markers, markers)); + } +} + +#[tokio::test] +async fn pre_assignment_failure_terminates_suspended_root() { + let _reset = ResetHooks; + let dir = tempfile::tempdir().expect("fixture directory"); + let marker = dir.path().join("must-not-execute.txt"); + let retained = Arc::new(parking_lot::Mutex::new(None)); + BEFORE_ASSIGNMENT.with_borrow_mut(|hook| { + let retained = retained.clone(); + *hook = Some(Box::new(move |child| { + *retained.lock() = Some(retain_process(child)); + Err(io::Error::from_raw_os_error(ERROR_ACCESS_DENIED as i32)) + })); + }); + let error = super::spawn(&mut marker_command(&marker)) + .err() + .expect("assignment failure"); + assert_eq!(error.raw_os_error(), Some(ERROR_ACCESS_DENIED as i32)); + assert_exited(retained.lock().as_ref().expect("retained root")); + assert!(!marker.exists()); +} + +#[test] +fn pss_status_uses_returned_win32_error() { + assert!(check_status(0).is_ok()); + assert_eq!( + check_status(ERROR_ACCESS_DENIED) + .expect_err("direct status error") + .raw_os_error(), + Some(ERROR_ACCESS_DENIED as i32) + ); +} + +#[test] +fn invalid_process_capture_returns_error_without_resources() { + let _reset = ResetHooks; + SNAPSHOTS.set((0, 0)); + MARKERS.set((0, 0)); + assert!(resume_initial_thread(ptr::null_mut(), 1).is_err()); + assert_eq!(SNAPSHOTS.get(), (0, 0)); + assert_eq!(MARKERS.get(), (0, 0)); +} + +#[test] +fn foreign_snapshot_entries_cannot_be_resumed() { + let _reset = ResetHooks; + SNAPSHOTS.set((0, 0)); + MARKERS.set((0, 0)); + // SAFETY: the pseudo handle references the current live process. + let error = resume_initial_thread(unsafe { GetCurrentProcess() }, u32::MAX) + .expect_err("no matching owned thread"); + assert_eq!(error.kind(), io::ErrorKind::NotFound); + assert_eq!(SNAPSHOTS.get(), (1, 1)); + assert_eq!(MARKERS.get(), (1, 1)); +} + +#[test] +fn opened_foreign_thread_is_rejected_before_resume() { + let _reset = ResetHooks; + // SAFETY: the thread ID identifies this live test thread. + let handle = unsafe { + OpenThread( + THREAD_QUERY_LIMITED_INFORMATION | THREAD_SUSPEND_RESUME, + 0, + GetCurrentThreadId(), + ) + }; + assert!(!handle.is_null(), "{}", io::Error::last_os_error()); + // SAFETY: OpenThread returned a new uniquely owned handle. + let thread = unsafe { OwnedHandle::from_raw_handle(handle) }; + let error = resume_owned_thread(thread.as_raw_handle().cast(), unsafe { + GetCurrentProcessId().wrapping_add(1) + }) + .expect_err("opened handle belongs to a different process"); + assert_eq!(error.kind(), io::ErrorKind::PermissionDenied); +} + +#[test] +fn invalid_thread_ownership_query_returns_error() { + let _reset = ResetHooks; + assert!(resume_owned_thread(ptr::null_mut(), 1).is_err()); +} diff --git a/rust/src/tests.rs b/rust/src/tests.rs index 8656d6f4d3..bd4d519b87 100644 --- a/rust/src/tests.rs +++ b/rust/src/tests.rs @@ -6,6 +6,61 @@ use super::*; +#[tokio::test] +async fn settings_apply_top_key_preserves_value_presence_on_wire() { + use crate::generated::api_types::UserSettingsApplyTopKeyRequest; + + for (name, value, delete) in [ + ("omitted", None, Some(false)), + ("explicit null", Some(serde_json::Value::Null), None), + ("value", Some(serde_json::json!("chosen")), None), + ("delete", None, Some(true)), + ] { + let temp = tempfile::tempdir().unwrap(); + let (client_stream, server_stream) = tokio::io::duplex(8192); + let (client_read, client_write) = tokio::io::split(client_stream); + let (server_read, server_write) = tokio::io::split(server_stream); + let client = + Client::from_streams(client_read, client_write, temp.path().to_owned()).unwrap(); + let (notifications, _) = tokio::sync::broadcast::channel(1); + let (requests, _) = tokio::sync::mpsc::unbounded_channel(); + let server = + jsonrpc::JsonRpcClient::new(server_write, server_read, notifications, requests); + let (captured, mut received) = tokio::sync::mpsc::unbounded_channel(); + server + .register_request_handler( + "user.settings.applyTopKey", + Arc::new(move |params| { + captured.send(params).unwrap(); + Box::pin(async { Ok(serde_json::json!({ "status": "ok" })) }) + }), + ) + .unwrap(); + + let result = tokio::time::timeout( + Duration::from_secs(5), + client + .rpc() + .user() + .settings() + .apply_top_key(UserSettingsApplyTopKeyRequest { + canonical_path: vec!["model".to_owned()], + top_key: "model".to_owned(), + value: value.clone(), + delete, + complete_staff_update_channel_migration: None, + }), + ) + .await; + client.force_stop(); + server.force_close(); + + result.expect(name).expect(name); + let params = received.try_recv().expect(name); + assert_eq!(params.get("value"), value.as_ref(), "{name}: {params}"); + } +} + #[test] fn is_transport_failure_matches_request_cancelled() { let err = Error::from(ErrorKind::Protocol(ProtocolErrorKind::RequestCancelled)); diff --git a/rust/src/types.rs b/rust/src/types.rs index 9917693110..8f027e56dd 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -667,6 +667,9 @@ impl Serialize for CommandDefinition { #[serde(rename_all = "camelCase")] #[non_exhaustive] pub struct CustomAgentConfig { + /// Declarative hook action objects keyed by event name, active only for this agent. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub hooks: Option>>>, /// Unique name of the custom agent. pub name: String, /// Display name for UI purposes. @@ -704,6 +707,12 @@ pub struct CustomAgentConfig { } impl CustomAgentConfig { + /// Set declarative hook action objects scoped to this agent. + pub fn with_hooks(mut self, hooks: IndexMap>>) -> Self { + self.hooks = Some(hooks); + self + } + /// Construct a custom agent configuration with the required `name` /// and `prompt` fields populated. /// @@ -2053,6 +2062,13 @@ pub enum AskUserVariant { pub struct SessionConfig { /// Custom session ID. When unset, the CLI generates one. pub session_id: Option, + /// Name the session at creation, as `session.name.set` would, and validated + /// the same way: non-empty, no leading or trailing whitespace, at most 100 + /// UTF-16 units, no control characters, and no double quotes. A name also + /// makes the session persist from the start, so it can be listed and resumed + /// even if it never runs a turn. Local sessions only: cloud creation rejects + /// it. + pub name: Option, /// Model to use (e.g. `"gpt-4"`, `"claude-sonnet-4"`). pub model: Option, /// Exact model IDs this session may use. When unset, the host imposes no @@ -2158,7 +2174,8 @@ pub struct SessionConfig { pub refresh_custom_instructions: Option, /// When true, enables on-demand instruction discovery for this session. pub enable_on_demand_instruction_discovery: Option, - /// When true, enables file hooks for this session. + /// Enables repository-origin file hooks from `.github/hooks/` and trusted + /// repository-configured roots, not explicit `hook_directories` or callback hooks. pub enable_file_hooks: Option, /// When true, allows host Git operations for this session. pub enable_host_git_operations: Option, @@ -2205,10 +2222,30 @@ pub struct SessionConfig { /// `disable_form_deferral` only applies to that server and only has an /// effect when MCP Apps and form-backed GitHub tools are enabled. pub github_mcp_tool_config: Option, - /// Skill directory paths passed through to the GitHub Copilot CLI. + /// Explicit discovery-only skill roots, not general filesystem grants. + /// Available without `enable_config_discovery`, subject to skill/managed disables. + /// Relative paths resolve once when supplied against the request's effective + /// `working_directory`; retained roots do not move on cwd changes. + /// `None` and omission are equivalent; an empty list clears only the explicit SDK contribution. pub skill_directories: Option>, - /// Additional directories to search for custom instruction files. - /// Forwarded to the CLI; not the same as [`skill_directories`](Self::skill_directories). + /// Explicit discovery-only agent roots, separate from `custom_agents` objects. + /// No general filesystem grant. Available without `enable_config_discovery`, + /// subject to source/managed disables. Relative paths resolve once when supplied + /// against the request's effective `working_directory`; retained roots do not move. + /// `None` and omission are equivalent; an empty list clears only the explicit SDK contribution. + pub agent_directories: Option>, + /// Explicit discovery-only file-hook roots, separate from callback `hooks`. + /// No general filesystem grant. Available without `enable_config_discovery` or + /// `enable_file_hooks` (repository-origin hooks only), subject to hook/managed disables. + /// Relative paths resolve once when supplied against the request's effective + /// `working_directory`; retained roots do not move on cwd changes. + /// `None` and omission are equivalent; an empty list clears only the explicit SDK contribution. + pub hook_directories: Option>, + /// Explicit discovery-only instruction roots using existing SDK formats. + /// No general filesystem grant. Available without `enable_config_discovery`, + /// subject to instruction/managed disables. Relative paths resolve once when supplied + /// against the request's effective `working_directory`; retained roots do not move. + /// `None` and omission are equivalent; an empty list clears only the explicit SDK contribution. pub instruction_directories: Option>, /// Open Plugin directory paths passed through to the CLI. pub plugin_directories: Option>, @@ -2443,6 +2480,7 @@ impl std::fmt::Debug for SessionConfig { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("SessionConfig") .field("session_id", &self.session_id) + .field("name", &self.name) .field("model", &self.model) .field("allowed_models", &self.allowed_models) .field("client_name", &self.client_name) @@ -2505,6 +2543,8 @@ impl std::fmt::Debug for SessionConfig { ) .field("enable_mcp_apps", &self.enable_mcp_apps) .field("skill_directories", &self.skill_directories) + .field("agent_directories", &self.agent_directories) + .field("hook_directories", &self.hook_directories) .field("instruction_directories", &self.instruction_directories) .field("plugin_directories", &self.plugin_directories) .field("large_output", &self.large_output) @@ -2605,6 +2645,7 @@ impl Default for SessionConfig { fn default() -> Self { Self { session_id: None, + name: None, model: None, allowed_models: None, client_name: None, @@ -2644,6 +2685,8 @@ impl Default for SessionConfig { enable_mcp_apps: None, github_mcp_tool_config: None, skill_directories: None, + agent_directories: None, + hook_directories: None, instruction_directories: None, plugin_directories: None, large_output: None, @@ -2772,6 +2815,7 @@ impl SessionConfig { let wire = crate::wire::SessionCreateWire { session_id, + name: self.name, model: self.model, allowed_models: self.allowed_models, client_name: self.client_name, @@ -2817,6 +2861,8 @@ impl SessionConfig { github_mcp_tool_config: self.github_mcp_tool_config, hooks: hooks_flag, skill_directories: self.skill_directories, + agent_directories: self.agent_directories, + hook_directories: self.hook_directories, instruction_directories: self.instruction_directories, plugin_directories: self.plugin_directories, large_output: self.large_output, @@ -2998,6 +3044,15 @@ impl SessionConfig { self } + /// Set [`Self::name`]. The runtime rejects a name that is empty, padded with + /// whitespace, longer than 100 UTF-16 units, or contains control characters + /// or double quotes, so `create_session` fails rather than creating an + /// unnamed or unrenameable session. + pub fn with_name(mut self, name: impl Into) -> Self { + self.name = Some(name.into()); + self + } + /// Set the model identifier (e.g. `"claude-sonnet-4"`). pub fn with_model(mut self, model: impl Into) -> Self { self.model = Some(model.into()); @@ -3268,6 +3323,26 @@ impl SessionConfig { self } + /// Set explicit discovery-only agent roots. See [`Self::agent_directories`]. + pub fn with_agent_directories(mut self, paths: I) -> Self + where + I: IntoIterator, + P: Into, + { + self.agent_directories = Some(paths.into_iter().map(Into::into).collect()); + self + } + + /// Set explicit discovery-only file-hook roots. See [`Self::hook_directories`]. + pub fn with_hook_directories(mut self, paths: I) -> Self + where + I: IntoIterator, + P: Into, + { + self.hook_directories = Some(paths.into_iter().map(Into::into).collect()); + self + } + /// Set the runtime-bundled skill allowlist. pub fn with_included_builtin_skills(mut self, names: I) -> Self where @@ -3694,7 +3769,8 @@ pub struct ResumeSessionConfig { pub organization_custom_instructions: Option, /// When true, enables on-demand instruction discovery on resume. pub enable_on_demand_instruction_discovery: Option, - /// When true, enables file hooks on resume. + /// Enables repository-origin file hooks from `.github/hooks/` and trusted + /// repository-configured roots, not explicit `hook_directories` or callback hooks. pub enable_file_hooks: Option, /// When true, allows host Git operations on resume. pub enable_host_git_operations: Option, @@ -3718,10 +3794,30 @@ pub struct ResumeSessionConfig { /// `disable_form_deferral` only applies to that server and only has an /// effect when MCP Apps and form-backed GitHub tools are enabled. pub github_mcp_tool_config: Option, - /// Skill directory paths passed through to the GitHub Copilot CLI on resume. + /// Explicit discovery-only skill roots, not general filesystem grants. + /// Available without `enable_config_discovery`, subject to skill/managed disables. + /// Relative paths resolve once when supplied against the request's effective + /// `working_directory`; retained roots do not move on cwd changes. + /// `None` and omission are equivalent; an empty list clears only the explicit SDK contribution. pub skill_directories: Option>, - /// Additional directories to search for custom instruction files on - /// resume. Forwarded to the CLI; not the same as [`skill_directories`](Self::skill_directories). + /// Explicit discovery-only agent roots, separate from `custom_agents` objects. + /// No general filesystem grant. Available without `enable_config_discovery`, + /// subject to source/managed disables. Relative paths resolve once when supplied + /// against the request's effective `working_directory`; retained roots do not move. + /// `None` and omission are equivalent; an empty list clears only the explicit SDK contribution. + pub agent_directories: Option>, + /// Explicit discovery-only file-hook roots, separate from callback `hooks`. + /// No general filesystem grant. Available without `enable_config_discovery` or + /// `enable_file_hooks` (repository-origin hooks only), subject to hook/managed disables. + /// Relative paths resolve once when supplied against the request's effective + /// `working_directory`; retained roots do not move on cwd changes. + /// `None` and omission are equivalent; an empty list clears only the explicit SDK contribution. + pub hook_directories: Option>, + /// Explicit discovery-only instruction roots using existing SDK formats. + /// No general filesystem grant. Available without `enable_config_discovery`, + /// subject to instruction/managed disables. Relative paths resolve once when supplied + /// against the request's effective `working_directory`; retained roots do not move. + /// `None` and omission are equivalent; an empty list clears only the explicit SDK contribution. pub instruction_directories: Option>, /// Open Plugin directory paths passed through to the CLI on resume. pub plugin_directories: Option>, @@ -3959,6 +4055,8 @@ impl std::fmt::Debug for ResumeSessionConfig { ) .field("enable_mcp_apps", &self.enable_mcp_apps) .field("skill_directories", &self.skill_directories) + .field("agent_directories", &self.agent_directories) + .field("hook_directories", &self.hook_directories) .field("instruction_directories", &self.instruction_directories) .field("plugin_directories", &self.plugin_directories) .field("large_output", &self.large_output) @@ -4135,6 +4233,8 @@ impl ResumeSessionConfig { github_mcp_tool_config: self.github_mcp_tool_config, hooks: hooks_flag, skill_directories: self.skill_directories, + agent_directories: self.agent_directories, + hook_directories: self.hook_directories, instruction_directories: self.instruction_directories, plugin_directories: self.plugin_directories, large_output: self.large_output, @@ -4245,6 +4345,8 @@ impl ResumeSessionConfig { enable_mcp_apps: None, github_mcp_tool_config: None, skill_directories: None, + agent_directories: None, + hook_directories: None, instruction_directories: None, plugin_directories: None, large_output: None, @@ -4669,6 +4771,26 @@ impl ResumeSessionConfig { self } + /// Set explicit discovery-only agent roots. See [`Self::agent_directories`]. + pub fn with_agent_directories(mut self, paths: I) -> Self + where + I: IntoIterator, + P: Into, + { + self.agent_directories = Some(paths.into_iter().map(Into::into).collect()); + self + } + + /// Set explicit discovery-only file-hook roots. See [`Self::hook_directories`]. + pub fn with_hook_directories(mut self, paths: I) -> Self + where + I: IntoIterator, + P: Into, + { + self.hook_directories = Some(paths.into_iter().map(Into::into).collect()); + self + } + /// Set the runtime-bundled skill allowlist on resume. pub fn with_included_builtin_skills(mut self, names: I) -> Self where @@ -6575,6 +6697,9 @@ impl Default for ExitPlanModeData { } } +#[cfg(test)] +mod customization_directory_tests; + #[cfg(test)] mod tests; diff --git a/rust/src/types/customization_directory_tests.rs b/rust/src/types/customization_directory_tests.rs new file mode 100644 index 0000000000..67a5dadf15 --- /dev/null +++ b/rust/src/types/customization_directory_tests.rs @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. + +#![cfg(test)] + +use std::path::PathBuf; + +use serde_json::{Value, json}; + +use super::{ResumeSessionConfig, SessionConfig, SessionId}; + +fn assert_roots(wire: &Value, roots: Option<&[PathBuf]>) { + for (key, kind) in [ + ("skillDirectories", "skills"), + ("agentDirectories", "agents"), + ("instructionDirectories", "instructions"), + ("hookDirectories", "hooks"), + ] { + match roots { + Some(paths) => assert_eq!( + wire[key], + serde_json::to_value(paths.iter().map(|path| path.join(kind)).collect::>()) + .unwrap() + ), + None => assert!(wire.get(key).is_none(), "unexpected {key}: {wire}"), + } + } + assert!(wire.get("additionalDirectories").is_none()); + assert!(wire.get("customAgents").is_none()); + assert_eq!(wire["hooks"], false); + assert_eq!(wire["enableFileHooks"], false); + assert_eq!(wire["enableConfigDiscovery"], false); +} + +#[test] +fn create_and_resume_preserve_discovery_roots_without_client_rebasing() { + for roots in [ + None, + Some(Vec::new()), + Some(vec![ + PathBuf::from("relative-root"), + PathBuf::from("other-root"), + ]), + ] { + let mut create = SessionConfig::default() + .with_working_directory("request-cwd") + .with_enable_config_discovery(false) + .with_enable_file_hooks(false); + let mut resume = ResumeSessionConfig::new(SessionId::from("resumed")) + .with_working_directory("resume-cwd") + .with_enable_config_discovery(false) + .with_enable_file_hooks(false); + if let Some(paths) = &roots { + create = create + .with_skill_directories(paths.iter().map(|path| path.join("skills"))) + .with_agent_directories(paths.iter().map(|path| path.join("agents"))) + .with_instruction_directories(paths.iter().map(|path| path.join("instructions"))) + .with_hook_directories(paths.iter().map(|path| path.join("hooks"))); + resume = resume + .with_skill_directories(paths.iter().map(|path| path.join("skills"))) + .with_agent_directories(paths.iter().map(|path| path.join("agents"))) + .with_instruction_directories(paths.iter().map(|path| path.join("instructions"))) + .with_hook_directories(paths.iter().map(|path| path.join("hooks"))); + } + let (wire, _) = create.into_wire(None).unwrap(); + assert_roots(&serde_json::to_value(wire).unwrap(), roots.as_deref()); + let (wire, _) = resume.into_wire().unwrap(); + assert_roots(&serde_json::to_value(wire).unwrap(), roots.as_deref()); + } +} + +#[test] +fn host_factory_forwards_agent_and_hook_roots() { + let create = SessionConfig::default() + .with_agent_directories(["relative-agents"]) + .with_hook_directories(Vec::::new()); + let resume = ResumeSessionConfig::new(SessionId::from("resumed")) + .with_agent_directories(["relative-agents"]) + .with_hook_directories(Vec::::new()); + for wire in [ + crate::ahp_host::config_for_host(&create).unwrap(), + crate::ahp_host::resume_config_for_host(&resume).unwrap(), + ] { + assert_eq!(wire["agentDirectories"], json!(["relative-agents"])); + assert_eq!(wire["hookDirectories"], json!([])); + assert!(wire.get("customAgents").is_none()); + assert!(wire.get("hooks").is_none()); + } +} diff --git a/rust/src/types/tests.rs b/rust/src/types/tests.rs index 0749d946bd..451fe35191 100644 --- a/rust/src/types/tests.rs +++ b/rust/src/types/tests.rs @@ -135,6 +135,55 @@ fn custom_agent_config_omits_reasoning_effort_when_none() { assert!(wire.get("reasoningEffort").is_none()); } +#[test] +fn custom_agent_config_hooks_round_trip() { + use indexmap::IndexMap; + + let action: IndexMap = IndexMap::from([ + ("type".into(), json!("command")), + ("bash".into(), json!("echo scoped-hook")), + ("timeoutSec".into(), json!(10)), + ]); + let hooks = IndexMap::from([("preToolUse".into(), vec![action])]); + let agent = CustomAgentConfig::new("hook-agent", "prompt").with_hooks(hooks.clone()); + assert_eq!(agent.hooks.as_ref(), Some(&hooks)); + + let wire = serde_json::to_value(&agent).unwrap(); + assert_eq!( + wire["hooks"], + json!({"preToolUse": [{"type": "command", "bash": "echo scoped-hook", "timeoutSec": 10}]}) + ); + let restored: CustomAgentConfig = serde_json::from_value(wire).unwrap(); + assert_eq!(restored.hooks, Some(hooks)); +} + +#[test] +fn custom_agent_config_hooks_reject_non_object_actions() { + for action in [ + json!(null), + json!(true), + json!(42), + json!("command"), + json!([]), + ] { + let result = serde_json::from_value::(json!({ + "name": "invalid-hook-agent", + "prompt": "prompt", + "hooks": {"preToolUse": [action]} + })); + assert!( + result.is_err(), + "expected non-object hook action {action} to fail, got {result:?}" + ); + } +} + +#[test] +fn custom_agent_config_omits_hooks_when_unset() { + let wire = serde_json::to_value(CustomAgentConfig::new("plain-agent", "prompt")).unwrap(); + assert!(wire.get("hooks").is_none()); +} + #[test] #[should_panic(expected = "tool parameter schema must be a JSON object")] fn tool_with_parameters_panics_on_non_object_value() { diff --git a/rust/src/wire.rs b/rust/src/wire.rs index 32c46bc85f..7c5e2ccbd4 100644 --- a/rust/src/wire.rs +++ b/rust/src/wire.rs @@ -51,6 +51,8 @@ pub(crate) struct SessionCreateWire { #[serde(skip_serializing_if = "Option::is_none")] pub session_id: Option, #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub model: Option, #[serde(skip_serializing_if = "Option::is_none")] pub allowed_models: Option>, @@ -137,6 +139,10 @@ pub(crate) struct SessionCreateWire { #[serde(skip_serializing_if = "Option::is_none")] pub skill_directories: Option>, #[serde(skip_serializing_if = "Option::is_none")] + pub agent_directories: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub hook_directories: Option>, + #[serde(skip_serializing_if = "Option::is_none")] pub instruction_directories: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub plugin_directories: Option>, @@ -311,6 +317,10 @@ pub(crate) struct SessionResumeWire { #[serde(skip_serializing_if = "Option::is_none")] pub skill_directories: Option>, #[serde(skip_serializing_if = "Option::is_none")] + pub agent_directories: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub hook_directories: Option>, + #[serde(skip_serializing_if = "Option::is_none")] pub instruction_directories: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub plugin_directories: Option>, diff --git a/rust/tests/e2e/client_options.rs b/rust/tests/e2e/client_options.rs index c516f84be6..563ae1328b 100644 --- a/rust/tests/e2e/client_options.rs +++ b/rust/tests/e2e/client_options.rs @@ -18,6 +18,10 @@ use serde::Deserialize; use serde_json::{Value, json}; use tempfile::TempDir; +#[cfg(windows)] +#[path = "client_options/windows_process_tree.rs"] +mod windows_process_tree; + #[tokio::test] async fn should_forward_advanced_session_creation_options_to_the_cli() { let fake = FakeCli::new(); @@ -32,6 +36,7 @@ async fn should_forward_advanced_session_creation_options_to_the_cli() { .create_session( SessionConfig::default() .with_session_id("advanced-session-id") + .with_name("advanced session") .with_client_name("rust-sdk-e2e-client") .with_model("claude-sonnet-5") .with_reasoning_effort("low") @@ -95,6 +100,7 @@ async fn should_forward_advanced_session_creation_options_to_the_cli() { params, [ ("sessionId", json!("advanced-session-id")), + ("name", json!("advanced session")), ("clientName", json!("rust-sdk-e2e-client")), ("model", json!("claude-sonnet-5")), ("reasoningEffort", json!("low")), diff --git a/rust/tests/e2e/client_options/windows_process_tree.rs b/rust/tests/e2e/client_options/windows_process_tree.rs new file mode 100644 index 0000000000..36035536ac --- /dev/null +++ b/rust/tests/e2e/client_options/windows_process_tree.rs @@ -0,0 +1,252 @@ +#![cfg(windows)] + +use std::io; +use std::os::windows::io::{AsRawHandle, FromRawHandle, OwnedHandle}; +use std::path::Path; +use std::time::Duration; + +use github_copilot_sdk::{CliProgram, Client, ClientOptions, Transport}; +use windows_sys::Win32::System::Threading::{ + OpenProcess, PROCESS_SYNCHRONIZE, PROCESS_TERMINATE, TerminateProcess, WaitForSingleObject, +}; + +use super::ShutdownCli; + +struct FixtureProcess(OwnedHandle); + +impl FixtureProcess { + fn open(pid: u32) -> Self { + // SAFETY: this PID was published by this test's owned fixture. + let handle = unsafe { OpenProcess(PROCESS_SYNCHRONIZE | PROCESS_TERMINATE, 0, pid) }; + assert!(!handle.is_null(), "{}", io::Error::last_os_error()); + // SAFETY: OpenProcess returned a new independently owned handle. + Self(unsafe { OwnedHandle::from_raw_handle(handle) }) + } + + fn alive(&self) -> bool { + // SAFETY: the retained process handle is valid even after the process exits. + match unsafe { WaitForSingleObject(self.0.as_raw_handle().cast(), 0) } { + 0 => false, + 258 => true, + result => panic!( + "process wait failed ({result}): {}", + io::Error::last_os_error() + ), + } + } + + fn terminate(&self) { + // SAFETY: this handle uniquely identifies a fixture-owned process, not a reused PID. + assert_ne!( + unsafe { TerminateProcess(self.0.as_raw_handle().cast(), 1) }, + 0, + "{}", + io::Error::last_os_error() + ); + } + + async fn assert_exited(&self) { + tokio::time::timeout(Duration::from_secs(5), async { + while self.alive() { + tokio::time::sleep(Duration::from_millis(10)).await; + } + }) + .await + .expect("owned root and descendant must terminate"); + } +} + +impl Drop for FixtureProcess { + fn drop(&mut self) { + // SAFETY: fallback cleanup targets only this fixture's retained process handle. + unsafe { + if WaitForSingleObject(self.0.as_raw_handle().cast(), 0) == 258 { + if TerminateProcess(self.0.as_raw_handle().cast(), 1) == 0 { + eprintln!( + "fixture fallback termination failed: {}", + io::Error::last_os_error() + ); + } + if WaitForSingleObject(self.0.as_raw_handle().cast(), 5000) != 0 { + eprintln!( + "fixture fallback reap failed: {}", + io::Error::last_os_error() + ); + } + } + } + } +} + +fn options(fake: &ShutdownCli, tcp: bool) -> ClientOptions { + let mut options = fake.options(); + options.prefix_args.push("--fixture-descendant".into()); + if tcp { + options.prefix_args.push("--fixture-tcp".into()); + options.transport = Transport::Tcp { + port: 0, + connection_token: None, + }; + } + options +} + +async fn published_pid(path: &Path) -> u32 { + tokio::time::timeout(Duration::from_secs(10), async { + loop { + match std::fs::read_to_string(path) { + Ok(value) => { + if let Ok(pid) = value.trim().parse() { + return pid; + } + } + Err(error) if error.kind() == io::ErrorKind::NotFound => {} + Err(error) => panic!("read fixture PID: {error}"), + } + tokio::time::sleep(Duration::from_millis(10)).await; + } + }) + .await + .expect("fixture must publish its PID") +} + +async fn retain_tree(fake: &ShutdownCli) -> (FixtureProcess, FixtureProcess) { + let root = FixtureProcess::open(published_pid(&fake.pid_file).await); + let descendant_path = fake.pid_file.with_file_name("child.pid.descendant"); + let descendant = FixtureProcess::open(published_pid(&descendant_path).await); + assert!(root.alive()); + assert!(descendant.alive()); + (root, descendant) +} + +#[tokio::test] +async fn stop_force_stop_and_drop_terminate_owned_descendants() { + for tcp in [false, true] { + for action in ["stop", "force_stop", "drop"] { + let fake = ShutdownCli::new("force"); + let client = Client::start(options(&fake, tcp)) + .await + .expect("start fixture CLI"); + let (root, descendant) = retain_tree(&fake).await; + match action { + "stop" => client.stop().await.expect("stop fixture CLI"), + "force_stop" => client.force_stop(), + "drop" => {} + _ => unreachable!(), + } + drop(client); + root.assert_exited().await; + descendant.assert_exited().await; + } + } +} + +#[tokio::test] +async fn cancelled_startup_terminates_root_and_descendant() { + for (tcp, mode) in [ + (false, "connect-stall"), + (true, "connect-stall"), + (true, "port-stall"), + ] { + let fake = ShutdownCli::new(mode); + let starting = tokio::spawn(Client::start(options(&fake, tcp))); + let (root, descendant) = retain_tree(&fake).await; + starting.abort(); + assert!(starting.await.expect_err("cancel startup").is_cancelled()); + root.assert_exited().await; + descendant.assert_exited().await; + } +} + +#[tokio::test] +async fn startup_process_exit_terminates_descendant() { + for tcp in [false, true] { + let fake = ShutdownCli::new("connect-stall"); + let starting = tokio::spawn(Client::start(options(&fake, tcp))); + let (root, descendant) = retain_tree(&fake).await; + root.terminate(); + let result = tokio::time::timeout(Duration::from_secs(5), starting) + .await + .expect("startup failure must be bounded") + .expect("join startup task"); + assert!(result.is_err()); + root.assert_exited().await; + descendant.assert_exited().await; + } +} + +#[tokio::test] +async fn last_clone_drop_is_private_to_its_client_job() { + for tcp in [false, true] { + let first = ShutdownCli::new("force"); + let client = Client::start(options(&first, tcp)) + .await + .expect("start first client"); + let retained_client = client.clone(); + let first_tree = retain_tree(&first).await; + let second = ShutdownCli::new("force"); + let second_client = Client::start(options(&second, tcp)) + .await + .expect("start second client"); + let second_tree = retain_tree(&second).await; + + drop(client); + assert!(first_tree.0.alive()); + assert!(first_tree.1.alive()); + drop(retained_client); + first_tree.0.assert_exited().await; + first_tree.1.assert_exited().await; + assert!(second_tree.0.alive()); + assert!(second_tree.1.alive()); + second_client + .ping(Some("private-job-isolation")) + .await + .expect("other client's Job must remain alive"); + second_client.force_stop(); + second_tree.0.assert_exited().await; + second_tree.1.assert_exited().await; + } +} + +#[tokio::test] +async fn abrupt_host_exit_terminates_root_and_descendant_without_rust_cleanup() { + for tcp in [false, true] { + let fake = ShutdownCli::new("force"); + let options = options(&fake, tcp); + let CliProgram::Path(program) = options.program else { + panic!("fixture uses an explicit program"); + }; + let prefix: Vec<_> = options + .prefix_args + .iter() + .map(|arg| arg.to_str().expect("fixture argument is UTF-8")) + .collect(); + let host_pid_file = fake.dir.path().join("host-cli.pid"); + let mut host = + tokio::process::Command::new(env!("CARGO_BIN_EXE_copilot-host-crash-fixture")) + .env("HOST_CRASH_FIXTURE_PROGRAM", program) + .env( + "HOST_CRASH_FIXTURE_PREFIX_ARGS_JSON", + serde_json::to_string(&prefix).expect("fixture args"), + ) + .env("HOST_CRASH_FIXTURE_CWD", fake.dir.path()) + .env("HOST_CRASH_FIXTURE_ENV_JSON", "[]") + .env("HOST_CRASH_FIXTURE_PID_FILE", &host_pid_file) + .env( + "HOST_CRASH_FIXTURE_TRANSPORT", + if tcp { "tcp" } else { "stdio" }, + ) + .kill_on_drop(true) + .spawn() + .expect("spawn SDK host fixture"); + let reported_root = published_pid(&host_pid_file).await; + assert_eq!(reported_root, published_pid(&fake.pid_file).await); + let (root, descendant) = retain_tree(&fake).await; + tokio::time::timeout(Duration::from_secs(5), host.kill()) + .await + .expect("bound abrupt host termination") + .expect("kill and reap SDK host"); + root.assert_exited().await; + descendant.assert_exited().await; + } +} diff --git a/rust/tests/e2e/session_lifecycle.rs b/rust/tests/e2e/session_lifecycle.rs index 545bb49885..d406297e02 100644 --- a/rust/tests/e2e/session_lifecycle.rs +++ b/rust/tests/e2e/session_lifecycle.rs @@ -1,7 +1,12 @@ +use std::sync::Arc; + +use github_copilot_sdk::ResumeSessionConfig; +use github_copilot_sdk::handler::ApproveAllHandler; use github_copilot_sdk::session_events::SessionEventType; use super::support::{ - assistant_message_content, collect_until_idle, event_types, wait_for_condition, + DEFAULT_TEST_TOKEN, assistant_message_content, collect_until_idle, event_types, + wait_for_condition, }; #[tokio::test] @@ -57,6 +62,75 @@ async fn should_list_created_sessions_after_sending_a_message() { .await; } +#[tokio::test] +async fn should_persist_a_session_named_at_create_without_a_turn() { + // Dedicated context: the persisted name must survive a real CLI restart, and the + // shared group's client is never actually stopped. + super::support::with_dedicated_e2e_context( + "session_lifecycle", + "should_persist_a_session_named_at_create_without_a_turn", + |ctx| { + Box::pin(async move { + ctx.set_default_copilot_user(); + let client = ctx.start_client().await; + let named = client + .create_session( + ctx.approve_all_session_config() + .with_name("Named at create"), + ) + .await + .expect("create named session"); + let named_id = named.id().clone(); + let unnamed = client + .create_session(ctx.approve_all_session_config()) + .await + .expect("create unnamed session"); + let unnamed_id = unnamed.id().clone(); + + let created_name = named.rpc().name().get().await.expect("get name").name; + assert_eq!(created_name.as_deref(), Some("Named at create")); + + named.disconnect().await.expect("disconnect named session"); + unnamed + .disconnect() + .await + .expect("disconnect unnamed session"); + + // Neither session ran a turn: only the create-time name makes one persist. + let listed: std::collections::HashSet<_> = client + .list_sessions(None) + .await + .expect("list sessions") + .into_iter() + .map(|session| session.session_id) + .collect(); + assert!(listed.contains(&named_id), "named session is listed"); + assert!(!listed.contains(&unnamed_id), "unnamed session is not"); + + // Restart the CLI so the resume below reads the name back from disk. + client.stop().await.expect("stop client"); + let cold_client = ctx.start_client().await; + let resumed = cold_client + .resume_session( + ResumeSessionConfig::new(named_id.clone()) + .with_permission_handler(Arc::new(ApproveAllHandler)) + .with_github_token(DEFAULT_TEST_TOKEN), + ) + .await + .expect("resume named session"); + let read = resumed.rpc().name().get().await.expect("get resumed name"); + assert_eq!(read.name.as_deref(), Some("Named at create")); + resumed + .disconnect() + .await + .expect("disconnect resumed session"); + cold_client.stop().await.expect("stop cold client"); + }) + }, + ) + .await; +} + #[tokio::test] async fn should_delete_session_permanently() { super::support::with_shared_e2e_context( diff --git a/rust/tests/e2e/telemetry.rs b/rust/tests/e2e/telemetry.rs index fe83a1e2ea..0d54f31868 100644 --- a/rust/tests/e2e/telemetry.rs +++ b/rust/tests/e2e/telemetry.rs @@ -1,3 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. + use std::sync::Arc; use async_trait::async_trait; @@ -194,12 +196,19 @@ async fn should_export_per_request_subagent_chat_spans() { .iter() .filter(|entry| string_property(entry, "type") == Some("span")) .collect(); - assert!(spans.iter().all(|span| { - span.get("instrumentationScope") - .and_then(|scope| string_property(scope, "name")) - == Some(source_name) - && status_code(span) != Some(2) - })); + for span in &spans { + assert_eq!( + span.get("instrumentationScope") + .and_then(|scope| string_property(scope, "name")), + Some(source_name), + "unexpected instrumentation scope: {span:#}" + ); + assert_ne!( + status_code(span), + Some(2), + "unexpected error span: {span:#}" + ); + } let invocations: Vec<_> = spans .iter() .copied() diff --git a/rust/tests/fixtures/host_crash_fixture.rs b/rust/tests/fixtures/host_crash_fixture.rs index 8c48379001..204b5dbb67 100644 --- a/rust/tests/fixtures/host_crash_fixture.rs +++ b/rust/tests/fixtures/host_crash_fixture.rs @@ -13,6 +13,7 @@ //! on the spawned CLI's environment. //! - `HOST_CRASH_FIXTURE_PID_FILE`: path this process atomically publishes the //! CLI child's OS process id to, once the client finishes starting. +//! - `HOST_CRASH_FIXTURE_TRANSPORT`: optional `stdio` (default) or `tcp`. use std::io::Write; use std::path::PathBuf; @@ -38,13 +39,21 @@ async fn main() { std::env::var("HOST_CRASH_FIXTURE_PID_FILE").expect("HOST_CRASH_FIXTURE_PID_FILE"), ); + let transport = match std::env::var("HOST_CRASH_FIXTURE_TRANSPORT").as_deref() { + Ok("tcp") => Transport::Tcp { + port: 0, + connection_token: None, + }, + Ok("stdio") | Err(std::env::VarError::NotPresent) => Transport::Stdio, + value => panic!("invalid HOST_CRASH_FIXTURE_TRANSPORT: {value:?}"), + }; let options = ClientOptions::new() .with_program(CliProgram::Path(PathBuf::from(program))) .with_prefix_args(prefix_args) .with_cwd(PathBuf::from(cwd)) .with_env(env_pairs) .with_use_logged_in_user(false) - .with_transport(Transport::Stdio); + .with_transport(transport); let client = Client::start(options).await.expect("start CLI client"); let pid = client.pid().expect("client reports spawned CLI pid"); diff --git a/rust/tests/http_request_body_test.rs b/rust/tests/http_request_body_test.rs new file mode 100644 index 0000000000..d200803d63 --- /dev/null +++ b/rust/tests/http_request_body_test.rs @@ -0,0 +1,614 @@ +//! The LLM-callback request body on its way through the dispatcher: the runtime sends an HTTP +//! request body in `llmInference.httpRequestChunk` frames, and the dispatcher moves the body out +//! of the parsed frame instead of copying it (a deep clone of the params `Value`, a clone of +//! `data`, and a copy of the first frame into an empty buffer). The handler must see the +//! runtime's bytes exactly: an escaped JSON body, an empty body, a body in several chunks, a +//! base64 chunk, a chunk that races ahead of its start frame, and a cancel chunk after part of +//! the body. The wire around the body is pinned too: every case asserts the exact ack of each +//! request it sends and the response frames in order, and one more case the exact error reply +//! to params that do not parse. And once the frame is parsed, a single-chunk body must not be +//! copied again: a counting allocator counts the allocations of exactly the body's length +//! between the chunk frame's write and the handler's entry. +//! +//! Each case drives the real dispatcher: `Client::start` over loopback TCP with a request +//! handler, the test playing the CLI. The allocator is process-global and `cargo test` runs a +//! binary's tests on parallel threads, so the counting case is `#[serial]` and every other case +//! `#[parallel]`: nothing else runs while it counts. + +use std::alloc::{GlobalAlloc, Layout, System}; +use std::collections::HashMap; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::time::Duration; + +use async_trait::async_trait; +use bytes::Bytes; +use futures_util::stream; +use github_copilot_sdk::{ + Client, ClientOptions, CopilotHttpRequest, CopilotHttpResponse, CopilotRequestContext, + CopilotRequestError, CopilotRequestHandler, SDK_PROTOCOL_VERSION, Transport, +}; +use http::HeaderMap; +use serde_json::{Value, json}; +use serial_test::{parallel, serial}; +use tokio::io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader}; +use tokio::net::TcpListener; +use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf}; +use tokio::sync::mpsc; +use tokio::time::timeout; + +/// A backstop against a hang, never a measurement. +const DEADLINE: Duration = Duration::from_secs(30); +/// The single-chunk body the allocation count watches. Odd, so no buffer that grows by doubling +/// (serde_json's unescape scratch) lands on it, and larger than every buffer between the socket +/// and the dispatcher. +const WATCHED_BODY_BYTES: usize = 2 * 1024 * 1024 + 1; + +/// The system allocator, counting the allocations (and reallocations) of exactly [`WATCHED`] +/// bytes while it is non-zero. +struct ExactSizeCounting; + +static WATCHED: AtomicUsize = AtomicUsize::new(0); +static HITS: AtomicUsize = AtomicUsize::new(0); + +fn note(size: usize) { + let watched = WATCHED.load(Ordering::SeqCst); + if watched != 0 && size == watched { + HITS.fetch_add(1, Ordering::SeqCst); + } +} + +// SAFETY: every method forwards to `System` with the caller's own arguments, so `System`'s +// contract is the caller's; the counters are plain atomics and never touch the memory. +unsafe impl GlobalAlloc for ExactSizeCounting { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + note(layout.size()); + // SAFETY: forwarded unchanged (see the impl's SAFETY note). + unsafe { System.alloc(layout) } + } + + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + note(layout.size()); + // SAFETY: forwarded unchanged (see the impl's SAFETY note). + unsafe { System.alloc_zeroed(layout) } + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + // SAFETY: forwarded unchanged (see the impl's SAFETY note). + unsafe { System.dealloc(ptr, layout) } + } + + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + note(new_size); + // SAFETY: forwarded unchanged (see the impl's SAFETY note). + unsafe { System.realloc(ptr, layout, new_size) } + } +} + +#[global_allocator] +static ALLOCATOR: ExactSizeCounting = ExactSizeCounting; + +/// What the handler saw: the body, and the watched-size allocations counted when it was entered. +struct Captured { + body: Vec, + hits_at_entry: usize, +} + +/// What the SDK wrote while one exchange ran: its replies to the test's requests, by id, and the +/// response requests it sent (method and params), in order. +struct Wire { + replies: HashMap, + response_frames: Vec<(String, Value)>, +} + +/// The wire of a well-formed exchange: the empty-result ack of every request the test sent, and +/// nothing else, then the response head (200, no headers) and its terminal empty chunk. +fn assert_wire(wire: &Wire, request_id: &str, request_ids: &[u64]) { + for id in request_ids { + assert_eq!( + wire.replies[id], + json!({"jsonrpc": "2.0", "id": id, "result": {}}), + "the ack of request {id}" + ); + } + assert_eq!( + wire.replies.len(), + request_ids.len(), + "replies: {:?}", + wire.replies + ); + assert_eq!( + wire.response_frames, + vec![ + ( + "llmInference.httpResponseStart".to_owned(), + json!({"requestId": request_id, "status": 200, "headers": {}}), + ), + ( + "llmInference.httpResponseChunk".to_owned(), + json!({"requestId": request_id, "data": "", "end": true}), + ), + ] + ); +} + +/// Hands every request's body to the test and answers an empty 200. +struct CaptureHandler(mpsc::UnboundedSender); + +#[async_trait] +impl CopilotRequestHandler for CaptureHandler { + async fn send_request( + &self, + request: CopilotHttpRequest, + _ctx: &CopilotRequestContext, + ) -> Result { + let hits_at_entry = HITS.load(Ordering::SeqCst); + let _ = self.0.send(Captured { + body: request.body, + hits_at_entry, + }); + Ok(CopilotHttpResponse::new( + 200, + None, + HeaderMap::new(), + Box::pin(stream::empty::>()), + )) + } +} + +/// One frame in the SDK's JSON-RPC shape: a `Content-Length` header, a blank line, the body. +fn frame_bytes(message: &Value) -> Vec { + let body = serde_json::to_vec(message).expect("a JSON-RPC message serialises"); + let mut frame = format!("Content-Length: {}\r\n\r\n", body.len()).into_bytes(); + frame.extend_from_slice(&body); + frame +} + +/// The next frame the SDK wrote, decoded. +async fn read_frame(read: &mut BufReader) -> Value { + let mut length = None; + loop { + let mut line = String::new(); + let read_bytes = read.read_line(&mut line).await.expect("a header line"); + assert_ne!(read_bytes, 0, "the SDK closed the socket"); + if line == "\r\n" { + break; + } + if let Some(value) = line.strip_prefix("Content-Length:") { + length = Some(value.trim().parse::().expect("a decimal length")); + } + } + let mut body = vec![0; length.expect("a Content-Length header")]; + read.read_exact(&mut body).await.expect("the frame body"); + serde_json::from_slice(&body).expect("a JSON frame body") +} + +/// The CLI's side of one SDK client: the public `Client` over real loopback TCP, with the +/// request handler registered through `llmInference.setProvider`. +struct Peer { + client: Client, + read: BufReader, + write: OwnedWriteHalf, + captured: mpsc::UnboundedReceiver, + _work: tempfile::TempDir, +} + +impl Peer { + async fn start() -> Self { + let listener = TcpListener::bind("127.0.0.1:0") + .await + .expect("a loopback listener"); + let port = listener.local_addr().expect("a bound address").port(); + let work = tempfile::tempdir().expect("a temp dir"); + let (captured_tx, captured) = mpsc::unbounded_channel(); + let options = ClientOptions::new() + .with_program(std::env::current_exe().expect("the test binary's path")) + .with_cwd(work.path()) + .with_transport(Transport::External { + host: "127.0.0.1".into(), + port, + connection_token: None, + }) + .with_request_handler(CaptureHandler(captured_tx)); + let (client, (read, write)) = timeout(DEADLINE, async { + tokio::join!(Client::start(options), async { + let (socket, _) = listener.accept().await.expect("the SDK connects"); + socket.set_nodelay(true).expect("TCP_NODELAY"); + let (read, mut write) = socket.into_split(); + let mut read = BufReader::new(read); + for method in ["connect", "llmInference.setProvider"] { + let message = read_frame(&mut read).await; + assert_eq!(message["method"], method); + let result = if method == "connect" { + json!({ + "ok": true, + "version": "test", + "protocolVersion": SDK_PROTOCOL_VERSION + }) + } else { + json!({"success": true}) + }; + let reply = json!({"jsonrpc": "2.0", "id": message["id"], "result": result}); + write + .write_all(&frame_bytes(&reply)) + .await + .expect("the handshake reply"); + } + (read, write) + }) + }) + .await + .expect("the client handshake finishes"); + Self { + client: client.expect("the client starts"), + read, + write, + captured, + _work: work, + } + } + + /// Bounded: an SDK that stops reading with the socket open would otherwise park a large frame's + /// write on TCP backpressure, past every receive deadline. + async fn send(&mut self, message: &Value) { + timeout(DEADLINE, self.write.write_all(&frame_bytes(message))) + .await + .expect("the SDK takes the frame in time") + .expect("a frame to the SDK"); + } + + async fn start_request(&mut self, request_id: &str, id: u64) { + self.send(&json!({ + "jsonrpc": "2.0", + "id": id, + "method": "llmInference.httpRequestStart", + "params": { + "requestId": request_id, + "method": "POST", + "url": "http://unused.test/chat", + "headers": {} + } + })) + .await; + } + + async fn chunk(&mut self, id: u64, params: Value) { + self.send(&json!({ + "jsonrpc": "2.0", + "id": id, + "method": "llmInference.httpRequestChunk", + "params": params + })) + .await; + } + + /// What the handler received for the next request. + async fn captured(&mut self) -> Captured { + timeout(DEADLINE, self.captured.recv()) + .await + .expect("the handler is entered") + .expect("the handler's channel is open") + } + + /// Serves the CLI's side of the response (acking the SDK's head and body requests) until its + /// terminal body chunk has arrived and every one of `request_ids` has its reply, so the + /// exchange finishes before the client stops; returns everything the SDK wrote meanwhile. + async fn finish_response(&mut self, request_ids: &[u64]) -> Wire { + let mut wire = Wire { + replies: HashMap::new(), + response_frames: Vec::new(), + }; + timeout(DEADLINE, async { + let mut terminal = false; + while !terminal || request_ids.iter().any(|id| !wire.replies.contains_key(id)) { + let message = read_frame(&mut self.read).await; + let Some(method) = message.get("method").and_then(Value::as_str) else { + let id = message["id"] + .as_u64() + .expect("a reply carries its request's id"); + wire.replies.insert(id, message); + continue; + }; + terminal = + method == "llmInference.httpResponseChunk" && message["params"]["end"] == true; + wire.response_frames + .push((method.to_owned(), message["params"].clone())); + let ack = json!({ + "jsonrpc": "2.0", + "id": message["id"], + "result": {"accepted": true} + }); + self.send(&ack).await; + } + }) + .await + .expect("the response finishes and every request is answered"); + wire + } + + /// The SDK's replies to `request_ids`, for frames that start no exchange: any request from the + /// SDK meanwhile fails the test. + async fn replies(&mut self, request_ids: &[u64]) -> HashMap { + let mut replies = HashMap::new(); + timeout(DEADLINE, async { + while request_ids.iter().any(|id| !replies.contains_key(id)) { + let message = read_frame(&mut self.read).await; + assert!( + message.get("method").is_none(), + "an unexpected request: {message}" + ); + let id = message["id"] + .as_u64() + .expect("a reply carries its request's id"); + replies.insert(id, message); + } + }) + .await + .expect("every request is answered"); + replies + } + + async fn stop(self) { + self.client.stop().await.expect("the client stops"); + } +} + +/// A chat-request-shaped JSON body of exactly `len` bytes, dense with quotes and backslashes so +/// its frame carries it escaped, as the runtime's does. +fn escaped_body(len: usize) -> String { + let unit = r#"{"role":"user","content":"a \"quoted\" path C:\\dir\\file, tab\there"},"#; + let mut out = String::with_capacity(len); + out.push_str(r#"{"messages":["#); + while out.len() + unit.len() <= len { + out.push_str(unit); + } + while out.len() < len { + out.push('x'); + } + out +} + +/// Every JSON escape class (quote, backslash, the short escapes, the other control bytes) and +/// multi-byte UTF-8, after a body large enough to span many socket reads. +fn every_escape_class_body() -> String { + let mut out = escaped_body(1024 * 1024); + out.push_str( + "controls: \u{0}\u{1}\u{8}\u{b}\u{c}\u{1f} cr\r lf\n unicode: \u{e9}\u{4e2d}\u{1f600}", + ); + out +} + +#[tokio::test(flavor = "multi_thread")] +#[parallel] +async fn an_escaped_json_body_reaches_the_handler_byte_for_byte() { + let mut peer = Peer::start().await; + let body = every_escape_class_body(); + + peer.start_request("escaped", 10).await; + peer.chunk( + 11, + json!({"requestId": "escaped", "data": body, "end": true}), + ) + .await; + + let captured = peer.captured().await; + assert_eq!(captured.body, body.as_bytes()); + let wire = peer.finish_response(&[10, 11]).await; + assert_wire(&wire, "escaped", &[10, 11]); + peer.stop().await; +} + +#[tokio::test(flavor = "multi_thread")] +#[parallel] +async fn an_empty_body_reaches_the_handler_empty() { + let mut peer = Peer::start().await; + + peer.start_request("empty", 20).await; + peer.chunk(21, json!({"requestId": "empty", "data": "", "end": true})) + .await; + + let captured = peer.captured().await; + assert_eq!(captured.body, Vec::::new()); + let wire = peer.finish_response(&[20, 21]).await; + assert_wire(&wire, "empty", &[20, 21]); + peer.stop().await; +} + +#[tokio::test(flavor = "multi_thread")] +#[parallel] +async fn a_body_in_several_chunks_reaches_the_handler_in_order() { + let mut peer = Peer::start().await; + let parts = [ + escaped_body(64 * 1024), + escaped_body(1000), + escaped_body(70_001), + ]; + + peer.start_request("several", 30).await; + peer.chunk(31, json!({"requestId": "several", "data": parts[0]})) + .await; + // An empty, non-terminal chunk carries no bytes and must not disturb the order. + peer.chunk(32, json!({"requestId": "several", "data": ""})) + .await; + peer.chunk(33, json!({"requestId": "several", "data": parts[1]})) + .await; + peer.chunk( + 34, + json!({"requestId": "several", "data": parts[2], "end": true}), + ) + .await; + + let captured = peer.captured().await; + assert_eq!(captured.body, parts.concat().as_bytes()); + let wire = peer.finish_response(&[30, 31, 32, 33, 34]).await; + assert_wire(&wire, "several", &[30, 31, 32, 33, 34]); + peer.stop().await; +} + +#[tokio::test(flavor = "multi_thread")] +#[parallel] +async fn a_base64_chunk_reaches_the_handler_decoded_before_a_text_chunk() { + let mut peer = Peer::start().await; + + peer.start_request("binary", 40).await; + // "AAEC/w==" is the standard base64 of the bytes 0x00 0x01 0x02 0xff. + peer.chunk( + 41, + json!({"requestId": "binary", "data": "AAEC/w==", "binary": true}), + ) + .await; + peer.chunk( + 42, + json!({"requestId": "binary", "data": "tail", "end": true}), + ) + .await; + + let captured = peer.captured().await; + assert_eq!(captured.body, b"\x00\x01\x02\xfftail".to_vec()); + let wire = peer.finish_response(&[40, 41, 42]).await; + assert_wire(&wire, "binary", &[40, 41, 42]); + peer.stop().await; +} + +#[tokio::test(flavor = "multi_thread")] +#[parallel] +async fn a_chunk_ahead_of_its_start_frame_reaches_the_handler() { + let mut peer = Peer::start().await; + let body = escaped_body(300_001); + + peer.chunk(51, json!({"requestId": "early", "data": body, "end": true})) + .await; + peer.start_request("early", 50).await; + + let captured = peer.captured().await; + assert_eq!(captured.body, body.as_bytes()); + let wire = peer.finish_response(&[50, 51]).await; + assert_wire(&wire, "early", &[50, 51]); + peer.stop().await; +} + +/// A cancel chunk after part of the body, on the `apply_chunk` path that moves `data`: the handler +/// sees the bytes that arrived before it, each request is acked, and the response is its head and +/// then a terminal chunk carrying the cancellation. +#[tokio::test(flavor = "multi_thread")] +#[parallel] +async fn a_cancel_chunk_ends_the_body_and_the_response_with_the_cancellation() { + let mut peer = Peer::start().await; + let part = escaped_body(10_001); + + peer.start_request("cancelled", 80).await; + peer.chunk(81, json!({"requestId": "cancelled", "data": part})) + .await; + peer.chunk( + 82, + json!({"requestId": "cancelled", "data": "", "cancel": true}), + ) + .await; + + let captured = peer.captured().await; + assert_eq!(captured.body, part.as_bytes()); + let wire = peer.finish_response(&[80, 81, 82]).await; + for id in [80, 81, 82] { + assert_eq!( + wire.replies[&id], + json!({"jsonrpc": "2.0", "id": id, "result": {}}), + "the ack of request {id}" + ); + } + assert_eq!(wire.replies.len(), 3, "replies: {:?}", wire.replies); + assert_eq!( + wire.response_frames, + vec![ + ( + "llmInference.httpResponseStart".to_owned(), + json!({"requestId": "cancelled", "status": 200, "headers": {}}), + ), + ( + "llmInference.httpResponseChunk".to_owned(), + json!({ + "requestId": "cancelled", + "data": "", + "end": true, + "error": {"code": "cancelled", "message": "Request cancelled by runtime"} + }), + ), + ] + ); + peer.stop().await; +} + +/// A start or chunk frame whose params do not parse gets the dispatcher's error reply: the params +/// move into the parse instead of being cloned into it, and a failed parse still answers. +#[tokio::test(flavor = "multi_thread")] +#[parallel] +async fn unparsable_start_and_chunk_params_get_the_error_reply() { + let mut peer = Peer::start().await; + + // Neither frame names the requestId that both params types require. + peer.send(&json!({ + "jsonrpc": "2.0", + "id": 70, + "method": "llmInference.httpRequestStart", + "params": {"method": "POST", "url": "http://unused.test/chat", "headers": {}} + })) + .await; + peer.chunk(71, json!({"data": "x", "end": true})).await; + + let replies = peer.replies(&[70, 71]).await; + assert_eq!( + replies[&70], + json!({ + "jsonrpc": "2.0", + "id": 70, + "error": {"code": -32603, "message": "invalid llmInference.httpRequestStart params"} + }) + ); + assert_eq!( + replies[&71], + json!({ + "jsonrpc": "2.0", + "id": 71, + "error": {"code": -32603, "message": "invalid llmInference.httpRequestChunk params"} + }) + ); + peer.stop().await; +} + +/// The mechanism: between the chunk frame's write and the handler's entry, the body is +/// allocated at its exact length once, by the frame parse (`serde_json`'s `Value` string), and +/// the dispatcher moves that buffer to the handler. Copying it instead allocated it three more +/// times (the params `Value` clone, the `data` clone, the drain into an empty `Vec`); reverting +/// any one of the three moves adds one. +#[tokio::test(flavor = "multi_thread")] +#[serial] +async fn a_single_chunk_body_reaches_the_handler_without_a_copy() { + let mut peer = Peer::start().await; + let body = escaped_body(WATCHED_BODY_BYTES); + assert_eq!(body.len(), WATCHED_BODY_BYTES); + peer.start_request("single", 60).await; + // Encoded before the count starts: building the frame allocates the body's length too. + let chunk = frame_bytes(&json!({ + "jsonrpc": "2.0", + "id": 61, + "method": "llmInference.httpRequestChunk", + "params": {"requestId": "single", "data": body, "end": true} + })); + + HITS.store(0, Ordering::SeqCst); + WATCHED.store(WATCHED_BODY_BYTES, Ordering::SeqCst); + timeout(DEADLINE, peer.write.write_all(&chunk)) + .await + .expect("the SDK takes the chunk frame in time") + .expect("the chunk frame to the SDK"); + let captured = peer.captured().await; + WATCHED.store(0, Ordering::SeqCst); + + assert_eq!(captured.body, body.as_bytes()); + assert_eq!( + captured.hits_at_entry, 1, + "allocations of exactly the body's {WATCHED_BODY_BYTES} bytes between the frame's write \ + and the handler's entry: the frame parse's one, and no relay copy" + ); + let wire = peer.finish_response(&[60, 61]).await; + assert_wire(&wire, "single", &[60, 61]); + peer.stop().await; +} diff --git a/scripts/ci/check-generated.test.mjs b/scripts/ci/check-generated.test.mjs index 23c95ced04..6827464fdb 100644 --- a/scripts/ci/check-generated.test.mjs +++ b/scripts/ci/check-generated.test.mjs @@ -8,7 +8,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import test from "node:test"; -import { fileURLToPath } from "node:url"; +import { fileURLToPath, pathToFileURL } from "node:url"; import { SCHEMA_FILES } from "../build-prerequisites.mjs"; import { assertGeneratedClean, @@ -64,6 +64,15 @@ function fixture(t) { return { root, git, write, commit, schemas, options }; } +function shallowClone(t, source, depth) { + const root = fs.mkdtempSync(path.join(os.tmpdir(), "sdk-freshness-shallow-")); + t.after(() => fs.rmSync(root, { recursive: true, force: true })); + execFileSync("git", ["clone", "--quiet", "--depth", String(depth), pathToFileURL(source).href, root]); + const git = (...args) => execFileSync("git", args, { cwd: root, encoding: "utf8" }).trim(); + assert.equal(git("rev-parse", "--is-shallow-repository"), "true"); + return { root, git }; +} + for (const name of SCHEMA_FILES) { test(`rejects stale ${name} before SDK generation`, (t) => { const f = fixture(t); @@ -207,10 +216,39 @@ test("uses the tested PR merge's actual base, not an earlier event base", (t) => const actualBase = f.commit(); f.git("merge", "--quiet", "--no-ff", "topic", "-m", "test merge"); assert.equal(generationBaseline(f.root, "pull_request", { pull_request: { base: { sha: oldBase } } }), actualBase); + const clone = shallowClone(t, f.root, 2); + assert.equal( + generationBaseline(clone.root, "pull_request", { pull_request: { base: { sha: oldBase } } }), + actualBase, + ); const paths = f.git("diff", "--name-only", actualBase, "HEAD").split("\n"); assert.equal(requiresSdkGeneration(paths), false); }); +for (const eventName of ["merge_group", "push"]) { + test(`uses a separately fetched ${eventName} baseline beyond shallow history`, (t) => { + const f = fixture(t); + f.write("generated/api.schema.json", '{"earlierCommit":true}\n'); + f.commit(); + f.write("internal", "last commit"); + f.commit(); + const clone = shallowClone(t, f.root, 1); + const event = + eventName === "merge_group" + ? { merge_group: { base_sha: f.options.baseline } } + : { before: f.options.baseline }; + assert.throws(() => generationBaseline(clone.root, eventName, event)); + clone.git("fetch", "--quiet", "--no-tags", "--depth=1", "origin", f.options.baseline); + const baseline = generationBaseline(clone.root, eventName, event); + assert.equal(baseline, f.options.baseline); + assert.equal( + requiresSdkGeneration(clone.git("diff", "--name-only", baseline, "HEAD").split("\n")), + true, + ); + assert.equal(clone.git("rev-parse", "--is-shallow-repository"), "true"); + }); +} + test("uses the whole merge-group/push range, not just the final commit", (t) => { const f = fixture(t); f.write("generated/api.schema.json", '{"earlierCommit":true}\n'); diff --git a/scripts/ci/run-dotnet-tests.sh b/scripts/ci/run-dotnet-tests.sh index ea0312c4a6..b1840e323e 100755 --- a/scripts/ci/run-dotnet-tests.sh +++ b/scripts/ci/run-dotnet-tests.sh @@ -11,6 +11,7 @@ Usage: run-dotnet-tests.sh [--help] Runs the full .NET SDK test project. Environment variables: DOTNET_TEST_FILTER Optional dotnet test filter (e.g. for a backend or transport). DOTNET_TEST_RUNTIME Optional runtime identifier passed to dotnet test. + DOTNET_TEST_FRAMEWORK Optional target framework (default: all project frameworks). DOTNET_TEST_RESULTS_DIRECTORY Results directory (default: TestResults). EOF } @@ -40,6 +41,7 @@ args=( ) filter="${DOTNET_TEST_FILTER:-}" runtime="${DOTNET_TEST_RUNTIME:-}" +framework="${DOTNET_TEST_FRAMEWORK:-}" if [[ -n "$filter" ]]; then args+=(--filter "$filter") @@ -47,5 +49,8 @@ fi if [[ -n "$runtime" ]]; then args+=(--runtime "$runtime") fi +if [[ -n "$framework" ]]; then + args+=(--framework "$framework") +fi dotnet test "${args[@]}" diff --git a/scripts/ci/run-dotnet-tests.test.mjs b/scripts/ci/run-dotnet-tests.test.mjs index 582fcd6b2c..f979b8042c 100644 --- a/scripts/ci/run-dotnet-tests.test.mjs +++ b/scripts/ci/run-dotnet-tests.test.mjs @@ -19,7 +19,7 @@ function fromBashPath(value) { return value; } -await test("runs all .NET tests with optional filter, runtime, and results directory", (t) => { +await test("runs all .NET tests with optional filter, runtime, framework, and results directory", (t) => { const root = fs.mkdtempSync(path.join(os.tmpdir(), "sdk-dotnet-test-")); t.after(() => fs.rmSync(root, { recursive: true, force: true })); const argumentsPath = path.join(root, "arguments"); @@ -31,9 +31,12 @@ await test("runs all .NET tests with optional filter, runtime, and results direc ); fs.chmodSync(fakeDotnet, 0o755); - for (const [filter, runtime, resultsDirectory] of [ - ["", "", ""], - ["E2EBackend!=CapiOnly", "win-x64", "TestResults/inprocess"], + for (const [filter, runtime, framework, resultsDirectory] of [ + ["", "", "", ""], + ["E2EBackend!=CapiOnly", "win-x64", "net8.0", "TestResults/inprocess"], + ["", "win-x64", "net472", "TestResults/subprocess"], + ["FullyQualifiedName~GitHub.Copilot.Test.E2E.S", "win-x64", "net8.0", "TestResults/subprocess"], + ["FullyQualifiedName!~GitHub.Copilot.Test.E2E.S", "win-x64", "net472", "TestResults/subprocess"], ]) { const result = spawnSync("bash", [script], { encoding: "utf8", @@ -42,6 +45,7 @@ await test("runs all .NET tests with optional filter, runtime, and results direc ARGUMENTS_PATH: argumentsPath, DOTNET_TEST_FILTER: filter, DOTNET_TEST_RUNTIME: runtime, + DOTNET_TEST_FRAMEWORK: framework, DOTNET_TEST_RESULTS_DIRECTORY: resultsDirectory, PATH: `${root}${path.delimiter}${process.env.PATH ?? ""}`, WORKING_DIRECTORY_PATH: workingDirectoryPath, @@ -67,6 +71,10 @@ await test("runs all .NET tests with optional filter, runtime, and results direc if (runtime) { assert.equal(arguments_[arguments_.indexOf("--runtime") + 1], runtime); } + assert.equal(arguments_.includes("--framework"), framework !== ""); + if (framework) { + assert.equal(arguments_[arguments_.indexOf("--framework") + 1], framework); + } } }); @@ -75,6 +83,7 @@ await test("documents its environment and rejects positional arguments", () => { assert.equal(help.status, 0, help.stderr); assert.match(help.stdout, /DOTNET_TEST_FILTER/); assert.match(help.stdout, /DOTNET_TEST_RUNTIME/); + assert.match(help.stdout, /DOTNET_TEST_FRAMEWORK/); assert.match(help.stdout, /DOTNET_TEST_RESULTS_DIRECTORY/); const invalid = spawnSync("bash", [script, "unexpected"], { encoding: "utf8" }); diff --git a/scripts/codegen/csharp.ts b/scripts/codegen/csharp.ts index faef5dd771..2ab2c3c7e7 100644 --- a/scripts/codegen/csharp.ts +++ b/scripts/codegen/csharp.ts @@ -2312,7 +2312,7 @@ function emitServerInstanceMethod( const opaqueListOptional = naturalType === "IList?"; const opaque = opaqueRequired || opaqueOptional || opaqueListRequired || opaqueListOptional; const csType = opaqueRequired - ? "object" + ? "object?" : opaqueOptional ? "object?" : opaqueListRequired @@ -2322,7 +2322,7 @@ function emitServerInstanceMethod( : naturalType; sigParams.push(`${csType} ${pName}${isReq ? "" : " = null"}`); const assignedValue = opaqueRequired - ? `CopilotClient.ToJsonElementForWire(${pName})!.Value` + ? `CopilotClient.ToJsonElementForWire(${pName}) ?? JsonElement.Parse("null")` : opaqueOptional ? `CopilotClient.ToJsonElementForWire(${pName})` : opaqueListRequired @@ -2331,7 +2331,7 @@ function emitServerInstanceMethod( ? `${pName}?.Select(static v => CopilotClient.ToJsonElementForWire(v)!.Value).ToList()` : pName; bodyAssignments.push(`${csharpName} = ${assignedValue}`); - if (opaqueRequired || opaqueListRequired || (!opaque && requiresArgumentNullCheck(csType, isReq))) { + if (opaqueListRequired || (!opaque && requiresArgumentNullCheck(csType, isReq))) { argumentNullChecks.push(`${indent} ArgumentNullException.ThrowIfNull(${pName});`); } if (opaqueListRequired || (!opaque && requiresArgumentNullCheck(csType, isReq))) { @@ -2364,7 +2364,18 @@ function emitServerInstanceMethod( } if (requestClassName && bodyAssignments.length > 0) { lines.push(`${indent} var ${localRequestName} = new ${requestClassName} { ${bodyAssignments.join(", ")} };`); - if (!isVoidSchema(resultSchema)) { + if ( + method.rpcMethod === "user.settings.applyTopKey" || + method.rpcMethod === "repo.settings.writeKey" + ) { + lines.push(`${indent} var payload = JsonSerializer.SerializeToNode(${localRequestName}, RpcJsonContext.Default.${requestClassName})!.AsObject();`); + lines.push(`${indent} if (${localRequestName}.Delete != true && ${localRequestName}.Value is null) payload["value"] = null;`); + if (!isVoidSchema(resultSchema)) { + lines.push(`${indent} return await CopilotClient.InvokeRpcAsync<${resultClassName}>(_rpc, "${method.rpcMethod}", [payload], cancellationToken);`); + } else { + lines.push(`${indent} await CopilotClient.InvokeRpcAsync(_rpc, "${method.rpcMethod}", [payload], cancellationToken);`); + } + } else if (!isVoidSchema(resultSchema)) { lines.push(`${indent} return await CopilotClient.InvokeRpcAsync<${resultClassName}>(_rpc, "${method.rpcMethod}", [${localRequestName}], cancellationToken);`); } else { lines.push(`${indent} await CopilotClient.InvokeRpcAsync(_rpc, "${method.rpcMethod}", [${localRequestName}], cancellationToken);`); @@ -2548,7 +2559,7 @@ function emitSessionMethod(key: string, method: RpcMethod, lines: string[], clas const opaqueListOptional = naturalType === "IList?"; const opaque = opaqueRequired || opaqueOptional || opaqueListRequired || opaqueListOptional; const csType = opaqueRequired - ? "object" + ? "object?" : opaqueOptional ? "object?" : opaqueListRequired @@ -2558,7 +2569,7 @@ function emitSessionMethod(key: string, method: RpcMethod, lines: string[], clas : naturalType; sigParams.push(`${csType} ${pName}${isReq ? "" : " = null"}`); const assignedValue = opaqueRequired - ? `CopilotClient.ToJsonElementForWire(${pName})!.Value` + ? `CopilotClient.ToJsonElementForWire(${pName}) ?? JsonElement.Parse("null")` : opaqueOptional ? `CopilotClient.ToJsonElementForWire(${pName})` : opaqueListRequired @@ -2567,7 +2578,7 @@ function emitSessionMethod(key: string, method: RpcMethod, lines: string[], clas ? `${pName}?.Select(static v => CopilotClient.ToJsonElementForWire(v)!.Value).ToList()` : pName; bodyAssignments.push(`${csharpName} = ${assignedValue}`); - if (opaqueRequired || opaqueListRequired || (!opaque && requiresArgumentNullCheck(csType, isReq))) { + if (opaqueListRequired || (!opaque && requiresArgumentNullCheck(csType, isReq))) { argumentNullChecks.push(`${indent} ArgumentNullException.ThrowIfNull(${pName});`); } if (opaqueListRequired || (!opaque && requiresArgumentNullCheck(csType, isReq))) { @@ -2599,7 +2610,18 @@ function emitSessionMethod(key: string, method: RpcMethod, lines: string[], clas lines.push(`${indent} _session.ThrowIfDisposed();`); lines.push(""); lines.push(`${indent} var ${localRequestName} = new ${wireRequestClassName} { ${bodyAssignments.join(", ")} };`); - if (!isVoidSchema(resultSchema)) { + if ( + method.rpcMethod === "user.settings.applyTopKey" || + method.rpcMethod === "repo.settings.writeKey" + ) { + lines.push(`${indent} var payload = JsonSerializer.SerializeToNode(${localRequestName}, RpcJsonContext.Default.${wireRequestClassName})!.AsObject();`); + lines.push(`${indent} if (${localRequestName}.Delete != true && ${localRequestName}.Value is null) payload["value"] = null;`); + if (!isVoidSchema(resultSchema)) { + lines.push(`${indent} return await CopilotClient.InvokeRpcAsync<${resultClassName}>(_session.Rpc, "${method.rpcMethod}", [payload], cancellationToken);`, `${indent}}`); + } else { + lines.push(`${indent} await CopilotClient.InvokeRpcAsync(_session.Rpc, "${method.rpcMethod}", [payload], cancellationToken);`, `${indent}}`); + } + } else if (!isVoidSchema(resultSchema)) { lines.push(`${indent} return await CopilotClient.InvokeRpcAsync<${resultClassName}>(_session.Rpc, "${method.rpcMethod}", [${localRequestName}], cancellationToken);`, `${indent}}`); } else { lines.push(`${indent} await CopilotClient.InvokeRpcAsync(_session.Rpc, "${method.rpcMethod}", [${localRequestName}], cancellationToken);`, `${indent}}`); diff --git a/scripts/codegen/go.ts b/scripts/codegen/go.ts index 378d36678a..b2a75aea37 100644 --- a/scripts/codegen/go.ts +++ b/scripts/codegen/go.ts @@ -4090,9 +4090,10 @@ async function generateRpc(schemaPath?: string): Promise { } } for (const typeName of internalTypeNames) { + const emittedTypeName = resolveType(typeName); generatedTypeCode = generatedTypeCode.replace( - new RegExp(`^(type ${typeName} struct)`, "m"), - `// Internal: ${typeName} is an internal SDK API and is not part of the public surface.\n$1` + new RegExp(`^(type ${escapeRegExp(emittedTypeName)} struct)`, "m"), + `// Internal: ${emittedTypeName} is an internal SDK API and is not part of the public surface.\n$1` ); } // Remove trailing blank lines before appending. @@ -4303,6 +4304,7 @@ function emitMethod(lines: string[], receiver: string, name: string, method: Rpc const paramsType = hasParams ? resolveType(goParamsTypeName(method)) : ""; const hasRequiredNonSessionParams = nonSessionParams.some((name) => requiredParams.has(name)); const paramsAreOptional = hasParams && !!method.params && !!getNullableInner(method.params) && !hasRequiredNonSessionParams; + const supportsExplicitNullValue = method.rpcMethod === "user.settings.edit"; // For wrapper-level methods, access fields through a.common; for service type aliases, use a directly const clientRef = isWrapper ? "a.common.client" : "a.client"; @@ -4361,14 +4363,41 @@ function emitMethod(lines: string[], receiver: string, name: string, method: Rpc } lines.push(`\traw, err := ${clientRef}.Request(ctx, "${method.rpcMethod}", req)`); } else { - if (method.rpcMethod === "managedSettings.resolve") { - // A typed nil inside Request's any argument marshals as null, not omitted params. - lines.push(`\tif ${paramsRef} == nil {`); - lines.push(`\t\t${paramsRef} = &${paramsType}{}`); + if (hasParams && supportsExplicitNullValue) { + lines.push(`\treq := map[string]any{}`); + lines.push(`\tif ${paramsRef} != nil {`); + for (const pName of nonSessionParams) { + const field = fields.get(paramsType)?.get(pName); + const goField = field?.name ?? toGoFieldName(pName); + const goType = field?.type; + const isOptional = !requiredParams.has(pName); + if (isOptional) { + lines.push(`\t\tif ${paramsRef}.${goField} != nil {`); + const valueExpr = goOptionalFieldNeedsDereference(goType) ? `*${paramsRef}.${goField}` : `${paramsRef}.${goField}`; + lines.push(`\t\t\treq["${pName}"] = ${valueExpr}`); + lines.push(`\t\t}`); + } else { + lines.push(`\t\treq["${pName}"] = ${paramsRef}.${goField}`); + } + } + const operationField = fields.get(paramsType)?.get("operation")?.name ?? toGoFieldName("operation"); + lines.push(`\t\tif ${paramsRef}.${operationField} != SettingsEditOperationRemove {`); + lines.push(`\t\t\tif _, ok := req["value"]; !ok {`); + lines.push(`\t\t\t\treq["value"] = nil`); + lines.push(`\t\t\t}`); + lines.push(`\t\t}`); lines.push(`\t}`); + lines.push(`\traw, err := ${clientRef}.Request(ctx, "${method.rpcMethod}", req)`); + } else { + if (method.rpcMethod === "managedSettings.resolve") { + // A typed nil inside Request's any argument marshals as null, not omitted params. + lines.push(`\tif ${paramsRef} == nil {`); + lines.push(`\t\t${paramsRef} = &${paramsType}{}`); + lines.push(`\t}`); + } + const arg = hasParams ? paramsRef : "nil"; + lines.push(`\traw, err := ${clientRef}.Request(ctx, "${method.rpcMethod}", ${arg})`); } - const arg = hasParams ? paramsRef : "nil"; - lines.push(`\traw, err := ${clientRef}.Request(ctx, "${method.rpcMethod}", ${arg})`); } lines.push(`\tif err != nil {`); diff --git a/scripts/codegen/python.ts b/scripts/codegen/python.ts index a30a96b011..ceb5598d80 100644 --- a/scripts/codegen/python.ts +++ b/scripts/codegen/python.ts @@ -1854,6 +1854,58 @@ function pythonParamsTypeName(method: RpcMethod): string { return getRpcSchemaTypeName(schema, fallback); } +function applyExplicitNullableFieldPresenceSentinel( + code: string, + resolveType: (name: string) => string +): string { + const escapeRegex = (value: string): string => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + const explicitNullableFields: Array<{ className: string; jsonName: string; pyName: string }> = [ + { + className: resolveType("UserSettingsApplyTopKeyRequest"), + jsonName: "value", + pyName: "value", + }, + { + className: resolveType("RepoSettingsWriteKeyRequest"), + jsonName: "value", + pyName: "value", + }, + { + className: resolveType("UserSettingsEditRequest"), + jsonName: "value", + pyName: "value", + }, + ]; + + let result = code; + for (const { className, jsonName, pyName } of explicitNullableFields) { + const classPattern = new RegExp( + `(@dataclass\\r?\\nclass ${escapeRegex(className)}\\b[\\s\\S]*?\\r?\\n)(?=@dataclass\\r?\\nclass |class\\s+\\w+\\(Enum\\):|def\\s+\\w+\\(|$)`, + "g" + ); + result = result.replace(classPattern, (classBlock) => { + let next = classBlock; + next = next.replace( + new RegExp(`^(\\s{4}${escapeRegex(pyName)}:\\s[^=\\r\\n]+\\=\\s*)None(\\r?\\n)`, "m"), + "$1UNSET_SENTINEL$2" + ); + next = next.replace( + new RegExp( + `^(\\s{8}${escapeRegex(pyName)}\\s*=\\s*)(.+?)obj\\.get\\("${escapeRegex(jsonName)}"\\)(.*)$`, + "m" + ), + `$1$2obj["${jsonName}"]$3 if "${jsonName}" in obj else UNSET_SENTINEL` + ); + next = next.replace( + new RegExp(`^(\\s{8}if\\s+self\\.${escapeRegex(pyName)}\\s+is\\s+not\\s+)None(\\s*:\\s*\\r?\\n)`, "m"), + "$1UNSET_SENTINEL$2" + ); + return next; + }); + } + return result; +} + // ── Session Events ────────────────────────────────────────────────────────── // ── Session Events (custom codegen — dedicated per-event payload types) ───── @@ -3779,6 +3831,7 @@ import dateutil.parser T = TypeVar("T") EnumT = TypeVar("EnumT", bound=Enum) +UNSET_SENTINEL = object() `); lines.push(typesCode); @@ -3873,6 +3926,7 @@ def _patch_model_capabilities(data: dict) -> dict: finalCode, new Set(Object.keys(allDefinitions).map((name) => name.toLowerCase())) ); + finalCode = applyExplicitNullableFieldPresenceSentinel(finalCode, resolveType); // Apply `_`-prefix to type names of internal RPC types so the leading-underscore // Python convention signals "internal, no stability guarantees" to consumers. @@ -3889,7 +3943,11 @@ def _patch_model_capabilities(data: dict) -> dict: } } if (internalDefs.size > 0) { - finalCode = renameInternalPythonSymbols(finalCode, internalDefs); + // Resolve class-name casing without following aliases to shared public types. + const internalSymbols = new Set( + [...internalDefs].flatMap((name) => [name, actualTypeNames.get(name.toLowerCase()) ?? name]) + ); + finalCode = renameInternalPythonSymbols(finalCode, internalSymbols); } } @@ -4251,10 +4309,16 @@ export function emitMethod(lines: string[], name: string, method: RpcMethod, isS if (isSession) { if (hasParams) { + const serializeParams = + method.rpcMethod === "user.settings.applyTopKey" || + method.rpcMethod === "repo.settings.writeKey" || + method.rpcMethod === "user.settings.edit" + ? "params.to_dict()" + : "{k: v for k, v in params.to_dict().items() if v is not None}"; if (paramsOptional) { - lines.push(` params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {}`); + lines.push(` params_dict: dict[str, Any] = ${serializeParams} if params is not None else {}`); } else { - lines.push(` params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None}`); + lines.push(` params_dict: dict[str, Any] = ${serializeParams}`); } lines.push(` params_dict["sessionId"] = self._session_id`); emitRequestCall("params_dict"); @@ -4263,10 +4327,16 @@ export function emitMethod(lines: string[], name: string, method: RpcMethod, isS } } else { if (hasParams) { + const serializeParams = + method.rpcMethod === "user.settings.applyTopKey" || + method.rpcMethod === "repo.settings.writeKey" || + method.rpcMethod === "user.settings.edit" + ? "params.to_dict()" + : "{k: v for k, v in params.to_dict().items() if v is not None}"; if (paramsOptional) { - lines.push(` params_dict = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {}`); + lines.push(` params_dict = ${serializeParams} if params is not None else {}`); } else { - lines.push(` params_dict = {k: v for k, v in params.to_dict().items() if v is not None}`); + lines.push(` params_dict = ${serializeParams}`); } emitRequestCall("params_dict"); } else { diff --git a/scripts/codegen/rust.ts b/scripts/codegen/rust.ts index aad957837d..20b6f100d7 100644 --- a/scripts/codegen/rust.ts +++ b/scripts/codegen/rust.ts @@ -2522,7 +2522,9 @@ function pushNamespaceMethodBody( // Build the params Value sent over the wire. if (isSession) { if (hasParams) { - out.push(` let mut wire_params = serde_json::to_value(params)?;`); + out.push( + ` let mut wire_params = serde_json::to_value(params)?;`, + ); out.push( ` wire_params["sessionId"] = serde_json::Value::String(self.session.id().to_string());`, ); @@ -2536,7 +2538,9 @@ function pushNamespaceMethodBody( ); } else { if (hasParams) { - out.push(` let wire_params = serde_json::to_value(params)?;`); + out.push( + ` let wire_params = serde_json::to_value(params)?;`, + ); } else { out.push(` let wire_params = serde_json::json!({});`); } diff --git a/scripts/corrections/package-lock.json b/scripts/corrections/package-lock.json index a975812af3..faa7a956f7 100644 --- a/scripts/corrections/package-lock.json +++ b/scripts/corrections/package-lock.json @@ -10,7 +10,7 @@ "@octokit/rest": "^22.0.1", "@types/node": "^22.0.0", "typescript": "^5.8.0", - "vitest": "^4.1.0" + "vitest": "^4.1.11" } }, "node_modules/@actions/github": { @@ -40,66 +40,13 @@ "undici": "^6.23.0" } }, - "node_modules/@emnapi/core": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", - "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.1", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", - "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", - "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "dev": true, "license": "MIT" }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", - "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" - } - }, "node_modules/@octokit/auth-token": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz", @@ -268,19 +215,36 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.133.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", - "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", + "version": "0.153.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.153.0.tgz", + "integrity": "sha512-jSNrRIyvPVLL5E1z/tS5zLAprosGz/FuI1PWwEOz59j3E4TTTzSpqKb/RDGqJhhW0QHYISGXxq582wGx6T11Tw==", "dev": true, "license": "MIT", "funding": { - "url": "https://github.com/sponsors/Boshen" + "url": "https://github.com/sponsors/oxc-project" + } + }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.13.tgz", + "integrity": "sha512-Vu/NICrgdRvUOeaJZIyB2FP63s6fO/4ud5l8dXmxDx9yDyn+mN0y+gsvsVviSli+T361Aqo0h46EuMoobrwawA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", - "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.13.tgz", + "integrity": "sha512-6LEoIrGy5vvCd2boNnv2soPSUZj/PRvhp8R/t9KlX+mIZxThIE/ZqxrGXxmuNX0FuvQFvLdZr7S4HrYpYBVhEQ==", "cpu": [ "arm64" ], @@ -295,9 +259,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz", - "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.13.tgz", + "integrity": "sha512-CaJSRzlQ6Q+zkDMVA9OkVxBjVoPRCDEE3v0FSJ9kIQBgRjFApA3Si4ijhbNVUji7ZJt+PfO0e46qy4nPInHUPA==", "cpu": [ "arm64" ], @@ -312,9 +276,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", - "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.13.tgz", + "integrity": "sha512-e4r340I5hxSzJkD3YJBxgzq/rJ3wwxwdLLb2FPt1Zpyem20nrQPT11DDEEkazwxaHumH8wpglsp/Ozgj/wT6mw==", "cpu": [ "x64" ], @@ -329,9 +293,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", - "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.13.tgz", + "integrity": "sha512-hoBWDZ4/K/mJKVMbsgUd1jfpA2DiOrJ54mpegObU9TBHBBrtX4FLIXJJQRDPZ/2Dn91GvPob+Z2hwKJzf4E5SQ==", "cpu": [ "x64" ], @@ -346,9 +310,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", - "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.13.tgz", + "integrity": "sha512-oF9fZu3vTWnTiVAkDFxU9PJLt1nh20K9RRpuHsR7ZnE2L7XookBbDBVLojCVSLGbvtSlxeUNnjAj6DbNsKyzbg==", "cpu": [ "arm" ], @@ -363,13 +327,16 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", - "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.13.tgz", + "integrity": "sha512-DTpb/+jMiqWMPgphn4ksW1zW+XLJ6dJJ9FMvnIk9I291LhCctMPhMYJrP5t9p6C9qa3KXadDdUEZHBaPh3kNxQ==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -380,13 +347,16 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", - "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.13.tgz", + "integrity": "sha512-xU+Kvv9N2A3SY35zFh1FWWNjxbadE/BKeqnkXe7vScU4GZsw757BlVmDLITZEq8DPpk6m7uoDYkK7P+x/uU5Ow==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -397,13 +367,16 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", - "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.13.tgz", + "integrity": "sha512-XMk/hnhh25oQ756Lclb1Q11h4ll0xC0Esa5w4Vzp+mAE2S3AGJgeM0SonrIgY8fHhjarb6hcoTuwoFG0VVP2ig==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -414,13 +387,16 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", - "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.13.tgz", + "integrity": "sha512-U1BoTHYmlywE2n3HUWjzZ+8EQsKr+OwpxYuDWaubx42tUL8QSL7nOqRz/NVHanibbFP3M1Rxuprz/wNcbMKjqw==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -431,13 +407,16 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", - "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.13.tgz", + "integrity": "sha512-J4cm80Pc6wEwV5AZ42o62sIQgDk+Y7R2s646jIwuvO+4V46QB58N4vVuMPWCBaNgursXLpmUWJV//WQAkPvHBQ==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -448,13 +427,16 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", - "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.13.tgz", + "integrity": "sha512-W0euZS40U4V6JkmEnVCIX9mcsL6cbXQ4X8c2w+MMOIjFg68TXUW+u3RT+2e1t1pv9mg/EP3pDtK3POXdQ7Rxyw==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -465,9 +447,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", - "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.13.tgz", + "integrity": "sha512-do/AF/4n9MRshia3a5aXoy8xM2c6mgfT6D7H/dY6my5z+hfCIR4ab7mk4IRj++nsEQpKy39kd0DQnDq+r692tw==", "cpu": [ "arm64" ], @@ -481,29 +463,10 @@ "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", - "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "1.10.0", - "@emnapi/runtime": "1.10.0", - "@napi-rs/wasm-runtime": "^1.1.4" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", - "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.13.tgz", + "integrity": "sha512-6FtUf2cJZobutJdxnGYX8z0vtbgqU0b2v8vfBhkXb9wp2MppMFtkunE+IaOntyi01rkIQoPW2GHABtfzsC0BRQ==", "cpu": [ "arm64" ], @@ -518,9 +481,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", - "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.13.tgz", + "integrity": "sha512-UKhFaZTeTcbKrb3iU82m17jVcPEAoqDkCN5MBqgPyZSwp/cQmib21crTS0DdH7T1B7wZRWEI89YQAOJMet5yhg==", "cpu": [ "x64" ], @@ -548,17 +511,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", - "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@types/chai": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", @@ -595,31 +547,31 @@ } }, "node_modules/@vitest/expect": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.0.tgz", - "integrity": "sha512-EIxG7k4wlWweuCLG9Y5InKFwpMEOyrMb6ZJ1ihYu02LVj/bzUwn2VMU+13PinsjRW75XnITeFrQBMH5+dLvCDA==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz", + "integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.0", - "@vitest/utils": "4.1.0", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", "chai": "^6.2.2", - "tinyrainbow": "^3.0.3" + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/mocker": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.0.tgz", - "integrity": "sha512-evxREh+Hork43+Y4IOhTo+h5lGmVRyjqI739Rz4RlUPqwrkFFDF6EMvOOYjTx4E8Tl6gyCLRL8Mu7Ry12a13Tw==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz", + "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.0", + "@vitest/spy": "4.1.11", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -628,7 +580,7 @@ }, "peerDependencies": { "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0-0" + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "msw": { @@ -640,26 +592,26 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.0.tgz", - "integrity": "sha512-3RZLZlh88Ib0J7NQTRATfc/3ZPOnSUn2uDBUoGNn5T36+bALixmzphN26OUD3LRXWkJu4H0s5vvUeqBiw+kS0A==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz", + "integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==", "dev": true, "license": "MIT", "dependencies": { - "tinyrainbow": "^3.0.3" + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/runner": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.0.tgz", - "integrity": "sha512-Duvx2OzQ7d6OjchL+trw+aSrb9idh7pnNfxrklo14p3zmNL4qPCDeIJAK+eBKYjkIwG96Bc6vYuxhqDXQOWpoQ==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz", + "integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.0", + "@vitest/utils": "4.1.11", "pathe": "^2.0.3" }, "funding": { @@ -667,14 +619,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.0.tgz", - "integrity": "sha512-0Vy9euT1kgsnj1CHttwi9i9o+4rRLEaPRSOJ5gyv579GJkNpgJK+B4HSv/rAWixx2wdAFci1X4CEPjiu2bXIMg==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.11.tgz", + "integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.0", - "@vitest/utils": "4.1.0", + "@vitest/pretty-format": "4.1.11", + "@vitest/utils": "4.1.11", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -683,9 +635,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.0.tgz", - "integrity": "sha512-pz77k+PgNpyMDv2FV6qmk5ZVau6c3R8HC8v342T2xlFxQKTrSeYw9waIJG8KgV9fFwAtTu4ceRzMivPTH6wSxw==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.11.tgz", + "integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==", "dev": true, "license": "MIT", "funding": { @@ -693,15 +645,15 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.0.tgz", - "integrity": "sha512-XfPXT6a8TZY3dcGY8EdwsBulFCIw+BeeX0RZn2x/BtiY/75YGh8FeWGG8QISN/WhaqSrE2OrlDgtF8q5uhOTmw==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.11.tgz", + "integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.0", + "@vitest/pretty-format": "4.1.11", "convert-source-map": "^2.0.0", - "tinyrainbow": "^3.0.3" + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" @@ -725,9 +677,9 @@ "license": "Apache-2.0" }, "node_modules/chai": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.3.0.tgz", + "integrity": "sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==", "dev": true, "license": "MIT", "engines": { @@ -836,9 +788,9 @@ "license": "MIT" }, "node_modules/lightningcss": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", - "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", "dev": true, "license": "MPL-2.0", "dependencies": { @@ -852,23 +804,23 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "lightningcss-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" } }, "node_modules/lightningcss-android-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", - "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", "cpu": [ "arm64" ], @@ -887,9 +839,9 @@ } }, "node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", - "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", "cpu": [ "arm64" ], @@ -908,9 +860,9 @@ } }, "node_modules/lightningcss-darwin-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", - "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", "cpu": [ "x64" ], @@ -929,9 +881,9 @@ } }, "node_modules/lightningcss-freebsd-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", - "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", "cpu": [ "x64" ], @@ -950,9 +902,9 @@ } }, "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", - "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", "cpu": [ "arm" ], @@ -971,13 +923,16 @@ } }, "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", - "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -992,13 +947,16 @@ } }, "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", - "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1013,13 +971,16 @@ } }, "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", - "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1034,13 +995,16 @@ } }, "node_modules/lightningcss-linux-x64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", - "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1055,9 +1019,9 @@ } }, "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", - "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", "cpu": [ "arm64" ], @@ -1076,9 +1040,9 @@ } }, "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", - "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", "cpu": [ "x64" ], @@ -1107,9 +1071,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.17", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.17.tgz", - "integrity": "sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g==", + "version": "3.3.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", "dev": true, "funding": [ { @@ -1151,9 +1115,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "dev": true, "license": "MIT", "engines": { @@ -1164,9 +1128,9 @@ } }, "node_modules/postcss": { - "version": "8.5.25", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz", - "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==", + "version": "8.5.29", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.29.tgz", + "integrity": "sha512-49cGhUbXj8Qenv0iTMxA1cFBzxXoctpC9Ujd77t1WcbJIr6nF/eI7g/8MgxrYldFRuAXvja7xQRwavoW7kgrxQ==", "dev": true, "funding": [ { @@ -1184,22 +1148,22 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.16", + "nanoid": "^3.3.19", "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "source-map-js": "^1.2.2" }, "engines": { "node": "^10 || ^12 || >=14" } }, "node_modules/rolldown": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", - "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.13.tgz", + "integrity": "sha512-/5apOkwWxtACcQtZ5WlrAsKS4JwXVThQPJZ3RqIruRY9UG9M8e0VlXN068xum/JRKA4aIUoJ13ghe/kGCvidiQ==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.133.0", + "@oxc-project/types": "=0.153.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -1209,21 +1173,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.3", - "@rolldown/binding-darwin-arm64": "1.0.3", - "@rolldown/binding-darwin-x64": "1.0.3", - "@rolldown/binding-freebsd-x64": "1.0.3", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", - "@rolldown/binding-linux-arm64-gnu": "1.0.3", - "@rolldown/binding-linux-arm64-musl": "1.0.3", - "@rolldown/binding-linux-ppc64-gnu": "1.0.3", - "@rolldown/binding-linux-s390x-gnu": "1.0.3", - "@rolldown/binding-linux-x64-gnu": "1.0.3", - "@rolldown/binding-linux-x64-musl": "1.0.3", - "@rolldown/binding-openharmony-arm64": "1.0.3", - "@rolldown/binding-wasm32-wasi": "1.0.3", - "@rolldown/binding-win32-arm64-msvc": "1.0.3", - "@rolldown/binding-win32-x64-msvc": "1.0.3" + "@rolldown/binding-android-arm-eabi": "1.2.13", + "@rolldown/binding-android-arm64": "1.2.13", + "@rolldown/binding-darwin-arm64": "1.2.13", + "@rolldown/binding-darwin-x64": "1.2.13", + "@rolldown/binding-freebsd-x64": "1.2.13", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.13", + "@rolldown/binding-linux-arm64-gnu": "1.2.13", + "@rolldown/binding-linux-arm64-musl": "1.2.13", + "@rolldown/binding-linux-ppc64-gnu": "1.2.13", + "@rolldown/binding-linux-s390x-gnu": "1.2.13", + "@rolldown/binding-linux-x64-gnu": "1.2.13", + "@rolldown/binding-linux-x64-musl": "1.2.13", + "@rolldown/binding-openharmony-arm64": "1.2.13", + "@rolldown/binding-win32-arm64-msvc": "1.2.13", + "@rolldown/binding-win32-x64-msvc": "1.2.13" } }, "node_modules/siginfo": { @@ -1234,9 +1198,9 @@ "license": "ISC" }, "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -1292,23 +1256,15 @@ } }, "node_modules/tinyrainbow": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", - "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.2.0.tgz", + "integrity": "sha512-LgO3D9yZJjApUiuUfl9iFAwrtaX4+lok3wJIqttGoKCHlWUqHqbQpnxCf82L8FjgKsh4iGo78hqJwgL8F6To2A==", "dev": true, "license": "MIT", "engines": { "node": ">=14.0.0" } }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD", - "optional": true - }, "node_modules/tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", @@ -1358,16 +1314,16 @@ "license": "ISC" }, "node_modules/vite": { - "version": "8.0.16", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", - "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.4.tgz", + "integrity": "sha512-IftLE8phJhdNRIGNEV4JCCvfNScoZQVfcXaN8TQropWGJtOHcu+iAB9pHcuGvmEb/kddw0LBe/jS8ztdC6xdiQ==", "dev": true, "license": "MIT", "dependencies": { - "lightningcss": "^1.32.0", - "picomatch": "^4.0.4", - "postcss": "^8.5.15", - "rolldown": "1.0.3", + "lightningcss": "^1.33.0", + "picomatch": "^4.0.7", + "postcss": "^8.5.29", + "rolldown": "~1.2.12", "tinyglobby": "^0.2.17" }, "bin": { @@ -1384,7 +1340,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.1.18", + "@vitejs/devtools": "^0.7.1", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", @@ -1436,19 +1392,19 @@ } }, "node_modules/vitest": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.0.tgz", - "integrity": "sha512-YbDrMF9jM2Lqc++2530UourxZHmkKLxrs4+mYhEwqWS97WJ7wOYEkcr+QfRgJ3PW9wz3odRijLZjHEaRLTNbqw==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz", + "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.0", - "@vitest/mocker": "4.1.0", - "@vitest/pretty-format": "4.1.0", - "@vitest/runner": "4.1.0", - "@vitest/snapshot": "4.1.0", - "@vitest/spy": "4.1.0", - "@vitest/utils": "4.1.0", + "@vitest/expect": "4.1.11", + "@vitest/mocker": "4.1.11", + "@vitest/pretty-format": "4.1.11", + "@vitest/runner": "4.1.11", + "@vitest/snapshot": "4.1.11", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -1459,8 +1415,8 @@ "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.0.3", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0-0", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "bin": { @@ -1476,13 +1432,15 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.0", - "@vitest/browser-preview": "4.1.0", - "@vitest/browser-webdriverio": "4.1.0", - "@vitest/ui": "4.1.0", + "@vitest/browser-playwright": "4.1.11", + "@vitest/browser-preview": "4.1.11", + "@vitest/browser-webdriverio": "4.1.11", + "@vitest/coverage-istanbul": "4.1.11", + "@vitest/coverage-v8": "4.1.11", + "@vitest/ui": "4.1.11", "happy-dom": "*", "jsdom": "*", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0-0" + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "@edge-runtime/vm": { @@ -1503,6 +1461,12 @@ "@vitest/browser-webdriverio": { "optional": true }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, "@vitest/ui": { "optional": true }, diff --git a/scripts/corrections/package.json b/scripts/corrections/package.json index 0afee52cc9..0dc9cfeb4b 100644 --- a/scripts/corrections/package.json +++ b/scripts/corrections/package.json @@ -10,6 +10,6 @@ "@octokit/rest": "^22.0.1", "@types/node": "^22.0.0", "typescript": "^5.8.0", - "vitest": "^4.1.0" + "vitest": "^4.1.11" } } diff --git a/scripts/docs-validation/package-lock.json b/scripts/docs-validation/package-lock.json index 0c2751fa78..0f0c48a705 100644 --- a/scripts/docs-validation/package-lock.json +++ b/scripts/docs-validation/package-lock.json @@ -480,9 +480,9 @@ } }, "node_modules/brace-expansion": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", - "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" diff --git a/test/harness/package-lock.json b/test/harness/package-lock.json index 0c31f6ea1d..8a72836f53 100644 --- a/test/harness/package-lock.json +++ b/test/harness/package-lock.json @@ -9,51 +9,20 @@ "version": "1.0.0", "license": "ISC", "devDependencies": { - "@modelcontextprotocol/sdk": "^1.26.0", + "@modelcontextprotocol/sdk": "^1.31.0", "@types/node": "^25.3.3", "@types/node-forge": "^1.3.14", "node-forge": "^1.4.0", "openai": "^6.17.0", "tsx": "^4.21.0", "typescript": "^5.9.3", - "vitest": "^4.0.18", + "vitest": "^4.1.11", "yaml": "^2.8.2" }, "engines": { "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@emnapi/core": { - "version": "1.10.0", - "integrity": "sha1-OAzMjyQS6iLR2XLff47iOjucdGc=", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.1", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.10.0", - "integrity": "sha1-SyYMDTU0IE6YxhELjbGph9JuyHw=", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "integrity": "sha1-KP7SGhuhznl8RKBwq8lNQvOuhUg=", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@esbuild/aix-ppc64": { "version": "0.28.1", "integrity": "sha1-egGo0uwvuy2seK2tCbD6eB5Agr4=", @@ -469,28 +438,19 @@ "node": ">=18" } }, - "node_modules/@hono/node-server": { - "version": "1.19.14", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.14.1" - }, - "peerDependencies": { - "hono": "^4" - } - }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", + "version": "1.6.0", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "dev": true, "license": "MIT" }, "node_modules/@modelcontextprotocol/sdk": { - "version": "1.26.0", + "version": "1.32.1", + "integrity": "sha512-2DdE+SJDtzLEEWzY1ZjY7Q+VcPhcV1KisD3zI4u0XZyktsjHum1mwbMI+JaulUBi2OZk+KJAi2uPXzxichPkdw==", "dev": true, "license": "MIT", "dependencies": { - "@hono/node-server": "^1.19.9", + "@hono/node-server": "^1.19.9 || ^2.0.5", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", @@ -524,38 +484,46 @@ } } }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.2.3", - "integrity": "sha1-l+PUXXQk3F2h1OMvO/OykvbBtEw=", + "node_modules/@modelcontextprotocol/sdk/node_modules/@hono/node-server": { + "version": "1.19.17", + "integrity": "sha512-dSneS5qhiauZWGDCeK4o695Xd9nUNjviSZCMQrj10eetr8Uln1ucn6bbphOM6UynAMMtNIzZNSpL9vnASJwrPQ==", "dev": true, "license": "MIT", - "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.3" - }, "engines": { - "node": "^20.19.0 || ^22.13.0 || >=23.5.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" + "node": ">=18.14.1" }, "peerDependencies": { - "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", - "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" + "hono": "^4" } }, "node_modules/@oxc-project/types": { - "version": "0.133.0", + "version": "0.153.0", + "integrity": "sha512-jSNrRIyvPVLL5E1z/tS5zLAprosGz/FuI1PWwEOz59j3E4TTTzSpqKb/RDGqJhhW0QHYISGXxq582wGx6T11Tw==", "dev": true, "license": "MIT", "funding": { - "url": "https://github.com/sponsors/Boshen" + "url": "https://github.com/sponsors/oxc-project" + } + }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.13", + "integrity": "sha512-Vu/NICrgdRvUOeaJZIyB2FP63s6fO/4ud5l8dXmxDx9yDyn+mN0y+gsvsVviSli+T361Aqo0h46EuMoobrwawA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.3", - "integrity": "sha1-VM6Pg4IhP0oxSgwve6g/gf/q5ZI=", + "version": "1.2.13", + "integrity": "sha512-6LEoIrGy5vvCd2boNnv2soPSUZj/PRvhp8R/t9KlX+mIZxThIE/ZqxrGXxmuNX0FuvQFvLdZr7S4HrYpYBVhEQ==", "cpu": [ "arm64" ], @@ -570,7 +538,8 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.3", + "version": "1.2.13", + "integrity": "sha512-CaJSRzlQ6Q+zkDMVA9OkVxBjVoPRCDEE3v0FSJ9kIQBgRjFApA3Si4ijhbNVUji7ZJt+PfO0e46qy4nPInHUPA==", "cpu": [ "arm64" ], @@ -585,8 +554,8 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.3", - "integrity": "sha1-U/V94fWZ7PHbE4I8/IjBj7gJVK0=", + "version": "1.2.13", + "integrity": "sha512-e4r340I5hxSzJkD3YJBxgzq/rJ3wwxwdLLb2FPt1Zpyem20nrQPT11DDEEkazwxaHumH8wpglsp/Ozgj/wT6mw==", "cpu": [ "x64" ], @@ -601,8 +570,8 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.3", - "integrity": "sha1-bz/dobeuqsnSaKUmgEtPuW5ONfE=", + "version": "1.2.13", + "integrity": "sha512-hoBWDZ4/K/mJKVMbsgUd1jfpA2DiOrJ54mpegObU9TBHBBrtX4FLIXJJQRDPZ/2Dn91GvPob+Z2hwKJzf4E5SQ==", "cpu": [ "x64" ], @@ -617,8 +586,8 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.3", - "integrity": "sha1-2HpFS/WFzJZ2hJN36R1uN1KXMm8=", + "version": "1.2.13", + "integrity": "sha512-oF9fZu3vTWnTiVAkDFxU9PJLt1nh20K9RRpuHsR7ZnE2L7XookBbDBVLojCVSLGbvtSlxeUNnjAj6DbNsKyzbg==", "cpu": [ "arm" ], @@ -633,12 +602,15 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.3", - "integrity": "sha1-QZ/Wv2Es80jxBSjLzZTrq5YH2NE=", + "version": "1.2.13", + "integrity": "sha512-DTpb/+jMiqWMPgphn4ksW1zW+XLJ6dJJ9FMvnIk9I291LhCctMPhMYJrP5t9p6C9qa3KXadDdUEZHBaPh3kNxQ==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -649,12 +621,15 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.3", - "integrity": "sha1-/MaRhpa7doRId+HkkwoY/Q03QGk=", + "version": "1.2.13", + "integrity": "sha512-xU+Kvv9N2A3SY35zFh1FWWNjxbadE/BKeqnkXe7vScU4GZsw757BlVmDLITZEq8DPpk6m7uoDYkK7P+x/uU5Ow==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -665,12 +640,15 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.3", - "integrity": "sha1-Mq7LfI2uXU8qjN5XoFjshpkVQvg=", + "version": "1.2.13", + "integrity": "sha512-XMk/hnhh25oQ756Lclb1Q11h4ll0xC0Esa5w4Vzp+mAE2S3AGJgeM0SonrIgY8fHhjarb6hcoTuwoFG0VVP2ig==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -681,12 +659,15 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.3", - "integrity": "sha1-vtk0bqgea7i5PPEfXYi3fbiQt2M=", + "version": "1.2.13", + "integrity": "sha512-U1BoTHYmlywE2n3HUWjzZ+8EQsKr+OwpxYuDWaubx42tUL8QSL7nOqRz/NVHanibbFP3M1Rxuprz/wNcbMKjqw==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -697,12 +678,15 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.3", - "integrity": "sha1-ZMLSb3Xf/ZtaH5dVegCudyUMjLc=", + "version": "1.2.13", + "integrity": "sha512-J4cm80Pc6wEwV5AZ42o62sIQgDk+Y7R2s646jIwuvO+4V46QB58N4vVuMPWCBaNgursXLpmUWJV//WQAkPvHBQ==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -713,12 +697,15 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.3", - "integrity": "sha1-WkUTLopHZZ7qrztUDClUqXyGD/M=", + "version": "1.2.13", + "integrity": "sha512-W0euZS40U4V6JkmEnVCIX9mcsL6cbXQ4X8c2w+MMOIjFg68TXUW+u3RT+2e1t1pv9mg/EP3pDtK3POXdQ7Rxyw==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -729,8 +716,8 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.3", - "integrity": "sha1-KQUTBoxV6EnchFejKv7h17Csswk=", + "version": "1.2.13", + "integrity": "sha512-do/AF/4n9MRshia3a5aXoy8xM2c6mgfT6D7H/dY6my5z+hfCIR4ab7mk4IRj++nsEQpKy39kd0DQnDq+r692tw==", "cpu": [ "arm64" ], @@ -744,27 +731,9 @@ "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.3", - "integrity": "sha1-PZly2/GpU9PHr6pKDyDvKy458xs=", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "1.10.0", - "@emnapi/runtime": "1.10.0", - "@napi-rs/wasm-runtime": "^1.1.4" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.3", - "integrity": "sha1-oASrYHoW1vA7y1VXKP+IivdXc60=", + "version": "1.2.13", + "integrity": "sha512-6FtUf2cJZobutJdxnGYX8z0vtbgqU0b2v8vfBhkXb9wp2MppMFtkunE+IaOntyi01rkIQoPW2GHABtfzsC0BRQ==", "cpu": [ "arm64" ], @@ -779,8 +748,8 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.3", - "integrity": "sha1-4qJbNGkaHMihIJ195wkGMCbdDNs=", + "version": "1.2.13", + "integrity": "sha512-UKhFaZTeTcbKrb3iU82m17jVcPEAoqDkCN5MBqgPyZSwp/cQmib21crTS0DdH7T1B7wZRWEI89YQAOJMet5yhg==", "cpu": [ "x64" ], @@ -796,26 +765,19 @@ }, "node_modules/@rolldown/pluginutils": { "version": "1.0.1", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "dev": true, "license": "MIT" }, "node_modules/@standard-schema/spec": { "version": "1.1.0", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", "dev": true, "license": "MIT" }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.3", - "integrity": "sha1-AVy6np3UfOFNA9KoxdVHv7FpZl0=", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@types/chai": { "version": "5.2.3", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", "dev": true, "license": "MIT", "dependencies": { @@ -825,11 +787,13 @@ }, "node_modules/@types/deep-eql": { "version": "4.0.2", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", "dev": true, "license": "MIT" }, "node_modules/@types/estree": { "version": "1.0.9", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", "dev": true, "license": "MIT" }, @@ -850,14 +814,15 @@ } }, "node_modules/@vitest/expect": { - "version": "4.1.8", + "version": "4.1.11", + "integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -866,11 +831,12 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.8", + "version": "4.1.11", + "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.8", + "@vitest/spy": "4.1.11", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -891,7 +857,8 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.8", + "version": "4.1.11", + "integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==", "dev": true, "license": "MIT", "dependencies": { @@ -902,11 +869,12 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.8", + "version": "4.1.11", + "integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.8", + "@vitest/utils": "4.1.11", "pathe": "^2.0.3" }, "funding": { @@ -914,12 +882,13 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.8", + "version": "4.1.11", + "integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/pretty-format": "4.1.11", + "@vitest/utils": "4.1.11", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -928,7 +897,8 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.8", + "version": "4.1.11", + "integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==", "dev": true, "license": "MIT", "funding": { @@ -936,11 +906,12 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.8", + "version": "4.1.11", + "integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.8", + "@vitest/pretty-format": "4.1.11", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -993,6 +964,7 @@ }, "node_modules/assertion-error": { "version": "2.0.1", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, "license": "MIT", "engines": { @@ -1000,19 +972,20 @@ } }, "node_modules/body-parser": { - "version": "2.2.2", + "version": "2.3.0", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", "dev": true, "license": "MIT", "dependencies": { "bytes": "^3.1.2", - "content-type": "^1.0.5", + "content-type": "^2.0.0", "debug": "^4.4.3", - "http-errors": "^2.0.0", - "iconv-lite": "^0.7.0", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", "on-finished": "^2.4.1", - "qs": "^6.14.1", - "raw-body": "^3.0.1", - "type-is": "^2.0.1" + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" }, "engines": { "node": ">=18" @@ -1022,6 +995,19 @@ "url": "https://opencollective.com/express" } }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.1.0", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/bytes": { "version": "3.1.2", "dev": true, @@ -1032,6 +1018,7 @@ }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1044,6 +1031,7 @@ }, "node_modules/call-bound": { "version": "1.0.4", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "dev": true, "license": "MIT", "dependencies": { @@ -1058,7 +1046,8 @@ } }, "node_modules/chai": { - "version": "6.2.2", + "version": "6.3.0", + "integrity": "sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==", "dev": true, "license": "MIT", "engines": { @@ -1087,6 +1076,7 @@ }, "node_modules/convert-source-map": { "version": "2.0.0", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, "license": "MIT" }, @@ -1161,6 +1151,7 @@ }, "node_modules/detect-libc": { "version": "2.1.2", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1169,6 +1160,7 @@ }, "node_modules/dunder-proto": { "version": "1.0.1", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "dev": true, "license": "MIT", "dependencies": { @@ -1195,6 +1187,7 @@ }, "node_modules/es-define-property": { "version": "1.0.1", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, "license": "MIT", "engines": { @@ -1203,6 +1196,7 @@ }, "node_modules/es-errors": { "version": "1.3.0", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, "license": "MIT", "engines": { @@ -1215,7 +1209,8 @@ "license": "MIT" }, "node_modules/es-object-atoms": { - "version": "1.1.1", + "version": "1.1.2", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", "dev": true, "license": "MIT", "dependencies": { @@ -1272,6 +1267,7 @@ }, "node_modules/estree-walker": { "version": "3.0.3", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "dev": true, "license": "MIT", "dependencies": { @@ -1378,8 +1374,8 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.7", - "integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==", + "version": "3.1.8", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", "dev": true, "funding": [ { @@ -1395,6 +1391,7 @@ }, "node_modules/fdir": { "version": "6.5.0", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, "license": "MIT", "engines": { @@ -1459,6 +1456,7 @@ }, "node_modules/function-bind": { "version": "1.1.2", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, "license": "MIT", "funding": { @@ -1467,6 +1465,7 @@ }, "node_modules/get-intrinsic": { "version": "1.3.0", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1490,6 +1489,7 @@ }, "node_modules/get-proto": { "version": "1.0.1", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "dev": true, "license": "MIT", "dependencies": { @@ -1502,6 +1502,7 @@ }, "node_modules/gopd": { "version": "1.2.0", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, "license": "MIT", "engines": { @@ -1513,6 +1514,7 @@ }, "node_modules/has-symbols": { "version": "1.1.0", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "license": "MIT", "engines": { @@ -1523,7 +1525,8 @@ } }, "node_modules/hasown": { - "version": "2.0.2", + "version": "2.0.4", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", "dev": true, "license": "MIT", "dependencies": { @@ -1582,7 +1585,8 @@ "license": "ISC" }, "node_modules/ip-address": { - "version": "10.4.0", + "version": "10.7.4", + "integrity": "sha512-DWBMKyeM25D70nrIiTkgQth59/G+naKOTep6huF9j+GmeK3DMD60Zvxg5d5qQnz+38AHgou6ean2LECX+lrKDg==", "dev": true, "license": "MIT", "engines": { @@ -1626,7 +1630,8 @@ "license": "BSD-2-Clause" }, "node_modules/lightningcss": { - "version": "1.32.0", + "version": "1.33.0", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", "dev": true, "license": "MPL-2.0", "dependencies": { @@ -1640,22 +1645,22 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "lightningcss-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" } }, "node_modules/lightningcss-android-arm64": { - "version": "1.32.0", - "integrity": "sha1-8DOIURbf79nG9UeHUj41FLYeGWg=", + "version": "1.33.0", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", "cpu": [ "arm64" ], @@ -1674,7 +1679,8 @@ } }, "node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", + "version": "1.33.0", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", "cpu": [ "arm64" ], @@ -1693,8 +1699,8 @@ } }, "node_modules/lightningcss-darwin-x64": { - "version": "1.32.0", - "integrity": "sha1-NfPpczLRMLnKGB4RtWje1q68bV4=", + "version": "1.33.0", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", "cpu": [ "x64" ], @@ -1713,8 +1719,8 @@ } }, "node_modules/lightningcss-freebsd-x64": { - "version": "1.32.0", - "integrity": "sha1-l3enZHK2Ttb/lDQq1kx7r9eUpXU=", + "version": "1.33.0", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", "cpu": [ "x64" ], @@ -1733,8 +1739,8 @@ } }, "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.32.0", - "integrity": "sha1-E65lLhq3O5E117faFy9mbEEK1T0=", + "version": "1.33.0", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", "cpu": [ "arm" ], @@ -1753,12 +1759,15 @@ } }, "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.32.0", - "integrity": "sha1-QXhYeVqUWS9oASOhsfnaig4e8zU=", + "version": "1.33.0", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1773,12 +1782,15 @@ } }, "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.32.0", - "integrity": "sha1-a+NmkugQtxgECAL9gJYjz/5zITM=", + "version": "1.33.0", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1793,12 +1805,15 @@ } }, "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.32.0", - "integrity": "sha1-C3gDr06yHP043Tn+Kru1PH3QkfY=", + "version": "1.33.0", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1813,12 +1828,15 @@ } }, "node_modules/lightningcss-linux-x64-musl": { - "version": "1.32.0", - "integrity": "sha1-iNyLqGXd3bGsXvBLDxYYBEGMFjs=", + "version": "1.33.0", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1833,8 +1851,8 @@ } }, "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.32.0", - "integrity": "sha1-TzC6P6XpJfW3n5RejMDRdsOxqzg=", + "version": "1.33.0", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", "cpu": [ "arm64" ], @@ -1853,8 +1871,8 @@ } }, "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.32.0", - "integrity": "sha1-FBqlYFZFBkkokCu0rwRfp9n0Igo=", + "version": "1.33.0", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", "cpu": [ "x64" ], @@ -1874,6 +1892,7 @@ }, "node_modules/magic-string": { "version": "0.30.21", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1882,6 +1901,7 @@ }, "node_modules/math-intrinsics": { "version": "1.1.0", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "dev": true, "license": "MIT", "engines": { @@ -1936,7 +1956,8 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.17", + "version": "3.3.20", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", "dev": true, "funding": [ { @@ -1978,6 +1999,7 @@ }, "node_modules/object-inspect": { "version": "1.13.4", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, "license": "MIT", "engines": { @@ -2062,16 +2084,19 @@ }, "node_modules/pathe": { "version": "2.0.3", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, "license": "MIT" }, "node_modules/picocolors": { "version": "1.1.1", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.4", + "version": "4.0.7", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "dev": true, "license": "MIT", "engines": { @@ -2090,7 +2115,8 @@ } }, "node_modules/postcss": { - "version": "8.5.25", + "version": "8.5.29", + "integrity": "sha512-49cGhUbXj8Qenv0iTMxA1cFBzxXoctpC9Ujd77t1WcbJIr6nF/eI7g/8MgxrYldFRuAXvja7xQRwavoW7kgrxQ==", "dev": true, "funding": [ { @@ -2108,16 +2134,17 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.16", + "nanoid": "^3.3.19", "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "source-map-js": "^1.2.2" }, "engines": { "node": "^10 || ^12 || >=14" } }, "node_modules/proxy-addr": { - "version": "2.0.7", + "version": "2.0.8", + "integrity": "sha512-5nnx0yGyVUcY6t9RnWcARWtwT9F1D8O9rt08htPvnd49W1IgZtmLkhu9WfMzQj1cFxjHIO6connUNVW5k7AVyQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2126,14 +2153,20 @@ }, "engines": { "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/qs": { - "version": "6.15.2", + "version": "6.16.0", + "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.1.0" + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" }, "engines": { "node": ">=0.6" @@ -2173,11 +2206,12 @@ } }, "node_modules/rolldown": { - "version": "1.0.3", + "version": "1.2.13", + "integrity": "sha512-/5apOkwWxtACcQtZ5WlrAsKS4JwXVThQPJZ3RqIruRY9UG9M8e0VlXN068xum/JRKA4aIUoJ13ghe/kGCvidiQ==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.133.0", + "@oxc-project/types": "=0.153.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -2187,21 +2221,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.3", - "@rolldown/binding-darwin-arm64": "1.0.3", - "@rolldown/binding-darwin-x64": "1.0.3", - "@rolldown/binding-freebsd-x64": "1.0.3", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", - "@rolldown/binding-linux-arm64-gnu": "1.0.3", - "@rolldown/binding-linux-arm64-musl": "1.0.3", - "@rolldown/binding-linux-ppc64-gnu": "1.0.3", - "@rolldown/binding-linux-s390x-gnu": "1.0.3", - "@rolldown/binding-linux-x64-gnu": "1.0.3", - "@rolldown/binding-linux-x64-musl": "1.0.3", - "@rolldown/binding-openharmony-arm64": "1.0.3", - "@rolldown/binding-wasm32-wasi": "1.0.3", - "@rolldown/binding-win32-arm64-msvc": "1.0.3", - "@rolldown/binding-win32-x64-msvc": "1.0.3" + "@rolldown/binding-android-arm-eabi": "1.2.13", + "@rolldown/binding-android-arm64": "1.2.13", + "@rolldown/binding-darwin-arm64": "1.2.13", + "@rolldown/binding-darwin-x64": "1.2.13", + "@rolldown/binding-freebsd-x64": "1.2.13", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.13", + "@rolldown/binding-linux-arm64-gnu": "1.2.13", + "@rolldown/binding-linux-arm64-musl": "1.2.13", + "@rolldown/binding-linux-ppc64-gnu": "1.2.13", + "@rolldown/binding-linux-s390x-gnu": "1.2.13", + "@rolldown/binding-linux-x64-gnu": "1.2.13", + "@rolldown/binding-linux-x64-musl": "1.2.13", + "@rolldown/binding-openharmony-arm64": "1.2.13", + "@rolldown/binding-win32-arm64-msvc": "1.2.13", + "@rolldown/binding-win32-x64-msvc": "1.2.13" } }, "node_modules/router": { @@ -2292,13 +2326,14 @@ } }, "node_modules/side-channel": { - "version": "1.1.0", + "version": "1.1.1", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" }, @@ -2310,12 +2345,13 @@ } }, "node_modules/side-channel-list": { - "version": "1.0.0", + "version": "1.0.1", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" + "object-inspect": "^1.13.4" }, "engines": { "node": ">= 0.4" @@ -2326,6 +2362,7 @@ }, "node_modules/side-channel-map": { "version": "1.0.1", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "dev": true, "license": "MIT", "dependencies": { @@ -2343,6 +2380,7 @@ }, "node_modules/side-channel-weakmap": { "version": "1.0.2", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "dev": true, "license": "MIT", "dependencies": { @@ -2365,7 +2403,8 @@ "license": "ISC" }, "node_modules/source-map-js": { - "version": "1.2.1", + "version": "1.2.2", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -2405,6 +2444,7 @@ }, "node_modules/tinyglobby": { "version": "0.2.17", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "dev": true, "license": "MIT", "dependencies": { @@ -2419,7 +2459,8 @@ } }, "node_modules/tinyrainbow": { - "version": "3.1.0", + "version": "3.2.0", + "integrity": "sha512-LgO3D9yZJjApUiuUfl9iFAwrtaX4+lok3wJIqttGoKCHlWUqHqbQpnxCf82L8FjgKsh4iGo78hqJwgL8F6To2A==", "dev": true, "license": "MIT", "engines": { @@ -2434,13 +2475,6 @@ "node": ">=0.6" } }, - "node_modules/tslib": { - "version": "2.8.1", - "integrity": "sha1-YS7+TtI11Wfoq6Xypfq3AoCt6D8=", - "dev": true, - "license": "0BSD", - "optional": true - }, "node_modules/tsx": { "version": "4.22.4", "dev": true, @@ -2459,16 +2493,34 @@ } }, "node_modules/type-is": { - "version": "2.0.1", + "version": "2.1.0", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", "dev": true, "license": "MIT", "dependencies": { - "content-type": "^1.0.5", + "content-type": "^2.0.0", "media-typer": "^1.1.0", "mime-types": "^3.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.1.0", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/typescript": { @@ -2505,14 +2557,15 @@ } }, "node_modules/vite": { - "version": "8.0.16", + "version": "8.3.4", + "integrity": "sha512-IftLE8phJhdNRIGNEV4JCCvfNScoZQVfcXaN8TQropWGJtOHcu+iAB9pHcuGvmEb/kddw0LBe/jS8ztdC6xdiQ==", "dev": true, "license": "MIT", "dependencies": { - "lightningcss": "^1.32.0", - "picomatch": "^4.0.4", - "postcss": "^8.5.15", - "rolldown": "1.0.3", + "lightningcss": "^1.33.0", + "picomatch": "^4.0.7", + "postcss": "^8.5.29", + "rolldown": "~1.2.12", "tinyglobby": "^0.2.17" }, "bin": { @@ -2529,7 +2582,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.1.18", + "@vitejs/devtools": "^0.7.1", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", @@ -2581,17 +2634,18 @@ } }, "node_modules/vitest": { - "version": "4.1.8", + "version": "4.1.11", + "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.8", - "@vitest/mocker": "4.1.8", - "@vitest/pretty-format": "4.1.8", - "@vitest/runner": "4.1.8", - "@vitest/snapshot": "4.1.8", - "@vitest/spy": "4.1.8", - "@vitest/utils": "4.1.8", + "@vitest/expect": "4.1.11", + "@vitest/mocker": "4.1.11", + "@vitest/pretty-format": "4.1.11", + "@vitest/runner": "4.1.11", + "@vitest/snapshot": "4.1.11", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -2619,12 +2673,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.8", - "@vitest/browser-preview": "4.1.8", - "@vitest/browser-webdriverio": "4.1.8", - "@vitest/coverage-istanbul": "4.1.8", - "@vitest/coverage-v8": "4.1.8", - "@vitest/ui": "4.1.8", + "@vitest/browser-playwright": "4.1.11", + "@vitest/browser-preview": "4.1.11", + "@vitest/browser-webdriverio": "4.1.11", + "@vitest/coverage-istanbul": "4.1.11", + "@vitest/coverage-v8": "4.1.11", + "@vitest/ui": "4.1.11", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" diff --git a/test/harness/package.json b/test/harness/package.json index 9b37dfb9d0..055121c48e 100644 --- a/test/harness/package.json +++ b/test/harness/package.json @@ -14,14 +14,17 @@ "node": "^20.19.0 || >=22.12.0" }, "devDependencies": { - "@modelcontextprotocol/sdk": "^1.26.0", + "@modelcontextprotocol/sdk": "^1.31.0", "@types/node": "^25.3.3", "@types/node-forge": "^1.3.14", "node-forge": "^1.4.0", "openai": "^6.17.0", "tsx": "^4.21.0", "typescript": "^5.9.3", - "vitest": "^4.0.18", + "vitest": "^4.1.11", "yaml": "^2.8.2" + }, + "overrides": { + "@hono/node-server": "^1.19.15" } } diff --git a/test/harness/replayingCapiProxy.test.ts b/test/harness/replayingCapiProxy.test.ts index cbd51c1b09..347b2b9547 100644 --- a/test/harness/replayingCapiProxy.test.ts +++ b/test/harness/replayingCapiProxy.test.ts @@ -11,6 +11,7 @@ import type { } from "openai/resources/chat/completions"; import os from "os"; import path from "path"; +import { gzipSync } from "zlib"; import { afterEach, beforeEach, describe, expect, test, vi } from "vitest"; import yaml from "yaml"; import { @@ -148,6 +149,31 @@ describe("ReplayingCapiProxy", () => { } }); + test("accepts telemetry locally before replay configuration", async () => { + const proxy = new ReplayingCapiProxy("http://localhost"); + const address = await proxy.start(); + try { + const response = await fetch(`${address}/telemetry`, { + method: "POST", + headers: { + "content-type": "application/x-json-stream", + "content-encoding": "gzip", + }, + body: gzipSync('{"name":"fixture-event"}\n'), + }); + expect(response.status).toBe(204); + expect(await response.text()).toBe(""); + expect(proxy.exchanges).toMatchObject([ + { + request: { url: "/telemetry", method: "POST" }, + response: { statusCode: 204, body: "" }, + }, + ]); + } finally { + await proxy.stop(); + } + }); + test("does not write file when no chat completion exchanges", async () => { const outputPath = path.join(tempDir, "output.yaml"); const proxy = new ReplayingCapiProxy( diff --git a/test/harness/replayingCapiProxy.ts b/test/harness/replayingCapiProxy.ts index ad21f0d317..b4e0f455a5 100644 --- a/test/harness/replayingCapiProxy.ts +++ b/test/harness/replayingCapiProxy.ts @@ -352,6 +352,15 @@ export class ReplayingCapiProxy extends CapturingHttpProxy { return; } + if ( + options.requestOptions.path === "/telemetry" && + options.requestOptions.method === "POST" + ) { + options.onResponseStart(204, {}); + options.onResponseEnd(); + return; + } + if ( options.requestOptions.path === "/memory-api-config" && options.requestOptions.method === "POST" diff --git a/test/harness/sdk-diagnostics.mjs b/test/harness/sdk-diagnostics.mjs index 817df78c39..829c8ed27d 100644 --- a/test/harness/sdk-diagnostics.mjs +++ b/test/harness/sdk-diagnostics.mjs @@ -46,15 +46,62 @@ const shellState = { }; const records = { "workflow availability decision": { available: "boolean" }, + "sdk transport teardown": { + connection: "count", + active_requests: "count", + driver_finished: "boolean", + phase: [ + "shutdown_writer", + "launcher", + "launcher_complete", + "driver", + "driver_complete", + "driver_failed", + "driver_timeout", + "driver_abort_complete", + "writer_shutdown_complete", + "peer_eof", + "notification_worker", + "notification_worker_complete", + "notification_worker_failed", + "notification_worker_timed_out", + "active_request_grace", + "handle_close", + "handle_close_complete", + "active_requests", + "active_requests_complete", + "active_requests_timed_out", + "flush", + "flush_complete", + "flush_cancelled", + "flush_timed_out", + "flush_unavailable", + "writer_join", + "writer_join_complete", + "complete", + ], + }, "sdk pending permission response": { ...presence, prepared_replay: "boolean", aborting: "boolean", - reason: ["prepared_replay", "completed_request", "unknown_request", "resolved_tool", "accepted"], + reason: [ + "prepared_replay", + "completed_request", + "unknown_request", + "resolved_tool", + "accepted", + ], }, "sdk pending tool response": { ...presence, - reason: ["completed_request", "unknown_request", "non_pending_request", "completed_tool", "accepted"], + reason: [ + "completed_request", + "unknown_request", + "non_pending_request", + "completed_tool", + "accepted", + ], }, "sdk pending permission delivery": { generation: "number", @@ -163,6 +210,105 @@ const records = { child_span_handle: "number", chat_span_handle: "number", }, + "sdk otel admission": { + phase: ["received", "no_tracker", "fenced", "pending", "submitted"], + event_sequence: "count", + policy_revision: "count", + authority_fenced: "boolean", + preparation_pending: "boolean", + policy_enabled: "boolean", + projected_event_count: "count", + submitted: "boolean", + }, + "sdk otel policy state": { + origin: [ + "host_prepare", + "host_commit", + "host_commit_initial", + "host_bind", + "host_rollback", + "explicit_fence", + "legacy_settled", + "native_pending", + "native_settled", + "native_apply", + "reserved_apply", + "direct_apply", + ], + kind: [ + "transition", + "restore", + "fence", + "apply_stale_source", + "apply_retry", + "apply_superseded", + "apply_settled", + ], + expected_some: "boolean", + expected_incarnation: "count", + expected_revision: "count", + previous_incarnation: "count", + previous_revision: "count", + current_incarnation: "count", + current_revision: "count", + previous_authority_fenced: "boolean", + authority_fenced: "boolean", + previous_preparation_pending: "boolean", + preparation_pending: "boolean", + previous_native_owned: "boolean", + native_owned: "boolean", + policy_enabled: "boolean", + returned_some: "boolean", + applied: "boolean", + build_succeeded: "boolean", + }, + "sdk otel core policy publication": { + origin: [ + "clear_account_policy", + "retained_device_update", + "retained_server_update", + "retained_signed_out_update", + "registry_rotation", + "signed_out_policy_clear", + "refresh_start", + "ingest_settlement", + "standalone_provider_rebind", + "standalone_provider_restore", + "construction_options_auth", + "manager_auth_changed", + "resolved_session_auth", + "hydrated_session_auth", + "set_credentials", + "clear_credentials", + "other_auth_mutation", + ], + kind: ["pending_publish", "pending_publish_returned"], + registry_generation: "count", + previous_auth_generation: "count", + auth_generation: "count", + auth_generation_changed: "boolean", + previous_server_pending: "boolean", + server_pending: "boolean", + policy_identity_present: "boolean", + source_recovery: "boolean", + clear_retained: "boolean", + composition_succeeded: "boolean", + refresh_generation: "count", + has_resolved_managed_settings: "boolean", + has_eligible_current_otel_policy: "boolean", + expected_auth_generation: "count", + }, + "sdk otel policy settlement": { + origin: ["standalone_commit"], + kind: ["reservation", "application"], + succeeded: "boolean", + reservation_some: "boolean", + committed_incarnation: "count", + committed_revision: "count", + expected_incarnation: "count", + expected_revision: "count", + applied: "boolean", + }, "sdk assistant message": { ...childParts, scope: ["parent", "child"], @@ -174,7 +320,12 @@ const records = { ...childParts, scope: ["parent", "child"], operation: ["chat"], - reason: [...childCloseReasons, "model_call_start", "assistant_turn_end", "parent_turn_close"], + reason: [ + ...childCloseReasons, + "model_call_start", + "assistant_turn_end", + "parent_turn_close", + ], status: ["unset", "error"], }, "sdk child completion": { @@ -230,7 +381,14 @@ const records = { }, "sdk shell wait": { ...shellState, - phase: ["interrupted", "stale_generation", "completion", "cancelled", "deadline", "completion_after_deadline"], + phase: [ + "interrupted", + "stale_generation", + "completion", + "cancelled", + "deadline", + "completion_after_deadline", + ], wait_generation: "number", current_wait_generation: "number", elapsed_ms: "elapsed", @@ -257,9 +415,11 @@ export function sanitizeDiagnosticLine(line) { ? rule.includes(value) : rule === "number" ? Number.isSafeInteger(value) - : rule === "elapsed" - ? Number.isFinite(value) && value >= 0 - : typeof value === rule; + : rule === "count" + ? Number.isSafeInteger(value) && value >= 0 + : rule === "elapsed" + ? Number.isFinite(value) && value >= 0 + : typeof value === rule; if (!valid) return undefined; output[key] = value; } @@ -285,7 +445,10 @@ export async function readDiagnosticTail(home) { } for (const file of files.sort()) { if (!file.endsWith(".log")) continue; - const lines = createInterface({ input: createReadStream(join(home, "logs", file)), crlfDelay: Infinity }); + const lines = createInterface({ + input: createReadStream(join(home, "logs", file)), + crlfDelay: Infinity, + }); for await (const line of lines) append(line); } return tail; diff --git a/test/harness/sdk-diagnostics.test.ts b/test/harness/sdk-diagnostics.test.ts index 53d372a284..9a57c8b8d9 100644 --- a/test/harness/sdk-diagnostics.test.ts +++ b/test/harness/sdk-diagnostics.test.ts @@ -11,6 +11,251 @@ import { readDiagnosticTail, sanitizeDiagnosticLine } from "./sdk-diagnostics.mj const prefix = "2026-10-05T12:00:00Z [DEBUG] [rust:sdk_diagnostics] "; describe("SDK failure diagnostics", () => { + it("projects model admission phases, authoritative sequences and policy metadata without content", () => { + const cases = [ + { phase: "received" }, + { phase: "no_tracker" }, + { + phase: "fenced", + event_sequence: 17, + policy_revision: 3, + authority_fenced: false, + preparation_pending: true, + policy_enabled: true, + }, + { phase: "pending", event_sequence: 17 }, + { phase: "submitted", event_sequence: 17, projected_event_count: 1, submitted: true }, + { phase: "submitted", projected_event_count: 0, submitted: false }, + ]; + for (const fields of cases) { + const safe = sanitizeDiagnosticLine( + `${prefix}sdk otel admission ${JSON.stringify({ + ...fields, + session_id: "PRIVATE_SESSION", + event_id: "PRIVATE_EVENT", + model: "PRIVATE_MODEL", + payload: { content: "PRIVATE_PAYLOAD" }, + error: "PRIVATE_ERROR", + path: "PRIVATE_PATH", + })}` + ); + expect(safe).toBeDefined(); + expect(JSON.parse(safe!.slice("sdk otel admission ".length))).toEqual(fields); + expect(safe).not.toContain("PRIVATE"); + } + for (const fields of [ + { phase: "PRIVATE_PHASE" }, + { event_sequence: -1 }, + { event_sequence: 0.5 }, + { event_sequence: Number.MAX_SAFE_INTEGER + 1 }, + { event_sequence: "PRIVATE_SEQUENCE" }, + { event_sequence: null }, + { policy_revision: -1 }, + { policy_revision: 0.5 }, + { projected_event_count: -1 }, + { projected_event_count: 0.5 }, + { authority_fenced: "PRIVATE_STATE" }, + { preparation_pending: null }, + { policy_enabled: "PRIVATE_STATE" }, + { submitted: "PRIVATE_STATE" }, + { session_id: "PRIVATE_SESSION" }, + ]) { + expect( + sanitizeDiagnosticLine(`${prefix}sdk otel admission ${JSON.stringify(fields)}`) + ).toBeUndefined(); + } + }); + + it.each([ + { + label: "native authority fence", + record: "sdk otel policy state", + fields: { + origin: "native_pending", + kind: "fence", + expected_some: false, + previous_incarnation: 2, + previous_revision: 10, + current_incarnation: 2, + current_revision: 11, + previous_authority_fenced: false, + authority_fenced: true, + previous_preparation_pending: true, + preparation_pending: true, + previous_native_owned: true, + native_owned: true, + policy_enabled: true, + returned_some: true, + }, + }, + { + label: "resident credential publication", + record: "sdk otel core policy publication", + fields: { + origin: "standalone_provider_rebind", + kind: "pending_publish_returned", + registry_generation: 1, + previous_auth_generation: 2, + auth_generation: 3, + auth_generation_changed: true, + previous_server_pending: false, + server_pending: true, + policy_identity_present: true, + source_recovery: false, + }, + }, + { + label: "superseded host reservation", + record: "sdk otel policy settlement", + fields: { + origin: "standalone_commit", + kind: "reservation", + succeeded: true, + reservation_some: false, + }, + }, + { + label: "successfully disabled application", + record: "sdk otel policy settlement", + fields: { + origin: "standalone_commit", + kind: "application", + expected_incarnation: 2, + expected_revision: 3, + succeeded: true, + applied: false, + }, + }, + ])("projects $label without credential or policy content", ({ record, fields }) => { + const safe = sanitizeDiagnosticLine( + `${prefix}${record} ${JSON.stringify({ + ...fields, + session_id: "PRIVATE_SESSION", + registration: "PRIVATE_REGISTRATION", + account: "PRIVATE_ACCOUNT", + policy: { endpoint: "PRIVATE_ENDPOINT", headers: { token: "PRIVATE_TOKEN" } }, + error: "PRIVATE_ERROR", + })}` + ); + expect(safe).toBeDefined(); + expect(JSON.parse(safe!.slice(record.length + 1))).toEqual(fields); + expect(safe).not.toContain("PRIVATE"); + }); + + it.each([ + ["sdk otel policy state", "current_revision", "authority_fenced"], + ["sdk otel core policy publication", "auth_generation", "server_pending"], + ["sdk otel policy settlement", "committed_revision", "reservation_some"], + ])("rejects unaudited or invalid %s fields", (record, count, flag) => { + for (const fields of [ + { origin: "PRIVATE_ORIGIN" }, + { kind: "PRIVATE_KIND" }, + ...[-1, 0.5, Number.MAX_SAFE_INTEGER + 1, "PRIVATE_COUNT", null].map((value) => ({ + [count]: value, + })), + { [flag]: "PRIVATE_STATE" }, + { [flag]: null }, + { session_id: "PRIVATE_SESSION" }, + ]) { + expect( + sanitizeDiagnosticLine(`${prefix}${record} ${JSON.stringify(fields)}`) + ).toBeUndefined(); + } + }); + + it("preserves policy attribution through the audited file collector", async () => { + const home = await mkdtemp(join(tmpdir(), "sdk-policy-diagnostics-")); + onTestFinished(() => rm(home, { recursive: true, force: true })); + await mkdir(join(home, "logs")); + await writeFile( + join(home, "logs", "policy.log"), + [ + `${prefix}sdk otel core policy publication {"origin":"standalone_provider_rebind","kind":"pending_publish_returned","auth_generation":3,"account":"PRIVATE"}`, + `${prefix}sdk otel policy state {"origin":"native_pending","kind":"fence","current_revision":11,"authority_fenced":true,"policy":"PRIVATE"}`, + `${prefix}sdk otel policy settlement {"origin":"standalone_commit","kind":"reservation","succeeded":true,"reservation_some":false,"session_id":"PRIVATE"}`, + ].join("\n") + ); + expect(await readDiagnosticTail(home)).toEqual([ + 'sdk otel core policy publication {"origin":"standalone_provider_rebind","kind":"pending_publish_returned","auth_generation":3}', + 'sdk otel policy state {"origin":"native_pending","kind":"fence","current_revision":11,"authority_fenced":true}', + 'sdk otel policy settlement {"origin":"standalone_commit","kind":"reservation","succeeded":true,"reservation_some":false}', + ]); + }); + + it("projects fixed transport teardown phases and bounded counts without SDK content", () => { + for (const phase of [ + "shutdown_writer", + "launcher", + "launcher_complete", + "driver", + "driver_complete", + "driver_failed", + "driver_timeout", + "driver_abort_complete", + "writer_shutdown_complete", + "peer_eof", + "notification_worker", + "notification_worker_complete", + "notification_worker_failed", + "notification_worker_timed_out", + "active_request_grace", + "handle_close", + "handle_close_complete", + "active_requests", + "active_requests_complete", + "active_requests_timed_out", + "flush", + "flush_complete", + "flush_cancelled", + "flush_timed_out", + "flush_unavailable", + "writer_join", + "writer_join_complete", + "complete", + ]) { + const safe = sanitizeDiagnosticLine( + `${prefix}sdk transport teardown ${JSON.stringify({ + connection: 4, + active_requests: 2, + driver_finished: false, + phase, + method: "PRIVATE_METHOD", + request: { token: "PRIVATE_TOKEN" }, + sdkLog: "PRIVATE_LOG", + error: "PRIVATE_ERROR", + })}` + ); + expect(safe).toBeDefined(); + expect(JSON.parse(safe!.slice("sdk transport teardown ".length))).toEqual({ + connection: 4, + active_requests: 2, + driver_finished: false, + phase, + }); + expect(safe).not.toContain("PRIVATE"); + } + for (const fields of [ + { phase: "PRIVATE_PHASE" }, + { active_requests: -1 }, + { active_requests: 0.5 }, + { active_requests: Number.MAX_SAFE_INTEGER + 1 }, + { active_requests: "PRIVATE_COUNT" }, + { connection: -1 }, + { connection: null }, + { driver_finished: "PRIVATE_STATE" }, + { method: "PRIVATE_METHOD" }, + ]) { + expect( + sanitizeDiagnosticLine(`${prefix}sdk transport teardown ${JSON.stringify(fields)}`) + ).toBeUndefined(); + } + expect( + sanitizeDiagnosticLine( + `${prefix}sdk transport teardown {"phase":"complete","active_requests":0}` + ) + ).toBe('sdk transport teardown {"active_requests":0,"phase":"complete"}'); + }); + it("projects only audited fields and never falls back to raw data", () => { expect( sanitizeDiagnosticLine( @@ -26,8 +271,8 @@ describe("SDK failure diagnostics", () => { payload: "PRIVATE_PROMPT", credential: "PRIVATE_CREDENTIAL", endpoint: "PRIVATE_ENDPOINT", - })}`, - ), + })}` + ) ).toBe('sdk pending tool response {"generation":9,"reason":"completed_request"}'); expect( sanitizeDiagnosticLine( @@ -40,10 +285,10 @@ describe("SDK failure diagnostics", () => { origin: "client_response", terminal_cancelled: false, requestId: "PRIVATE_REQUEST", - })}`, - ), + })}` + ) ).toBe( - 'sdk pending transition {"generation":9,"event_count":4,"kind":"permission","origin":"client_response","terminal_cancelled":false}', + 'sdk pending transition {"generation":9,"event_count":4,"kind":"permission","origin":"client_response","terminal_cancelled":false}' ); expect( sanitizeDiagnosticLine( @@ -56,9 +301,11 @@ describe("SDK failure diagnostics", () => { requestId: "PRIVATE_REQUEST", result: "PRIVATE_RESULT", error: "PRIVATE_ERROR", - })}`, - ), - ).toBe('sdk pending tool delivery {"generation":9,"origin":"client_response","accepted":true,"success":true,"failed":false}'); + })}` + ) + ).toBe( + 'sdk pending tool delivery {"generation":9,"origin":"client_response","accepted":true,"success":true,"failed":false}' + ); for (const line of [ `${prefix}PRIVATE_MESSAGE {"generation":9}`, `${prefix}sdk pending tool response {"reason":"PRIVATE_REASON"}`, @@ -86,8 +333,8 @@ describe("SDK failure diagnostics", () => { Array.from( { length: 150 }, (_, generation) => - `${prefix}sdk pending stale drain ${JSON.stringify({ generation, expected_generation: 1, secret: "PRIVATE" })}`, - ).join("\n"), + `${prefix}sdk pending stale drain ${JSON.stringify({ generation, expected_generation: 1, secret: "PRIVATE" })}` + ).join("\n") ); } await writeFile( @@ -96,13 +343,15 @@ describe("SDK failure diagnostics", () => { `${prefix}sdk detach {"phase":"received","connection":2,"dispatch":1,"content":"PRIVATE"}`, `${prefix}sdk detach {"phase":"dispatch_complete","connection":2,"dispatch":1,"failed":false,"elapsed_ms":4}`, '[sdk_diagnostics] sdk detach {"phase":"received","content":"PRIVATE"}', - ].join("\n"), + ].join("\n") ); const tail = await readDiagnosticTail(home); expect(tail).toHaveLength(200); expect(tail[0]).toContain('"generation":102'); expect(tail.at(-2)).toBe('sdk detach {"connection":2,"dispatch":1,"phase":"received"}'); - expect(tail.at(-1)).toBe('sdk detach {"connection":2,"dispatch":1,"elapsed_ms":4,"failed":false,"phase":"dispatch_complete"}'); + expect(tail.at(-1)).toBe( + 'sdk detach {"connection":2,"dispatch":1,"elapsed_ms":4,"failed":false,"phase":"dispatch_complete"}' + ); expect(tail.join("\n")).not.toContain("PRIVATE"); expect(tail.join("\n")).not.toContain(home); }); @@ -237,7 +486,7 @@ describe("SDK failure diagnostics", () => { span: { content: "PRIVATE_SPAN" }, sessionId: "PRIVATE_SESSION", childId: "PRIVATE_CHILD", - })}`, + })}` ); expect(safe).toBeDefined(); expect(JSON.parse(safe!.slice(message.length + 1))).toEqual(fields); @@ -250,7 +499,9 @@ describe("SDK failure diagnostics", () => { { phase: "PRIVATE_PHASE" }, { stream: "PRIVATE_STREAM" }, ]) { - expect(sanitizeDiagnosticLine(`${prefix}sdk shell reader ${JSON.stringify(fields)}`)).toBeUndefined(); + expect( + sanitizeDiagnosticLine(`${prefix}sdk shell reader ${JSON.stringify(fields)}`) + ).toBeUndefined(); } }); }); diff --git a/test/harness/sessionExpiryMcpServer.test.mjs b/test/harness/sessionExpiryMcpServer.test.mjs index 3a24a708e3..091b218072 100644 --- a/test/harness/sessionExpiryMcpServer.test.mjs +++ b/test/harness/sessionExpiryMcpServer.test.mjs @@ -2,15 +2,19 @@ * Copyright (c) Microsoft Corporation. All rights reserved. *--------------------------------------------------------------------------------------------*/ +import { Agent, request } from "node:http"; import { test } from "vitest"; import { startSessionExpiryMcpServer } from "./test-mcp-session-expiry-server.mjs"; -test("negotiates legacy session semantics even when the client requests modern MCP", async ({ +test("legacy session expiry is independent of HTTP connection lifetime even for modern clients", async ({ expect, onTestFinished, }) => { const server = await startSessionExpiryMcpServer(); onTestFinished(() => server.close()); + const agent = new Agent({ keepAlive: true }); + onTestFinished(() => agent.destroy()); + const probeSockets = new Set(); const initialize = () => fetch(`${server.url}/mcp`, { @@ -29,29 +33,70 @@ test("negotiates legacy session semantics even when the client requests modern M }); const initialized = await initialize(); expect(initialized.status).toBe(200); + expect(initialized.headers.get("connection")).toBe("close"); expect((await initialized.json()).result.protocolVersion).toBe("2025-03-26"); const sessionId = initialized.headers.get("mcp-session-id"); expect(sessionId).toBeTruthy(); - const ping = () => - fetch(`${server.url}/mcp`, { - method: "POST", - headers: { - "content-type": "application/json", - "mcp-session-id": sessionId, - }, - body: JSON.stringify({ jsonrpc: "2.0", id: 2, method: "ping" }), + const ping = async () => { + const response = await new Promise((resolve, reject) => { + const req = request( + `${server.url}/mcp`, + { + agent, + method: "POST", + headers: { + "content-type": "application/json", + "mcp-session-id": sessionId, + }, + }, + (res) => { + const socket = res.socket; + let body = ""; + res.setEncoding("utf8"); + res.on("data", (chunk) => (body += chunk)); + res.on("error", reject); + res.on("end", () => + resolve({ status: res.statusCode, headers: res.headers, socket, body }) + ); + } + ); + req.on("error", reject); + req.end(JSON.stringify({ jsonrpc: "2.0", id: 2, method: "ping" })); }); + expect(response.headers.connection).toBe("close"); + expect(probeSockets.has(response.socket)).toBe(false); + probeSockets.add(response.socket); + return { status: response.status, body: JSON.parse(response.body) }; + }; const alive = await ping(); expect(alive.status).toBe(200); - expect(await alive.json()).toEqual({ jsonrpc: "2.0", id: 2, result: {} }); + expect(alive.body).toEqual({ jsonrpc: "2.0", id: 2, result: {} }); const expired = await fetch(`${server.url}/__expire`, { method: "POST" }); expect(expired.status).toBe(200); expect(await expired.json()).toEqual({ expired: 1 }); - const afterExpiry = await ping(); - expect(afterExpiry.status).toBe(404); - expect(await afterExpiry.json()).toEqual({ error: "session_expired" }); + for (let probe = 0; probe < 3; probe++) { + const afterExpiry = await ping(); + expect(afterExpiry.status).toBe(404); + expect(afterExpiry.body).toEqual({ error: "session_expired" }); + } + const observed = await fetch(`${server.url}/__stats`).then((response) => response.json()); + expect(observed.pings).toBe(1); + expect(observed.expiredRequests).toBe(3); + expect(observed.expiredRequestLog).toEqual( + Array.from({ length: 3 }, () => ({ method: "POST", elapsedMs: expect.any(Number) })), + ); + expect(observed.protocolVersions).toEqual(["2026-07-28"]); + expect(observed.recentRequests).toContainEqual( + expect.objectContaining({ + httpMethod: "POST", + sessionAttached: true, + expiredSession: true, + status: 404, + }), + ); + expect(JSON.stringify(observed)).not.toContain(sessionId); const reinitialized = await initialize(); expect(reinitialized.status).toBe(200); @@ -107,3 +152,40 @@ test("distinguishes answered expiry probes from unrelated traffic", async ({ expect(observed.status).toBe(200); expect(await observed.json()).toMatchObject({ activeSessions: 0, expiredSessionProbes: 1 }); }); + +test("bounds session-expiry diagnostics without retaining request payloads", async ({ expect, onTestFinished }) => { + const startingServer = startSessionExpiryMcpServer(); + onTestFinished(async () => (await startingServer).close()); + const server = await startingServer; + for (let i = 0; i < 40; i++) { + const response = await fetch(`${server.url}/mcp`, { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ + jsonrpc: "2.0", + id: `private-request-${i}`, + method: "initialize", + params: { + protocolVersion: "2025-03-26", + clientInfo: { name: "private-client", version: "1" }, + }, + }), + }); + expect(response.status).toBe(200); + await response.json(); + } + const observed = await fetch(`${server.url}/__stats`).then((response) => response.json()); + expect(observed.initializations).toBe(40); + expect(observed.recentRequests).toHaveLength(32); + for (const request of observed.recentRequests) { + expect(request).toEqual({ + elapsedMs: expect.any(Number), + httpMethod: "POST", + sessionAttached: false, + expiredSession: false, + rpcMethods: ["initialize"], + status: 200, + }); + } + expect(JSON.stringify(observed)).not.toContain("private-"); +}); diff --git a/test/harness/stdio-shutdown-runtime.cjs b/test/harness/stdio-shutdown-runtime.cjs index 154537a3c0..f3230a041d 100644 --- a/test/harness/stdio-shutdown-runtime.cjs +++ b/test/harness/stdio-shutdown-runtime.cjs @@ -9,13 +9,23 @@ const { dirname } = require("node:path"); const [marker, mode, pidFile] = process.argv.slice(2); const useTcp = process.argv.includes("--fixture-tcp"); -if (!marker || !pidFile || !["stop", "dispose", "force", "fallback", "start-failure", "shutdown-error"].includes(mode)) { +if (!marker || !pidFile || !["stop", "dispose", "force", "fallback", "start-failure", "shutdown-error", "connect-stall", "port-stall"].includes(mode)) { throw new Error("Expected cleanup marker, shutdown mode, and PID file arguments"); } fs.writeFileSync(pidFile, String(process.pid)); -if (mode === "fallback" || mode === "start-failure") { +if (mode === "fallback" || mode === "start-failure" || mode === "connect-stall" || mode === "port-stall") { setInterval(() => {}, 1000); } +if (process.argv.includes("--fixture-descendant")) { + const child = require("node:child_process").spawn( + process.execPath, + ["-e", "setInterval(() => {}, 1000)"], + { stdio: "ignore" }, + ); + child.on("error", (error) => { throw error; }); + fs.writeFileSync(`${pidFile}.descendant`, String(child.pid)); + child.unref(); +} let buffered = Buffer.alloc(0); let shutdownRequested = false; @@ -35,6 +45,7 @@ const handleData = (chunk, output) => { let error; switch (message.method) { case "connect": + if (mode === "connect-stall") continue; result = { ok: true, protocolVersion: mode === "start-failure" ? -1 : 3, @@ -42,7 +53,7 @@ const handleData = (chunk, output) => { }; break; case "ping": - result = { message: message.params?.message, timestamp: Date.now(), protocolVersion: 3 }; + result = { message: message.params?.message, timestamp: new Date().toISOString(), protocolVersion: 3 }; break; case "runtime.shutdown": shutdownRequested = true; @@ -68,7 +79,7 @@ if (useTcp) { socket.on("data", (chunk) => handleData(chunk, socket)); }); server.listen(0, "127.0.0.1", () => { - console.log(`listening on port ${server.address().port}`); + if (mode !== "port-stall") console.log(`listening on port ${server.address().port}`); }); } else { process.stdin.on("data", (chunk) => handleData(chunk, process.stdout)); diff --git a/test/harness/test-mcp-server.mjs b/test/harness/test-mcp-server.mjs index dfc791e127..a1c3609767 100644 --- a/test/harness/test-mcp-server.mjs +++ b/test/harness/test-mcp-server.mjs @@ -33,6 +33,7 @@ const startupMarkerPath = getArgument("--startup-marker"); const diagnosticStderr = getArgument("--diagnostic-stderr"); const serverName = getArgument("--server-name") ?? "env-echo"; const toolName = getArgument("--tool-name") ?? "get_env"; +const toolDescriptionFile = getArgument("--tool-description-file"); const server = new McpServer({ name: serverName, version: "1.0.0" }); const fixtures = JSON.parse(await readFile(new URL("./mcp-prompt-fixtures.json", import.meta.url), "utf8")); // Fixtures contain SDK extension bags; MCP sends those entries as ordinary object fields. @@ -98,7 +99,9 @@ server.server.setRequestHandler(GetPromptRequestSchema, async ({ params }) => { server.tool( toolName, - "Returns the value of the specified environment variable.", + toolDescriptionFile + ? await readFile(toolDescriptionFile, "utf8") + : "Returns the value of the specified environment variable.", { name: z.string().describe("Environment variable name") }, async ({ name }) => ({ content: [{ type: "text", text: process.env[name] ?? "" }], diff --git a/test/harness/test-mcp-session-expiry-server.mjs b/test/harness/test-mcp-session-expiry-server.mjs index a28343b151..4751be0bfd 100644 --- a/test/harness/test-mcp-session-expiry-server.mjs +++ b/test/harness/test-mcp-session-expiry-server.mjs @@ -16,6 +16,8 @@ * server-side idle expiry is observed by a real Streamable HTTP client. * `GET /__stats` reports the counters tests assert on, including answered * expired-session probes so recovery assertions need not budget the idle delay. + * HTTP connections close after each response so socket idle retirement cannot + * interfere with the independently managed MCP session lifetime. */ import http from "node:http"; @@ -24,6 +26,7 @@ import { randomUUID } from "node:crypto"; import { fileURLToPath } from "node:url"; const PROTOCOL_VERSION = "2025-03-26"; +const MAX_RECENT_REQUESTS = 32; export async function startSessionExpiryMcpServer({ host = "127.0.0.1", port = 0 } = {}) { const activeSessions = new Set(); @@ -39,12 +42,16 @@ export async function startSessionExpiryMcpServer({ host = "127.0.0.1", port = 0 protocolVersions: [], expiredSessionProbes: 0, }; + const recentRequests = []; + const startedAt = performance.now(); const server = http.createServer(async (req, res) => { + // MCP session expiry is independent of TCP keep-alive expiry. + res.setHeader("connection", "close"); const url = new URL(req.url ?? "/", `http://${req.headers.host ?? `${host}:${port}`}`); if (req.method === "GET" && url.pathname === "/__stats") { - respondJson(res, 200, { ...stats, activeSessions: activeSessions.size }); + respondJson(res, 200, { ...stats, activeSessions: activeSessions.size, recentRequests }); return; } @@ -64,7 +71,21 @@ export async function startSessionExpiryMcpServer({ host = "127.0.0.1", port = 0 } const sessionId = req.headers["mcp-session-id"]; - if (typeof sessionId === "string" && expiredSessions.has(sessionId)) { + const expiredSession = typeof sessionId === "string" && expiredSessions.has(sessionId); + const observation = { + elapsedMs: Math.round(performance.now() - startedAt), + httpMethod: req.method, + sessionAttached: typeof sessionId === "string", + expiredSession, + rpcMethods: [], + status: null, + }; + recentRequests.push(observation); + if (recentRequests.length > MAX_RECENT_REQUESTS) recentRequests.shift(); + res.once("finish", () => { + observation.status = res.statusCode; + }); + if (expiredSession) { stats.expiredRequests++; if (stats.expiredRequestLog.length < 8) { stats.expiredRequestLog.push({ @@ -99,6 +120,10 @@ export async function startSessionExpiryMcpServer({ host = "127.0.0.1", port = 0 } const messages = Array.isArray(parsedBody.value) ? parsedBody.value : [parsedBody.value]; + observation.rpcMethods = messages + .map((message) => message?.method) + .filter((method) => typeof method === "string") + .slice(0, 4); const isInitialize = messages.some((message) => message?.method === "initialize"); let responseSessionId = typeof sessionId === "string" ? sessionId : undefined; diff --git a/test/snapshots/permissions/should_handle_async_permission_handler_dotnet.yaml b/test/snapshots/permissions/should_handle_async_permission_handler_dotnet.yaml new file mode 100644 index 0000000000..08ee2fa0f2 --- /dev/null +++ b/test/snapshots/permissions/should_handle_async_permission_handler_dotnet.yaml @@ -0,0 +1,20 @@ +models: + - claude-sonnet-5 +conversations: + - messages: + - role: system + content: ${system} + - role: user + content: Call async_permission_echo once and reply with only its returned text. + - role: assistant + tool_calls: + - id: toolcall_0 + type: function + function: + name: async_permission_echo + arguments: "{}" + - role: tool + tool_call_id: toolcall_0 + content: DOTNET_ASYNC_PERMISSION_RESULT + - role: assistant + content: DOTNET_ASYNC_PERMISSION_RESULT diff --git a/test/snapshots/rpc_session_state/should_read_the_reasoning_summaries_policy_for_the_current_model.yaml b/test/snapshots/rpc_session_state/should_read_the_reasoning_summaries_policy_for_the_current_model.yaml new file mode 100644 index 0000000000..0c6b353c19 --- /dev/null +++ b/test/snapshots/rpc_session_state/should_read_the_reasoning_summaries_policy_for_the_current_model.yaml @@ -0,0 +1,3 @@ +models: + - claude-sonnet-5 +conversations: [] From 0a3643feb05e6a666c5b02c0727988dc9ad7bbad Mon Sep 17 00:00:00 2001 From: "copilot-cli-release-app[bot]" Date: Mon, 12 Oct 2026 23:03:16 +0000 Subject: [PATCH 8/9] Update SDK snapshot for Copilot CLI 1.0.97-1 --- dotnet/src/Generated/Rpc.cs | 45848 ++++++++-------- go/rpc/zrpc.go | 3106 +- java/scripts/codegen/java.ts | 9 + ...FeatureFlagsResolveStartupGatesParams.java | 52 + .../generated/rpc/FolderTrustCheckResult.java | 27 + .../generated/rpc/ForceLoginOrgsDecision.java | 40 + .../rpc/LocationPermissionsCleanupResult.java | 28 + .../ManagedSettingsApplyControlsParams.java | 33 + .../ManagedSettingsApplyControlsResult.java | 27 + .../ManagedSettingsBypassDisableSource.java | 37 + ...ManagedSettingsBypassPolicyResolution.java | 37 + .../rpc/ManagedSettingsIngestParams.java | 59 + .../rpc/ManagedSettingsIngestResult.java | 78 + ...anagedSettingsLoadRemoteControlParams.java | 51 + ...anagedSettingsLoadRemoteControlResult.java | 27 + .../rpc/ManagedSettingsLogLevel.java | 39 + .../rpc/ManagedSettingsLogMessage.java | 29 + ...ManagedSettingsParseClientValueParams.java | 30 + ...ManagedSettingsParseClientValueResult.java | 27 + .../ManagedSettingsPolicyHelperAuthority.java | 35 + .../ManagedSettingsPolicyHelperReason.java | 35 + .../rpc/ManagedSettingsReadDeviceResult.java | 31 + ...sResolveBypassDisableTransitionParams.java | 36 + ...sResolveBypassDisableTransitionResult.java | 33 + ...ResolveDeviceForceLoginOrgsGateParams.java | 33 + ...edSettingsResolveEffectiveValueParams.java | 36 + ...edSettingsResolveEffectiveValueResult.java | 27 + ...gedSettingsResolveStartupPolicyParams.java | 61 + ...gedSettingsResolveStartupPolicyResult.java | 62 + .../ManagedSettingsRetainPolicyParams.java | 60 + .../ManagedSettingsServerPolicyCacheMode.java | 39 + ...ManagedSettingsServerPolicyResolution.java | 45 + ...ermissionsEvaluateManagedPolicyParams.java | 30 + ...ermissionsEvaluateManagedPolicyResult.java | 31 + ...ermissionsFolderTrustCheckTrustParams.java | 32 + .../PersistenceWriteRawJsonLockedParams.java | 34 + .../PersistenceWriteRawJsonLockedResult.java | 29 + .../generated/rpc/RepoSettingsEditParams.java | 38 + .../generated/rpc/RepoSettingsEditScope.java | 39 + .../SandboxCheckEnforcementCommandParams.java | 33 + .../generated/rpc/SandboxDocsUrlResult.java | 27 + .../SandboxEffectiveForOptionalResult.java | 27 + .../SandboxFilterPickerCandidatesParams.java | 35 + .../SandboxFilterPickerCandidatesResult.java | 28 + ...dboxGetUnsupportedStartupNoticeParams.java | 32 + .../generated/rpc/SandboxPickerCandidate.java | 29 + .../rpc/SandboxPreparePickerPolicyParams.java | 32 + .../rpc/SandboxPreparePickerPolicyResult.java | 27 + .../SandboxProxyCaCheckRelevanceParams.java | 30 + .../rpc/SandboxProxySecretGetResult.java | 27 + .../rpc/SandboxProxySecretLocation.java | 29 + .../rpc/SandboxProxySecretSaveParams.java | 30 + .../rpc/SandboxProxySecretSaveResult.java | 27 + .../SandboxResolveFlooredConfigParams.java | 32 + .../SandboxResolveFlooredConfigResult.java | 27 + .../rpc/SandboxResolveForOptionalParams.java | 32 + .../SandboxSettingsApplyDefaultsParams.java | 31 + ...SandboxUnsupportedStartupNoticeResult.java | 27 + .../generated/rpc/ServerFeatureFlagsApi.java | 11 + .../rpc/ServerManagedSettingsApi.java | 110 + .../generated/rpc/ServerPermissionsApi.java | 47 + .../rpc/ServerPermissionsFolderTrustApi.java | 40 + .../rpc/ServerPermissionsLocationsApi.java | 40 + .../generated/rpc/ServerPersistenceApi.java | 40 + .../generated/rpc/ServerRepoSettingsApi.java | 11 + .../copilot/generated/rpc/ServerRpc.java | 36 +- .../generated/rpc/ServerSandboxApi.java | 127 + .../rpc/ServerSandboxProxyCaApi.java | 22 + .../rpc/ServerSandboxProxySecretApi.java | 73 + .../rpc/ServerSandboxSettingsApi.java | 41 + .../generated/rpc/ServerUserSettingsApi.java | 155 + .../generated/rpc/SessionGitHubAuthApi.java | 8 +- .../copilot/generated/rpc/SessionRpc.java | 4 +- .../rpc/StaffLogLevelMigrationStatus.java | 37 + .../StaffUpdateChannelMigrationStatus.java | 41 + .../rpc/UserSettingsBuildRuntimeParams.java | 37 + ...erSettingsGetUnknownKeysWarningParams.java | 30 + .../rpc/UserSettingsHostContext.java | 32 + .../UserSettingsLoadAndMergeRepoParams.java | 33 + .../UserSettingsLoadAndMergeRepoResult.java | 30 + .../UserSettingsLoadForConfigDirParams.java | 30 + .../rpc/UserSettingsLoadRepoParams.java | 30 + .../rpc/UserSettingsLoadRepoResult.java | 30 + .../UserSettingsLoadWithWarningResult.java | 30 + ...UserSettingsMergeManagedAndUserParams.java | 32 + ...UserSettingsMergeManagedAndUserResult.java | 27 + .../rpc/UserSettingsMergeRepoValueParams.java | 34 + .../rpc/UserSettingsMergeRepoValueResult.java | 27 + ...erSettingsMigrateObsoleteOnDiskParams.java | 30 + ...erSettingsMigrateObsoleteOnDiskResult.java | 27 + ...erSettingsMigrateObsoleteOnDiskStatus.java | 39 + ...ettingsMigrateStaffLogLevelOnceParams.java | 32 + ...ettingsMigrateStaffLogLevelOnceResult.java | 32 + ...gsMigrateStaffUpdateChannelOnceParams.java | 35 + ...gsMigrateStaffUpdateChannelOnceResult.java | 29 + .../generated/rpc/UserSettingsPathResult.java | 27 + ...ngsResetStaffModelSelectionOnceParams.java | 34 + ...ngsResetStaffModelSelectionOnceResult.java | 34 + .../UserSettingsSetHookDisabledParams.java | 34 + .../UserSettingsSetHookDisabledResult.java | 33 + .../UserSettingsUnknownKeysWarningResult.java | 27 + .../com/github/copilot/JsonRpcClientTest.java | 22 + nodejs/package.json | 2 +- nodejs/src/cliVersion.ts | 2 +- nodejs/src/generated/rpc.ts | 22901 ++++---- nodejs/test/csharp-codegen.test.ts | 54 + .../test/e2e/rpc_surface_coverage.e2e.test.ts | 2 +- nodejs/test/e2e/startup_policy.e2e.test.ts | 33 + nodejs/test/java-codegen.test.ts | 37 + python/copilot/generated/rpc.py | 3953 +- rust/src/generated/api_types.rs | 2671 +- rust/src/generated/rpc.rs | 3853 +- samples/startup-policy/README.md | 28 + samples/startup-policy/read-settings.mts | 141 + .../csharp-dictionary-roundtrip.test.ts | 90 + scripts/codegen/csharp.ts | 18 +- 116 files changed, 52774 insertions(+), 33603 deletions(-) create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagsResolveStartupGatesParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/FolderTrustCheckResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ForceLoginOrgsDecision.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/LocationPermissionsCleanupResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsApplyControlsParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsApplyControlsResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsBypassDisableSource.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsBypassPolicyResolution.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsIngestParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsIngestResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLoadRemoteControlParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLoadRemoteControlResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLogLevel.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLogMessage.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsParseClientValueParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsParseClientValueResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPolicyHelperAuthority.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPolicyHelperReason.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsReadDeviceResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveBypassDisableTransitionParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveBypassDisableTransitionResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveDeviceForceLoginOrgsGateParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveEffectiveValueParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveEffectiveValueResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveStartupPolicyParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveStartupPolicyResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsRetainPolicyParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsServerPolicyCacheMode.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsServerPolicyResolution.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionsEvaluateManagedPolicyParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionsEvaluateManagedPolicyResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionsFolderTrustCheckTrustParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/PersistenceWriteRawJsonLockedParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/PersistenceWriteRawJsonLockedResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsEditParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsEditScope.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxCheckEnforcementCommandParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxDocsUrlResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxEffectiveForOptionalResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxFilterPickerCandidatesParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxFilterPickerCandidatesResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxGetUnsupportedStartupNoticeParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxPickerCandidate.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxPreparePickerPolicyParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxPreparePickerPolicyResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxyCaCheckRelevanceParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretGetResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretLocation.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretSaveParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretSaveResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxResolveFlooredConfigParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxResolveFlooredConfigResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxResolveForOptionalParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxSettingsApplyDefaultsParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxUnsupportedStartupNoticeResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPermissionsApi.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPermissionsFolderTrustApi.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPermissionsLocationsApi.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPersistenceApi.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxProxySecretApi.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxSettingsApi.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/StaffLogLevelMigrationStatus.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/StaffUpdateChannelMigrationStatus.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsBuildRuntimeParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetUnknownKeysWarningParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsHostContext.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadAndMergeRepoParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadAndMergeRepoResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadForConfigDirParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadRepoParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadRepoResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadWithWarningResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeManagedAndUserParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeManagedAndUserResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeRepoValueParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeRepoValueResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateObsoleteOnDiskParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateObsoleteOnDiskResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateObsoleteOnDiskStatus.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffLogLevelOnceParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffLogLevelOnceResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffUpdateChannelOnceParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffUpdateChannelOnceResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsPathResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsResetStaffModelSelectionOnceParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsResetStaffModelSelectionOnceResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetHookDisabledParams.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetHookDisabledResult.java create mode 100644 java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsUnknownKeysWarningResult.java create mode 100644 nodejs/test/e2e/startup_policy.e2e.test.ts create mode 100644 samples/startup-policy/README.md create mode 100644 samples/startup-policy/read-settings.mts create mode 100644 scripts/codegen/csharp-dictionary-roundtrip.test.ts diff --git a/dotnet/src/Generated/Rpc.cs b/dotnet/src/Generated/Rpc.cs index b3c4714dbf..abd757747b 100644 --- a/dotnet/src/Generated/Rpc.cs +++ b/dotnet/src/Generated/Rpc.cs @@ -107,2217 +107,2383 @@ internal sealed class ConnectRequest public string? Token { get; set; } } -/// Hosting capabilities and session capacity advertised by an environment. +/// The user's sandbox settings raised to the managed floor. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class EnvironmentCapabilities +internal sealed class SandboxResolveFlooredConfigResult { - /// Advertised Agent Host Protocol version. - [JsonPropertyName("ahpVersion")] - public string? AhpVersion { get; set; } - - /// Current session count, when advertised. - [JsonPropertyName("currentSessions")] - public long? CurrentSessions { get; set; } + /// The floored sandbox config, normalized through the declared sandbox shape so only declared fields in a fixed order are present. + [JsonPropertyName("sandboxJson")] + public JsonElement SandboxJson { get; set; } +} - /// Feature identifiers advertised by the environment. - [JsonPropertyName("features")] - public IList Features { get => field ??= []; set; } +/// The user's sandbox settings and the managed sandbox floor to raise them to. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SandboxResolveFlooredConfigParams +{ + /// The effective managed `sandbox` slice acting as a floor. Omitted when no administrator policy applies, in which case the user's own settings stand unchanged. + [JsonPropertyName("managedSandbox")] + public JsonElement? ManagedSandbox { get; set; } - /// Maximum session capacity, when advertised. - [JsonPropertyName("maxSessions")] - public long? MaxSessions { get; set; } + /// The user's own `sandbox` settings slice. Omitted when the user has configured none, which still yields the managed floor rather than a disabled sandbox. + [JsonPropertyName("userSandbox")] + public JsonElement? UserSandbox { get; set; } } -/// Safe discovery information. Host-side relay bootstrap credentials are never included. +/// The prepared file-picker policy, or none when the sandbox is disabled. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class GitHubEnvironment +internal sealed class SandboxPreparePickerPolicyResult { - /// Hosting capabilities advertised by the environment. - [JsonPropertyName("capabilities")] - public EnvironmentCapabilities? Capabilities { get; set; } - - /// Identifier assigned by Mission Control. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// The prepared policy to pass back to `sandbox.filterPickerCandidates`. Absent when the sandbox is disabled or absent, in which case filtering keeps every candidate. + [JsonPropertyName("sandboxJson")] + public JsonElement? SandboxJson { get; set; } +} - /// Compute kind reported by Mission Control. - [JsonPropertyName("kind")] - public EnvironmentKind Kind { get; set; } +/// The working directory and sandbox settings to build a file-picker policy from. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SandboxPreparePickerPolicyParams +{ + /// The session's working directory. Git discovery and grant canonicalization are resolved against it. + [JsonPropertyName("cwd")] + public string Cwd { get; set; } = string.Empty; - /// Discovery labels attached to the environment. - [JsonPropertyName("labels")] - public IDictionary? Labels { get; set; } + /// The session's resolved `sandbox` slice. Omitted, or disabled, yields no policy and every candidate is kept. + [JsonPropertyName("sandbox")] + public JsonElement? Sandbox { get; set; } +} - /// Timestamp of the last heartbeat received by Mission Control. - [JsonPropertyName("lastHeartbeatAt")] - public string? LastHeartbeatAt { get; set; } +/// Per-candidate allow decisions, positionally aligned with the request. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SandboxFilterPickerCandidatesResult +{ + /// One decision per candidate, in the same order. Always the same length as the request's `candidates`. + [JsonPropertyName("allowed")] + public IList Allowed { get => field ??= []; set; } +} - /// Human-readable environment name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; +/// One file-picker suggestion offered up for the sandbox filesystem check. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SandboxPickerCandidate +{ + /// Whether the suggestion is a directory. A directory the policy does not itself allow may still be needed as a waypoint to an allowed subtree. + [JsonPropertyName("isDirectory")] + public bool IsDirectory { get; set; } - /// Organization identifier, when the environment belongs to an organization. - [JsonPropertyName("orgId")] - public string? OrgId { get; set; } + /// Absolute path the suggestion would attach. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; +} - /// Identifier of the environment owner. - [JsonPropertyName("ownerId")] - public string? OwnerId { get; set; } +/// A batch of file-picker candidates to check against a prepared policy. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SandboxFilterPickerCandidatesParams +{ + /// The candidates to check, in the order the answers are returned. + [JsonPropertyName("candidates")] + public IList Candidates { get => field ??= []; set; } - /// Owner category reported by Mission Control. - [JsonPropertyName("ownerType")] - public string? OwnerType { get; set; } + /// The session's working directory, matching the one the policy was prepared from. + [JsonPropertyName("cwd")] + public string Cwd { get; set; } = string.Empty; - /// Open-ended operational status vocabulary. - [JsonPropertyName("status")] - public string Status { get; set; } = string.Empty; + /// The policy returned by `sandbox.preparePickerPolicy`. Omitted keeps every candidate. + [JsonPropertyName("sandbox")] + public JsonElement? Sandbox { get; set; } } -/// Environments visible to the authenticated caller and matching the supplied filters. +/// The sandbox a named feature actually launches under. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class EnvironmentsListResult +internal sealed class SandboxEffectiveForOptionalResult { - /// Safe discovery records without relay bootstrap credentials. - [JsonPropertyName("environments")] - public IList Environments { get => field ??= []; set; } + /// The effective sandbox config for the requested feature, or a disabled sandbox when the feature is routed out of it. + [JsonPropertyName("sandboxJson")] + public JsonElement SandboxJson { get; set; } } -/// Optional discovery filters supported by GitHub Mission Control. +/// A sandbox config and the per-feature routing flag to resolve it for. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class EnvironmentsListRequest +internal sealed class SandboxEffectiveForOptionalParams { - /// Restrict discovery to this compute kind. - [JsonPropertyName("kind")] - public EnvironmentKind? Kind { get; set; } + /// The routing flag naming the feature being launched, such as `sandboxMcpServers` or `sandboxLspServers`. + [JsonPropertyName("routingFlag")] + public string RoutingFlag { get; set; } = string.Empty; - /// Operational status, such as online, offline, degraded, waking, or draining. - [JsonPropertyName("status")] - public string? Status { get; set; } + /// The session's resolved `sandbox` slice. Omitted when the host has none, which yields a disabled sandbox rather than an error. + [JsonPropertyName("sandbox")] + public JsonElement? Sandbox { get; set; } } -/// Safe discovery information for the requested environment. +/// The startup warning, absent when the machine can run a sandbox. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class EnvironmentsGetResult +internal sealed class SandboxUnsupportedStartupNoticeResult { - /// The requested environment without relay bootstrap credentials. - [JsonPropertyName("environment")] - public GitHubEnvironment Environment { get => field ??= new(); set; } + /// The user-facing warning, carrying the platform remedy and the recovery the policy in force actually allows. Absent when this machine supports a sandbox, so a host can call unconditionally and print only what it gets. + [JsonPropertyName("notice")] + public string? Notice { get; set; } } -/// Identify a Mission Control environment to retrieve. +/// The managed sandbox policy in force, which selects which remedy the notice offers. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class EnvironmentsGetRequest +internal sealed class SandboxUnsupportedStartupNoticeParams { - /// Identifier assigned by Mission Control. - [JsonPropertyName("environmentId")] - public string EnvironmentId { get; set; } = string.Empty; + /// True when the sandbox stayed on only because the managed policy could not be determined. Distinguishes a policy that positively enforces the sandbox from one that merely failed to resolve, which is the difference between telling the user to contact an administrator and telling them to wait. Defaults to false. + [JsonPropertyName("enabledByUndeterminedPolicy")] + public bool? EnabledByUndeterminedPolicy { get; set; } + + /// The managed `sandbox` slice, when a policy supplies one. The notice treats the sandbox as enforced only when this both enables it and sets `failIfUnavailable`, because a managed sandbox that tolerates being unavailable still leaves the user able to turn it off. + [JsonPropertyName("managedSandbox")] + public JsonElement? ManagedSandbox { get; set; } } -/// Acknowledgement that the requested environment was deleted. +/// One slash command, as typed, to test against the enforcement-block allowlist. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class EnvironmentsDeleteResult +internal sealed class SandboxEnforcementCommandAllowedParams { + /// The command's arguments, in order. Pass an empty array for a bare command: several entries in the allowlist admit the bare form and refuse every argument. + [JsonPropertyName("args")] + public IList Args { get => field ??= []; set; } + + /// The command name as the user typed it, with or without its leading slash. + [JsonPropertyName("commandName")] + public string CommandName { get; set; } = string.Empty; } -/// Identify a user-managed Mission Control environment to delete. +/// The documentation URL a host cites when it declines or downgrades a sandbox setting. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class EnvironmentsDeleteRequest +internal sealed class SandboxDocsUrlResult { - /// User-managed environment to delete. GitHub-managed environments cannot be deleted. - [JsonPropertyName("environmentId")] - public string EnvironmentId { get; set; } = string.Empty; + /// Documentation URL describing the sandbox and the settings that control it. + [JsonPropertyName("url")] + public string Url { get; set; } = string.Empty; } -/// The existing runtime identity and its resource on the listener. +/// Whether this host can run one sandbox policy feature. A session whose effective policy uses an unsupported feature fails each sandboxed command with `reason`, except `filesystem_enumeration`, whose absence degrades sandboxed PowerShell instead of failing it. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HostPublishSessionResult +public sealed class SandboxHostCapability { - /// Canonical runtime ID of the published session. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// The policy feature, as an extensible string: ignore names you do not recognize. Known values: `network` (sandboxed commands can reach the network; on Linux this needs the tooling for Bubblewrap's private network namespace, such as slirp4netns), `network_filtering` (host rules and the sandbox proxy; on Linux this needs the same tooling as `network`; on Windows it needs Process Security Environment 1.1 host-loopback support or MXC's PSEC 1.0-only proxy-loopback compatibility capability, and a policy that uses it must also set `network.allowLocalNetwork`; compatibility applies only to an explicit identity-less runtime proxy, not general host-loopback access, and other policy restrictions still apply), `denied_paths` (native enforcement of `filesystem.deniedPaths`), `shell` (shell commands inside the sandbox), and `filesystem_enumeration` (enumerate-only filesystem grants; on Windows this needs Process Security Environment 1.1 filesystem enumeration support, and without it sandboxed PowerShell still runs but cannot resolve its current location; other platforms always report it). + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// AHP resource URI for the session on this listener. - [JsonPropertyName("sessionUri")] - public string SessionUri { get; set; } = string.Empty; + /// Human-readable reason and remedy when the feature is unsupported, such as a package to install or an OS update. Present only when `supported` is false. + [JsonPropertyName("reason")] + public string? Reason { get; set; } + + /// Whether this host can run the feature. + [JsonPropertyName("supported")] + public bool Supported { get; set; } } -/// Publishes a resident session attached to the listener's owning connection. +/// Whether the host running this runtime can run the command sandbox. The runtime checks `supported` once per process. A capability answer can change while the process runs, for example after the user installs a missing package. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HostPublishSessionRequest +public sealed class SandboxHostSupport { - /// Listener UUID returned by host.start. - [JsonPropertyName("hostId")] - public string HostId { get; set; } = string.Empty; + /// Sandbox policy features whose availability varies between hosts that can run the backend. Empty when `supported` is false, because no feature can run without a backend. Later runtimes can add entries; ignore an entry whose `name` you do not recognize. + [JsonPropertyName("capabilities")] + public IList Capabilities { get => field ??= []; set; } - /// Canonical runtime session ID attached to the listener's owning connection. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Human-readable reason the sandbox cannot run on this host. Present only when `supported` is false. + [JsonPropertyName("reason")] + public string? Reason { get; set; } + + /// Whether a process-containment backend is usable on this host: Seatbelt on macOS, Bubblewrap on Linux, or ProcessContainer on Windows. + [JsonPropertyName("supported")] + public bool Supported { get; set; } } -/// Metadata advertised by the AHP host, not a guarantee that history can be resumed. +/// Credential-injection capability flags applied while the sandbox is enabled. For the same capability independent of sandboxing, and matched to the credential's GitHub host, see `shell.credentials`; the two are additive. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HostSessionSummary +public sealed class SandboxConfigAuth { - /// Optional activity description advertised by the host. - [JsonPropertyName("activity")] - public string? Activity { get; set; } - - /// Session creation time as an ISO 8601 timestamp. - [JsonPropertyName("createdAt")] - public string CreatedAt { get; set; } = string.Empty; - - /// Last modification time as an ISO 8601 timestamp. - [JsonPropertyName("modifiedAt")] - public string ModifiedAt { get; set; } = string.Empty; - - /// Stable AHP resource URI identifying the session on this host. - [JsonPropertyName("resource")] - public string Resource { get; set; } = string.Empty; + /// Whether to authenticate sandboxed gh through the local masking proxy. The child receives a fake GH_TOKEN; its real value is substituted only at github.com, api.github.com and uploads.github.com (github.com because gh repo clone authenticates git through gh auth git-credential). The repository's GitHub account takes precedence over the Copilot login. Default: false (opt-in). + [JsonPropertyName("gh")] + public bool? Gh { get; set; } - /// Unsigned 32-bit AHP session status bitset (0..=4294967295); unknown bits must be preserved. - [JsonPropertyName("status")] - public long Status { get; set; } + /// Whether to authenticate sandboxed HTTPS git through the local masking proxy. The child receives a fake `http.<url>.extraheader`; the real Authorization header is substituted only at its original HTTPS host, port, and repository path scope. github.com uses the Copilot token; other forges use credentials resolved from the user's own helper on the host. Default: false (opt-in). + [JsonPropertyName("git")] + public bool? Git { get; set; } +} - /// Authoritative title advertised by the host. - [JsonPropertyName("title")] - public string Title { get; set; } = string.Empty; +/// Destinations authorized to receive one masked environment credential. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SandboxMaskedEnvVar +{ + /// Nonempty list of HTTPS injection hostnames or *.example.com patterns. Bare * is not accepted. These grants never override the sandbox network policy. Values in plaintext HTTP requests, URLs, bodies, encoded credentials, and signed requests are not substituted. + [JsonPropertyName("injectHosts")] + public IList InjectHosts { get => field ??= []; set; } } -/// The complete live and dormant advertised catalog, without subscribing to sessions. +/// Whole-value environment credential masking for sandboxed children. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HostListSessionsResult +public sealed class SandboxCredentialsConfig { - /// Complete advertised session summaries, in the host's catalog order. - [JsonPropertyName("sessions")] - public IList Sessions { get => field ??= []; set; } + /// Environment variable names and their HTTPS injection destinations. Absent variables stay absent. No real values or sentinels are stored in this map. + [JsonPropertyName("envVars")] + public IDictionary EnvVars { get => field ??= new Dictionary(); set; } } -/// Reads a running host's catalog or the runtime's saved default catalog. +/// macOS seatbelt experimental options. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HostListSessionsRequest +public sealed class SandboxConfigUserPolicyExperimentalSeatbelt { - /// - /// Listener UUID returned by host.start; the caller must own it. Omit to read - /// the saved default compute-identity catalog without starting a listener. - /// - [JsonPropertyName("hostId")] - public string? HostId { get; set; } + /// Whether the macOS seatbelt profile may access the keychain. + [JsonPropertyName("keychainAccess")] + public bool? KeychainAccess { get; set; } } -/// The resident session the application has materialized on its own connection. +/// Platform-specific experimental policy fields. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HostCreateSessionResult +public sealed class SandboxConfigUserPolicyExperimental { - /// Runtime session UUID materialized on the application's SDK connection. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// macOS seatbelt experimental options. + [JsonPropertyName("seatbelt")] + public SandboxConfigUserPolicyExperimentalSeatbelt? Seatbelt { get; set; } } -/// One application-owned session handoff, requested by the supervised hosting participant. +/// Filesystem rules to merge into the base policy. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HostCreateSessionRequest +public sealed class SandboxConfigUserPolicyFilesystem { - /// Host-selected SDK creation or resume settings, without executable callbacks or tools. - [JsonPropertyName("config")] - public IDictionary Config { get => field ??= new Dictionary(); set; } + /// Whether to clear the policy when the session exits. + [JsonPropertyName("clearPolicyOnExit")] + public bool? ClearPolicyOnExit { get; set; } - /// Unique identity for this participation, independent of the session lifetime. - [JsonPropertyName("handoffId")] - public string HandoffId { get; set; } = string.Empty; + /// Paths explicitly denied. + [JsonPropertyName("deniedPaths")] + public IList? DeniedPaths { get; set; } - /// - /// For an explicit publication, borrow an existing owning-connection resident - /// instead of invoking the resume factory. Cold sessions still use the factory. - /// - [JsonPropertyName("preferResident")] - public bool? PreferResident { get; set; } + /// Paths granted read-only access. + [JsonPropertyName("readonlyPaths")] + public IList? ReadonlyPaths { get; set; } - /// Resume an app-owned durable session instead of creating a new session. - [JsonPropertyName("resume")] - public bool? Resume { get; set; } + /// Paths granted read/write access. + [JsonPropertyName("readwritePaths")] + public IList? ReadwritePaths { get; set; } } -/// Empty acknowledgement for a completed host lifecycle operation. +/// HTTP proxy configuration for sandboxed traffic. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HostReleaseSessionResult +public sealed class SandboxConfigUserPolicyNetworkProxy { -} + /// Optional password for proxy authentication, combined with the URL at spawn time. The persisted value may be a literal password, a `${secret:…}` reference resolved from the OS keychain, or a `${VAR}`/`$VAR` environment reference; it is resolved just before the sandboxed process routes through the proxy. The /sandbox dialog stores a real password in the OS keychain and persists only a `${secret:…}` placeholder (never plaintext in settings.json); the field is masked in the dialog and redacted by /settings show. + [JsonPropertyName("password")] + public string? Password { get; set; } -/// Ends one participation, not the application's session lifetime. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HostReleaseSessionRequest -{ - /// Identity of the participation to release without destroying the session. - [JsonPropertyName("handoffId")] - public string HandoffId { get; set; } = string.Empty; + /// Proxy URL (e.g. http://proxy.example.com:8080). The port is optional and defaults to the scheme's standard port when omitted; an explicit port must be between 1 and 65535. Credentials must not be embedded here — a `user:pass@` authority is rejected; put them in the separate `username`/`password` fields. A credential-free http:// loopback proxy URL is routed through the localhost proxy automatically; loopback covers localhost and any *.localhost subdomain, the whole 127.0.0.0/8 range, ::1, and IPv4-mapped loopback (::ffff:127.0.0.1). An https:// URL, or one with a username/password set, is used as-is. + [JsonPropertyName("url")] + public string Url { get; set; } = string.Empty; + + /// Optional username for proxy authentication. Combined with the URL (and `password`) into `user:pass@host` when the sandboxed process routes through the proxy. + [JsonPropertyName("username")] + public string? Username { get; set; } } -/// Listener readiness, returned only after binding and the supervised participant's SDK handshake. +/// Network rules to merge into the base policy. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HostStartResult +public sealed class SandboxConfigUserPolicyNetwork { - /// GitHub Mission Control environment ID, present when its relay transport is ready. - [JsonPropertyName("environmentId")] - public string? EnvironmentId { get; set; } + /// Hosts allowed through the built-in sandbox proxy. A non-empty list denies unmatched hosts; an absent or empty list allows all hosts not blocked. Supports exact hostnames, IP addresses, and *.example.com for strict subdomains. Host rules do not override the outbound or local-network toggles. + [JsonPropertyName("allowedHosts")] + public IList? AllowedHosts { get; set; } - /// Caller-generated listener UUID. - [JsonPropertyName("hostId")] - public string HostId { get; set; } = string.Empty; + /// Whether traffic to local/loopback addresses is allowed. + [JsonPropertyName("allowLocalNetwork")] + public bool? AllowLocalNetwork { get; set; } - /// Separate host process ID, when provided by a legacy runtime. Absent for in-process listeners. - [JsonPropertyName("pid")] - public long? Pid { get; set; } + /// Whether outbound network traffic is allowed at all. + [JsonPropertyName("allowOutbound")] + public bool? AllowOutbound { get; set; } - /// Secret connection token, absent when authentication is disabled. - [JsonPropertyName("token")] - public string? Token { get; set; } + /// Hosts denied by the built-in sandbox proxy. Deny rules take precedence over allowedHosts. A domain also denies all its subdomains. IP addresses match exactly; *.example.com matches strict subdomains, and * denies every host. + [JsonPropertyName("blockedHosts")] + public IList? BlockedHosts { get; set; } - /// Actual bound WebSocket URL, including the allocated port. - [JsonPropertyName("url")] - public string? Url { get; set; } + /// HTTP(S) proxy for sandboxed traffic. This is the built-in local proxy's upstream: every sandboxed command reaches it through a loopback listener, so credentials stay in the runtime and never reach the child. On Windows the sandbox also needs local network access, because it reaches that listener over host loopback. Configure credentials in the separate username/password fields. The transient local listener URL is never persisted. + [JsonPropertyName("proxy")] + public SandboxConfigUserPolicyNetworkProxy? Proxy { get; set; } } -/// GitHub Mission Control registration options. The compute ID is application-owned and stable. +/// macOS seatbelt-specific options. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HostGitHubEnvironmentOptions +public sealed class SandboxConfigUserPolicySeatbelt { - /// Stable application installation identity, reused across host restarts. - [JsonPropertyName("computeId")] - public string ComputeId { get; set; } = string.Empty; - - /// Human-readable environment display name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - - /// Require sealed, connection-bound authentication (default true), independent of listener address. False permits unsealed direct credentials and unbound sealed relay credentials; use only when the caller fully controls and trusts the direct transport. Relay token encryption remains mandatory. - [JsonPropertyName("requireConnectionBinding")] - public bool? RequireConnectionBinding { get; set; } + /// Whether the macOS seatbelt profile may access the keychain. + [JsonPropertyName("keychainAccess")] + public bool? KeychainAccess { get; set; } } -/// Local WebSocket transport options. +/// User-managed sandbox policy fragment merged into the auto-discovered base policy. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HostLocalServerOptions +public sealed class SandboxConfigUserPolicy { - /// Listener hostname. Defaults to 127.0.0.1; explicit non-loopback binds are allowed. - [JsonPropertyName("hostname")] - public string? Hostname { get; set; } + /// Deprecated legacy location for `seatbelt`; read only when the top-level `seatbelt` is absent. + [JsonPropertyName("experimental")] + public SandboxConfigUserPolicyExperimental? Experimental { get; set; } - /// Listener port. Omitted or zero requests an OS-allocated port. - [JsonPropertyName("port")] - public int? Port { get; set; } + /// Filesystem rules to merge into the base policy. + [JsonPropertyName("filesystem")] + public SandboxConfigUserPolicyFilesystem? Filesystem { get; set; } - /// Require token authentication (default true). Cannot be false with a token. - [JsonPropertyName("requireConnectionToken")] - public bool? RequireConnectionToken { get; set; } + /// Network rules to merge into the base policy. + [JsonPropertyName("network")] + public SandboxConfigUserPolicyNetwork? Network { get; set; } - /// Nonempty connection token. Generated randomly when required and omitted. - [JsonPropertyName("token")] - public string? Token { get; set; } + /// macOS seatbelt options to merge into the base policy. + [JsonPropertyName("seatbelt")] + public SandboxConfigUserPolicySeatbelt? Seatbelt { get; set; } } -/// Starts a supervised AHP host with at least one explicitly selected transport. +/// Resolved sandbox configuration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HostStartRequest +public sealed class SandboxConfig { - /// Stable application identity selecting its durable host catalog. Defaults to the persisted runtime compute GUID; must agree with githubEnvironment.computeId when both are supplied. - [JsonPropertyName("computeId")] - public string? ComputeId { get; set; } + /// Whether to auto-add the current working directory to readwritePaths. Default: true. + [JsonPropertyName("addCurrentWorkingDirectory")] + public bool? AddCurrentWorkingDirectory { get; set; } - /// Registers a GitHub Mission Control environment and enables its relay transport. - [JsonPropertyName("githubEnvironment")] - public HostGitHubEnvironmentOptions? GitHubEnvironment { get; set; } + /// Whether the agent may request that an individual command run outside the sandbox, which the host then approves or denies through the usual permission flow. A host capability flag rather than part of the policy: it is stripped from the effective spawn policy and only has an effect while `enabled` is true. Fail-closed, unlike the opt-out flags on this object: omitting it offers no bypass. Default: false (opt-in). + [JsonPropertyName("allowBypass")] + public bool? AllowBypass { get; set; } - /// Caller-generated UUID identifying this connection-owned listener. - [JsonPropertyName("hostId")] - public required string HostId { get; set; } + /// Whether to auto-grant read access to tool directories discovered on PATH and in toolchain environment variables (GOROOT, JAVA_HOME, VIRTUAL_ENV, and similar), and to common developer-tool caches, config, and toolchains. Writable grants cover scratch caches, the Unix GitHub CLI cache, and Cargo's registry, git store, and lock/tracker files. A relocated CARGO_HOME gets the same narrow split: registry and git are read-write; bin is read-only; the home root, config.toml, and credentials.toml stay ungranted. Set to false to disable every grant listed above; user-installed toolchains and caches then need explicit userPolicy.filesystem readonlyPaths and readwritePaths entries. The working directory (see addCurrentWorkingDirectory), temporary storage, session log paths, and system locations follow their own rules and stay granted. Default: true (enabled by default; set to false to opt out). + [JsonPropertyName("allowDevToolAccess")] + public bool? AllowDevToolAccess { get; set; } - /// Enables a local WebSocket listener. - [JsonPropertyName("localServer")] - public HostLocalServerOptions? LocalServer { get; set; } + /// Credential-injection capability flags. + [JsonPropertyName("auth")] + public SandboxConfigAuth? Auth { get; set; } - /// Ask the owning application to resume its durable AHP sessions. - [JsonPropertyName("resumeFactory")] - public bool? ResumeFactory { get; set; } + /// Opt-in whole-value environment masking for sandboxed shell, MCP, and LSP children. Configured names get random sentinels; the local proxy substitutes them only in HTTPS request headers at their injection hosts. Approved bypasses skip masking and the sandbox proxy, so bypassed shells may receive the real environment values. Disabled or explicitly opted-out routes are not protected. No credential values are stored in this configuration. + [JsonPropertyName("credentials")] + public SandboxCredentialsConfig? Credentials { get; set; } - /// Ask the owning SDK application to materialize AHP sessions. - [JsonPropertyName("sessionFactory")] - public bool? SessionFactory { get; set; } -} + /// Whether sandboxing is enabled for the session. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } -/// Empty acknowledgement for a completed host lifecycle operation. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HostDisposeResult -{ + /// The `sandboxLspServers` counterpart of `managedMcpRoutingLocked`. + [JsonInclude] + [JsonPropertyName("managedLspRoutingLocked")] + internal bool? ManagedLspRoutingLocked { get; set; } + + /// Set by the runtime when a managed policy forced `sandboxMcpServers` on and took the local opt-out away. Provenance rather than policy: it lets a sandbox startup failure point at the administrator instead of a setting the next managed merge would override, and it is ignored when comparing two configs for change. Only the managed merge may set it; a caller-supplied value is stripped. + [JsonInclude] + [JsonPropertyName("managedMcpRoutingLocked")] + internal bool? ManagedMcpRoutingLocked { get; set; } + + /// Whether language servers the session launches are confined by the sandbox. Only an explicit `false` opts out. Ignored while `enabled` is false. Default: true (enabled by default; set to false to opt out). + [JsonPropertyName("sandboxLspServers")] + public bool? SandboxLspServers { get; set; } + + /// Whether MCP servers the session launches are confined by the sandbox. Only an explicit `false` opts out; doing so also lets remote-MCP egress leave the sandbox, so the flag and `enabled` are always read together. Ignored while `enabled` is false. Default: true (enabled by default; set to false to opt out). + [JsonPropertyName("sandboxMcpServers")] + public bool? SandboxMcpServers { get; set; } + + /// User-managed sandbox policy fragment merged into the auto-discovered base policy. + [JsonPropertyName("userPolicy")] + public SandboxConfigUserPolicy? UserPolicy { get; set; } } -/// Stops a connection-owned listener and joins its teardown. +/// Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HostDisposeRequest +internal sealed class SandboxProxyCaRequest { - /// Listener UUID. Unknown or successfully stopped IDs are harmless. - [JsonPropertyName("hostId")] - public string HostId { get; set; } = string.Empty; + /// The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. + [JsonPropertyName("sandboxConfig")] + public SandboxConfig? SandboxConfig { get; set; } } -/// Private credentials delivered only to a runtime-owned Mission Control hosting participant. +/// Status of the persistent certificate authority of the sandbox credential proxy. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HostGetEnvironmentCredentialsResult +public sealed class SandboxProxyCaStatus { - /// GitHub API base URL for the authenticated service. - [JsonPropertyName("githubApiUrl")] - public string GitHubApiUrl { get; set; } = string.Empty; - - /// Hostname of the authenticated GitHub service. - [JsonPropertyName("githubHost")] - public string GitHubHost { get; set; } = string.Empty; + /// Whether this process can add the certificate authority to OS trust without credentials from a different user. False where OS trust is unsupported, and on Windows when the process cannot elevate itself to write the machine trust store. When false, do not offer to set up the certificate authority. + [JsonPropertyName("canInstall")] + public bool CanInstall { get; set; } - /// Mission Control API origin for environment registration and management. - [JsonPropertyName("missionControlUrl")] - public string MissionControlUrl { get; set; } = string.Empty; + /// Human-readable reason for the state. On `installed` or `notInstalled`, present only when the certificate authority must be rotated, and then says why. + [JsonPropertyName("detail")] + public string? Detail { get; set; } - /// Current bearer token for the authenticated GitHub identity. - [JsonPropertyName("token")] - public string Token { get; set; } = string.Empty; + /// The state of the certificate authority. + [JsonPropertyName("state")] + public SandboxProxyCaState State { get; set; } } -/// Normalized local WebSocket listener settings. +/// Result of creating the persistent certificate authority of the sandbox credential proxy. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HostLocalServerConfiguration +public sealed class SandboxProxyCaCreateResult { - /// Hostname or IP address to bind. - [JsonPropertyName("hostname")] - public string Hostname { get; set; } = string.Empty; - - /// Port to bind, with zero requesting OS allocation. - [JsonPropertyName("port")] - public int Port { get; set; } + /// Absolute path of the public certificate of the certificate authority, in PEM format. + [JsonPropertyName("certificatePath")] + public string CertificatePath { get; set; } = string.Empty; +} - /// Whether the listener requires token authentication. - [JsonPropertyName("requireConnectionToken")] - public bool RequireConnectionToken { get; set; } +/// Where this runtime keeps the sandbox proxy password. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SandboxProxySecretLocation +{ + /// Absolute path of the credential store holding the sandbox proxy password. The proxy password belongs to no MCP server, so it is kept in its own directory rather than in the MCP secret store. + [JsonPropertyName("configDir")] + public string ConfigDir { get; set; } = string.Empty; - /// Secret connection token, absent when authentication is disabled. - [JsonPropertyName("token")] - public string? Token { get; set; } + /// Identifier of the proxy password entry within that store. Derived from the configuration directory, so two Copilot homes on one machine never share an entry. Use it to recognize a `${secret:…}` reference in stored settings as this runtime's own proxy password. + [JsonPropertyName("secretId")] + public string SecretId { get; set; } = string.Empty; } -/// Normalized listener settings delivered only to the supervised hosting participant. +/// The stored sandbox proxy password, if one is present. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HostGetConfigurationResult +internal sealed class SandboxProxySecretGetResult { - /// Requested GitHub Mission Control registration. - [JsonPropertyName("githubEnvironment")] - public HostGitHubEnvironmentOptions? GitHubEnvironment { get; set; } - - /// Normalized local listener settings, absent for relay-only hosts. - [JsonPropertyName("localServer")] - public HostLocalServerConfiguration? LocalServer { get; set; } + /// The stored password. Absent when no entry exists in either the keychain or the on-disk fallback store. + [JsonPropertyName("value")] + public string? Value { get; set; } +} - /// Whether app-owned durable sessions are resumed by the owning application. - [JsonPropertyName("resumeFactory")] - public bool ResumeFactory { get; set; } +/// Where the sandbox proxy password was stored. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SandboxProxySecretSaveResult +{ + /// Whether the OS keychain accepted the value. False means it was written to the on-disk fallback store instead, which is still readable by `sandbox.proxySecret.get`. + [JsonPropertyName("storedInKeychain")] + public bool StoredInKeychain { get; set; } +} - /// Whether session materialization is delegated to the owning application. - [JsonPropertyName("sessionFactory")] - public bool SessionFactory { get; set; } +/// The sandbox proxy password to store. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SandboxProxySecretSaveRequest +{ + /// The password to store for the sandbox proxy. + [JsonPropertyName("value")] + public string Value { get; set; } = string.Empty; } -/// Empty acknowledgement for a completed host lifecycle operation. +/// The stored sandbox settings to resolve against the defaults. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HostReadyResult +internal sealed class SandboxApplyDefaultsRequest { + /// The sandbox settings as stored in the settings file. An empty object resolves to the defaults alone. + [JsonPropertyName("stored")] + public JsonElement Stored { get; set; } } -/// Readiness reported by the supervised hosting participant on its own SDK connection. +/// The outcome of a locked snapshot write. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HostReadyRequest +internal sealed class PersistenceWriteRawJsonLockedResult { - /// Actual bound WebSocket URL. - [JsonPropertyName("address")] - public string? Address { get; set; } - - /// Registered environment ID, reported only once the relay transport is connected. - [JsonPropertyName("environmentId")] - public string? EnvironmentId { get; set; } + /// Why the write failed. Absent when `success` is true. A lock the runtime could not acquire in time reports here rather than raising. + [JsonPropertyName("error")] + public string? Error { get; set; } - /// Configured secret token, absent when authentication is disabled. - [JsonPropertyName("token")] - public string? Token { get; set; } + /// Whether the file now holds the requested contents. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// One server-discovered hook action from user, repository, plugin, or managed-policy configuration. +/// A complete JSON snapshot to write under the runtime's per-path file lock. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DiscoveredHook +internal sealed class PersistenceWriteRawJsonLockedRequest { - /// Durable content hash used by hook enablement. Identical actions may intentionally share this key. Omitted when changing the user's disabled-hooks setting cannot change the action's current server-discovered state, including managed-policy hooks, session-start prompt actions, actions suppressed by disable-all settings, and projectless plugin actions that require project-directory expansion. - [JsonPropertyName("disableKey")] - public string? DisableKey { get; set; } - - /// Whether this action is enabled under the server-side discovery settings. Concrete sessions may differ because they can add session-specific directories, plugins, or trust. False when its disable key is present in the user's disabled-hooks setting or disable-all settings suppress the action. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } - - /// Hook event that invokes this action. - [JsonPropertyName("hookType")] - public HookType HookType { get; set; } - - /// Deterministic identifier for this server-discovered action row. It remains stable while the project, origin, source, event, action content, and duplicate ordinal are unchanged. This is row identity, not the key persisted in disabledHooks. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - - /// Configuration tier that contributed this hook action. - [JsonPropertyName("origin")] - public HookOrigin Origin { get; set; } + /// The serialized JSON document to write. It replaces the file's contents entirely; nothing is merged. + [JsonPropertyName("dataJson")] + public string DataJson { get; set; } = string.Empty; - /// Input project path for which this server-side action was resolved. Set on every row returned for project-scoped discovery, including repeated user and policy actions. - [JsonPropertyName("projectPath")] - public string? ProjectPath { get; set; } + /// Comment lines to emit above the document, for a format that tolerates them. Omit for strict JSON. + [JsonPropertyName("fileHeader")] + public string? FileHeader { get; set; } - /// Human-readable source label, such as a hook file path, settings source, or plugin name. - [JsonPropertyName("source")] - public string? Source { get; set; } + /// Absolute path of the file to replace. Parent directories are created when missing. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; } -/// Server-discovered hook actions and partial-load diagnostics from user, repository, plugin, and managed-policy sources. Concrete sessions may include additional session-specific hook sources. +/// Outcome of rewriting the `disabledHooks` setting. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HooksDiscoverResult +internal sealed class UserSettingsSetHookDisabledResult { - /// Errors for hook sources or actions that could not be loaded, making the result partially incomplete. Other valid actions are still returned. Project-resolution and repository-settings errors are prefixed with their project path. - [JsonPropertyName("errors")] - public IList Errors { get => field ??= []; set; } - - /// All discovered hook actions. Byte-identical actions remain separate rows even when they share a disable key. - [JsonPropertyName("hooks")] - public IList Hooks { get => field ??= []; set; } + /// Why the write failed. Absent when the status is `ok`. + [JsonPropertyName("errorMessage")] + public string? ErrorMessage { get; set; } - /// Non-fatal source-loading warnings. Discovery remains complete for the affected source, although the source had a recoverable issue. Repository-settings warnings are prefixed with their project path when attribution is available. - [JsonPropertyName("warnings")] - public IList Warnings { get => field ??= []; set; } + /// `ok` when the setting was written, `invalid` when settings.json could not be parsed and was left alone, `error` when the write itself failed. + [JsonPropertyName("status")] + public string Status { get; set; } = string.Empty; } -/// Optional project paths and host-exclusion behavior for server-scoped hook discovery. +/// One hook to disable or re-enable. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HooksDiscoverRequest +internal sealed class UserSettingsSetHookDisabledRequest { - /// When true, omit host-owned user and plugin hook rows and their diagnostics. Managed-policy hooks and trusted repository hooks remain visible, and host disabledHooks still contribute to each remaining row's effective enabled state. This filters sources rather than simulating a host with no settings. - [JsonPropertyName("excludeHostHooks")] - public bool? ExcludeHostHooks { get; set; } + /// True adds the key to `disabledHooks`, false removes it. + [JsonPropertyName("disabled")] + public bool Disabled { get; set; } - /// Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without ambient discovery or repository file-hook enablement, subject to managed/hook disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. - [JsonPropertyName("hookDirectories")] - public IList? HookDirectories { get; set; } + /// Durable content-hash key of the hook, as `hooks.loadResources` reports it. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("disableKey")] + public string DisableKey { get; set; } = string.Empty; - /// Optional project directory paths whose trusted repository and project-expanded plugin hooks should be discovered. When omitted or empty, user, managed-policy, and globally enabled installed or explicit plugin hooks are returned without project expansion. - [JsonPropertyName("projectPaths")] - public IList? ProjectPaths { get; set; } + /// Path of the settings.json to rewrite. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("settingsPath")] + public string SettingsPath { get; set; } = string.Empty; } -/// Active server-driven promotion for a model, including its discount and optional expiry. +/// Selects the configuration directory whose user settings to read. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelBillingPromo +internal sealed class UserSettingsLoadForConfigDirRequest { - /// Percentage discount (0-100) applied while the promotion is active. May be fractional. - [JsonPropertyName("discountPercent")] - public double? DiscountPercent { get; set; } - - /// UTC ISO 8601 timestamp marking when the promotion ends. Optional: an open-ended promotion omits this field. When present, the API only surfaces a promo whose expiry parses and is in the future, so consumers should treat a past value as expired. - [JsonPropertyName("endsAt")] - public string? EndsAt { get; set; } - - /// Stable identifier for the promotion campaign. - [JsonPropertyName("id")] - public string? Id { get; set; } - - /// Human-readable promotion message. Does not include the expiry timestamp; consumers may format endsAt and append it when present. - [JsonPropertyName("message")] - public string? Message { get; set; } - - /// Whether the service asked hosts to give this promotion a prominent surface, such as a dedicated banner, in addition to listing it with the model. `true` requests that surface and `false` asks for the model list only. Absent means the service expressed no preference — for example a response that predates the field — so hosts should apply their own default rather than read it as `false`. - [JsonPropertyName("showBanner")] - public bool? ShowBanner { get; set; } + /// Copilot configuration directory to read the settings document from, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to read the directory the server resolved for itself. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } } -/// Long context tier pricing (available for models with extended context windows). +/// A repository's settings as stored, together with any diagnostic raised while reading them. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelBillingTokenPricesLongContext +internal sealed class UserSettingsLoadRepoResult { - /// Use cacheReadPrice instead. AI Credits cost per billing batch of cached tokens. - [EditorBrowsable(EditorBrowsableState.Never)] -#if NET5_0_OR_GREATER - [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] -#else - [Obsolete("This member is deprecated and will be removed in a future version.")] -#endif - [JsonPropertyName("cachePrice")] - public double? CachePrice { get; set; } - - /// AI Credits cost per billing batch of cached (read) tokens. - [JsonPropertyName("cacheReadPrice")] - public double? CacheReadPrice { get; set; } - - /// AI Credits cost per billing batch of 1-hour cache-write (cache creation) tokens. - [JsonPropertyName("cacheWrite1hPrice")] - public double? CacheWrite1hPrice { get; set; } - - /// AI Credits cost per billing batch of cache-write (cache creation) tokens. - [JsonPropertyName("cacheWritePrice")] - public double? CacheWritePrice { get; set; } - - /// Use maxPromptTokens instead. Prompt token budget for the long context tier. The total context window is this value plus the model's max_output_tokens. - [EditorBrowsable(EditorBrowsableState.Never)] -#if NET5_0_OR_GREATER - [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] -#else - [Obsolete("This member is deprecated and will be removed in a future version.")] -#endif - [JsonPropertyName("contextMax")] - public long? ContextMax { get; set; } - - /// AI Credits cost per billing batch of input tokens. - [JsonPropertyName("inputPrice")] - public double? InputPrice { get; set; } - - /// Prompt token budget for the long context tier. The total context window is this value plus the model's max_output_tokens. - [JsonPropertyName("maxPromptTokens")] - public long? MaxPromptTokens { get; set; } + /// The repository's settings document, keyed by setting name, with each value carried verbatim. Null when the repository declares no settings. + [JsonPropertyName("settings")] + public IDictionary? Settings { get; set; } - /// AI Credits cost per billing batch of output tokens. - [JsonPropertyName("outputPrice")] - public double? OutputPrice { get; set; } + /// Why part of the document was ignored, as a single human-readable string joining every diagnostic with `; `. Null when the document loaded cleanly. The settings that did load are still reported, so a consumer should surface this and continue rather than treat it as a failure. + [JsonPropertyName("warning")] + public string? Warning { get; set; } } -/// Token-level pricing information for this model. +/// Selects the repository whose checked-in settings to read. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelBillingTokenPrices +internal sealed class UserSettingsLoadRepoRequest { - /// Number of tokens per standard billing batch. - [JsonPropertyName("batchSize")] - public long? BatchSize { get; set; } - - /// Use cacheReadPrice instead. AI Credits cost per billing batch of cached tokens. - [EditorBrowsable(EditorBrowsableState.Never)] -#if NET5_0_OR_GREATER - [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] -#else - [Obsolete("This member is deprecated and will be removed in a future version.")] -#endif - [JsonPropertyName("cachePrice")] - public double? CachePrice { get; set; } - - /// AI Credits cost per billing batch of cached (read) tokens. - [JsonPropertyName("cacheReadPrice")] - public double? CacheReadPrice { get; set; } - - /// AI Credits cost per billing batch of 1-hour cache-write (cache creation) tokens. - [JsonPropertyName("cacheWrite1hPrice")] - public double? CacheWrite1hPrice { get; set; } - - /// AI Credits cost per billing batch of cache-write (cache creation) tokens. - [JsonPropertyName("cacheWritePrice")] - public double? CacheWritePrice { get; set; } - - /// Use maxPromptTokens instead. Prompt token budget for the default tier. The total context window is this value plus the model's max_output_tokens. - [EditorBrowsable(EditorBrowsableState.Never)] -#if NET5_0_OR_GREATER - [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] -#else - [Obsolete("This member is deprecated and will be removed in a future version.")] -#endif - [JsonPropertyName("contextMax")] - public long? ContextMax { get; set; } - - /// AI Credits cost per billing batch of input tokens. - [JsonPropertyName("inputPrice")] - public double? InputPrice { get; set; } - - /// Long context tier pricing (available for models with extended context windows). - [JsonPropertyName("longContext")] - public ModelBillingTokenPricesLongContext? LongContext { get; set; } - - /// Prompt token budget for the default tier. The total context window is this value plus the model's max_output_tokens. - [JsonPropertyName("maxPromptTokens")] - public long? MaxPromptTokens { get; set; } - - /// AI Credits cost per billing batch of output tokens. - [JsonPropertyName("outputPrice")] - public double? OutputPrice { get; set; } + /// Absolute path of the repository root whose settings to read. When this is the user's home directory, the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as if it were repository policy. + [JsonPropertyName("repoRoot")] + public string RepoRoot { get; set; } = string.Empty; } -/// Billing information. +/// The settings a consumer should act on inside a repository, together with any diagnostic raised while reading the repository layer. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelBilling +internal sealed class UserSettingsLoadAndMergeRepoResult { - /// Whole-number percentage discount (0-100) applied to usage billed through this model. Populated for the synthetic `auto` model, where requests routed by auto-mode are billed at a reduced rate; absent for concrete models. - [JsonPropertyName("discountPercent")] - public int? DiscountPercent { get; set; } - - /// Billing cost multiplier relative to the base rate. - [JsonPropertyName("multiplier")] - public double? Multiplier { get; set; } - - /// Active server-driven promotion for this model, if any. Present when the model is being promoted with a discount, which may be time-boxed or open-ended. - [JsonPropertyName("promo")] - public ModelBillingPromo? Promo { get; set; } + /// The merged settings document, keyed by setting name. Equals the supplied user layer when the repository declares no settings. + [JsonPropertyName("settings")] + public IDictionary Settings { get => field ??= new Dictionary(); set; } - /// Token-level pricing information for this model. - [JsonPropertyName("tokenPrices")] - public ModelBillingTokenPrices? TokenPrices { get; set; } + /// Why part of the repository document was ignored, as a single human-readable string joining every diagnostic with `; `. Null when it loaded cleanly. The settings that did load are still merged, so a consumer should surface this and continue rather than treat it as a failure. + [JsonPropertyName("warning")] + public string? Warning { get; set; } } -/// Vision-specific limits. +/// A repository to read settings from, and the user layer they are merged over. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelCapabilitiesLimitsVision +internal sealed class UserSettingsLoadAndMergeRepoRequest { - /// Maximum image size in bytes. - [JsonPropertyName("max_prompt_image_size")] - public long MaxPromptImageSize { get; set; } - - /// Maximum number of images per prompt. - [JsonPropertyName("max_prompt_images")] - public long MaxPromptImages { get; set; } + /// Absolute path of the repository root whose settings to read. When this is the user's home directory, the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as if it were repository policy. + [JsonPropertyName("repoRoot")] + public string RepoRoot { get; set; } = string.Empty; - /// MIME types the model accepts. - [JsonPropertyName("supported_media_types")] - public IList SupportedMediaTypes { get => field ??= []; set; } + /// The user's own settings, keyed by setting name. The repository layer is merged over this; a repository may only add to the collection settings it is allowed to influence, so a user setting it does not name survives unchanged. + [JsonPropertyName("userSettings")] + public IDictionary UserSettings { get => field ??= new Dictionary(); set; } } -/// Token limits for prompts, outputs, and context window. +/// The on-disk location of the user's settings document. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelCapabilitiesLimits +internal sealed class UserSettingsPathResult { - /// Maximum total context window size in tokens. - [JsonPropertyName("max_context_window_tokens")] - public long? MaxContextWindowTokens { get; set; } - - /// Maximum number of output/completion tokens. - [JsonPropertyName("max_output_tokens")] - public long? MaxOutputTokens { get; set; } - - /// Maximum number of prompt/input tokens. - [JsonPropertyName("max_prompt_tokens")] - public long? MaxPromptTokens { get; set; } - - /// Vision-specific limits. - [JsonPropertyName("vision")] - public ModelCapabilitiesLimitsVision? Vision { get; set; } + /// Absolute path to the settings file this runtime reads and writes. Normally `settings.json` under the Copilot configuration directory; an extensionless legacy `settings` file is reported instead when it exists and `settings.json` does not. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; } -/// Feature flags indicating what the model supports. +/// The user's stored settings, together with any diagnostic raised while reading them. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelCapabilitiesSupports +internal sealed class UserSettingsLoadWithWarningResult { - /// Resolved Anthropic adaptive-thinking capability — unsupported / optional / required / adaptive_only. 'required' models reject thinking.type='enabled' with HTTP 400 but still accept 'disabled' (e.g. opus-4.7/4.8/5, sonnet-5); 'adaptive_only' models accept nothing but 'adaptive' (e.g. fable, mythos). - [JsonPropertyName("adaptive_thinking")] - public AdaptiveThinkingSupport? AdaptiveThinking { get; set; } - - /// Whether this model supports reasoning effort configuration. - [JsonPropertyName("reasoningEffort")] - public bool? ReasoningEffort { get; set; } - - /// Whether the model supports provider-native thinking. Independent of configurable reasoning effort; omission means unknown. - [JsonPropertyName("thinking")] - public bool? Thinking { get; set; } - - /// Whether this model supports canonical tool calling. - [JsonPropertyName("toolCalls")] - public bool? ToolCalls { get; set; } + /// The stored user settings document, keyed by setting name, with each value carried verbatim. Empty when the file could not be read at all. + [JsonPropertyName("settings")] + public IDictionary Settings { get => field ??= new Dictionary(); set; } - /// Whether this model supports vision/image input. - [JsonPropertyName("vision")] - public bool? Vision { get; set; } + /// Why part of the document was ignored, phrased for display to the user. Null when the document loaded cleanly. The settings that did load are still reported, so a consumer may surface this and continue rather than treat it as a failure. + [JsonPropertyName("warning")] + public string? Warning { get; set; } } -/// Model capabilities and limits. +/// The user layer folded over the managed layer. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelCapabilities +internal sealed class UserSettingsMergeManagedAndUserResult { - /// Token limits for prompts, outputs, and context window. - [JsonPropertyName("limits")] - public ModelCapabilitiesLimits? Limits { get; set; } - - /// Feature flags indicating what the model supports. - [JsonPropertyName("supports")] - public ModelCapabilitiesSupports? Supports { get; set; } + /// The merged settings. An empty object when neither layer was supplied, so an unmanaged host with no user settings governs nothing. + [JsonPropertyName("settingsJson")] + public JsonElement SettingsJson { get; set; } } -/// A service-published message about a model, carrying a stable machine-readable code alongside human-readable text. +/// The managed (enterprise policy) layer and the user layer to fold together. The field names carry the layer identity: nothing about a settings object identifies which layer produced it, so a generic base/override pair would let a caller transpose them and silently resolve the governance keys in the user's favour. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelMessage +internal sealed class UserSettingsMergeManagedAndUserParams { - /// Stable machine-readable identifier for the message, such as `client_version_deprecated`. Hosts can key custom presentation off this; unrecognized codes should fall back to displaying `message`. - [JsonPropertyName("code")] - public string Code { get; set; } = string.Empty; + /// The managed layer. Its governance keys win, and the per-entry `enabledPlugins` and `extraKnownMarketplaces` control maps are stamped back from it after the union. Omitted when the host is unmanaged. + [JsonPropertyName("managed")] + public JsonElement? Managed { get; set; } - /// Human-readable message text intended for display to the user. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; + /// The user's own settings layer. Wins on every key the managed layer does not govern. Omitted when the user has no settings yet. + [JsonPropertyName("user")] + public JsonElement? User { get; set; } } -/// Policy state (if applicable). +/// The repository layer folded into the user layer. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelPolicy +internal sealed class UserSettingsMergeRepoValueResult { - /// Current policy state for this model. - [JsonPropertyName("state")] - public ModelPolicyState State { get; set; } - - /// Usage terms or conditions for this model. - [JsonPropertyName("terms")] - public string? Terms { get; set; } + /// The merged settings, with the per-entry managed control maps re-stamped from the runtime's ambient managed policy. + [JsonPropertyName("settingsJson")] + public JsonElement SettingsJson { get; set; } } -/// Service-published warning text that hosts should display when presenting a model. +/// The user layer and the repository layer to fold together. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelWarningText +internal sealed class UserSettingsMergeRepoValueParams { - /// Data-retention warning for the model. The text may contain Markdown links and should be rendered as Markdown when supported. - [JsonPropertyName("dataRetention")] - public string? DataRetention { get; set; } + /// The repository's checked-in settings layer. + [JsonPropertyName("repoSettings")] + public JsonElement RepoSettings { get; set; } + + /// The user's settings, already resolved against any managed layer. + [JsonPropertyName("userSettings")] + public JsonElement UserSettings { get; set; } } -/// Copilot model metadata, including identifier, display name, capabilities, policy, billing, reasoning efforts, and picker categories. +/// The outcome of the one-time staff update-channel migration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class Model +internal sealed class UserSettingsMigrateStaffUpdateChannelOnceResult { - /// Billing information. - [JsonPropertyName("billing")] - public ModelBilling? Billing { get; set; } - - /// Model capabilities and limits. - [JsonPropertyName("capabilities")] - public ModelCapabilities Capabilities { get => field ??= new(); set; } - - /// Default reasoning effort level (only present if model supports reasoning effort). - [JsonPropertyName("defaultReasoningEffort")] - public string? DefaultReasoningEffort { get; set; } - - /// Model identifier (e.g., "claude-sonnet-4.5"). - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - - /// Informational notices the service published for this model, such as an upcoming change or a recommended alternative. Present only when the service published at least one notice. Hosts should surface these without implying anything is wrong with the model. - [JsonPropertyName("infoMessages")] - public IList? InfoMessages { get; set; } - - /// Provider-supplied model metadata. Keys and JSON-compatible values are preserved unchanged. This is factual metadata published by the model provider; it carries no picker or UX semantics. - [JsonPropertyName("metadata")] - public IDictionary? Metadata { get; set; } - - /// Model capability category for grouping in the model picker. - [JsonPropertyName("modelPickerCategory")] - public ModelPickerCategory? ModelPickerCategory { get; set; } - - /// Relative cost tier for token-based billing users. - [JsonPropertyName("modelPickerPriceCategory")] - public ModelPickerPriceCategory? ModelPickerPriceCategory { get; set; } + /// When the migration was recorded as done, as an ISO-8601 timestamp. Absent only for `ineligible`, which records nothing. + [JsonPropertyName("completedAt")] + public string? CompletedAt { get; set; } - /// Display name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// What the migration did. Only `migrated` means the persisted settings changed. + [JsonPropertyName("status")] + public StaffUpdateChannelMigrationStatus Status { get; set; } +} - /// Policy state (if applicable). - [JsonPropertyName("policy")] - public ModelPolicy? Policy { get; set; } +/// The filesystem and environment facts a user-settings file is resolved from. Passed explicitly rather than read from the runtime's own process, so a host whose configuration directory differs from its process environment resolves the file it means. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsHostContext +{ + /// The Copilot configuration directory, when the host set one. Takes precedence over `COPILOT_HOME` and the home directory. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } - /// The model provider that produced this model, as a neutral reference (opaque id, human-readable label, and provider kind). Present on models returned by `session.model.list`, which resolves provider attribution from the session's account roster; absent on the flat `server.models.list`, which does not resolve a session roster. The model picker groups by this reference. - [JsonPropertyName("provider")] - public ModelProviderRef? Provider { get; set; } + /// The host's environment variables. `COPILOT_HOME` is read from here, as are the variables a settings hook may expand. + [JsonPropertyName("environment")] + public IDictionary Environment { get => field ??= new Dictionary(); set; } - /// Context-window tiers this model offers, when the provider advertises them independently of tiered token pricing. Copilot models carry their tiers in `billing.tokenPrices`; a provider that has no pricing to publish (an agent host reached over AHP, for example) declares them here instead, so the model picker can still offer the tier toggle. - [JsonPropertyName("supportedContextTiers")] - public IList? SupportedContextTiers { get; set; } + /// The user's home directory, used when neither a configuration directory nor `COPILOT_HOME` is set. + [JsonPropertyName("homeDirectory")] + public string HomeDirectory { get; set; } = string.Empty; +} - /// Supported reasoning effort levels (only present if model supports reasoning effort). - [JsonPropertyName("supportedReasoningEfforts")] - public IList? SupportedReasoningEfforts { get; set; } +/// The outcome of the one-time staff model-selection reset. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsResetStaffModelSelectionOnceResult +{ + /// The cutoff this reset is gated on, as an ISO-8601 timestamp. A recorded timestamp at or after it means the reset is already done. + [JsonPropertyName("cutoff")] + public string Cutoff { get; set; } = string.Empty; - /// Model vendor as the Copilot API reports it, for example "Anthropic" or "Azure OpenAI". Open vocabulary, passed through unchanged. It can name the vendor that serves the model instead of the one that built it, or a label that is not a vendor, such as "Experimental". Absent when the Copilot API reports no vendor. - [JsonPropertyName("vendor")] - public string? Vendor { get; set; } + /// Whether the persisted model selection was cleared. Only `true` means the settings document changed and the host should adopt the returned settings. + [JsonPropertyName("didReset")] + public bool DidReset { get; set; } - /// Warnings the service published for this model, such as a deprecated client version. Present only when the service published at least one warning. The model remains usable; hosts should surface these as advisory rather than blocking. - [JsonPropertyName("warningMessages")] - public IList? WarningMessages { get; set; } + /// The timestamp the host should now record, as an ISO-8601 timestamp. Carries the caller's own value back unchanged when nothing was reset. + [JsonPropertyName("resetAt")] + public string? ResetAt { get; set; } - /// Warning text the service requires hosts to surface for this model. Present only when the service published at least one warning. - [JsonPropertyName("warningText")] - public ModelWarningText? WarningText { get; set; } + /// The settings document as it stands after the reset, keyed by setting name. Present only when `didReset` is true. + [JsonPropertyName("settings")] + public IDictionary? Settings { get; set; } } -/// List of Copilot models available to the resolved user, including capabilities and billing metadata. +/// Selects the configuration directory to run the one-time staff model-selection reset against, and supplies the caller's record of whether it has already run. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelList +internal sealed class UserSettingsResetStaffModelSelectionOnceRequest { - /// List of available models with full metadata. - [JsonPropertyName("models")] - public IList Models { get => field ??= []; set; } -} + /// The configuration directory, home directory and environment to resolve the settings and global-state documents from. A host that scopes a session to its own Copilot home must pass that directory here, or the reset is evaluated against the server's own home instead. + [JsonPropertyName("context")] + public UserSettingsHostContext Context { get => field ??= new(); set; } -/// RPC data type for ModelsList operations. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModelsListRequest -{ - /// GitHub token accepted for compatibility with existing SDK clients. When provided, resolves this token instead of using the current account. - [JsonPropertyName("gitHubToken")] - public string? GitHubToken { get; set; } + /// Whether the signed-in account is a staff account. The reset applies only to staff, so anything other than `true` returns `didReset: false` without touching the settings document. + [JsonPropertyName("staff")] + public bool? Staff { get; set; } - /// Opaque account identifier returned by `account.getAllUsers`. When omitted, the current account is used. - [JsonPropertyName("selectionId")] - public string? SelectionId { get; set; } + /// When the caller last recorded this reset, as an ISO-8601 timestamp. A timestamp at or after the cutoff means the reset already ran and is returned unchanged. + [JsonPropertyName("staffModelResetAt")] + public string? StaffModelResetAt { get; set; } } -/// A well-known model in the runtime's built-in catalog. +/// The unrecognized top-level keys found in the user settings document, already phrased for display. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class BuiltInModelCatalogEntry +internal sealed class UserSettingsUnknownKeysWarningResult { - /// Well-known runtime model ID suitable for provider or provider-model metadata. This is not necessarily the provider-facing deployment or model name and does not indicate CAPI entitlement or provider availability. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// The warning to show the user, naming the unrecognized keys and the file they were found in. Absent when every top-level key is recognized, and also when the document is missing or could not be read, because an unknown-key list taken from a document the runtime could not load would name keys that may not be there. + [JsonPropertyName("warning")] + public string? Warning { get; set; } } -/// The running runtime's complete catalog of well-known built-in model IDs, including supported models and additional IDs with built-in metadata. +/// Selects the configuration directory whose user settings document should be inspected for unrecognized top-level keys. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class BuiltInModelCatalog +internal sealed class UserSettingsUnknownKeysWarningRequest { - /// Built-in model entries. - [JsonPropertyName("models")] - public IList Models { get => field ??= []; set; } + /// The configuration directory, home directory and environment to resolve the settings document from. A host that scopes a session to its own Copilot home must pass that directory here, or the server's own home is inspected instead. + [JsonPropertyName("context")] + public UserSettingsHostContext Context { get => field ??= new(); set; } } -/// Whether this host can run one sandbox policy feature. A session whose effective policy uses an unsupported feature fails each sandboxed command with `reason`, except `filesystem_enumeration`, whose absence degrades sandboxed PowerShell instead of failing it. +/// The overrides and host context to resolve effective runtime settings from. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxHostCapability +internal sealed class UserSettingsBuildRuntimeRequest { - /// The policy feature, as an extensible string: ignore names you do not recognize. Known values: `network` (sandboxed commands can reach the network; on Linux this needs the tooling for Bubblewrap's private network namespace, such as slirp4netns), `network_filtering` (host rules and the sandbox proxy; on Linux this needs the same tooling as `network`; on Windows it needs Process Security Environment 1.1 host-loopback support or MXC's PSEC 1.0-only proxy-loopback compatibility capability, and a policy that uses it must also set `network.allowLocalNetwork`; compatibility applies only to an explicit identity-less runtime proxy, not general host-loopback access, and other policy restrictions still apply), `denied_paths` (native enforcement of `filesystem.deniedPaths`), `shell` (shell commands inside the sandbox), and `filesystem_enumeration` (enumerate-only filesystem grants; on Windows this needs Process Security Environment 1.1 filesystem enumeration support, and without it sandboxed PowerShell still runs but cannot resolve its current location; other platforms always report it). - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// The environment to read settings-bearing variables from. Passed explicitly rather than read from the server process so a host can resolve settings for an environment it is about to create rather than the one it runs in. + [JsonPropertyName("environment")] + public IDictionary Environment { get => field ??= new Dictionary(); set; } - /// Human-readable reason and remedy when the feature is unsupported, such as a package to install or an OS update. Present only when `supported` is false. - [JsonPropertyName("reason")] - public string? Reason { get; set; } + /// Settings that take precedence over every document and environment layer, such as the values a host derived from its own command line. Keyed by setting name, with each value carried verbatim, so a host may pass keys this runtime does not recognize. Absent when the host contributes no overrides of its own. + [JsonPropertyName("overrides")] + public IDictionary? Overrides { get; set; } - /// Whether this host can run the feature. - [JsonPropertyName("supported")] - public bool Supported { get; set; } + /// The platform to apply platform-specific defaults for, in the same spelling the host's own runtime reports. + [JsonPropertyName("platform")] + public string Platform { get; set; } = string.Empty; + + /// The directory the settings are being resolved for. This selects the repository-scoped document, so a host resolving settings for a directory other than its own process working directory must pass that directory here. + [JsonPropertyName("workingDirectory")] + public string WorkingDirectory { get; set; } = string.Empty; } -/// Whether the host running this runtime can run the command sandbox. The runtime checks `supported` once per process. A capability answer can change while the process runs, for example after the user installs a missing package. +/// The outcome of the one-time staff log-level migration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxHostSupport +internal sealed class UserSettingsMigrateStaffLogLevelOnceResult { - /// Sandbox policy features whose availability varies between hosts that can run the backend. Empty when `supported` is false, because no feature can run without a backend. Later runtimes can add entries; ignore an entry whose `name` you do not recognize. - [JsonPropertyName("capabilities")] - public IList Capabilities { get => field ??= []; set; } + /// When the migration was recorded as done, as an ISO-8601 timestamp. Absent only for `ineligible`, which records nothing. + [JsonPropertyName("completedAt")] + public string? CompletedAt { get; set; } - /// Human-readable reason the sandbox cannot run on this host. Present only when `supported` is false. - [JsonPropertyName("reason")] - public string? Reason { get; set; } + /// The settings document as it stands after the migration, keyed by setting name. Present only for `refreshed`, and only when the document could be re-read cleanly. + [JsonPropertyName("settings")] + public IDictionary? Settings { get; set; } - /// Whether a process-containment backend is usable on this host: Seatbelt on macOS, Bubblewrap on Linux, or ProcessContainer on Windows. - [JsonPropertyName("supported")] - public bool Supported { get; set; } + /// What the migration did. Only `refreshed` can have changed the persisted settings. + [JsonPropertyName("status")] + public StaffLogLevelMigrationStatus Status { get; set; } } -/// Status of the persistent certificate authority of the sandbox credential proxy. +/// Selects the configuration directory to run the one-time staff log-level migration against, and supplies the caller's record of whether it has already run. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxProxyCaStatus +internal sealed class UserSettingsMigrateStaffLogLevelOnceRequest { - /// Whether this process can add the certificate authority to OS trust without credentials from a different user. False where OS trust is unsupported, and on Windows when the process cannot elevate itself to write the machine trust store. When false, do not offer to set up the certificate authority. - [JsonPropertyName("canInstall")] - public bool CanInstall { get; set; } - - /// Human-readable reason for the state. On `installed` or `notInstalled`, present only when the certificate authority must be rotated, and then says why. - [JsonPropertyName("detail")] - public string? Detail { get; set; } + /// When the caller last recorded this migration, as an ISO-8601 timestamp. Supplying it lets the runtime answer `current` without re-running the evaluation. + [JsonPropertyName("cachedCompletedAt")] + public string? CachedCompletedAt { get; set; } - /// The state of the certificate authority. - [JsonPropertyName("state")] - public SandboxProxyCaState State { get; set; } + /// The configuration directory, home directory and environment to resolve the settings and global-state documents from. A host that scopes a session to its own Copilot home must pass that directory here, or the migration is evaluated against the server's own home instead. + [JsonPropertyName("context")] + public UserSettingsHostContext Context { get => field ??= new(); set; } } -/// Credential-injection capability flags applied while the sandbox is enabled. For the same capability independent of sandboxing, and matched to the credential's GitHub host, see `shell.credentials`; the two are additive. +/// The outcome of the one-time obsolete-settings cleanup. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxConfigAuth +internal sealed class UserSettingsMigrateObsoleteOnDiskResult { - /// Whether to authenticate sandboxed gh through the local masking proxy. The child receives a fake GH_TOKEN; its real value is substituted only at github.com, api.github.com and uploads.github.com (github.com because gh repo clone authenticates git through gh auth git-credential). The repository's GitHub account takes precedence over the Copilot login. Default: false (opt-in). - [JsonPropertyName("gh")] - public bool? Gh { get; set; } - - /// Whether to authenticate sandboxed HTTPS git through the local masking proxy. The child receives a fake `http.<url>.extraheader`; the real Authorization header is substituted only at its original HTTPS host, port, and repository path scope. github.com uses the Copilot token; other forges use credentials resolved from the user's own helper on the host. Default: false (opt-in). - [JsonPropertyName("git")] - public bool? Git { get; set; } + /// What the cleanup did. Only `changed` rewrote the document. The cleaned settings are not returned here: the document is written before this replies, so `user.settings.load` reads it authoritatively. + [JsonPropertyName("status")] + public UserSettingsMigrateObsoleteOnDiskStatus Status { get; set; } } -/// Destinations authorized to receive one masked environment credential. +/// Selects the configuration directory whose settings document to clean. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxMaskedEnvVar +internal sealed class UserSettingsMigrateObsoleteOnDiskRequest { - /// Nonempty list of HTTPS injection hostnames or *.example.com patterns. Bare * is not accepted. These grants never override the sandbox network policy. Values in plaintext HTTP requests, URLs, bodies, encoded credentials, and signed requests are not substituted. - [JsonPropertyName("injectHosts")] - public IList InjectHosts { get => field ??= []; set; } + /// The configuration directory holding the settings document to clean. A host that scopes a session to its own Copilot home passes that directory here; omit it to clean the document under the home the server resolved for itself. The home directory and environment are deliberately not caller-supplied: they decide only the settings path root and the two hook-parsing flags, and those describe the process doing the reading rather than the caller. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } } -/// Whole-value environment credential masking for sandboxed children. +/// A single user setting's effective value alongside its default, so consumers can render settings left at their default. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxCredentialsConfig +public sealed class UserSettingMetadata { - /// Environment variable names and their HTTPS injection destinations. Absent variables stay absent. No real values or sentinels are stored in this map. - [JsonPropertyName("envVars")] - public IDictionary EnvVars { get => field ??= new Dictionary(); set; } + /// The centrally-known default for this setting (null when no default is registered). + [JsonPropertyName("default")] + public JsonElement Default { get; set; } + + /// True when the user has not set an explicit value for this setting (i.e. it is left at its default). Reflects whether the user has overridden the key, not whether the effective value happens to equal the default — a key explicitly set to a value identical to the default still reports false. + [JsonPropertyName("isDefault")] + public bool IsDefault { get; set; } + + /// The effective value: the user's value if set, otherwise the default. + [JsonPropertyName("value")] + public JsonElement Value { get; set; } } -/// macOS seatbelt experimental options. +/// Per-key metadata for every known user setting in settings.json, including settings left at their default. Excludes repository- and enterprise-managed overrides. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxConfigUserPolicyExperimentalSeatbelt +public sealed class UserSettingsGetResult { - /// Whether the macOS seatbelt profile may access the keychain. - [JsonPropertyName("keychainAccess")] - public bool? KeychainAccess { get; set; } + /// Every known user setting keyed by setting name, each with its effective value, default, and whether it is at the default. + [JsonPropertyName("settings")] + public IDictionary Settings { get => field ??= new Dictionary(); set; } } -/// Platform-specific experimental policy fields. +/// On-disk locations of the settings files this runtime reads. A path is reported whether or not the file exists. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxConfigUserPolicyExperimental +internal sealed class UserSettingsGetPathsResult { - /// macOS seatbelt experimental options. - [JsonPropertyName("seatbelt")] - public SandboxConfigUserPolicyExperimentalSeatbelt? Seatbelt { get; set; } + /// The repository's local, untracked settings file, or null when no repository root was supplied. + [JsonPropertyName("repoLocalSettings")] + public string? RepoLocalSettings { get; set; } + + /// The repository's checked-in settings file, or null when no repository root was supplied. + [JsonPropertyName("repoSettings")] + public string? RepoSettings { get; set; } + + /// The user settings file: `settings.json` under the resolved Copilot home. This is the file `user.settings.get`, `user.settings.load`, and `user.settings.set` read and write. + [JsonPropertyName("userSettings")] + public string UserSettings { get; set; } = string.Empty; } -/// Filesystem rules to merge into the base policy. +/// Selects which settings file paths to resolve. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxConfigUserPolicyFilesystem +internal sealed class UserSettingsGetPathsRequest { - /// Whether to clear the policy when the session exits. - [JsonPropertyName("clearPolicyOnExit")] - public bool? ClearPolicyOnExit { get; set; } - - /// Paths explicitly denied. - [JsonPropertyName("deniedPaths")] - public IList? DeniedPaths { get; set; } - - /// Paths granted read-only access. - [JsonPropertyName("readonlyPaths")] - public IList? ReadonlyPaths { get; set; } + /// Absolute path of a repository root. Supply it to also resolve that repository's two settings file paths; omit it to resolve only the user path. + [JsonPropertyName("repoRoot")] + public string? RepoRoot { get; set; } +} - /// Paths granted read/write access. - [JsonPropertyName("readwritePaths")] - public IList? ReadwritePaths { get; set; } +/// Partial user settings to write to settings.json. Each top-level key is written individually, replacing the existing value; a key whose value is null is removed. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsSetRequest +{ + /// Partial user settings to write, as a free-form object keyed by setting name. + [JsonPropertyName("settings")] + public JsonElement Settings { get; set; } } -/// HTTP proxy configuration for sandboxed traffic. +/// Top-level user-setting keys grouped by who may govern them. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxConfigUserPolicyNetworkProxy +internal sealed class UserSettingsGovernanceKeysResult { - /// Optional password for proxy authentication, combined with the URL at spawn time. The persisted value may be a literal password, a `${secret:…}` reference resolved from the OS keychain, or a `${VAR}`/`$VAR` environment reference; it is resolved just before the sandboxed process routes through the proxy. The /sandbox dialog stores a real password in the OS keychain and persists only a `${secret:…}` placeholder (never plaintext in settings.json); the field is masked in the dialog and redacted by /settings show. - [JsonPropertyName("password")] - public string? Password { get; set; } + /// Top-level keys a repository may override through a Claude-compatible repository config. + [JsonPropertyName("claudeRepo")] + public IList ClaudeRepo { get => field ??= []; set; } - /// Proxy URL (e.g. http://proxy.example.com:8080). The port is optional and defaults to the scheme's standard port when omitted; an explicit port must be between 1 and 65535. Credentials must not be embedded here — a `user:pass@` authority is rejected; put them in the separate `username`/`password` fields. A credential-free http:// loopback proxy URL is routed through the localhost proxy automatically; loopback covers localhost and any *.localhost subdomain, the whole 127.0.0.0/8 range, ::1, and IPv4-mapped loopback (::ffff:127.0.0.1). An https:// URL, or one with a username/password set, is used as-is. - [JsonPropertyName("url")] - public string Url { get; set; } = string.Empty; + /// Top-level keys an enterprise policy may fix through managed settings. + [JsonPropertyName("managed")] + public IList Managed { get => field ??= []; set; } - /// Optional username for proxy authentication. Combined with the URL (and `password`) into `user:pass@host` when the sandboxed process routes through the proxy. - [JsonPropertyName("username")] - public string? Username { get; set; } + /// Top-level keys a repository may override through `.github/copilot/settings.json` or `.github/copilot/settings.local.json`. + [JsonPropertyName("repo")] + public IList Repo { get => field ??= []; set; } } -/// Network rules to merge into the base policy. +/// Outcome of an atomic user or repository settings edit. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxConfigUserPolicyNetwork +internal sealed class SettingsEditResult { - /// Hosts allowed through the built-in sandbox proxy. A non-empty list denies unmatched hosts; an absent or empty list allows all hosts not blocked. Supports exact hostnames, IP addresses, and *.example.com for strict subdomains. Host rules do not override the outbound or local-network toggles. - [JsonPropertyName("allowedHosts")] - public IList? AllowedHosts { get; set; } + /// Changed, unchanged or invalid existing file. Rejected input, validation failures and I/O errors remain RPC errors. + [JsonPropertyName("status")] + public SettingsEditStatus Status { get; set; } +} - /// Whether traffic to local/loopback addresses is allowed. - [JsonPropertyName("allowLocalNetwork")] - public bool? AllowLocalNetwork { get; set; } +/// One atomic edit of a canonical setting in settings.json. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsEditRequest +{ + /// Nonempty canonical path segments of the setting to edit, starting with its top-level key. + [JsonPropertyName("canonicalPath")] + public IList CanonicalPath { get => field ??= []; set; } - /// Whether outbound network traffic is allowed at all. - [JsonPropertyName("allowOutbound")] - public bool? AllowOutbound { get; set; } + /// Configuration directory to edit. Omitted or empty resolves the server's own home, as in `user.settings.loadForConfigDir`. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } - /// Hosts denied by the built-in sandbox proxy. Deny rules take precedence over allowedHosts. A domain also denies all its subdomains. IP addresses match exactly; *.example.com matches strict subdomains, and * denies every host. - [JsonPropertyName("blockedHosts")] - public IList? BlockedHosts { get; set; } + /// Set a scalar, add or remove a string list item, or remove the setting. The handler rejects a missing or incompatible value. + [JsonPropertyName("operation")] + public SettingsEditOperation Operation { get; set; } - /// HTTP(S) proxy for sandboxed traffic. This is the built-in local proxy's upstream: every sandboxed command reaches it through a loopback listener, so credentials stay in the runtime and never reach the child. On Windows the sandbox also needs local network access, because it reaches that listener over host loopback. Configure credentials in the separate username/password fields. The transient local listener URL is never persisted. - [JsonPropertyName("proxy")] - public SandboxConfigUserPolicyNetworkProxy? Proxy { get; set; } + /// Required boolean, string or number for set, required string for add-item and remove-item, and forbidden for remove. The runtime rejects all other JSON values. + [JsonPropertyName("value")] + public JsonElement? Value { get; set; } } -/// macOS seatbelt-specific options. +/// Settings object with canonical key names. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxConfigUserPolicySeatbelt +internal sealed class UserSettingsNormalizeResult { - /// Whether the macOS seatbelt profile may access the keychain. - [JsonPropertyName("keychainAccess")] - public bool? KeychainAccess { get; set; } + /// The same settings with every legacy or snake_case key renamed to its canonical spelling. + [JsonPropertyName("settings")] + public JsonElement Settings { get; set; } } -/// User-managed sandbox policy fragment merged into the auto-discovered base policy. +/// Settings object whose key names should be canonicalized. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxConfigUserPolicy +internal sealed class UserSettingsNormalizeRequest { - /// Deprecated legacy location for `seatbelt`; read only when the top-level `seatbelt` is absent. - [JsonPropertyName("experimental")] - public SandboxConfigUserPolicyExperimental? Experimental { get; set; } + /// Free-form settings object, possibly using legacy or snake_case key names. + [JsonPropertyName("settings")] + public JsonElement Settings { get; set; } +} - /// Filesystem rules to merge into the base policy. - [JsonPropertyName("filesystem")] - public SandboxConfigUserPolicyFilesystem? Filesystem { get; set; } +/// The settings layer a problem was found in. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class UserSettingsProblemLocation +{ + /// Absolute path of the file backing this layer. + [JsonPropertyName("filePath")] + public string FilePath { get; set; } = string.Empty; - /// Network rules to merge into the base policy. - [JsonPropertyName("network")] - public SandboxConfigUserPolicyNetwork? Network { get; set; } + /// Which layer this is: `user`, `repo`, or `local`. + [JsonPropertyName("kind")] + public string Kind { get; set; } = string.Empty; - /// macOS seatbelt options to merge into the base policy. - [JsonPropertyName("seatbelt")] - public SandboxConfigUserPolicySeatbelt? Seatbelt { get; set; } + /// The caller-supplied display label for the layer. + [JsonPropertyName("label")] + public string Label { get; set; } = string.Empty; } -/// Resolved sandbox configuration. +/// One setting that will not take effect, and why. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxConfig +public sealed class UserSettingsProblem { - /// Whether to auto-add the current working directory to readwritePaths. Default: true. - [JsonPropertyName("addCurrentWorkingDirectory")] - public bool? AddCurrentWorkingDirectory { get; set; } + /// Coarse grouping for the problem, for a caller that presents problems in sections. + [JsonPropertyName("category")] + public string Category { get; set; } = string.Empty; - /// Whether the agent may request that an individual command run outside the sandbox, which the host then approves or denies through the usual permission flow. A host capability flag rather than part of the policy: it is stripped from the effective spawn policy and only has an effect while `enabled` is true. Fail-closed, unlike the opt-out flags on this object: omitting it offers no bypass. Default: false (opt-in). - [JsonPropertyName("allowBypass")] - public bool? AllowBypass { get; set; } + /// Why the setting will not take effect. Never contains the setting's value, which may be a token or another secret. + [JsonPropertyName("explanation")] + public string Explanation { get; set; } = string.Empty; - /// Whether to auto-grant read access to tool directories discovered on PATH and in toolchain environment variables (GOROOT, JAVA_HOME, VIRTUAL_ENV, and similar), and to common developer-tool caches, config, and toolchains. Writable grants cover scratch caches, the Unix GitHub CLI cache, and Cargo's registry, git store, and lock/tracker files. A relocated CARGO_HOME gets the same narrow split: registry and git are read-write; bin is read-only; the home root, config.toml, and credentials.toml stay ungranted. Set to false to disable every grant listed above; user-installed toolchains and caches then need explicit userPolicy.filesystem readonlyPaths and readwritePaths entries. The working directory (see addCurrentWorkingDirectory), temporary storage, session log paths, and system locations follow their own rules and stay granted. Default: true (enabled by default; set to false to opt out). - [JsonPropertyName("allowDevToolAccess")] - public bool? AllowDevToolAccess { get; set; } + /// Stable identifier for this problem within the reported set, so a caller can track a selection across refreshes. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Credential-injection capability flags. - [JsonPropertyName("auth")] - public SandboxConfigAuth? Auth { get; set; } + /// What is wrong in machine-readable form, for a caller that wants to branch rather than display. + [JsonPropertyName("kind")] + public string Kind { get; set; } = string.Empty; - /// Opt-in whole-value environment masking for sandboxed shell, MCP, and LSP children. Configured names get random sentinels; the local proxy substitutes them only in HTTPS request headers at their injection hosts. Approved bypasses skip masking and the sandbox proxy, so bypassed shells may receive the real environment values. Disabled or explicitly opted-out routes are not protected. No credential values are stored in this configuration. - [JsonPropertyName("credentials")] - public SandboxCredentialsConfig? Credentials { get; set; } + /// The offending key as written in the file, when the problem is attributable to a single key. Absent when the whole file is at fault. + [JsonPropertyName("rawKey")] + public string? RawKey { get; set; } - /// Whether sandboxing is enabled for the session. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// The settings layer the problem was found in. + [JsonPropertyName("source")] + public UserSettingsProblemLocation Source { get => field ??= new(); set; } +} - /// The `sandboxLspServers` counterpart of `managedMcpRoutingLocked`. - [JsonInclude] - [JsonPropertyName("managedLspRoutingLocked")] - internal bool? ManagedLspRoutingLocked { get; set; } +/// The settings that will not take effect across the given layers. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsProblemsResult +{ + /// Each setting that will not take effect, and why. Empty when every layer is healthy. + [JsonPropertyName("problems")] + public IList? Problems { get; set; } +} - /// Set by the runtime when a managed policy forced `sandboxMcpServers` on and took the local opt-out away. Provenance rather than policy: it lets a sandbox startup failure point at the administrator instead of a setting the next managed merge would override, and it is ignored when comparing two configs for change. Only the managed merge may set it; a caller-supplied value is stripped. - [JsonInclude] - [JsonPropertyName("managedMcpRoutingLocked")] - internal bool? ManagedMcpRoutingLocked { get; set; } +/// One already-loaded settings layer to diagnose. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class UserSettingsProblemSource +{ + /// The layer's settings exactly as loaded, unnormalized. Empty when the file is missing or failed to parse. + [JsonPropertyName("config")] + public IDictionary? Config { get; set; } - /// Whether language servers the session launches are confined by the sandbox. Only an explicit `false` opts out. Ignored while `enabled` is false. Default: true (enabled by default; set to false to opt out). - [JsonPropertyName("sandboxLspServers")] - public bool? SandboxLspServers { get; set; } + /// Absolute path of the file backing this layer. + [JsonPropertyName("filePath")] + public string FilePath { get; set; } = string.Empty; - /// Whether MCP servers the session launches are confined by the sandbox. Only an explicit `false` opts out; doing so also lets remote-MCP egress leave the sandbox, so the flag and `enabled` are always read together. Ignored while `enabled` is false. Default: true (enabled by default; set to false to opt out). - [JsonPropertyName("sandboxMcpServers")] - public bool? SandboxMcpServers { get; set; } + /// True when the file itself failed to parse, so its keys could not be read at all. + [JsonPropertyName("invalid")] + public bool? Invalid { get; set; } - /// User-managed sandbox policy fragment merged into the auto-discovered base policy. - [JsonPropertyName("userPolicy")] - public SandboxConfigUserPolicy? UserPolicy { get; set; } + /// Which layer this is: `user`, `repo`, or `local`. + [JsonPropertyName("kind")] + public string Kind { get; set; } = string.Empty; + + /// Caller-chosen display label for the layer, echoed back on each problem so a caller can group by layer without re-deriving its own naming. + [JsonPropertyName("label")] + public string Label { get; set; } = string.Empty; } -/// Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. +/// The settings layers to diagnose. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SandboxProxyCaRequest +internal sealed class UserSettingsProblemsRequest { - /// The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. - [JsonPropertyName("sandboxConfig")] - public SandboxConfig? SandboxConfig { get; set; } + /// Layers to diagnose, in the precedence order the caller applies them. + [JsonPropertyName("sources")] + public IList? Sources { get; set; } } -/// Result of creating the persistent certificate authority of the sandbox credential proxy. +/// One problem found while validating a setting value. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxProxyCaCreateResult +public sealed class UserSettingsValidationIssue { - /// Absolute path of the public certificate of the certificate authority, in PEM format. - [JsonPropertyName("certificatePath")] - public string CertificatePath { get; set; } = string.Empty; + /// Human-readable description of the problem. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; + + /// Where in the settings tree the problem sits, as object keys and array indices. The first element is the top-level key; a whole-value problem is reported as that single key. + [JsonPropertyName("path")] + public IList Path { get => field ??= []; set; } } -/// Built-in tool metadata with identifier, optional namespaced name, description, input-parameter schema, and usage instructions. +/// Outcome of validating and writing one top-level setting subtree. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class Tool +internal sealed class UserSettingsApplyTopKeyResult { - /// Description of what the tool does. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; + /// Why the write failed, present only when `status` is `write-error`. + [JsonPropertyName("error")] + public string? Error { get; set; } - /// Optional instructions for how to use this tool effectively. - [JsonPropertyName("instructions")] - public string? Instructions { get; set; } + /// Problems found, present only when `status` is `validation-error`. + [JsonPropertyName("issues")] + public IList? Issues { get; set; } - /// Tool identifier (e.g., "bash", "grep", "str_replace_editor"). - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// `ok` when the value was written, `validation-error` when it was rejected before any write, `write-error` when validation passed but the write failed. + [JsonPropertyName("status")] + public string Status { get; set; } = string.Empty; +} - /// Optional namespaced name for declarative filtering (e.g., "playwright/navigate" for MCP tools). - [JsonPropertyName("namespacedName")] - public string? NamespacedName { get; set; } +/// A single top-level setting subtree to validate and write. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UserSettingsApplyTopKeyRequest +{ + /// Canonical path of the setting the caller is editing. Currently informational only. + [JsonPropertyName("canonicalPath")] + public IList CanonicalPath { get => field ??= []; set; } - /// JSON Schema for the tool's input parameters. - [JsonPropertyName("parameters")] - public IDictionary? Parameters { get; set; } + /// Records that the user chose an update channel explicitly, so the one-time staff channel migration stops reapplying. Honored only for the `autoUpdatesChannel` key. + [JsonPropertyName("completeStaffUpdateChannelMigration")] + public bool? CompleteStaffUpdateChannelMigration { get; set; } - /// Telemetry-safety policy for the tool name and input names, not input values. Treat omitted metadata as unsafe. - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] - [JsonPropertyName("safeForTelemetry")] - public JsonElement? SafeForTelemetry { get; set; } + /// True to remove the top-level key instead of writing it. + [JsonPropertyName("delete")] + public bool? Delete { get; set; } + + /// Top-level setting name to write. + [JsonPropertyName("topKey")] + public string TopKey { get; set; } = string.Empty; + + /// Value to write for the whole top-level key. Omitted when `delete` is true. Explicit null is preserved and validated as null. + [JsonPropertyName("value")] + public JsonElement? Value { get; set; } } -/// Built-in tools available for the requested model, with their parameters and instructions. +/// The whole content to store in the user settings file. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ToolList +internal sealed class UserSettingsWriteAllRequest { - /// List of available built-in tools with metadata. - [JsonPropertyName("tools")] - public IList Tools { get => field ??= []; set; } + /// The settings object to store. It replaces the file's entire content, so a key absent here is removed. + [JsonPropertyName("settings")] + public JsonElement Settings { get; set; } } -/// Optional model identifier whose tool overrides should be applied to the listing. +/// The stored value of the user setting after the merge. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ToolsListRequest +internal sealed class UserSettingsUpdateResult { - /// Optional model ID — when provided, the returned tool list reflects model-specific overrides. - [JsonPropertyName("model")] - public string? Model { get; set; } + /// The key's stored value after the write: the merged object when both the stored value and the supplied value are objects, otherwise the supplied value. + [JsonPropertyName("value")] + public JsonElement Value { get; set; } } -/// Quota usage snapshot for a Copilot quota type, including entitlement, used requests, overage, reset date, and remaining percentage. +/// Names the user setting to merge into, and the partial object to merge. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AccountQuotaSnapshot +internal sealed class UserSettingsUpdateRequest { - /// Number of requests included in the entitlement, or -1 for unlimited entitlements. - [JsonPropertyName("entitlementRequests")] - public long EntitlementRequests { get; set; } - - /// Whether the user has an unlimited usage entitlement. - [JsonPropertyName("isUnlimitedEntitlement")] - public bool IsUnlimitedEntitlement { get; set; } - - /// Number of additional usage requests made this period. - [JsonPropertyName("overage")] - public double Overage { get; set; } - - /// Whether additional usage is allowed when quota is exhausted. - [JsonPropertyName("overageAllowedWithExhaustedQuota")] - public bool OverageAllowedWithExhaustedQuota { get; set; } - - /// Percentage of entitlement remaining. - [JsonPropertyName("remainingPercentage")] - public double RemainingPercentage { get; set; } + /// Copilot configuration directory to write the settings document in, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to use the directory the server resolved for itself. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } - /// Date when the quota resets (ISO 8601 string). - [JsonPropertyName("resetDate")] - public DateTimeOffset? ResetDate { get; set; } + /// Top-level user-setting key to merge into, such as `extensions`. + [JsonPropertyName("key")] + public string Key { get; set; } = string.Empty; - /// Whether usage is still permitted after quota exhaustion. - [JsonPropertyName("usageAllowedWithExhaustedQuota")] - public bool UsageAllowedWithExhaustedQuota { get; set; } + /// Single-component name for the settings document at `<configDir>/settings/<subDir>.json`; path separators, `.` and `..` are rejected. Omit it, or pass an empty string, to use the main settings document. + [JsonPropertyName("subDir")] + public string? SubDir { get; set; } - /// Number of requests used so far this period. - [JsonPropertyName("usedRequests")] - public long UsedRequests { get; set; } + /// Value to store for `key`. When both the stored value and this value are objects, their fields are shallow-merged and fields this object does not name are preserved. Otherwise this value replaces the stored value. + [JsonPropertyName("value")] + public JsonElement Value { get; set; } } -/// Quota usage snapshots for the resolved user, keyed by quota type. +/// Contents of settings.json as stored, for a caller about to rewrite it. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AccountGetQuotaResult +internal sealed class UserSettingsLoadForEditResult { - /// Quota snapshots keyed by type (e.g., chat, completions, premium_interactions). - [JsonPropertyName("quotaSnapshots")] - public IDictionary QuotaSnapshots { get => field ??= new Dictionary(); set; } + /// Parsed contents, present only when `status` is `ok`. + [JsonPropertyName("settings")] + public JsonElement? Settings { get; set; } + + /// `ok` when the file parsed, `missing` when there is no file yet, `invalid` when the file exists but will not parse. + [JsonPropertyName("status")] + public string Status { get; set; } = string.Empty; } -/// RPC data type for AccountGetQuota operations. +/// Outcome of validating one top-level setting subtree. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AccountGetQuotaRequest +internal sealed class UserSettingsValidateResult { - /// GitHub token accepted for compatibility with existing SDK clients. When provided, resolves this token instead of using the current account. - [JsonPropertyName("gitHubToken")] - public string? GitHubToken { get; set; } + /// Problems found, empty when `ok` is true. + [JsonPropertyName("issues")] + public IList? Issues { get; set; } - /// Opaque account identifier returned by `account.getAllUsers`. When omitted, the current account is used. - [JsonPropertyName("selectionId")] - public string? SelectionId { get; set; } + /// True when the subtree is valid. + [JsonPropertyName("ok")] + public bool Ok { get; set; } } -/// Authentication credentials accepted only at native protocol ingress. Runtime outputs use credential-free `AuthIdentity` metadata. -/// Polymorphic base type discriminated by type. +/// A single top-level setting subtree to validate. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "type", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(AuthInfoHmac), "hmac")] -[JsonDerivedType(typeof(AuthInfoEnv), "env")] -[JsonDerivedType(typeof(AuthInfoToken), "token")] -[JsonDerivedType(typeof(AuthInfoTokenProvider), "token-provider")] -[JsonDerivedType(typeof(AuthInfoCopilotApiToken), "copilot-api-token")] -[JsonDerivedType(typeof(AuthInfoUser), "user")] -[JsonDerivedType(typeof(AuthInfoAccount), "account")] -[JsonDerivedType(typeof(AuthInfoGhCli), "gh-cli")] -[JsonDerivedType(typeof(AuthInfoApiKey), "api-key")] -public partial class AuthInfo +internal sealed class UserSettingsValidateRequest { - /// The type discriminator. - [JsonPropertyName("type")] - public virtual string Type { get; set; } = string.Empty; -} + /// True to validate a removal of this key. The current settings file is not read. + [JsonPropertyName("delete")] + public bool? Delete { get; set; } + + /// Top-level setting name to validate. + [JsonPropertyName("topKey")] + public string TopKey { get; set; } = string.Empty; + /// Value to validate. Omitted when `delete` is true. + [JsonPropertyName("value")] + public JsonElement? Value { get; set; } +} -/// Endpoint URLs from the raw Copilot `/copilot_internal/v2/token` user-response passthrough. +/// One atomic edit of an allowed top-level repository setting. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CopilotUserResponseEndpoints +internal sealed class RepoSettingsEditRequest { - /// Copilot API endpoint URL. - [JsonPropertyName("api")] - public string? Api { get; set; } + /// One canonical top-level repository setting that the allowlist permits. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("key")] + public string Key { get; set; } = string.Empty; - /// Experimental-service endpoint URL. - [JsonPropertyName("exp")] - public string? Exp { get; set; } + /// Set a scalar, add or remove a string list item, or remove the setting. The handler rejects a missing or incompatible value. + [JsonPropertyName("operation")] + public SettingsEditOperation Operation { get; set; } - /// Origin-tracker endpoint URL. - [JsonPropertyName("origin-tracker")] - public string? OriginTracker { get; set; } + /// Absolute path of the repository root. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("repoRoot")] + public string RepoRoot { get; set; } = string.Empty; - /// Copilot proxy endpoint URL. - [JsonPropertyName("proxy")] - public string? Proxy { get; set; } + /// Shared or local repository settings file. + [JsonPropertyName("scope")] + public RepoSettingsEditScope Scope { get; set; } - /// Copilot telemetry endpoint URL. - [JsonPropertyName("telemetry")] - public string? Telemetry { get; set; } + /// Required boolean, string or number for set, required string for add-item and remove-item, and forbidden for remove. The runtime rejects all other JSON values. + [JsonPropertyName("value")] + public JsonElement? Value { get; set; } } -/// RPC data type for CopilotUserResponseEnterpriseListItem operations. -public sealed class CopilotUserResponseEnterpriseListItem +/// Parsed repository settings without normalization or layering. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class RepoSettingsReadRawResult { - /// JavaScript-safe numeric database ID of the enterprise. - [JsonPropertyName("id")] - public long? Id { get; set; } + /// Stored JSON values after the existing JSONC parser and prototype-safety checks. Empty when the file is missing, blank, or invalid. + [JsonPropertyName("config")] + public JsonElement Config { get; set; } + + /// True when the file exists but did not parse, so `config` is empty for that reason rather than because nothing is set. + [JsonPropertyName("invalid")] + public bool Invalid { get; set; } } -/// RPC data type for CopilotUserResponseOrganizationListItem operations. -public sealed class CopilotUserResponseOrganizationListItem +/// Which repository settings file to read. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class RepoSettingsReadRawRequest { - /// Numeric database ID of the organization. - [JsonPropertyName("id")] - public double? Id { get; set; } - - /// GitHub login of the organization. - [JsonPropertyName("login")] - public string? Login { get; set; } + /// Absolute path of the repository root. + [JsonPropertyName("repoRoot")] + public string RepoRoot { get; set; } = string.Empty; - /// Display name of the organization. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + [JsonPropertyName("scope")] + public string Scope { get; set; } = string.Empty; } -/// Chat quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. +/// One key to write or remove in a repository settings file. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CopilotUserResponseQuotaSnapshotsChat +internal sealed class RepoSettingsWriteKeyRequest { - /// Number of requests/units included in the entitlement for this period; `-1` denotes an unlimited entitlement. - [JsonPropertyName("entitlement")] - public double? Entitlement { get; set; } - - /// Whether the user currently has quota available; when `false` and not unlimited, further requests are blocked until the quota resets. - [JsonPropertyName("has_quota")] - public bool? HasQuota { get; set; } - - /// Count of additional pay-per-request usage consumed this period beyond the entitlement. - [JsonPropertyName("overage_count")] - public double? OverageCount { get; set; } - - /// Whether usage may continue at pay-per-request rates once the entitlement is exhausted. - [JsonPropertyName("overage_permitted")] - public bool? OveragePermitted { get; set; } - - /// Percentage of the entitlement remaining at the snapshot timestamp. - [JsonPropertyName("percent_remaining")] - public double? PercentRemaining { get; set; } + /// True to remove the key instead of writing it. + [JsonPropertyName("delete")] + public bool? Delete { get; set; } - /// Identifier of the quota bucket this snapshot describes. - [JsonPropertyName("quota_id")] - public string? QuotaId { get; set; } + /// Canonical top-level key permitted by the repository settings allowlist. + [JsonPropertyName("key")] + public string Key { get; set; } = string.Empty; - /// Amount of quota remaining at the snapshot timestamp. - [JsonPropertyName("quota_remaining")] - public double? QuotaRemaining { get; set; } + /// Absolute path of the repository root. + [JsonPropertyName("repoRoot")] + public string RepoRoot { get; set; } = string.Empty; - /// Unix epoch time, in seconds, when this quota next resets. - [JsonPropertyName("quota_reset_at")] - public double? QuotaResetAt { get; set; } + /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + [JsonPropertyName("scope")] + public string Scope { get; set; } = string.Empty; - /// Remaining entitlement/quota amount at the snapshot timestamp. - [JsonPropertyName("remaining")] - public double? Remaining { get; set; } + /// Value to validate and write. Required unless delete is true; a null value is validated, not treated as deletion. + [JsonPropertyName("value")] + public JsonElement? Value { get; set; } +} - /// UTC timestamp when this snapshot was captured. - [JsonPropertyName("timestamp_utc")] - public string? TimestampUtc { get; set; } +/// The complete set of repository-overridable settings to store. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class RepoSettingsWriteAllRequest +{ + /// Absolute path of the repository root. + [JsonPropertyName("repoRoot")] + public string RepoRoot { get; set; } = string.Empty; - /// Whether this category uses usage-based (token/AI-credit) billing rather than a fixed premium-request count. - [JsonPropertyName("token_based_billing")] - public bool? TokenBasedBilling { get; set; } + /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + [JsonPropertyName("scope")] + public string Scope { get; set; } = string.Empty; - /// Whether the entitlement for this category is unlimited. - [JsonPropertyName("unlimited")] - public bool? Unlimited { get; set; } + /// Object of allowed settings to store. Missing allowlisted keys are removed. Other input keys are ignored, while unknown stored keys are preserved. + [JsonPropertyName("settings")] + public JsonElement Settings { get; set; } } -/// Completions quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. +/// Caller population and startup inputs to resolve named online-experiment gates for. Carries no account: the runtime resolves the assignment for the authentication it already holds. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CopilotUserResponseQuotaSnapshotsCompletions +internal sealed class FeatureFlagsResolveStartupGatesRequest { - /// Number of requests/units included in the entitlement for this period; `-1` denotes an unlimited entitlement. - [JsonPropertyName("entitlement")] - public double? Entitlement { get; set; } - - /// Whether the user currently has quota available; when `false` and not unlimited, further requests are blocked until the quota resets. - [JsonPropertyName("has_quota")] - public bool? HasQuota { get; set; } + /// User settings document whose `featureFlags` block is layered on top of the resolved set. + [JsonPropertyName("config")] + public JsonElement? Config { get; set; } - /// Count of additional pay-per-request usage consumed this period beyond the entitlement. - [JsonPropertyName("overage_count")] - public double? OverageCount { get; set; } + /// Environment to read flag overrides from. Defaults to this runtime process's own environment. + [JsonPropertyName("environment")] + public IDictionary? Environment { get; set; } - /// Whether usage may continue at pay-per-request rates once the entitlement is exhausted. - [JsonPropertyName("overage_permitted")] - public bool? OveragePermitted { get; set; } + /// When this installation first launched, in milliseconds since the Unix epoch. Experiments that segment on installation age read it. Omit when the first launch was never recorded. + [JsonPropertyName("firstLaunchAtMillis")] + public double? FirstLaunchAtMillis { get; set; } - /// Percentage of the entitlement remaining at the snapshot timestamp. - [JsonPropertyName("percent_remaining")] - public double? PercentRemaining { get; set; } + /// The feature flags to resolve. A name this runtime does not declare is reported as an error rather than as a disabled flag. + [JsonPropertyName("flags")] + public IList Flags { get => field ??= []; set; } - /// Identifier of the quota bucket this snapshot describes. - [JsonPropertyName("quota_id")] - public string? QuotaId { get; set; } + /// Whether the caller is in an experimental population. + [JsonPropertyName("isExperimental")] + public bool IsExperimental { get; set; } - /// Amount of quota remaining at the snapshot timestamp. - [JsonPropertyName("quota_remaining")] - public double? QuotaRemaining { get; set; } + /// Whether the caller is GitHub or Microsoft staff. + [JsonPropertyName("isStaff")] + public bool IsStaff { get; set; } - /// Unix epoch time, in seconds, when this quota next resets. - [JsonPropertyName("quota_reset_at")] - public double? QuotaResetAt { get; set; } + /// GitHub-staff membership. Omit when it was never recorded: a legacy staff account then counts as both staff populations and keeps every staff feature. + [JsonPropertyName("isStaffGithub")] + public bool? IsStaffGitHub { get; set; } - /// Remaining entitlement/quota amount at the snapshot timestamp. - [JsonPropertyName("remaining")] - public double? Remaining { get; set; } + /// Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. + [JsonPropertyName("isStaffMicrosoft")] + public bool? IsStaffMicrosoft { get; set; } - /// UTC timestamp when this snapshot was captured. - [JsonPropertyName("timestamp_utc")] - public string? TimestampUtc { get; set; } + /// Whether the caller belongs to a team plan. + [JsonPropertyName("isTeam")] + public bool IsTeam { get; set; } - /// Whether this category uses usage-based (token/AI-credit) billing rather than a fixed premium-request count. - [JsonPropertyName("token_based_billing")] - public bool? TokenBasedBilling { get; set; } + /// Whether the runtime may refresh the cached assignment over the network without an active session. The refresh never blocks this call: the answer comes from the cache either way, so a refresh only affects a later launch. + [JsonPropertyName("refreshWithoutSession")] + public bool RefreshWithoutSession { get; set; } - /// Whether the entitlement for this category is unlimited. - [JsonPropertyName("unlimited")] - public bool? Unlimited { get; set; } + /// Whether streamer mode is on, which withholds the populations an experiment would otherwise segment on. + [JsonPropertyName("streamerMode")] + public bool StreamerMode { get; set; } } -/// Premium-interactions quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. +/// The declared shape of one feature flag, independent of any caller population. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CopilotUserResponseQuotaSnapshotsPremiumInteractions +internal sealed class FeatureFlagMetadata { - /// Number of requests/units included in the entitlement for this period; `-1` denotes an unlimited entitlement. - [JsonPropertyName("entitlement")] - public double? Entitlement { get; set; } + /// The population the flag is declared for before any environment or user-settings override is applied. + [JsonPropertyName("availability")] + public FeatureFlagAvailability Availability { get; set; } - /// Whether the user currently has quota available; when `false` and not unlimited, further requests are blocked until the quota resets. - [JsonPropertyName("has_quota")] - public bool? HasQuota { get; set; } + /// Whether the flag participates in the CAPI sanity suite. + [JsonPropertyName("capiSanity")] + public bool CapiSanity { get; set; } - /// Count of additional pay-per-request usage consumed this period beyond the entitlement. - [JsonPropertyName("overage_count")] - public double? OverageCount { get; set; } + /// Text shown to a user choosing whether to turn the flag on in experimental mode. Absent when the flag is not user-facing. + [JsonPropertyName("experimentalDescription")] + public string? ExperimentalDescription { get; set; } - /// Whether usage may continue at pay-per-request rates once the entitlement is exhausted. - [JsonPropertyName("overage_permitted")] - public bool? OveragePermitted { get; set; } + /// The online-experiment (ExP) flag this maps to, when the flag is assigned by an experiment rather than declared statically. + [JsonPropertyName("expFlag")] + public string? ExpFlag { get; set; } - /// Percentage of the entitlement remaining at the snapshot timestamp. - [JsonPropertyName("percent_remaining")] - public double? PercentRemaining { get; set; } + /// Environment variable that overrides this flag's experiment assignment locally in the experiment service, not in `featureFlags.resolve`. Present exactly when `expFlag` is, and derived from it, so a caller reads a local override without reproducing the naming rule. + [JsonPropertyName("expFlagEnvVar")] + public string? ExpFlagEnvVar { get; set; } - /// Identifier of the quota bucket this snapshot describes. - [JsonPropertyName("quota_id")] - public string? QuotaId { get; set; } + /// The flag's name, matching the key it is listed under. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; +} - /// Amount of quota remaining at the snapshot timestamp. - [JsonPropertyName("quota_remaining")] - public double? QuotaRemaining { get; set; } +/// Every feature flag this runtime declares, with the shape each one was declared with. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class FeatureFlagsMetadataResult +{ + /// Declared feature flags keyed by flag name. + [JsonPropertyName("flags")] + public IDictionary Flags { get => field ??= new Dictionary(); set; } +} - /// Unix epoch time, in seconds, when this quota next resets. - [JsonPropertyName("quota_reset_at")] - public double? QuotaResetAt { get; set; } +/// Caller population and overrides for static feature-flag resolution, independent of experiment assignments and active runtime state. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class FeatureFlagsResolveRequest +{ + /// Resolve against this already-computed flag set rather than each flag's declared availability. Keyed by flag name. + [JsonPropertyName("baseFlags")] + public IDictionary? BaseFlags { get; set; } - /// Remaining entitlement/quota amount at the snapshot timestamp. - [JsonPropertyName("remaining")] - public double? Remaining { get; set; } + /// User settings to apply, including `enabledFeatureFlags`, legacy `feature_flags.enabled`, and supported convenience settings. + [JsonPropertyName("config")] + public JsonElement? Config { get; set; } - /// UTC timestamp when this snapshot was captured. - [JsonPropertyName("timestamp_utc")] - public string? TimestampUtc { get; set; } + /// Environment for direct feature-flag overrides and `COPILOT_CLI_ENABLED_FEATURE_FLAGS`. Does not apply `COPILOT_EXP_*` experiment assignments. Defaults to this runtime process's own environment. + [JsonPropertyName("environment")] + public IDictionary? Environment { get; set; } - /// Whether this category uses usage-based (token/AI-credit) billing rather than a fixed premium-request count. - [JsonPropertyName("token_based_billing")] - public bool? TokenBasedBilling { get; set; } + /// Flags forced to a value after every other layer, keyed by flag name. + [JsonPropertyName("flagOverrides")] + public IDictionary? FlagOverrides { get; set; } - /// Whether the entitlement for this category is unlimited. - [JsonPropertyName("unlimited")] - public bool? Unlimited { get; set; } -} + /// Whether the caller is in an experimental population. + [JsonPropertyName("isExperimental")] + public bool IsExperimental { get; set; } -/// Quota snapshot map from the raw Copilot user-response passthrough, with chat, completions, premium-interactions, and other entries. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CopilotUserResponseQuotaSnapshots -{ - /// Chat quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. - [JsonPropertyName("chat")] - public CopilotUserResponseQuotaSnapshotsChat? Chat { get; set; } + /// Whether the caller is GitHub or Microsoft staff. + [JsonPropertyName("isStaff")] + public bool IsStaff { get; set; } - /// Completions quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. - [JsonPropertyName("completions")] - public CopilotUserResponseQuotaSnapshotsCompletions? Completions { get; set; } + /// GitHub-staff membership. Omit when it was never recorded: a legacy staff account then counts as both staff populations and keeps every staff feature. + [JsonPropertyName("isStaffGithub")] + public bool? IsStaffGitHub { get; set; } - /// Premium-interactions quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. - [JsonPropertyName("premium_interactions")] - public CopilotUserResponseQuotaSnapshotsPremiumInteractions? PremiumInteractions { get; set; } + /// Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. + [JsonPropertyName("isStaffMicrosoft")] + public bool? IsStaffMicrosoft { get; set; } + + /// Whether the caller belongs to the team population used by feature availability. + [JsonPropertyName("isTeam")] + public bool IsTeam { get; set; } } -/// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. +/// The policy questions a host asks before granting elevated permissions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CopilotUserResponse +internal sealed class PermissionsEvaluateManagedPolicyResult { - /// Copilot access SKU identifier (e.g. `free_limited_copilot`, `copilot_for_business_seat_quota`) used to gate model and feature access. - [JsonPropertyName("access_type_sku")] - public string? AccessTypeSku { get; set; } + /// True when managed policy forbids bypass-permissions mode, so allow-all style flags must not take effect. + [JsonPropertyName("bypassPermissionsDisabled")] + public bool BypassPermissionsDisabled { get; set; } - /// Opaque analytics tracking identifier for the user, forwarded from the Copilot API. - [JsonPropertyName("analytics_tracking_id")] - public string? AnalyticsTrackingId { get; set; } + /// True when the managed layer supplies permission rules that the session must enforce. + [JsonPropertyName("permissionRulesActive")] + public bool PermissionRulesActive { get; set; } - /// Date the Copilot seat was assigned to the user, if applicable. - [JsonPropertyName("assigned_date")] - public string? AssignedDate { get; set; } + /// True when a managed policy exists but this build could not determine its meaning. Hosts fail closed on it rather than assuming permission was granted. + [JsonPropertyName("policyUndetermined")] + public bool PolicyUndetermined { get; set; } +} - /// Whether the user is eligible to sign up for the free/limited Copilot tier. - [JsonPropertyName("can_signup_for_limited")] - public bool? CanSignupForLimited { get; set; } +/// The verbatim managed `permissions` slice to interpret. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PermissionsEvaluateManagedPolicyParams +{ + /// The `permissions` object from a managed settings layer, for example `{"disableBypassPermissionsMode":"disable"}`. Omitted or null means no managed policy applies. + [JsonPropertyName("permissions")] + public JsonElement? Permissions { get; set; } +} - /// Whether the user is able to upgrade their Copilot plan. - [JsonPropertyName("can_upgrade_plan")] - public bool? CanUpgradePlan { get; set; } +/// Which stored location permissions were dropped because their directory is gone. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class LocationPermissionsCleanupResult +{ + /// Location keys whose grants were removed. Empty when every stored location still exists. + [JsonPropertyName("removedLocationKeys")] + public IList RemovedLocationKeys { get => field ??= []; set; } +} - /// Whether Copilot chat is enabled for the user. - [JsonPropertyName("chat_enabled")] - public bool? ChatEnabled { get; set; } +/// Folder trust check result. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class FolderTrustCheckResult +{ + /// Whether the folder is trusted. + [JsonPropertyName("trusted")] + public bool Trusted { get; set; } +} - /// Whether CLI remote control is enabled for the user. - [JsonPropertyName("cli_remote_control_enabled")] - public bool? CliRemoteControlEnabled { get; set; } +/// A folder to check against a persisted trusted-folders list, and the configuration directory holding that list. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class FolderTrustIsTrustedParams +{ + /// Configuration directory to read the trusted-folders list from. Omit it to read the default location; supply it when the host has redirected its configuration, or the check answers from a list the host is not using. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } - /// Whether cloud session storage is enabled for the user. - [JsonPropertyName("cloud_session_storage_enabled")] - public bool? CloudSessionStorageEnabled { get; set; } + /// Folder to check. A folder counts as trusted when it is itself listed, when an ancestor is listed, or when its git root is listed. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; +} - /// Whether the Codex agent is enabled for the user. - [JsonPropertyName("codex_agent_enabled")] - public bool? CodexAgentEnabled { get; set; } +/// The device-managed settings layer, with the sandbox floor and the load outcome a host needs to compose it into an effective policy. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ManagedSettingsReadDeviceResult +{ + /// Whether discovery or validation failed. A host must treat this as "policy unknown" rather than "no policy": absent settings with this set false mean the device genuinely has none. + [JsonPropertyName("loadFailed")] + public bool LoadFailed { get; set; } - /// Copilot plan name for the user (e.g. `individual`, `business`, `enterprise`). - [JsonPropertyName("copilot_plan")] - public string? CopilotPlan { get; set; } + /// Sandbox floor read from the discovered document before validation, so a document that is otherwise rejected can still raise the floor it declared. + [JsonPropertyName("sandboxFloor")] + public JsonElement? SandboxFloor { get; set; } - /// Whether `.copilotignore` content-exclusion support is enabled for the user. - [JsonPropertyName("copilotignore_enabled")] - public bool? CopilotignoreEnabled { get; set; } + /// Validated, canonical device-managed settings. Omitted when no device policy was discovered, when the discovered document failed validation, or when it validated to an empty object — an empty document carries no policy, and reporting it as present would outrank layers that do. + [JsonPropertyName("settings")] + public JsonElement? Settings { get; set; } +} - /// Endpoint URLs from the raw Copilot `/copilot_internal/v2/token` user-response passthrough. - [JsonPropertyName("endpoints")] - public CopilotUserResponseEndpoints? Endpoints { get; set; } +/// The managed layers to retain as this process's startup policy, with the outcome of fetching each one. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ManagedSettingsRetainPolicyParams +{ + /// Whether the device load failed. Report it honestly, for the same reason as `serverFetchFailed`. + [JsonPropertyName("deviceLoadFailed")] + public bool DeviceLoadFailed { get; set; } - /// Enterprises that provide the user's Copilot license; malformed entries are normalized to null or ID-less shapes. - [JsonPropertyName("enterprise_list")] - public IList? EnterpriseList { get; set; } + /// The device/MDM policy layer. + [JsonPropertyName("deviceResponse")] + public JsonElement? DeviceResponse { get; set; } - /// Whether MCP (Model Context Protocol) support is enabled for the user. - [JsonPropertyName("is_mcp_enabled")] - public bool? IsMcpEnabled { get; set; } + /// Sandbox floor declared by the device layer, carried separately so a document that failed validation can still raise the floor. + [JsonPropertyName("deviceSandboxFloor")] + public JsonElement? DeviceSandboxFloor { get; set; } - /// Whether the user is a GitHub/Microsoft staff member. - [JsonPropertyName("is_staff")] - public bool? IsStaff { get; set; } + /// Whether the device sandbox intent is unreadable independently of its other settings. + [JsonPropertyName("deviceSandboxUndetermined")] + public bool DeviceSandboxUndetermined { get; set; } - /// Per-category quota allotments for free/limited-tier users, keyed by quota category. - [JsonPropertyName("limited_user_quotas")] - public IDictionary? LimitedUserQuotas { get; set; } + /// Whether a device policy source demonstrably exists. This, not a read error, is the evidence a device is managed, so a fail-closed policy gates on it. + [JsonPropertyName("deviceSourceFound")] + public bool DeviceSourceFound { get; set; } - /// Date the free/limited-tier user's quotas next reset, as a raw string from the Copilot API. - [JsonPropertyName("limited_user_reset_date")] - public string? LimitedUserResetDate { get; set; } + /// Whether any managed policy source exists, independently of fetch failures. + [JsonPropertyName("managedPolicyPresent")] + public bool ManagedPolicyPresent { get; set; } - /// GitHub login of the authenticated user. - [JsonPropertyName("login")] - public string? Login { get; set; } + /// Whether permission policy is undetermined. Sandbox-only uncertainty does not imply this flag. + [JsonPropertyName("permissionPolicyUndetermined")] + public bool PermissionPolicyUndetermined { get; set; } - /// Per-category monthly quota allotments, keyed by quota category. - [JsonPropertyName("monthly_quotas")] - public IDictionary? MonthlyQuotas { get; set; } + /// The policy helper's response: the third managed layer that a process owning its startup policy resolves. It is retained with the other two so that every ambient read in this process, including the mutation guards and the governed marketplace allowlist that the `plugins.*` handlers derive, sees the whole policy the process fetched. A session-owning process omits it, because it resolves a helper per session against that session's working directory. + [JsonPropertyName("policyHelperResponse")] + public JsonElement? PolicyHelperResponse { get; set; } - /// Organizations the user belongs to, each with an optional ID, login, and display name. - [JsonPropertyName("organization_list")] - public IList? OrganizationList { get; set; } + /// Preserve the retained server layer during a device-only resolution. + [JsonPropertyName("preserveServerState")] + public bool PreserveServerState { get; set; } - /// Logins of the organizations the user belongs to. - [JsonPropertyName("organization_login_list")] - public IList? OrganizationLoginList { get; set; } + /// Whether uncertainty alone enabled the shared sandbox floor. + [JsonPropertyName("sandboxEnabledByUndeterminedPolicy")] + public bool SandboxEnabledByUndeterminedPolicy { get; set; } - /// Date the user's usage quota next resets, as a raw string from the Copilot API; see `quota_reset_date_utc` for the UTC-normalized value. - [JsonPropertyName("quota_reset_date")] - public string? QuotaResetDate { get; set; } + /// Whether the shared sandbox policy is undetermined. Diagnostic errors alone do not imply this flag. + [JsonPropertyName("sandboxFloorUndetermined")] + public bool SandboxFloorUndetermined { get; set; } - /// UTC-normalized form of `quota_reset_date` (the date the user's usage quota next resets). - [JsonPropertyName("quota_reset_date_utc")] - public string? QuotaResetDateUtc { get; set; } + /// Whether the server fetch failed. Report it honestly: true keeps the already-retained server layer rather than replacing it with an absent one. + [JsonPropertyName("serverFetchFailed")] + public bool ServerFetchFailed { get; set; } - /// Quota snapshot map from the raw Copilot user-response passthrough, with chat, completions, premium-interactions, and other entries. - [JsonPropertyName("quota_snapshots")] - public CopilotUserResponseQuotaSnapshots? QuotaSnapshots { get; set; } + /// Whether a required fresh server-policy confirmation failed. + [JsonPropertyName("serverForcedRefreshFailure")] + public bool ServerForcedRefreshFailure { get; set; } - /// Whether the user's telemetry is subject to restricted-data handling. - [JsonPropertyName("restricted_telemetry")] - public bool? RestrictedTelemetry { get; set; } + /// The resolved server policy. A known source can lack a response after a forced-refresh failure. + [JsonPropertyName("serverResponse")] + public JsonElement? ServerResponse { get; set; } - /// Raw passthrough of the Copilot API `te` flag for the user (an opaque server-side eligibility signal surfaced in telemetry); not otherwise interpreted by the runtime. - [JsonPropertyName("te")] - public bool? Te { get; set; } + /// Whether the server policy source exists, even when its response is unavailable. + [JsonPropertyName("serverSourceFound")] + public bool ServerSourceFound { get; set; } - /// Whether the account is on usage-based (token/AI-credit) billing rather than a fixed premium-request quota. - [JsonPropertyName("token_based_billing")] - public bool? TokenBasedBilling { get; set; } + /// Shared server/device sandbox floor, excluding session-local helper policy. + [JsonPropertyName("sharedSandboxFloor")] + public JsonElement? SharedSandboxFloor { get; set; } } -/// Authentication-info input variant for GitHub-internal HMAC auth, carrying the public GitHub host and HMAC secret. -/// The hmac variant of . +/// The user settings with the managed layer's controlled entries stamped on. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthInfoHmac : AuthInfo +internal sealed class ManagedSettingsApplyControlsResult { - /// - [JsonIgnore] - public override string Type => "hmac"; + /// The resulting settings document. + [JsonPropertyName("settingsJson")] + public JsonElement SettingsJson { get; set; } +} - /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } +/// A user settings document and the effective managed policy whose controlled entries should be stamped onto it. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ManagedSettingsApplyControlsParams +{ + /// The effective managed policy, as composed by `managedSettings.resolveEffectiveValue`. Omit it on an unmanaged host: the settings then come back unchanged. + [JsonPropertyName("managed")] + public JsonElement? Managed { get; set; } - /// HMAC secret used to sign requests. - [JsonPropertyName("hmac")] - public required string Hmac { get; set; } + /// The user settings document to stamp. Entries the managed layer does not name are returned exactly as supplied. + [JsonPropertyName("settings")] + public JsonElement Settings { get; set; } +} - /// Authentication host. HMAC auth always targets the public GitHub host. - [JsonPropertyName("host")] - public required string Host { get; set; } +/// The accepted managed settings, reduced to the keys a client is allowed to set. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ManagedSettingsParseClientValueResult +{ + /// The normalized settings. Omitted when the client supplied none. An accepted document that sets nothing comes back as an empty object, which is distinct from omission. + [JsonPropertyName("settingsJson")] + public JsonElement? SettingsJson { get; set; } } -/// Authentication-info input variant for a token sourced from an environment variable, with host, optional login, token, and env var name. -/// The env variant of . +/// The client-supplied managed settings to validate and normalize. Omitting them is valid and yields no policy. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthInfoEnv : AuthInfo +internal sealed class ManagedSettingsParseClientValueParams { - /// - [JsonIgnore] - public override string Type => "env"; + /// The managed settings a client is supplying for a session it is about to open. Omit them when the client is imposing no policy of its own. + [JsonPropertyName("settings")] + public JsonElement? Settings { get; set; } +} - /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } +/// The effective managed policy composed from the supplied layers. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ManagedSettingsResolveEffectiveValueResult +{ + /// The composed effective managed settings. Omitted when no layer sets anything, so an unmanaged host locks nothing. Carries `sandboxAdvisoryFloorDeclined: true` when an advisory server force-on was dropped because this host cannot run the sandbox. + [JsonPropertyName("settingsJson")] + public JsonElement? SettingsJson { get; set; } +} - /// Name of the environment variable the token was sourced from. - [JsonPropertyName("envVar")] - public required string EnvVar { get; set; } +/// The managed-settings layers to compose into an effective policy. Every layer is optional; omitting all of them yields no effective policy. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ManagedSettingsResolveEffectiveValueParams +{ + /// The device sandbox floor, folded into the device layer under `sandbox` before composition. + [JsonPropertyName("deviceSandboxFloor")] + public JsonElement? DeviceSandboxFloor { get; set; } - /// Authentication host (e.g. https://github.com or a GHES host). - [JsonPropertyName("host")] - public required string Host { get; set; } + /// The device layer: native MDM and managed-file settings describing the machine rather than the account. + [JsonPropertyName("mdm")] + public JsonElement? Mdm { get; set; } - /// User login associated with the token. Undefined for server-to-server tokens (those starting with `ghs_`). - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("login")] - public string? Login { get; set; } + /// The policy-helper layer, an enforced channel sourced from a platform policy helper process. + [JsonPropertyName("policyHelper")] + public JsonElement? PolicyHelper { get; set; } - /// The token value itself. Treat as a secret. - [JsonPropertyName("token")] - public required string Token { get; set; } + /// The account's server-delivered org policy, as returned by a managed-settings fetch. Omitted before sign-in or when the fetch has not landed. + [JsonPropertyName("server")] + public JsonElement? Server { get; set; } } -/// Authentication-info input variant for SDK-configured token authentication, carrying host and the secret token value. -/// The token variant of . +/// The bypass-permissions state a host should hold after the resolution, and what it must do to get there. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthInfoToken : AuthInfo +internal sealed class ManagedSettingsResolveBypassDisableTransitionResult { - /// - [JsonIgnore] - public override string Type => "token"; - - /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// The account the returned `managed` source is pinned to. Store it alongside `source`; the next call needs it to decide whether an account switch lifts the disable. + [JsonPropertyName("managedIdentity")] + public string? ManagedIdentity { get; set; } - /// Authentication host. - [JsonPropertyName("host")] - public required string Host { get; set; } + /// The value to store in the host's own bypass-disabled flag. Omitted means leave it exactly as it is, which is not the same as being told to store `false`. + [JsonPropertyName("setDisabledState")] + public bool? SetDisabledState { get; set; } - /// Opaque native GitHub credential registration backing this token identity, when applicable. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("registrationId")] - public string? RegistrationId { get; set; } + /// Which layer disables bypass mode after this resolution. Omitted when none does, which is what a lifted disable looks like. + [JsonPropertyName("source")] + public ManagedSettingsBypassDisableSource? Source { get; set; } - /// The token value itself. Treat as a secret. - [JsonPropertyName("token")] - public required string Token { get; set; } + /// Whether a bypass-permissions session already running must be turned off. True only when this resolution newly disables bypass mode, so a host that is already compliant is not interrupted. + [JsonPropertyName("suppressRuntimeAllowAll")] + public bool SuppressRuntimeAllowAll { get; set; } } -/// Authentication-info variant backed by an SDK GitHub token callback. It carries routing metadata but never a plaintext token. -/// The token-provider variant of . +/// The bypass-permissions state a host holds today, the account now signed in, and what the managed-policy resolution said. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthInfoTokenProvider : AuthInfo +internal sealed class ManagedSettingsResolveBypassDisableTransitionParams { - /// - [JsonIgnore] - public override string Type => "token-provider"; + /// The account signed in now. A `managed` disable pinned to a different account is lifted. + [JsonPropertyName("activeIdentity")] + public string ActiveIdentity { get; set; } = string.Empty; - /// Snapshot of the authenticated user's Copilot subscription info, if known. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// The account a `managed` disable is pinned to. Omit it when the current source is not `managed`; it is ignored for the other sources. + [JsonPropertyName("currentManagedIdentity")] + public string? CurrentManagedIdentity { get; set; } - /// Authentication host. - [JsonPropertyName("host")] - public required string Host { get; set; } + /// Which layer currently disables bypass mode. Omit it when nothing does. + [JsonPropertyName("currentSource")] + public ManagedSettingsBypassDisableSource? CurrentSource { get; set; } - /// Opaque SDK callback registration identifier. - [JsonPropertyName("registrationId")] - public required string RegistrationId { get; set; } + /// What the resolution said about bypass mode. Send `unknown` rather than omitting the field when there is no verdict. + [JsonPropertyName("policy")] + public ManagedSettingsBypassPolicyResolution Policy { get; set; } } -/// Authentication-info variant for direct Copilot API token auth sourced from environment variables, with public GitHub host. -/// The copilot-api-token variant of . +/// One diagnostic emitted while ingesting managed settings. Returned rather than logged by the runtime so the host decides where ingestion diagnostics go, which matters because an ingestion runs before a session exists to carry a log sink. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthInfoCopilotApiToken : AuthInfo +internal sealed class ManagedSettingsLogMessage { - /// - [JsonIgnore] - public override string Type => "copilot-api-token"; - - /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// Severity of this diagnostic. + [JsonPropertyName("level")] + public ManagedSettingsLogLevel Level { get; set; } - /// Authentication host (always the public GitHub host). - [JsonPropertyName("host")] - public required string Host { get; set; } + /// Human-readable diagnostic text. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; } -/// Authentication-info variant for OAuth user auth, with host and login; the token remains in the runtime secret store. -/// The user variant of . +/// The managed policy layers an ingestion resolved, together with the per-layer outcome flags a host needs to decide how much to trust the result. The flags are reported rather than folded into the settings because a host must be able to distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthInfoUser : AuthInfo +internal sealed class ManagedSettingsIngestResult { - /// - [JsonIgnore] - public override string Type => "user"; + /// The device layer could not be read, so it is unconfirmed rather than known-absent. + [JsonPropertyName("deviceLoadFailed")] + public bool DeviceLoadFailed { get; set; } - /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// The device layer discovered from the machine, when one exists. + [JsonPropertyName("deviceResponse")] + public JsonElement? DeviceResponse { get; set; } - /// Authentication host. - [JsonPropertyName("host")] - public required string Host { get; set; } + /// The sandbox floor contributed by the device layer. + [JsonPropertyName("deviceSandboxFloor")] + public JsonElement? DeviceSandboxFloor { get; set; } - /// OAuth user login. - [JsonPropertyName("login")] - public required string Login { get; set; } -} + /// Whether the device layer's sandbox intent could not be determined, so a consumer must not read its absence as permission to run unsandboxed. + [JsonPropertyName("deviceSandboxUndetermined")] + public bool DeviceSandboxUndetermined { get; set; } -/// An interactive account whose model provider owns its credentials. It carries no GitHub credential. -/// The account variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthInfoAccount : AuthInfo -{ - /// - [JsonIgnore] - public override string Type => "account"; + /// A device-managed policy is known to exist. + [JsonPropertyName("deviceSourceFound")] + public bool DeviceSourceFound { get; set; } - /// Host coordinate owned by the account's model provider. - [JsonPropertyName("host")] - public required string Host { get; set; } + /// Diagnostics emitted while resolving the layers, in the order they occurred. + [JsonPropertyName("logMessages")] + public IList LogMessages { get => field ??= []; set; } - /// Login identifying the provider-owned account. - [JsonPropertyName("login")] - public required string Login { get; set; } -} + /// The effective managed permissions layer, when the resolved policy carries one. + [JsonPropertyName("permissions")] + public JsonElement? Permissions { get; set; } -/// Authentication-info input variant for GitHub CLI credentials, carrying host, login, and the `gh auth token` value. -/// The gh-cli variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthInfoGhCli : AuthInfo -{ - /// - [JsonIgnore] - public override string Type => "gh-cli"; + /// Which channel registered the policy helper that produced the helper layer. + [JsonPropertyName("policyHelperAuthority")] + public ManagedSettingsPolicyHelperAuthority? PolicyHelperAuthority { get; set; } - /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// A policy helper is configured for this host. + [JsonPropertyName("policyHelperConfigured")] + public bool PolicyHelperConfigured { get; set; } - /// Authentication host. - [JsonPropertyName("host")] - public required string Host { get; set; } + /// The policy helper's failure must be treated as fail-closed rather than ignored. + [JsonPropertyName("policyHelperFailClosed")] + public bool PolicyHelperFailClosed { get; set; } - /// User login as reported by `gh auth status`. - [JsonPropertyName("login")] - public required string Login { get; set; } + /// The policy helper was configured but could not be run or its output could not be read. + [JsonPropertyName("policyHelperLoadFailed")] + public bool PolicyHelperLoadFailed { get; set; } - /// The token returned by `gh auth token`. Treat as a secret. - [JsonPropertyName("token")] - public required string Token { get; set; } -} + /// The layer produced by the platform policy helper, when one ran. + [JsonPropertyName("policyHelperResponse")] + public JsonElement? PolicyHelperResponse { get; set; } -/// Authentication-info input variant for API-key authentication to a non-GitHub LLM provider, carrying the secret `apiKey` and host. -/// The api-key variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthInfoApiKey : AuthInfo -{ - /// - [JsonIgnore] - public override string Type => "api-key"; + /// A live fetch failed but a recent cached entry was served in its place, so `serverFetchFailed` stays false. Lets a consumer distinguish a clean fetch from a cache-backed fallback. + [JsonPropertyName("serverCacheFallback")] + public bool ServerCacheFallback { get; set; } - /// The API key. Treat as a secret. - [JsonPropertyName("apiKey")] - public required string ApiKey { get; set; } + /// Minimum client version requested by a successful response. Advisory only; the delivered policy remains active. + [JsonPropertyName("serverClientUpdateRequested")] + public string? ServerClientUpdateRequested { get; set; } - /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// The server refused to deliver a policy because this client is too old to enforce it, carrying the user-facing sentence describing the refusal. No retry will help; the remedy is a client update. Gates that exist only because of managed policy should deny on this rather than falling back to their unmanaged default. + [JsonPropertyName("serverClientUpdateRequired")] + public string? ServerClientUpdateRequired { get; set; } - /// Authentication host. - [JsonPropertyName("host")] - public required string Host { get; set; } -} + /// The error that made the server fetch fail, when one did. + [JsonPropertyName("serverFetchError")] + public string? ServerFetchError { get; set; } -/// Current authentication state. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AccountGetCurrentAuthResult -{ - /// Authentication errors from the last auth attempt, if any. - [JsonPropertyName("authErrors")] - public IList? AuthErrors { get; set; } + /// The server fetch failed and no cached entry stood in for it, so the server layer is unconfirmed and fail-closed gates apply. + [JsonPropertyName("serverFetchFailed")] + public bool ServerFetchFailed { get; set; } - /// Current authentication information, if authenticated. - [JsonPropertyName("authInfo")] - public AuthInfo? AuthInfo { get; set; } + /// The server fetch failed while a policy demanded a fresh confirmation, which is the strict posture an enterprise opted into rather than an ordinary transient failure. + [JsonPropertyName("serverForcedRefreshFailure")] + public bool ServerForcedRefreshFailure { get; set; } + + /// The synthesized fail-closed permissions layer applied in place of a policy a refused client may not enforce. + [JsonPropertyName("serverPermissionsFloor")] + public JsonElement? ServerPermissionsFloor { get; set; } + + /// How the server layer was resolved. + [JsonPropertyName("serverResolution")] + public ManagedSettingsServerPolicyResolution ServerResolution { get; set; } + + /// The account's server-delivered policy, when one was resolved. + [JsonPropertyName("serverResponse")] + public JsonElement? ServerResponse { get; set; } + + /// The server fetch failed in a way a later retry could succeed at, as opposed to a refusal that no retry will change. + [JsonPropertyName("serverRetryableFailure")] + public bool ServerRetryableFailure { get; set; } + + /// The sandbox object from a cached server policy that a forced refresh declined to serve in full. Folded back into the effective sandbox layer so an outage during a forced refresh still synthesizes the fail-closed sandbox floor from the administrator's known intent. + [JsonPropertyName("serverSandboxFloor")] + public JsonElement? ServerSandboxFloor { get; set; } + + /// A server-managed policy is known to exist even though `serverResponse` is intentionally unset. Consumers should OR this with the presence of `serverResponse` when deciding whether the device is managed, so a fresh start during an outage still applies the fail-closed gates instead of treating the device as unmanaged. + [JsonPropertyName("serverSourceFound")] + public bool ServerSourceFound { get; set; } + + /// No usable token was available, so no server fetch was attempted. + [JsonPropertyName("serverTokenUnavailable")] + public bool ServerTokenUnavailable { get; set; } + + /// The effective managed settings composed from every resolved layer. Omitted when no layer set anything, so an unmanaged host locks nothing. + [JsonPropertyName("settings")] + public JsonElement? Settings { get; set; } } -/// Authenticated account entry returned by `account.getAllUsers`. +/// Inputs describing the host and account an ingestion should resolve managed policy for. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AccountAllUsers +internal sealed class ManagedSettingsIngestParams { - /// Authentication information for this user. + /// The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched. [JsonPropertyName("authInfo")] - public AuthInfo AuthInfo { get => field ??= new(); set; } + public JsonElement? AuthInfo { get; set; } - /// Opaque identifier accepted by account and model selection APIs. - [JsonPropertyName("selectionId")] - public string? SelectionId { get; set; } + /// Whether to ignore a cached server policy when reading, forcing the resolution to come from a live fetch. + [JsonPropertyName("bypassCacheRead")] + public bool? BypassCacheRead { get; set; } - /// Associated token, if available. - [JsonPropertyName("token")] - public string? Token { get; set; } -} + /// Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. Omit it and the runtime reports a generic identity; the runtime version sent alongside is the gate that actually matters. + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } -/// Result of a successful login; throws on failure. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AccountLoginResult -{ - /// Whether the credential was persisted to a secure store (system keychain, or the config file when plaintext storage is enabled). False when no secure store was available and the token was not saved, so the consumer can decide how to proceed. - [JsonPropertyName("storedInVault")] - public bool StoredInVault { get; set; } + /// A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + [JsonPropertyName("deviceResponse")] + public JsonElement? DeviceResponse { get; set; } + + /// The host's environment variables, read for cache location and policy overrides. Supplied by the host rather than read from the runtime process so a command that selected its own configuration home is honored. + [JsonPropertyName("environment")] + public JsonElement Environment { get; set; } + + /// Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. + [JsonPropertyName("hasDeviceResponse")] + public bool? HasDeviceResponse { get; set; } + + /// The host's home directory, used to resolve cache and managed-file locations. + [JsonPropertyName("homeDirectory")] + public string HomeDirectory { get; set; } = string.Empty; + + /// The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. + [JsonPropertyName("platform")] + public string Platform { get; set; } = string.Empty; + + /// Whether a configured platform policy helper may be run to produce an enforced helper layer. + [JsonPropertyName("policyHelperEnabled")] + public bool? PolicyHelperEnabled { get; set; } + + /// The policy-helper invocation reason. Defaults to sessionStart. + [JsonPropertyName("policyHelperReason")] + public ManagedSettingsPolicyHelperReason? PolicyHelperReason { get; set; } + + /// Directory the policy helper runs in when this ingestion is not owned by a registered session. A host resolving policy before its session exists must pass this, or a directory-sensitive helper judges the wrong repository. + [JsonPropertyName("policyHelperWorkingDirectory")] + public string? PolicyHelperWorkingDirectory { get; set; } + + /// Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. + [JsonPropertyName("selfFetch")] + public bool? SelfFetch { get; set; } + + /// How this ingestion may use the on-disk server-policy cache. Defaults to the runtime's own policy when omitted. + [JsonPropertyName("serverPolicyCacheMode")] + public ManagedSettingsServerPolicyCacheMode? ServerPolicyCacheMode { get; set; } + + /// The session whose credential store and working directory the policy helper should use. Omit it when no session exists yet and the process-wide store applies. + [JsonPropertyName("sessionId")] + public string? SessionId { get; set; } + + /// User agent to send with the policy fetch. + [JsonPropertyName("userAgent")] + public string UserAgent { get; set; } = string.Empty; } -/// Credentials to validate and store. Omit login to resolve the authenticated user from the token. +/// The verdict of the `forceLoginOrgs` enterprise sign-in pin for one credential. A managed device may pin Copilot to an approved set of GitHub organizations so a developer cannot sign in with a personal — or another enterprise's — account and escape every control that keys off the signed-in identity. A host must refuse to proceed when `allowed` is false; the remaining fields explain the refusal rather than qualifying it. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AccountLoginRequest +internal sealed class ForceLoginOrgsDecision { - /// GitHub host URL. - [JsonPropertyName("host")] - public string Host { get; set; } = string.Empty; + /// Whether the client may proceed. True whenever no pin is in force, so an unmanaged host is never blocked. + [JsonPropertyName("allowed")] + public bool Allowed { get; set; } - /// User login/username. When omitted, the runtime validates the token and resolves the login from GitHub. - [JsonPropertyName("login")] - public string? Login { get; set; } + /// A stable kebab-case reason code when refused: `org-not-approved`, `unverifiable-credential`, `policy-undetermined`, `policy-invalid`, `not-signed-in`, or `membership-unknown`. Omitted when allowed. Treat an unrecognized code as a refusal rather than mapping it to an allow: a code this host has not been taught about still denied the credential. + [JsonPropertyName("denial")] + public string? Denial { get; set; } - /// GitHub authentication token. - [JsonPropertyName("token")] - public string Token { get; set; } = string.Empty; + /// Whether a pin applies at all. Distinguishes "allowed because unmanaged" from "allowed because the account is approved", which a diagnostics surface needs and which also decides whether a bring-your-own-key provider may serve inference. + [JsonPropertyName("enforced")] + public bool Enforced { get; set; } + + /// The approved organization the account matched, when allowed under a pin. + [JsonPropertyName("matchedOrg")] + public string? MatchedOrg { get; set; } + + /// A developer-facing explanation of the refusal. Omitted when allowed. + [JsonPropertyName("message")] + public string? Message { get; set; } + + /// Error-level detail from managed-policy discovery — which file failed to load, which field failed validation. Carried on the decision rather than left to the log because a refusal can exit the process before a log sink exists, which would discard the only actionable diagnostic a misconfigured managed device produces. + [JsonPropertyName("policyDiagnostics")] + public IList PolicyDiagnostics { get => field ??= []; set; } + + /// The approved organization logins, as configured. Enterprise configuration rather than user data, so it is safe to name in a message or a log line. + [JsonPropertyName("requiredOrgs")] + public IList RequiredOrgs { get => field ??= []; set; } } -/// Logout result indicating if more users remain. +/// The startup policy a resolution composed, the per-layer outcome flags a host needs to decide how much to trust it, and the enterprise sign-in verdict for the credential it ran against. The flags are reported rather than folded into the settings because a host must distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AccountLogoutResult +internal sealed class ManagedSettingsResolveStartupPolicyResult { - /// Whether other authenticated users remain after logout. - [JsonPropertyName("hasMoreUsers")] - public bool HasMoreUsers { get; set; } + /// Advisory minimum client version from a successful server response. + [JsonPropertyName("clientUpdateRequested")] + public string? ClientUpdateRequested { get; set; } + + /// The server refused to deliver a policy because this client is too old to enforce it, carrying the user-facing sentence describing the refusal. No retry will help; the remedy is a client update. + [JsonPropertyName("clientUpdateRequired")] + public string? ClientUpdateRequired { get; set; } + + /// The device layer could not be read, so it is unconfirmed rather than known-absent. + [JsonPropertyName("deviceLoadFailed")] + public bool DeviceLoadFailed { get; set; } + + /// The device layer discovered from the machine, when one exists. + [JsonPropertyName("deviceResponse")] + public JsonElement? DeviceResponse { get; set; } + + /// The sandbox floor contributed by the device layer. + [JsonPropertyName("deviceSandboxFloor")] + public JsonElement? DeviceSandboxFloor { get; set; } + + /// The enterprise sign-in verdict for the credential this resolution ran against, evaluated over the effective policy so a server-delivered pin is honored alongside a device one. Computed on every resolution, including one that was not retained, so a host that declines to apply policy still cannot proceed past a pin. + [JsonPropertyName("forceLoginOrgs")] + public ForceLoginOrgsDecision ForceLoginOrgs { get => field ??= new(); set; } + + /// A managed policy is known to apply to this host, from a discovered source or a resolved document. + [JsonPropertyName("managedPolicyPresent")] + public bool ManagedPolicyPresent { get; set; } + + /// The permissions layer specifically could not be confirmed, so permission gates apply their fail-closed posture. + [JsonPropertyName("permissionPolicyUndetermined")] + public bool PermissionPolicyUndetermined { get; set; } + + /// The policy helper was configured but could not be run, or its output could not be read. + [JsonPropertyName("policyHelperLoadFailed")] + public bool PolicyHelperLoadFailed { get; set; } + + /// The layer produced by the platform policy helper, when one ran. + [JsonPropertyName("policyHelperResponse")] + public JsonElement? PolicyHelperResponse { get; set; } + + /// Some layer of the policy could not be confirmed, so its absence must not be read as permission. Folds in a failed server fetch as well as an unreadable device layer. + [JsonPropertyName("policyUndetermined")] + public bool PolicyUndetermined { get; set; } + + /// The sandbox was enabled because policy could not be confirmed rather than because an administrator asked for it. Lets a host explain a sandbox the user did not configure. + [JsonPropertyName("sandboxEnabledByUndeterminedPolicy")] + public bool SandboxEnabledByUndeterminedPolicy { get; set; } + + /// The effective sandbox floor composed across every layer, which a host must apply rather than its own default. + [JsonPropertyName("sandboxFloor")] + public JsonElement? SandboxFloor { get; set; } + + /// The server fetch failed and no cached entry stood in for it, so the server layer is unconfirmed and fail-closed gates apply. + [JsonPropertyName("serverFetchFailed")] + public bool ServerFetchFailed { get; set; } + + /// How the current runtime resolved the server layer. + [JsonPropertyName("serverResolution")] + public ManagedSettingsServerPolicyResolution ServerResolution { get; set; } + + /// The account's server-delivered policy, when one was resolved. + [JsonPropertyName("serverResponse")] + public JsonElement? ServerResponse { get; set; } + + /// Telemetry describing which layers answered and how, for the host to report alongside its own startup events. + [JsonPropertyName("telemetry")] + public JsonElement Telemetry { get; set; } + + /// Warnings raised while resolving, in the order they occurred. + [JsonPropertyName("warnings")] + public IList Warnings { get => field ??= []; set; } } -/// User to log out. +/// Inputs describing the host and account a startup policy resolution should run for. Mirrors `managedSettings.ingest`, and adds the decision of whether the resolved policy is retained for this runtime process. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AccountLogoutRequest +internal sealed class ManagedSettingsResolveStartupPolicyParams { - /// Authentication information for the user to log out. + /// The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched and the sign-in pin is evaluated against no credential. [JsonPropertyName("authInfo")] - public AuthInfo? AuthInfo { get; set; } + public JsonElement? AuthInfo { get; set; } - /// Opaque account identifier returned by `account.getAllUsers`. - [JsonPropertyName("selectionId")] - public string? SelectionId { get; set; } -} + /// Whether to ignore a cached server policy when reading, forcing the resolution to come from a live fetch. + [JsonPropertyName("bypassCacheRead")] + public bool? BypassCacheRead { get; set; } -/// The wording the runtime uses for an authentication identity. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AccountDescribeAuthInfoResult -{ - /// One-line description of the identity, suitable after a verb such as "Switched to". - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; + /// Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } - /// Sign-in banner announcing the authenticated user. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; -} + /// A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + [JsonPropertyName("deviceResponse")] + public JsonElement? DeviceResponse { get; set; } -/// Credential-free authentication identity safe to expose to hosts and user interfaces. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AuthIdentity -{ - /// Snapshot of the authenticated user's Copilot subscription info, if known. - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// The host's environment variables, read for cache location, policy overrides, and the variables that would make a membership snapshot forgeable. + [JsonPropertyName("environment")] + public JsonElement Environment { get; set; } - /// Name of the environment variable that supplied the credential, when applicable. - [JsonPropertyName("envVar")] - public string? EnvVar { get; set; } + /// Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. + [JsonPropertyName("hasDeviceResponse")] + public bool? HasDeviceResponse { get; set; } - /// Authentication host. - [JsonPropertyName("host")] - public string Host { get; set; } = string.Empty; + /// The host's home directory, used to resolve cache and managed-file locations. + [JsonPropertyName("homeDirectory")] + public string HomeDirectory { get; set; } = string.Empty; - /// Authenticated login, when available. - [JsonPropertyName("login")] - public string? Login { get; set; } + /// The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. + [JsonPropertyName("platform")] + public string Platform { get; set; } = string.Empty; - /// Opaque SDK GitHub credential registration backing this identity. Routing metadata only; never a credential. - [JsonPropertyName("registrationId")] - public string? RegistrationId { get; set; } + /// Whether a configured platform policy helper may be run to produce an enforced helper layer. + [JsonPropertyName("policyHelperEnabled")] + public bool? PolicyHelperEnabled { get; set; } - /// Authentication type. - [JsonPropertyName("type")] - public AuthInfoType Type { get; set; } + /// The policy-helper invocation reason. Defaults to sessionStart. + [JsonPropertyName("policyHelperReason")] + public ManagedSettingsPolicyHelperReason? PolicyHelperReason { get; set; } + + /// Directory the policy helper runs in when this resolution is not owned by a registered session. A host resolving policy before its session exists must pass this, or a directory-sensitive helper judges the wrong repository. + [JsonPropertyName("policyHelperWorkingDirectory")] + public string? PolicyHelperWorkingDirectory { get; set; } + + /// Whether to retain the resolved policy as this runtime process's startup policy, so later work in the process enforces it. Set false to resolve without side effects, which is what a protocol host wants before session creation: its sessions apply the complete policy through the normal lifecycle, and retaining here would let a readiness credential affect unrelated sessions. The returned verdict is identical either way — this decides only whether the process keeps it. + [JsonPropertyName("retainAndApply")] + public bool RetainAndApply { get; set; } + + /// Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. + [JsonPropertyName("selfFetch")] + public bool? SelfFetch { get; set; } + + /// How this resolution may use the on-disk server-policy cache. Defaults to the runtime's own policy when omitted. Rejected when combined with `bypassCacheRead`, because the two express the same decision and accepting both would leave the caller unsure which one the runtime honored. + [JsonPropertyName("serverPolicyCacheMode")] + public ManagedSettingsServerPolicyCacheMode? ServerPolicyCacheMode { get; set; } + + /// The session whose credential store, working directory and client kind the resolution should use. Omit it when no session exists yet and the process-wide store applies. A resolution whose session names a credential other than `authInfo` is returned but not retained, so a stale sign-in cannot apply policy for an account that has already been switched away from. + [JsonPropertyName("sessionId")] + public string? SessionId { get; set; } + + /// User agent to send with the policy fetch. + [JsonPropertyName("userAgent")] + public string UserAgent { get; set; } = string.Empty; } -/// The authentication identity whose shared wording should be rendered. +/// The managed remote-control policy in force for an account, if any. An absent policy means the account is unmanaged for this capability, which a host reads as allowed — so absence here is a positive statement that no policy applies, never a stand-in for a resolution that failed. A resolution that cannot be completed is rejected instead. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AccountDescribeAuthInfoRequest +internal sealed class ManagedSettingsLoadRemoteControlResult { - /// Identity to describe. - [JsonPropertyName("identity")] - public AuthIdentity Identity { get => field ??= new(); set; } + /// The account's `remoteControl` policy document. Absent when no managed policy governs remote control for this account. Reported as an explicit disabled policy, rather than as absence, when the service refused to deliver a policy this client is too old to enforce. + [JsonPropertyName("remoteControl")] + public JsonElement? RemoteControl { get; set; } } -/// Whether the identity can create gists, and why not when it cannot. +/// Inputs describing the host and account whose managed remote-control policy should be resolved. Mirrors `managedSettings.ingest`, and deliberately carries no retention decision: reading this gate never becomes this runtime process's startup policy. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AccountGetGistSupportResult +internal sealed class ManagedSettingsLoadRemoteControlParams { - /// Machine-readable reason category when unsupported. - [JsonPropertyName("kind")] - public string? Kind { get; set; } + /// The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched. + [JsonPropertyName("authInfo")] + public JsonElement? AuthInfo { get; set; } - /// Human-readable explanation to show where the gist action would have been. - [JsonPropertyName("reason")] - public string? Reason { get; set; } + /// Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. That refusal is exactly what turns into an explicit `disabled` below, so a host that omits this field forfeits the protection. + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } - /// True when the identity can create gists. - [JsonPropertyName("supported")] - public bool Supported { get; set; } + /// A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + [JsonPropertyName("deviceResponse")] + public JsonElement? DeviceResponse { get; set; } + + /// The host's environment variables, read for cache location and policy overrides. + [JsonPropertyName("environment")] + public JsonElement Environment { get; set; } + + /// Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. + [JsonPropertyName("hasDeviceResponse")] + public bool? HasDeviceResponse { get; set; } + + /// The host's home directory, used to resolve cache and managed-file locations. + [JsonPropertyName("homeDirectory")] + public string HomeDirectory { get; set; } = string.Empty; + + /// The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. + [JsonPropertyName("platform")] + public string Platform { get; set; } = string.Empty; + + /// Whether a configured platform policy helper may be run to produce an enforced helper layer. + [JsonPropertyName("policyHelperEnabled")] + public bool? PolicyHelperEnabled { get; set; } + + /// The policy-helper invocation reason. Defaults to sessionStart. + [JsonPropertyName("policyHelperReason")] + public ManagedSettingsPolicyHelperReason? PolicyHelperReason { get; set; } + + /// Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. + [JsonPropertyName("selfFetch")] + public bool? SelfFetch { get; set; } + + /// User agent to send with the policy fetch. + [JsonPropertyName("userAgent")] + public string UserAgent { get; set; } = string.Empty; } -/// The authentication identity whose gist support should be reported. +/// The credential and environment to evaluate the device-channel sign-in pin against. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AccountGetGistSupportRequest +internal sealed class ManagedSettingsResolveDeviceForceLoginOrgsGateParams { - /// Identity to evaluate. - [JsonPropertyName("identity")] - public AuthIdentity Identity { get => field ??= new(); set; } + /// The authenticated identity to judge. Omitted when signed out, which is the case the device channel exists to serve: it can refuse a first sign-in before any credential exists. + [JsonPropertyName("authInfo")] + public JsonElement? AuthInfo { get; set; } + + /// The host's environment variables. Read for the variables that would make an identity's membership snapshot forgeable, so a credential whose provenance cannot be trusted is refused rather than accepted. + [JsonPropertyName("environment")] + public JsonElement Environment { get; set; } } -/// An absolute URL on the identity's GitHub host. +/// Validated device-managed settings discovered before a session exists. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AccountGetWebUrlResult +public sealed class ManagedSettingsReadResult { - /// Absolute URL for the requested path. - [JsonPropertyName("url")] - public string Url { get; set; } = string.Empty; + /// Discovery or validation error text when managed settings could not be read safely. + [JsonPropertyName("errorMessage")] + public string? ErrorMessage { get; set; } + + /// Validated, canonical managed-settings JSON. Omitted when no managed settings were discovered or when discovered settings failed validation. + [JsonPropertyName("settingsJson")] + public JsonElement? SettingsJson { get; set; } } -/// A path to resolve against the GitHub host an identity is signed in to. +/// One validation finding for a managed-settings document. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AccountGetWebUrlRequest +public sealed class ManagedSettingsDiagnostic { - /// Identity whose host the path resolves against. Omit to resolve against the public github.com host. - [JsonPropertyName("identity")] - public AuthIdentity? Identity { get; set; } + /// Human-readable description of the finding. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; - /// Host-relative path, without a leading slash, for example `settings/copilot/features`. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] + /// Dot-separated path of the offending setting, such as `autoTier.overridable`. Empty for the document as a whole. [JsonPropertyName("path")] public string Path { get; set; } = string.Empty; -} -/// The environment variable supplying a classic personal access token, when one is set. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AccountGetTokenEnvVarResult -{ - /// Variable name, for example `GH_TOKEN`. Absent when no classic token is present in the environment. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Whether the finding rejects the document. + [JsonPropertyName("severity")] + public ManagedSettingsDiagnosticSeverity Severity { get; set; } } -/// Confirmation that the secret values were registered. +/// One managed-settings channel and the document it delivered. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SecretsAddFilterValuesResult +public sealed class ManagedSettingsLayer { - /// Whether the values were successfully registered. - [JsonPropertyName("ok")] - public bool Ok { get; set; } + /// Validated managed-settings document this channel delivered. Absent when the channel delivered none. + [JsonPropertyName("settings")] + public JsonElement? Settings { get; set; } + + /// Channel identifier: `device` (MDM, plist, registry, or managed file), `server` (account or organization policy), or `policyHelper` (session-local helper output, supported by compose). Treat unknown output values as additional channels; more may be added. + [JsonPropertyName("source")] + public string Source { get; set; } = string.Empty; } -/// Secret values to add to the redaction filter. +/// Lock state and provenance of one managed setting. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SecretsAddFilterValuesRequest +public sealed class ManagedSettingMeta { - /// Raw secret values to register for redaction. - [JsonPropertyName("values")] - public IList Values { get => field ??= []; set; } + /// Whether users and repositories may choose a different value. `false` means policy locks the value. + [JsonPropertyName("overridable")] + public bool Overridable { get; set; } + + /// Original managed value when the runtime adjusted it to a supported effective value. Omitted when no adjustment was needed. + [JsonPropertyName("requested")] + public string? Requested { get; set; } + + /// Channel that supplied this scalar value, matching a `layers[].source`: `device`, `server`, or `policyHelper`. These scalar defaults select one winning channel, not a mixed source. Treat unknown values as additional channels; more may be added. + [JsonPropertyName("source")] + public string Source { get; set; } = string.Empty; } -/// Concrete configuration file containing an MCP server declaration. +/// Per-key lock state and provenance for `ManagedSettingsValues`, with the same field names. Producers emit each typed key in values and meta together; both outer objects are omitted when no typed key is set. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpSourceFile +public sealed class ManagedSettingsMeta { - /// RFC 6901 JSON Pointer to the server declaration, when known. - [JsonPropertyName("jsonPointer")] - public string? JsonPointer { get; set; } + /// Lock state and provenance of `values.autoTier`. + [JsonPropertyName("autoTier")] + public ManagedSettingMeta? AutoTier { get; set; } - /// Canonical file URI for the configuration document. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("uri")] - public string Uri { get; set; } = string.Empty; + /// Lock state and provenance of `values.contextTier`. + [JsonPropertyName("contextTier")] + public ManagedSettingMeta? ContextTier { get; set; } + + /// Lock state and provenance of `values.effortLevel`. + [JsonPropertyName("effortLevel")] + public ManagedSettingMeta? EffortLevel { get; set; } + + /// Lock state and provenance of `values.model`. + [JsonPropertyName("model")] + public ManagedSettingMeta? Model { get; set; } } -/// Plugin identity associated with an MCP server declaration. +/// Effective enterprise managed settings and contributing channels. Session events report applied policy; sessionless resolve reports an account/device snapshot, and compose reports a non-applying preview of candidate documents. Device values take precedence over server values, then the policy helper, per ordinary key, while permissions compose restrictively. Session-local SDK-client policy is included only in session results. Marked experimental while the managed-settings surface stabilizes. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpSourcePlugin +public sealed class ManagedSettingsResolvedData { - /// Canonical plugin identity. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Whether an explicit enterprise policy restriction disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers; an unresolved policy does not force this on by itself. + [JsonPropertyName("bypassPermissionsDisabled")] + public bool BypassPermissionsDisabled { get; set; } - /// Human-readable plugin name, when available. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Whether a session-local permissions layer injected by the SDK host was present. + [JsonPropertyName("clientManaged")] + public bool? ClientManaged { get; set; } - /// Plugin version, when available. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("version")] - public string? Version { get; set; } + /// Whether an actual device MDM/plist/registry/file managed-settings layer was present. + [JsonPropertyName("deviceManaged")] + public bool DeviceManaged { get; set; } + + /// Whether managed policy could not be determined (e.g. a failed server fetch) and unresolved-policy safeguards remain active. This does not by itself disable bypass-permissions; `bypassPermissionsDisabled` reports only an explicit policy restriction. + [JsonPropertyName("failClosed")] + public bool FailClosed { get; set; } + + /// The setting keys under enterprise management in the effective managed settings (e.g. `model`, `enabledPlugins`, `permissions`). Empty when no managed settings are in force. + [JsonPropertyName("managedKeys")] + public IList ManagedKeys { get => field ??= []; set; } + + /// Whether at least two managed sources supplied permission allowlists, so enforcement intersects them and the flattened settings payload omits `permissions.allow`. + [JsonPropertyName("permissionsAllowIntersected")] + public bool? PermissionsAllowIntersected { get; set; } + + /// Reusable retained managed permission policy for managedSettings.permissions.evaluate, including source composition and session-local injection. Provided by live session snapshots; absent in older events. Refresh the context when managed policy changes. + [JsonPropertyName("permissionsContext")] + public ManagedPermissionsContext? PermissionsContext { get; set; } + + /// Whether the policy-helper managed-settings layer was present. The policy helper is the weakest channel: it fills keys no enterprise source set and can never replace one. + [JsonPropertyName("policyHelperManaged")] + public bool? PolicyHelperManaged { get; set; } + + /// Whether the effective sandbox policy forces the sandbox on *only* because managed policy could not be determined, rather than because the policy requires it. Lets clients tell a user whose `--no-sandbox` was overridden that the sandbox stayed on as a fail-closed fallback, instead of attributing it to an administrator who set no such policy. + [JsonPropertyName("sandboxEnabledByUndeterminedPolicy")] + public bool? SandboxEnabledByUndeterminedPolicy { get; set; } + + /// Whether the server (account/org) managed-settings layer was present. + [JsonPropertyName("serverManaged")] + public bool ServerManaged { get; set; } + + /// The effective (resolved) managed settings values, so clients can render exactly what is enforced. Absent when no managed policy is in force. + [JsonPropertyName("settings")] + public JsonElement? Settings { get; set; } + + /// Channel summary: `server`, `device`, `client`, or `policyHelper` when exactly one channel contributed; `mixed` when multiple channels contributed; otherwise `none`. Consult the per-channel booleans for exact provenance. + [JsonPropertyName("source")] + public ManagedSettingsResolvedSource Source { get; set; } } -/// Canonical identity and location of the effective MCP server declaration. The declaration is uniquely addressed by this source id together with the discovered server name. +/// Typed effective values of managed settings. Each field mirrors the managed-settings schema key of the same name; more keys are added as they are typed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpSourceRef +public sealed class ManagedSettingsValues { - /// Open semantic editability identifier. Known values are editable and read-only. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("editability")] - public string Editability { get; set; } = string.Empty; - - /// Configuration file location, when the declaration is file-backed. - [JsonPropertyName("file")] - public McpSourceFile? File { get; set; } + /// Managed Auto routing preference, used when the selected model is `auto`. + [JsonPropertyName("autoTier")] + public AutoTier? AutoTier { get; set; } - /// Opaque stable identity for the configuration source. Clients must not parse this value. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Managed context-tier default for the managed concrete model. + [JsonPropertyName("contextTier")] + public ContextTier? ContextTier { get; set; } - /// Open source-kind identifier. Known values include user, workspace, invocation, plugin, builtin, and device-registry. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("kind")] - public string Kind { get; set; } = string.Empty; + /// Managed reasoning-effort default for the managed concrete model. The runtime clamps it to an entitled effort when model availability is known. + [JsonPropertyName("effortLevel")] + public string? EffortLevel { get; set; } - /// Plugin identity, when the declaration is plugin-provided. - [JsonPropertyName("plugin")] - public McpSourcePlugin? Plugin { get; set; } + /// Managed default model identifier. When model availability was resolved, aliases and family names are projected to a concrete available model ID; otherwise the configured value is returned. + [JsonPropertyName("model")] + public string? Model { get; set; } } -/// MCP server discovered by `mcp.discover`, with config source, optional plugin source, transport type, and enabled state. +/// Effective enterprise managed settings for an account, resolved without a session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DiscoveredMcpServer +public sealed class ManagedSettingsResolveResult { - /// Canonical identity and location of the effective server declaration. - [JsonPropertyName("effectiveSource")] - public McpSourceRef? EffectiveSource { get; set; } + /// Printable opaque identity of the account the settings were resolved for, suitable for comparison and storage, not an account selectionId. Absent when no account was available, in which case only device policy is reported. + [JsonPropertyName("account")] + public string? Account { get; set; } - /// Whether the server is enabled (not in the disabled list). - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// Warnings about unavailable policy sources or a failed refresh served from cache. A cached response is not proof of a successful live fetch; `resolved.failClosed` separately describes enforcement. + [JsonPropertyName("diagnostics")] + public IList Diagnostics { get => field ??= []; set; } - /// Server name (config key). - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Each managed-settings channel consulted, strongest first, with the validated document it delivered before merging. `resolved.settings` is the merged result. More channels may be added over time. + [JsonPropertyName("layers")] + public IList Layers { get => field ??= []; set; } - /// Configuration source: user, workspace, plugin, or builtin. - [JsonPropertyName("source")] - public McpServerSource Source { get; set; } + /// Per-key lock state and provenance for the entries in `values`, using the same key names. + [JsonPropertyName("meta")] + public ManagedSettingsMeta? Meta { get; set; } - /// Plugin name that provided this server, when source is plugin. - [JsonPropertyName("sourcePlugin")] - public string? SourcePlugin { get; set; } + /// Reusable source-composed permission policy for managedSettings.permissions.evaluate. Unlike resolved.settings.permissions, this retains every source's allowlist and default-prompt semantics. Refresh through resolve when account/device policy changes. Absent on runtimes that do not support permission evaluation. + [JsonPropertyName("permissionsContext")] + public ManagedPermissionsContext? PermissionsContext { get; set; } - /// Plugin version that provided this server, when source is plugin. - [JsonPropertyName("sourcePluginVersion")] - public string? SourcePluginVersion { get; set; } + /// Effective managed settings from the device and account (server) channels, in the same shape as `session.managedSettings.get`, excluding session-local injection. + [JsonPropertyName("resolved")] + public ManagedSettingsResolvedData Resolved { get => field ??= new(); set; } - /// Server transport type: stdio, http, sse (deprecated), or memory. - [JsonPropertyName("type")] - public DiscoveredMcpServerType? Type { get; set; } + /// Typed effective values of managed settings, keyed like the managed-settings schema and already resolved across channels, with the `{ "overridable": ... }` wrapper removed. Present when policy sets at least one typed key. Keys not typed here are available in `resolved.settings`. + [JsonPropertyName("values")] + public ManagedSettingsValues? Values { get; set; } } -/// MCP servers discovered from user, workspace, plugin, and built-in sources. +/// RPC data type for ManagedSettingsResolve operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpDiscoverResult +internal sealed class ManagedSettingsResolveRequest { - /// MCP servers discovered from all sources. - [JsonPropertyName("servers")] - public IList Servers { get => field ??= []; set; } -} + /// Embedding client identity for server policy requests, as in session creation. Omit for the CLI identity. + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } -/// Optional working directory used as context for MCP server discovery. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpDiscoverRequest -{ - /// Whether to include canonical effectiveSource metadata for each discovered server. Callers must opt in so protocol-3 clients retain the legacy closed response shape. - [JsonPropertyName("includeEffectiveSource")] - public bool? IncludeEffectiveSource { get; set; } + /// GitHub token to resolve instead of the current account. The call fails when the token cannot be resolved. + [JsonPropertyName("gitHubToken")] + public string? GitHubToken { get; set; } - /// Working directory used as context for discovery (e.g., plugin resolution). + /// Opaque account identifier returned by `account.getAllUsers`. When omitted, the current account is used, or device policy only when no account is signed in. + [JsonPropertyName("selectionId")] + public string? SelectionId { get; set; } + + /// Working directory used to run an organization policy helper. When omitted, sessionless resolution does not run the helper. [JsonPropertyName("workingDirectory")] public string? WorkingDirectory { get; set; } } -/// Names of the MCP servers the runtime supplies itself. +/// The authoring JSON schema for managed settings recognized by this runtime. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpListBuiltinServerNamesResult +public sealed class ManagedSettingsSchemaResult { - /// Every built-in server name. A host disabling the built-ins wholesale suppresses exactly this set. - [JsonPropertyName("names")] - public IList Names { get => field ??= []; set; } + /// Version of the runtime that owns this schema. + [JsonPropertyName("runtimeVersion")] + public string RuntimeVersion { get; set; } = string.Empty; + + /// JSON schema (draft 2020-12) with descriptive shared `x-composition` annotations, not a complete runtime composition contract. Model, effortLevel, and contextTier remain coupled; use `managedSettings.compose` for the runtime's effective result. + [JsonPropertyName("schema")] + public JsonElement Schema { get; set; } } -/// Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by the request. +/// Result of validating a managed-settings document. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpShouldExcludeGitHubToolsResult +public sealed class ManagedSettingsValidateResult { - /// True only when both halves hold: the session's filters still reach the platform shell tool, and the host actually has the `gh` those tools would be replaced by. Feed it straight back as the `excludeGhReplaceableTools` build option. - [JsonPropertyName("excludeGhReplaceableTools")] - public bool ExcludeGhReplaceableTools { get; set; } + /// Errors that reject the document and warnings about content the runtime ignores. + [JsonPropertyName("diagnostics")] + public IList Diagnostics { get => field ??= []; set; } + + /// Canonical form of the document the runtime would apply, with unrecognized keys removed. Absent when the document is invalid. + [JsonPropertyName("settings")] + public JsonElement? Settings { get; set; } + + /// Whether the runtime would accept the document within the preview resource limits. Always equals whether `settings` is present. An invalid document is rejected as a whole. + [JsonPropertyName("valid")] + public bool Valid { get; set; } } -/// The session tool filters that decide whether the session still has a shell to run `gh` with. +/// A candidate managed-settings document to validate without applying it. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpShouldExcludeGitHubToolsRequest +internal sealed class ManagedSettingsValidateRequest { - /// The session's tool allowlist, when it set one. Omitted means the session constrains nothing this way. - [JsonPropertyName("availableTools")] - public IList? AvailableTools { get; set; } + /// The document to validate: a JSON object, or a string containing the document's JSON text. Preview documents are limited to 1 MiB and 64 levels of nesting, a stricter resource limit than delivered-policy parsing; violations are returned as diagnostics. + [JsonPropertyName("content")] + public JsonElement Content { get; set; } - /// The session's tool denylist, when it set one. Omitted means the session constrains nothing this way. - [JsonPropertyName("excludedTools")] - public IList? ExcludedTools { get; set; } + /// Channel the document is meant for (`device`, `server`, or `policyHelper`). Some keys are only honored in some channels; for example, a `policyHelper` registration is ignored in policy-helper output. When omitted, no channel-specific checks run. + [JsonPropertyName("layer")] + public string? Layer { get; set; } +} - /// How the allowlist and denylist combine when both are set. Omitted means the default every session gets, so a caller that never chose a precedence is answered as its sessions behave. - [JsonPropertyName("toolFilterPrecedence")] - public OptionsUpdateToolFilterPrecedence? ToolFilterPrecedence { get; set; } +/// The effective managed settings the runtime would enforce for the given documents, in the same shape `managedSettings.resolve` returns. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ManagedSettingsComposeResult +{ + /// Warnings about ignored content, with paths prefixed by the channel name. + [JsonPropertyName("diagnostics")] + public IList Diagnostics { get => field ??= []; set; } + + /// Only the supplied channels, strongest first, with canonical documents. Empty canonical documents are represented as absent settings, as in live resolution. + [JsonPropertyName("layers")] + public IList Layers { get => field ??= []; set; } + + /// Per-key lock state and provenance for `values`. + [JsonPropertyName("meta")] + public ManagedSettingsMeta? Meta { get; set; } + + /// Effective managed settings, in the same shape as `session.managedSettings.get`. + [JsonPropertyName("resolved")] + public ManagedSettingsResolvedData Resolved { get => field ??= new(); set; } + + /// Typed effective values, as in `managedSettings.resolve`. + [JsonPropertyName("values")] + public ManagedSettingsValues? Values { get; set; } } -/// Outcome of an mcp.planInstall call: either a normalised plan, or one typed refusal. Nothing is written in either case. -/// Polymorphic base type discriminated by kind. +/// One candidate channel; absent settings represents a channel that delivered no document. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ManagedSettingsComposeLayer +{ + /// Candidate managed-settings document. Omit when the channel delivered none, as in resolve output. + [JsonPropertyName("settings")] + public JsonElement? Settings { get; set; } + + /// The channel whose candidate document is being supplied. + [JsonPropertyName("source")] + public ManagedSettingsChannel Source { get; set; } +} + +/// Candidate managed-settings documents to merge without applying them. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ManagedSettingsComposeRequest +{ + /// One entry per channel. `source` must be `device`, `server`, or `policyHelper`, each at most once (checked at runtime); order does not matter, because channel precedence is fixed. To preview documents from resolve output, map recognized source strings to ManagedSettingsChannel and copy their settings; generated resolve and compose layer types are distinct. Omitted settings means this channel delivered no document. Supplied documents must be valid within the preview limits; warnings are returned in diagnostics. Compose does not reproduce source-failure state or retained enforcement floors from resolve. + [JsonPropertyName("layers")] + public IList Layers { get => field ??= []; set; } +} + +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( TypeDiscriminatorPropertyName = "kind", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpPlanInstallResultPlanned), "planned")] -[JsonDerivedType(typeof(McpPlanInstallResultNegotiationRefused), "negotiation-refused")] -[JsonDerivedType(typeof(McpPlanInstallResultHandleRejected), "handle-rejected")] -[JsonDerivedType(typeof(McpPlanInstallResultInvalidRequest), "invalid-request")] -[JsonDerivedType(typeof(McpPlanInstallResultAuthenticationRequired), "authentication-required")] -[JsonDerivedType(typeof(McpPlanInstallResultPolicyRejected), "policy-rejected")] -[JsonDerivedType(typeof(McpPlanInstallResultNetworkFailure), "network-failure")] -[JsonDerivedType(typeof(McpPlanInstallResultUnsafeRetrieval), "unsafe-retrieval")] -[JsonDerivedType(typeof(McpPlanInstallResultMalformedCard), "malformed-card")] -[JsonDerivedType(typeof(McpPlanInstallResultContractViolation), "contract-violation")] -[JsonDerivedType(typeof(McpPlanInstallResultUnavailableTransport), "unavailable-transport")] -[JsonDerivedType(typeof(McpPlanInstallResultNotInstallable), "not-installable")] -[JsonDerivedType(typeof(McpPlanInstallResultUnavailable), "unavailable")] -public partial class McpPlanInstallResult +[JsonDerivedType(typeof(ManagedPermissionOperationUrl), "url")] +public partial class ManagedPermissionOperation { /// The type discriminator. [JsonPropertyName("kind")] @@ -2325,2297 +2491,2178 @@ public partial class McpPlanInstallResult } -/// The protocol version and capability set the runtime actually honoured for a successful catalog operation. +/// The url variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CatalogNegotiatedContract +public partial class ManagedPermissionOperationUrl : ManagedPermissionOperation { - /// Wire features the runtime understood for this operation. Includes the five original catalog capabilities and only explicitly requested supported additions, in supported order without duplicates. Capabilities that introduce new success-union variants or operations are therefore included only when explicitly required, preserving older protocol-v3 clients. Always a superset of the caller's required features, because any shortfall is a refusal instead. Operation availability remains a separate typed result. - [JsonPropertyName("grantedCapabilities")] - public IList GrantedCapabilities { get => field ??= []; set; } + /// + [JsonIgnore] + public override string Kind => "url"; - /// Protocol version of the runtime that served the request. - [JsonPropertyName("runtimeProtocolVersion")] - public long RuntimeProtocolVersion { get; set; } + /// Absolute HTTP(S) URL with a host. Invalid URLs reject the entire evaluation batch. + [JsonPropertyName("url")] + public required string Url { get; set; } } -/// The configuration-change alternative for the transportChoices entry at the same index. Only the selected alternative is applied; entries are not cumulative. The payload stays behind the runtime boundary. +/// RPC data type for ManagedPermissionEvaluation operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPlanConfigurationChange +public sealed class ManagedPermissionEvaluation { - /// Names of the configuration fields the change would set, without their values. - [JsonPropertyName("changedFields")] - public IList ChangedFields { get => field ??= []; set; } - - /// Configuration key the change applies to. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("configKey")] - public string ConfigKey { get; set; } = string.Empty; - - /// Whether the change would create a new entry or modify an existing one. + /// Original input operation associated with this verdict. [JsonPropertyName("operation")] - public McpPlanConfigurationOperation Operation { get; set; } - - /// Scope the change would be written to. - [JsonPropertyName("scope")] - public McpPlanScope Scope { get; set; } + public ManagedPermissionOperation Operation { get => field ??= new(); set; } - /// Secret placeholders the written configuration would reference. The constrained placeholder type cannot carry a literal secret value. - [JsonPropertyName("secretReferences")] - public IList SecretReferences { get => field ??= []; set; } + /// Managed-policy decision only; never bypasses user permissions or other security controls. + [JsonPropertyName("verdict")] + public ManagedPermissionVerdict Verdict { get; set; } } -/// Normalised identity of the MCP server a plan targets, independent of how the card spelled it. +/// Ordered managed permission verdicts and the supplied policy's fail-closed posture. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPlanResourceIdentity +public sealed class ManagedSettingsPermissionsEvaluateResult { - /// Canonical, normalised name of the server, for example `io.github.owner/server`. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("canonicalName")] - public string CanonicalName { get; set; } = string.Empty; - - /// Registry identifier of the server, when it came from a registry. - [JsonPropertyName("registryId")] - public string? RegistryId { get; set; } - - /// Local configuration key the server would be recorded under. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Managed permission policy could not be determined; every operation is denied. + [JsonPropertyName("failClosed")] + public bool FailClosed { get; set; } - /// Version advertised by the card, when it declares one. - [JsonPropertyName("version")] - public string? Version { get; set; } + /// One verdict per input operation, in the same order, including duplicates. + [JsonPropertyName("results")] + public IList Results { get => field ??= []; set; } } -/// Outcome of evaluating the planned server against registry and enterprise policy. Evaluation is read-only. +/// Managed policy context and ordered operations for pure, sessionless evaluation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPlanPolicyResult +internal sealed class ManagedSettingsPermissionsEvaluateRequest { - /// What policy decided for this server. - [JsonPropertyName("decision")] - public McpPlanPolicyDecision Decision { get; set; } - - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("reason")] - public string? Reason { get; set; } + /// Trusted, reusable managed permission policy snapshot; no policy is discovered during evaluation. + [JsonPropertyName("context")] + public ManagedPermissionsContext Context { get; set; } = null!; - /// Which authority produced the decision. - [JsonPropertyName("source")] - public McpPlanPolicySource Source { get; set; } + /// Operations to evaluate, preserving input order and duplicates. An empty batch is valid. + [JsonPropertyName("operations")] + public IList Operations { get => field ??= []; set; } } -/// Semantic digest of a strictly parsed and schema-validated JSON MCP card. Both URL-backed and embedded cards are canonicalised with RFC 8785 JSON Canonicalization Scheme, encoded as UTF-8, and hashed with SHA-256. +/// Hosting capabilities and session capacity advertised by an environment. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CardDigest +public sealed class EnvironmentCapabilities { - /// Digest algorithm and canonical representation. - [JsonPropertyName("algorithm")] - public CardDigestAlgorithm Algorithm { get; set; } + /// Advertised Agent Host Protocol version. + [JsonPropertyName("ahpVersion")] + public string? AhpVersion { get; set; } - /// SHA-256 digest of the RFC 8785 canonical UTF-8 bytes, encoded as exactly 64 lowercase hexadecimal characters. - [RegularExpression("^[0-9a-f]{64}$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(64)] - [MaxLength(64)] - [JsonPropertyName("value")] - public string Value { get; set; } = string.Empty; + /// Current session count, when advertised. + [JsonPropertyName("currentSessions")] + public long? CurrentSessions { get; set; } + + /// Feature identifiers advertised by the environment. + [JsonPropertyName("features")] + public IList Features { get => field ??= []; set; } + + /// Maximum session capacity, when advertised. + [JsonPropertyName("maxSessions")] + public long? MaxSessions { get; set; } } -/// Provenance of the exact validated JSON MCP card content bound privately to a completed plan and its opaque handle. +/// Safe discovery information. Host-side relay bootstrap credentials are never included. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPlanProvenance +public sealed class GitHubEnvironment { - /// Authority associated with the validated card, without path, query, or credentials. Inert untrusted data. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("authority")] - public string Authority { get; set; } = string.Empty; + /// Hosting capabilities advertised by the environment. + [JsonPropertyName("capabilities")] + public EnvironmentCapabilities? Capabilities { get; set; } - /// Semantic digest of the exact validated JSON content bound to the plan handle. - [JsonPropertyName("cardDigest")] - public CardDigest CardDigest { get => field ??= new(); set; } + /// Identifier assigned by Mission Control. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// JSON MCP media type the validated card was interpreted as. - [JsonPropertyName("mediaType")] - public McpServerCardMediaType MediaType { get; set; } + /// Compute kind reported by Mission Control. + [JsonPropertyName("kind")] + public EnvironmentKind Kind { get; set; } - /// ISO 8601 timestamp at which the runtime completed strict parsing and schema validation of the card content. - [JsonPropertyName("validatedAt")] - public string ValidatedAt { get; set; } = string.Empty; -} + /// Discovery labels attached to the environment. + [JsonPropertyName("labels")] + public IDictionary? Labels { get; set; } -/// Where a plan would be written. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPlanTarget -{ - /// Configuration key the server would be recorded under within that scope. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("configKey")] - public string ConfigKey { get; set; } = string.Empty; + /// Timestamp of the last heartbeat received by Mission Control. + [JsonPropertyName("lastHeartbeatAt")] + public string? LastHeartbeatAt { get; set; } - /// Configuration scope the plan targets. - [JsonPropertyName("scope")] - public McpPlanScope Scope { get; set; } + /// Human-readable environment name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Organization identifier, when the environment belongs to an organization. + [JsonPropertyName("orgId")] + public string? OrgId { get; set; } + + /// Identifier of the environment owner. + [JsonPropertyName("ownerId")] + public string? OwnerId { get; set; } + + /// Owner category reported by Mission Control. + [JsonPropertyName("ownerType")] + public string? OwnerType { get; set; } + + /// Open-ended operational status vocabulary. + [JsonPropertyName("status")] + public string Status { get; set; } = string.Empty; } -/// One eligible way to run the server, represented as a tagged package or remote variant so package identity and endpoint states cannot contradict the install method. -/// Polymorphic base type discriminated by installMethod. +/// Environments visible to the authenticated caller and matching the supplied filters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "installMethod", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpPlanTransportChoicePackage), "package")] -[JsonDerivedType(typeof(McpPlanTransportChoiceRemote), "remote")] -public partial class McpPlanTransportChoice +public sealed class EnvironmentsListResult { - /// The type discriminator. - [JsonPropertyName("installMethod")] - public virtual string InstallMethod { get; set; } = string.Empty; + /// Safe discovery records without relay bootstrap credentials. + [JsonPropertyName("environments")] + public IList Environments { get => field ??= []; set; } } - -/// One non-secret value a transport choice needs, represented as a scalar or enumerated variant so enum values cannot be missing or attached to another type. -/// Polymorphic base type discriminated by kind. +/// Optional discovery filters supported by GitHub Mission Control. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpPlanRequiredValueScalar), "scalar")] -[JsonDerivedType(typeof(McpPlanRequiredValueEnum), "enum")] -public partial class McpPlanRequiredValue +internal sealed class EnvironmentsListRequest { - /// The type discriminator. + /// Restrict discovery to this compute kind. [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + public EnvironmentKind? Kind { get; set; } + /// Operational status, such as online, offline, degraded, waking, or draining. + [JsonPropertyName("status")] + public string? Status { get; set; } +} -/// One non-secret scalar value a transport choice needs before it can be applied. -/// The scalar variant of . +/// Safe discovery information for the requested environment. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanRequiredValueScalar : McpPlanRequiredValue +public sealed class EnvironmentsGetResult { - /// - [JsonIgnore] - public override string Kind => "scalar"; - - /// Where the value is applied when the server is launched. - [JsonPropertyName("category")] - public required McpPlanValueCategory Category { get; set; } - - /// Default supplied by the card, when the value can be resolved without input. Presence is the authoritative indication that a default exists. Inert untrusted data. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("defaultValue")] - public string? DefaultValue { get; set; } - - /// Human-readable explanation from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } + /// The requested environment without relay bootstrap credentials. + [JsonPropertyName("environment")] + public GitHubEnvironment Environment { get => field ??= new(); set; } +} - /// Whether the value may be supplied more than once. - [JsonPropertyName("isRepeated")] - public required bool IsRepeated { get; set; } +/// Identify a Mission Control environment to retrieve. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class EnvironmentsGetRequest +{ + /// Identifier assigned by Mission Control. + [JsonPropertyName("environmentId")] + public string EnvironmentId { get; set; } = string.Empty; +} - /// Key the value is supplied under. Inert untrusted data. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("key")] - public required string Key { get; set; } +/// Acknowledgement that the requested environment was deleted. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class EnvironmentsDeleteResult +{ +} - /// Whether the value must be present for the plan to be applicable. - [JsonPropertyName("required")] - public required bool Required { get; set; } +/// Identify a user-managed Mission Control environment to delete. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class EnvironmentsDeleteRequest +{ + /// User-managed environment to delete. GitHub-managed environments cannot be deleted. + [JsonPropertyName("environmentId")] + public string EnvironmentId { get; set; } = string.Empty; +} - /// Human-readable label from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(200)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("title")] - public string? Title { get; set; } +/// The existing runtime identity and its resource on the listener. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class HostPublishSessionResult +{ + /// Canonical runtime ID of the published session. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// Scalar type the value must conform to. - [JsonPropertyName("valueType")] - public required McpPlanScalarValueType ValueType { get; set; } + /// AHP resource URI for the session on this listener. + [JsonPropertyName("sessionUri")] + public string SessionUri { get; set; } = string.Empty; } -/// One enumerated non-secret value a transport choice needs before it can be applied. The permitted values are structurally required. -/// The enum variant of . +/// Publishes a resident session attached to the listener's owning connection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanRequiredValueEnum : McpPlanRequiredValue +internal sealed class HostPublishSessionRequest { - /// - [JsonIgnore] - public override string Kind => "enum"; - - /// Where the value is applied when the server is launched. - [JsonPropertyName("category")] - public required McpPlanValueCategory Category { get; set; } + /// Listener UUID returned by host.start. + [JsonPropertyName("hostId")] + public string HostId { get; set; } = string.Empty; - /// Default supplied by the card, when the value can be resolved without input. Presence is the authoritative indication that a default exists. Inert untrusted data. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("defaultValue")] - public string? DefaultValue { get; set; } + /// Canonical runtime session ID attached to the listener's owning connection. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Human-readable explanation from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } +/// Metadata advertised by the AHP host, not a guarantee that history can be resumed. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class HostSessionSummary +{ + /// Optional activity description advertised by the host. + [JsonPropertyName("activity")] + public string? Activity { get; set; } - /// Non-empty permitted value set. Inert untrusted data. - [JsonPropertyName("enumValues")] - public required IList EnumValues { get; set; } + /// Session creation time as an ISO 8601 timestamp. + [JsonPropertyName("createdAt")] + public string CreatedAt { get; set; } = string.Empty; - /// Whether the value may be supplied more than once. - [JsonPropertyName("isRepeated")] - public required bool IsRepeated { get; set; } + /// Last modification time as an ISO 8601 timestamp. + [JsonPropertyName("modifiedAt")] + public string ModifiedAt { get; set; } = string.Empty; - /// Key the value is supplied under. Inert untrusted data. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("key")] - public required string Key { get; set; } + /// Stable AHP resource URI identifying the session on this host. + [JsonPropertyName("resource")] + public string Resource { get; set; } = string.Empty; - /// Whether the value must be present for the plan to be applicable. - [JsonPropertyName("required")] - public required bool Required { get; set; } + /// Unsigned 32-bit AHP session status bitset (0..=4294967295); unknown bits must be preserved. + [JsonPropertyName("status")] + public long Status { get; set; } - /// Human-readable label from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(200)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + /// Authoritative title advertised by the host. [JsonPropertyName("title")] - public string? Title { get; set; } - - /// Discriminator: the value must be one of `enumValues`. - [JsonPropertyName("valueType")] - public required McpPlanEnumValueType ValueType { get; set; } + public string Title { get; set; } = string.Empty; } -/// A secret a transport choice needs, referenced by placeholder. No secret value ever appears in a plan, and the placeholder resolves against the keychain only when a plan is applied. +/// The complete live and dormant advertised catalog, without subscribing to sessions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPlanSecretPlaceholder +public sealed class HostListSessionsResult { - /// Key the secret is supplied under. Inert untrusted data. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("key")] - public string Key { get; set; } = string.Empty; - - /// The runtime-assigned `${secret:<id>}` placeholder written into configuration in place of the value. - [JsonPropertyName("placeholder")] - public string Placeholder { get; set; } = string.Empty; - - /// Human-readable label from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(200)] - [JsonPropertyName("title")] - public string? Title { get; set; } + /// Complete advertised session summaries, in the host's catalog order. + [JsonPropertyName("sessions")] + public IList Sessions { get => field ??= []; set; } } -/// An eligible local-package transport choice. Package identity is required and a remote endpoint cannot be represented. -/// The package variant of . +/// Reads a running host's catalog or the runtime's saved default catalog. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanTransportChoicePackage : McpPlanTransportChoice +internal sealed class HostListSessionsRequest { - /// - [JsonIgnore] - public override string InstallMethod => "package"; + /// + /// Listener UUID returned by host.start; the caller must own it. Omit to read + /// the saved default compute-identity catalog without starting a listener. + /// + [JsonPropertyName("hostId")] + public string? HostId { get; set; } +} - /// Stable identifier for this choice within the plan, used to select it when the plan is applied. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(128)] - [JsonPropertyName("choiceId")] - public required string ChoiceId { get; set; } +/// The resident session the application has materialized on its own connection. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class HostCreateSessionResult +{ + /// Runtime session UUID materialized on the application's SDK connection. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Package identifier. Inert untrusted data. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(512)] - [JsonPropertyName("packageIdentifier")] - public required string PackageIdentifier { get; set; } +/// One application-owned session handoff, requested by the supervised hosting participant. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class HostCreateSessionRequest +{ + /// Host-selected SDK creation or resume settings, without executable callbacks or tools. + [JsonPropertyName("config")] + public IDictionary Config { get => field ??= new Dictionary(); set; } - /// Packaging ecosystem, for example `oci` or `npm`. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(64)] - [JsonPropertyName("packageType")] - public required string PackageType { get; set; } + /// Unique identity for this participation, independent of the session lifetime. + [JsonPropertyName("handoffId")] + public string HandoffId { get; set; } = string.Empty; - /// Typed values this choice requires, excluding secrets. - [JsonPropertyName("requiredValues")] - public required IList RequiredValues { get; set; } + /// + /// For an explicit publication, borrow an existing owning-connection resident + /// instead of invoking the resume factory. Cold sessions still use the factory. + /// + [JsonPropertyName("preferResident")] + public bool? PreferResident { get; set; } - /// Secrets this choice requires, referenced by placeholder only. - [JsonPropertyName("secretPlaceholders")] - public required IList SecretPlaceholders { get; set; } + /// Resume an app-owned durable session instead of creating a new session. + [JsonPropertyName("resume")] + public bool? Resume { get; set; } +} - /// Local process transport this package choice would use. - [JsonPropertyName("transport")] - public required McpPlanPackageTransport Transport { get; set; } +/// Empty acknowledgement for a completed host lifecycle operation. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class HostReleaseSessionResult +{ } -/// An eligible remote-endpoint transport choice. The endpoint is required and package identity cannot be represented. -/// The remote variant of . +/// Ends one participation, not the application's session lifetime. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanTransportChoiceRemote : McpPlanTransportChoice +internal sealed class HostReleaseSessionRequest { - /// - [JsonIgnore] - public override string InstallMethod => "remote"; + /// Identity of the participation to release without destroying the session. + [JsonPropertyName("handoffId")] + public string HandoffId { get; set; } = string.Empty; +} - /// Stable identifier for this choice within the plan, used to select it when the plan is applied. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(128)] - [JsonPropertyName("choiceId")] - public required string ChoiceId { get; set; } +/// Listener readiness, returned only after binding and the supervised participant's SDK handshake. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class HostStartResult +{ + /// GitHub Mission Control environment ID, present when its relay transport is ready. + [JsonPropertyName("environmentId")] + public string? EnvironmentId { get; set; } - /// Endpoint URL. Inert untrusted data. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(2048)] - [JsonPropertyName("endpoint")] - public required string Endpoint { get; set; } + /// Caller-generated listener UUID. + [JsonPropertyName("hostId")] + public string HostId { get; set; } = string.Empty; - /// Typed values this choice requires, excluding secrets. - [JsonPropertyName("requiredValues")] - public required IList RequiredValues { get; set; } + /// Separate host process ID, when provided by a legacy runtime. Absent for in-process listeners. + [JsonPropertyName("pid")] + public long? Pid { get; set; } - /// Secrets this choice requires, referenced by placeholder only. - [JsonPropertyName("secretPlaceholders")] - public required IList SecretPlaceholders { get; set; } + /// Secret connection token, absent when authentication is disabled. + [JsonPropertyName("token")] + public string? Token { get; set; } - /// Endpoint transport this remote choice would use. - [JsonPropertyName("transport")] - public required McpPlanRemoteTransport Transport { get; set; } + /// Actual bound WebSocket URL, including the allocated port. + [JsonPropertyName("url")] + public string? Url { get; set; } } -/// A normalised, inert description of what installing an MCP server would involve. Carries no raw card, no install specification, and no secret value. +/// GitHub Mission Control registration options. The compute ID is application-owned and stable. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpInstallPlan +public sealed class HostGitHubEnvironmentOptions { - /// Alternative configuration changes, with exactly one entry for each transportChoices entry in the same order. Only the entry for the subsequently selected transport applies; these are not cumulative writes. Payloads remain behind the runtime boundary. - [JsonPropertyName("configurationChanges")] - public IList ConfigurationChanges { get => field ??= []; set; } + /// Stable application installation identity, reused across host restarts. + [JsonPropertyName("computeId")] + public string ComputeId { get; set; } = string.Empty; - /// Normalised identity of the server the plan would install. - [JsonPropertyName("identity")] - public McpPlanResourceIdentity Identity { get => field ??= new(); set; } + /// Human-readable environment display name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Opaque, runtime-instance scoped, TTL-bound, single-use handle for this plan. Rejected when stale, replayed, or presented to a different runtime instance. Never logged. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("planHandle")] - public string PlanHandle { get; set; } = string.Empty; + /// Require sealed, connection-bound authentication (default true), independent of listener address. False permits unsealed direct credentials and unbound sealed relay credentials; use only when the caller fully controls and trusts the direct transport. Relay token encryption remains mandatory. + [JsonPropertyName("requireConnectionBinding")] + public bool? RequireConnectionBinding { get; set; } +} - /// ISO 8601 timestamp after which the plan handle is stale and will be rejected. Abandoning a plan needs no call: an unused handle simply expires, so cancellation before commit is side-effect free. - [JsonPropertyName("planHandleExpiresAt")] - public string PlanHandleExpiresAt { get; set; } = string.Empty; +/// Local WebSocket transport options. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class HostLocalServerOptions +{ + /// Listener hostname. Defaults to 127.0.0.1; explicit non-loopback binds are allowed. + [JsonPropertyName("hostname")] + public string? Hostname { get; set; } - /// Outcome of evaluating the server against registry and enterprise policy. - [JsonPropertyName("policy")] - public McpPlanPolicyResult Policy { get => field ??= new(); set; } + /// Listener port. Omitted or zero requests an OS-allocated port. + [JsonPropertyName("port")] + public int? Port { get; set; } - /// Origin and semantic digest of the exact validated JSON MCP card content bound to this plan. - [JsonPropertyName("provenance")] - public McpPlanProvenance Provenance { get => field ??= new(); set; } + /// Require token authentication (default true). Cannot be false with a token. + [JsonPropertyName("requireConnectionToken")] + public bool? RequireConnectionToken { get; set; } - /// Identifier of the choice the runtime would pick by default. Omitted when there is no eligible transport, or when the runtime expresses no preference. - [JsonPropertyName("recommendedTransportChoiceId")] - public string? RecommendedTransportChoiceId { get; set; } + /// Nonempty connection token. Generated randomly when required and omitted. + [JsonPropertyName("token")] + public string? Token { get; set; } +} - /// Whether applying this plan would require an MCP reload to take effect. Planning itself never reloads. - [JsonPropertyName("reloadRequired")] - public bool ReloadRequired { get; set; } +/// Starts a supervised AHP host with at least one explicitly selected transport. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class HostStartRequest +{ + /// Stable application identity selecting its durable host catalog. Defaults to the persisted runtime compute GUID; must agree with githubEnvironment.computeId when both are supplied. + [JsonPropertyName("computeId")] + public string? ComputeId { get; set; } - /// True only when every eligible transport choice needs additional values or secrets. False means at least one choice needs no additional configuration, not that every choice is ready. A later apply operation must validate the selected choice's own inputs, secrets and policy after explicit confirmation. - [JsonPropertyName("requiresInteractiveConfiguration")] - public bool RequiresInteractiveConfiguration { get; set; } + /// Registers a GitHub Mission Control environment and enables its relay transport. + [JsonPropertyName("githubEnvironment")] + public HostGitHubEnvironmentOptions? GitHubEnvironment { get; set; } - /// Configuration scope and key the plan would write to. - [JsonPropertyName("target")] - public McpPlanTarget Target { get => field ??= new(); set; } + /// Caller-generated UUID identifying this connection-owned listener. + [JsonPropertyName("hostId")] + public required string HostId { get; set; } - /// Every eligible transport, so a host can present an explicit choice. A completed plan always has at least one; when none is eligible, planning returns `CatalogUnavailableTransportError` instead. - [JsonPropertyName("transportChoices")] - public IList TransportChoices { get => field ??= []; set; } + /// Enables a local WebSocket listener. + [JsonPropertyName("localServer")] + public HostLocalServerOptions? LocalServer { get; set; } + + /// Ask the owning application to resume its durable AHP sessions. + [JsonPropertyName("resumeFactory")] + public bool? ResumeFactory { get; set; } + + /// Ask the owning SDK application to materialize AHP sessions. + [JsonPropertyName("sessionFactory")] + public bool? SessionFactory { get; set; } } -/// A computed MCP install plan. Nothing has been applied: the plan describes what installing would change, and the plan handle is what a later apply operation would consume. -/// The planned variant of . +/// Empty acknowledgement for a completed host lifecycle operation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultPlanned : McpPlanInstallResult +public sealed class HostDisposeResult { - /// - [JsonIgnore] - public override string Kind => "planned"; - - /// Protocol version and capabilities the runtime honoured. - [JsonPropertyName("negotiated")] - public required CatalogNegotiatedContract Negotiated { get; set; } +} - /// The normalised plan. - [JsonPropertyName("plan")] - public required McpInstallPlan Plan { get; set; } +/// Stops a connection-owned listener and joins its teardown. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class HostDisposeRequest +{ + /// Listener UUID. Unknown or successfully stopped IDs are harmless. + [JsonPropertyName("hostId")] + public string HostId { get; set; } = string.Empty; } -/// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. -/// The negotiation-refused variant of . +/// Private credentials delivered only to a runtime-owned Mission Control hosting participant. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultNegotiationRefused : McpPlanInstallResult +internal sealed class HostGetEnvironmentCredentialsResult { - /// - [JsonIgnore] - public override string Kind => "negotiation-refused"; + /// GitHub API base URL for the authenticated service. + [JsonPropertyName("githubApiUrl")] + public string GitHubApiUrl { get; set; } = string.Empty; - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Hostname of the authenticated GitHub service. + [JsonPropertyName("githubHost")] + public string GitHubHost { get; set; } = string.Empty; - /// Lowest caller protocol version this runtime will serve. - [JsonPropertyName("minimumSupportedProtocolVersion")] - public required long MinimumSupportedProtocolVersion { get; set; } + /// Mission Control API origin for environment registration and management. + [JsonPropertyName("missionControlUrl")] + public string MissionControlUrl { get; set; } = string.Empty; - /// Whether the version or the capability set was the problem. - [JsonPropertyName("reason")] - public required CatalogNegotiationRefusedReason Reason { get; set; } + /// Current bearer token for the authenticated GitHub identity. + [JsonPropertyName("token")] + public string Token { get; set; } = string.Empty; +} - /// Protocol version of the runtime that refused the request. - [JsonPropertyName("runtimeProtocolVersion")] - public required long RuntimeProtocolVersion { get; set; } +/// Normalized local WebSocket listener settings. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class HostLocalServerConfiguration +{ + /// Hostname or IP address to bind. + [JsonPropertyName("hostname")] + public string Hostname { get; set; } = string.Empty; - /// Capabilities this runtime can safely advertise to this caller. The complete five-capability protocol-3 legacy set is always present; every capability added after that baseline appears only when the caller required it, so an older closed-enum decoder can still consume a refusal. This list does not imply that every deployment has enabled every operation. - [JsonPropertyName("supportedCapabilities")] - public required IList SupportedCapabilities { get; set; } + /// Port to bind, with zero requesting OS allocation. + [JsonPropertyName("port")] + public int Port { get; set; } - /// The subset of the caller's bounded extensible capability identifiers this runtime cannot honour. - [JsonPropertyName("unsupportedCapabilities")] - public required IList UnsupportedCapabilities { get; set; } + /// Whether the listener requires token authentication. + [JsonPropertyName("requireConnectionToken")] + public bool RequireConnectionToken { get; set; } + + /// Secret connection token, absent when authentication is disabled. + [JsonPropertyName("token")] + public string? Token { get; set; } } -/// A presented handle was not accepted. Handles are runtime-instance scoped, TTL-bound, and single-use, so each way of failing is reported distinctly. -/// The handle-rejected variant of . +/// Normalized listener settings delivered only to the supervised hosting participant. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultHandleRejected : McpPlanInstallResult +internal sealed class HostGetConfigurationResult { - /// - [JsonIgnore] - public override string Kind => "handle-rejected"; + /// Requested GitHub Mission Control registration. + [JsonPropertyName("githubEnvironment")] + public HostGitHubEnvironmentOptions? GitHubEnvironment { get; set; } - /// Which kind of handle was presented. - [JsonPropertyName("handleType")] - public required CatalogHandleType HandleType { get; set; } + /// Normalized local listener settings, absent for relay-only hosts. + [JsonPropertyName("localServer")] + public HostLocalServerConfiguration? LocalServer { get; set; } - /// Human-readable explanation, safe to surface. Never contains the handle itself, nor a query, URL, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Whether app-owned durable sessions are resumed by the owning application. + [JsonPropertyName("resumeFactory")] + public bool ResumeFactory { get; set; } - /// Why the handle was rejected. - [JsonPropertyName("reason")] - public required CatalogHandleRejectionReason Reason { get; set; } + /// Whether session materialization is delegated to the owning application. + [JsonPropertyName("sessionFactory")] + public bool SessionFactory { get; set; } } -/// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. -/// The invalid-request variant of . +/// Empty acknowledgement for a completed host lifecycle operation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultInvalidRequest : McpPlanInstallResult +internal sealed class HostReadyResult { - /// - [JsonIgnore] - public override string Kind => "invalid-request"; - - /// Which request field was rejected. - [JsonPropertyName("field")] - public required CatalogInvalidRequestField Field { get; set; } - - /// Human-readable explanation, safe to surface. Never echoes the offending value, nor a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } } -/// An optional catalog authentication exchange did not establish the caller's identity. Anonymous search remains supported; this refusal is reserved for an operation that cannot continue after the attempted exchange. It is distinct from `policy-rejected` and from a network failure, and the reason identifies the recovery action. -/// The authentication-required variant of . +/// Readiness reported by the supervised hosting participant on its own SDK connection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultAuthenticationRequired : McpPlanInstallResult +internal sealed class HostReadyRequest { - /// - [JsonIgnore] - public override string Kind => "authentication-required"; + /// Actual bound WebSocket URL. + [JsonPropertyName("address")] + public string? Address { get; set; } - /// Human-readable explanation, safe to surface. Never contains a credential or token, nor a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Registered environment ID, reported only once the relay transport is connected. + [JsonPropertyName("environmentId")] + public string? EnvironmentId { get; set; } - /// Why authentication failed. Only an expired credential justifies attempting a silent refresh; an absent or rejected credential requires sign-in. - [JsonPropertyName("reason")] - public required CatalogAuthenticationRequiredReason Reason { get; set; } + /// Configured secret token, absent when authentication is disabled. + [JsonPropertyName("token")] + public string? Token { get; set; } } -/// Registry or enterprise policy refused the operation. -/// The policy-rejected variant of . +/// One server-discovered hook action from user, repository, plugin, or managed-policy configuration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultPolicyRejected : McpPlanInstallResult +public sealed class DiscoveredHook { - /// - [JsonIgnore] - public override string Kind => "policy-rejected"; + /// Durable content hash used by hook enablement. Identical actions may intentionally share this key. Omitted when changing the user's disabled-hooks setting cannot change the action's current server-discovered state, including managed-policy hooks, session-start prompt actions, actions suppressed by disable-all settings, and projectless plugin actions that require project-directory expansion. + [JsonPropertyName("disableKey")] + public string? DisableKey { get; set; } - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Whether this action is enabled under the server-side discovery settings. Concrete sessions may differ because they can add session-specific directories, plugins, or trust. False when its disable key is present in the user's disabled-hooks setting or disable-all settings suppress the action. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } - /// Which authority produced the decision. + /// Hook event that invokes this action. + [JsonPropertyName("hookType")] + public HookType HookType { get; set; } + + /// Deterministic identifier for this server-discovered action row. It remains stable while the project, origin, source, event, action content, and duplicate ordinal are unchanged. This is row identity, not the key persisted in disabledHooks. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + /// Configuration tier that contributed this hook action. + [JsonPropertyName("origin")] + public HookOrigin Origin { get; set; } + + /// Input project path for which this server-side action was resolved. Set on every row returned for project-scoped discovery, including repeated user and policy actions. + [JsonPropertyName("projectPath")] + public string? ProjectPath { get; set; } + + /// Human-readable source label, such as a hook file path, settings source, or plugin name. [JsonPropertyName("source")] - public required McpPlanPolicySource Source { get; set; } + public string? Source { get; set; } } -/// The runtime could not reach the catalog authority or retrieve a card. Covers being offline as well as transport-level failure. -/// The network-failure variant of . +/// Server-discovered hook actions and partial-load diagnostics from user, repository, plugin, and managed-policy sources. Concrete sessions may include additional session-specific hook sources. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultNetworkFailure : McpPlanInstallResult +public sealed class HooksDiscoverResult { - /// - [JsonIgnore] - public override string Kind => "network-failure"; - - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } - - /// Categorised failure, low cardinality so it can be aggregated without carrying a URL. - [JsonPropertyName("reason")] - public required CatalogNetworkFailureReason Reason { get; set; } + /// Errors for hook sources or actions that could not be loaded, making the result partially incomplete. Other valid actions are still returned. Project-resolution and repository-settings errors are prefixed with their project path. + [JsonPropertyName("errors")] + public IList Errors { get => field ??= []; set; } - /// Bounded cooldown in seconds before another catalog request should be attempted, when the authority supplied a numeric Retry-After value or the runtime applied its documented fallback. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("retryAfterSeconds")] - public int? RetryAfterSeconds { get; set; } + /// All discovered hook actions. Byte-identical actions remain separate rows even when they share a disable key. + [JsonPropertyName("hooks")] + public IList Hooks { get => field ??= []; set; } - /// HTTP status code, when the failure was a rejected response. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("statusCode")] - public int? StatusCode { get; set; } + /// Non-fatal source-loading warnings. Discovery remains complete for the affected source, although the source had a recoverable issue. Repository-settings warnings are prefixed with their project path when attribution is available. + [JsonPropertyName("warnings")] + public IList Warnings { get => field ??= []; set; } } -/// Retrieval was refused by the runtime's hardened fetch boundary before any request left the process, or before a redirect was followed. -/// The unsafe-retrieval variant of . +/// Optional project paths and host-exclusion behavior for server-scoped hook discovery. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultUnsafeRetrieval : McpPlanInstallResult +public sealed class HooksDiscoverRequest { - /// - [JsonIgnore] - public override string Kind => "unsafe-retrieval"; + /// When true, omit host-owned user and plugin hook rows and their diagnostics. Managed-policy hooks and trusted repository hooks remain visible, and host disabledHooks still contribute to each remaining row's effective enabled state. This filters sources rather than simulating a host with no settings. + [JsonPropertyName("excludeHostHooks")] + public bool? ExcludeHostHooks { get; set; } - /// Human-readable explanation, safe to surface. Never contains the refused URL, nor a query, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without ambient discovery or repository file-hook enablement, subject to managed/hook disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + [JsonPropertyName("hookDirectories")] + public IList? HookDirectories { get; set; } - /// Which control refused the retrieval, low cardinality so it can be aggregated without carrying a URL. - [JsonPropertyName("reason")] - public required CatalogUnsafeRetrievalReason Reason { get; set; } + /// Optional project directory paths whose trusted repository and project-expanded plugin hooks should be discovered. When omitted or empty, user, managed-policy, and globally enabled installed or explicit plugin hooks are returned without project expansion. + [JsonPropertyName("projectPaths")] + public IList? ProjectPaths { get; set; } } -/// A card could not be parsed or did not satisfy its declared media type's schema. -/// The malformed-card variant of . +/// Active server-driven promotion for a model, including its discount and optional expiry. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultMalformedCard : McpPlanInstallResult +public sealed class ModelBillingPromo { - /// - [JsonIgnore] - public override string Kind => "malformed-card"; + /// Percentage discount (0-100) applied while the promotion is active. May be fractional. + [JsonPropertyName("discountPercent")] + public double? DiscountPercent { get; set; } - /// Media type the card was interpreted as, when it declared one this runtime recognises. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("mediaType")] - public CatalogMediaType? MediaType { get; set; } + /// UTC ISO 8601 timestamp marking when the promotion ends. Optional: an open-ended promotion omits this field. When present, the API only surfaces a promo whose expiry parses and is in the future, so consumers should treat a past value as expired. + [JsonPropertyName("endsAt")] + public string? EndsAt { get; set; } - /// Human-readable explanation, safe to surface. Never echoes card content, nor a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] + /// Stable identifier for the promotion campaign. + [JsonPropertyName("id")] + public string? Id { get; set; } + + /// Human-readable promotion message. Does not include the expiry timestamp; consumers may format endsAt and append it when present. [JsonPropertyName("message")] - public required string Message { get; set; } + public string? Message { get; set; } - /// How the card failed validation. - [JsonPropertyName("reason")] - public required CatalogMalformedCardReason Reason { get; set; } + /// Whether the service asked hosts to give this promotion a prominent surface, such as a dedicated banner, in addition to listing it with the model. `true` requests that surface and `false` asks for the model list only. Absent means the service expressed no preference — for example a response that predates the field — so hosts should apply their own default rather than read it as `false`. + [JsonPropertyName("showBanner")] + public bool? ShowBanner { get; set; } } -/// An upstream catalog response broke the wire contract. Most importantly, every result must carry exactly one of a URL or embedded data: a result carrying both, or neither, is refused here rather than being guessed at. -/// The contract-violation variant of . +/// Long context tier pricing (available for models with extended context windows). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultContractViolation : McpPlanInstallResult +public sealed class ModelBillingTokenPricesLongContext { - /// - [JsonIgnore] - public override string Kind => "contract-violation"; - - /// Human-readable explanation, safe to surface. Never echoes response content, nor a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Use cacheReadPrice instead. AI Credits cost per billing batch of cached tokens. + [EditorBrowsable(EditorBrowsableState.Never)] +#if NET5_0_OR_GREATER + [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] +#else + [Obsolete("This member is deprecated and will be removed in a future version.")] +#endif + [JsonPropertyName("cachePrice")] + public double? CachePrice { get; set; } - /// Which rule the response broke. - [JsonPropertyName("reason")] - public required CatalogContractViolationReason Reason { get; set; } + /// AI Credits cost per billing batch of cached (read) tokens. + [JsonPropertyName("cacheReadPrice")] + public double? CacheReadPrice { get; set; } + + /// AI Credits cost per billing batch of 1-hour cache-write (cache creation) tokens. + [JsonPropertyName("cacheWrite1hPrice")] + public double? CacheWrite1hPrice { get; set; } + + /// AI Credits cost per billing batch of cache-write (cache creation) tokens. + [JsonPropertyName("cacheWritePrice")] + public double? CacheWritePrice { get; set; } + + /// Use maxPromptTokens instead. Prompt token budget for the long context tier. The total context window is this value plus the model's max_output_tokens. + [EditorBrowsable(EditorBrowsableState.Never)] +#if NET5_0_OR_GREATER + [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] +#else + [Obsolete("This member is deprecated and will be removed in a future version.")] +#endif + [JsonPropertyName("contextMax")] + public long? ContextMax { get; set; } + + /// AI Credits cost per billing batch of input tokens. + [JsonPropertyName("inputPrice")] + public double? InputPrice { get; set; } + + /// Prompt token budget for the long context tier. The total context window is this value plus the model's max_output_tokens. + [JsonPropertyName("maxPromptTokens")] + public long? MaxPromptTokens { get; set; } + + /// AI Credits cost per billing batch of output tokens. + [JsonPropertyName("outputPrice")] + public double? OutputPrice { get; set; } } -/// No transport this runtime can use is available for the requested server. -/// The unavailable-transport variant of . +/// Token-level pricing information for this model. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultUnavailableTransport : McpPlanInstallResult +public sealed class ModelBillingTokenPrices { - /// - [JsonIgnore] - public override string Kind => "unavailable-transport"; + /// Number of tokens per standard billing batch. + [JsonPropertyName("batchSize")] + public long? BatchSize { get; set; } - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Use cacheReadPrice instead. AI Credits cost per billing batch of cached tokens. + [EditorBrowsable(EditorBrowsableState.Never)] +#if NET5_0_OR_GREATER + [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] +#else + [Obsolete("This member is deprecated and will be removed in a future version.")] +#endif + [JsonPropertyName("cachePrice")] + public double? CachePrice { get; set; } - /// Why no transport could be offered. - [JsonPropertyName("reason")] - public required CatalogUnavailableTransportReason Reason { get; set; } + /// AI Credits cost per billing batch of cached (read) tokens. + [JsonPropertyName("cacheReadPrice")] + public double? CacheReadPrice { get; set; } + + /// AI Credits cost per billing batch of 1-hour cache-write (cache creation) tokens. + [JsonPropertyName("cacheWrite1hPrice")] + public double? CacheWrite1hPrice { get; set; } + + /// AI Credits cost per billing batch of cache-write (cache creation) tokens. + [JsonPropertyName("cacheWritePrice")] + public double? CacheWritePrice { get; set; } + + /// Use maxPromptTokens instead. Prompt token budget for the default tier. The total context window is this value plus the model's max_output_tokens. + [EditorBrowsable(EditorBrowsableState.Never)] +#if NET5_0_OR_GREATER + [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] +#else + [Obsolete("This member is deprecated and will be removed in a future version.")] +#endif + [JsonPropertyName("contextMax")] + public long? ContextMax { get; set; } + + /// AI Credits cost per billing batch of input tokens. + [JsonPropertyName("inputPrice")] + public double? InputPrice { get; set; } + + /// Long context tier pricing (available for models with extended context windows). + [JsonPropertyName("longContext")] + public ModelBillingTokenPricesLongContext? LongContext { get; set; } + + /// Prompt token budget for the default tier. The total context window is this value plus the model's max_output_tokens. + [JsonPropertyName("maxPromptTokens")] + public long? MaxPromptTokens { get; set; } + + /// AI Credits cost per billing batch of output tokens. + [JsonPropertyName("outputPrice")] + public double? OutputPrice { get; set; } } -/// The candidate is discoverable but cannot be installed. `application/ai-skill` resolves here, because it stays searchable while remaining typed non-installable. -/// The not-installable variant of . +/// Billing information. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultNotInstallable : McpPlanInstallResult +public sealed class ModelBilling { - /// - [JsonIgnore] - public override string Kind => "not-installable"; + /// Whole-number percentage discount (0-100) applied to usage billed through this model. Populated for the synthetic `auto` model, where requests routed by auto-mode are billed at a reduced rate; absent for concrete models. + [JsonPropertyName("discountPercent")] + public int? DiscountPercent { get; set; } - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Billing cost multiplier relative to the base rate. + [JsonPropertyName("multiplier")] + public double? Multiplier { get; set; } - /// Why the candidate cannot be installed. - [JsonPropertyName("reason")] - public required CatalogNotInstallableReason Reason { get; set; } + /// Active server-driven promotion for this model, if any. Present when the model is being promoted with a discount, which may be time-boxed or open-ended. + [JsonPropertyName("promo")] + public ModelBillingPromo? Promo { get; set; } + + /// Token-level pricing information for this model. + [JsonPropertyName("tokenPrices")] + public ModelBillingTokenPrices? TokenPrices { get; set; } } -/// The operation is not available on this runtime. Distinct from a network failure: nothing was attempted. -/// The unavailable variant of . +/// Vision-specific limits. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallResultUnavailable : McpPlanInstallResult +public sealed class ModelCapabilitiesLimitsVision { - /// - [JsonIgnore] - public override string Kind => "unavailable"; + /// Maximum image size in bytes. + [JsonPropertyName("max_prompt_image_size")] + public long MaxPromptImageSize { get; set; } - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Maximum number of images per prompt. + [JsonPropertyName("max_prompt_images")] + public long MaxPromptImages { get; set; } - /// Why the operation is unavailable. - [JsonPropertyName("reason")] - public required CatalogUnavailableReason Reason { get; set; } + /// MIME types the model accepts. + [JsonPropertyName("supported_media_types")] + public IList SupportedMediaTypes { get => field ??= []; set; } } -/// The protocol version and capability set a caller requires, supplied on every catalog request so negotiation cannot be skipped by omission. +/// Token limits for prompts, outputs, and context window. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CatalogClientContract +public sealed class ModelCapabilitiesLimits { - /// SDK protocol version the caller was generated against. A caller below the runtime's minimum supported version is refused rather than served a partial result. - [JsonPropertyName("protocolVersion")] - public long ProtocolVersion { get; set; } + /// Maximum total context window size in tokens. + [JsonPropertyName("max_context_window_tokens")] + public long? MaxContextWindowTokens { get; set; } - /// Wire features the caller requires the runtime to understand. Identifiers are bounded but extensible so a newer caller can negotiate with an older runtime. Requiring an unknown feature yields a typed refusal listing what is understood, never a partial grant. A grant does not promise that a deployment has enabled the operation; typed unavailable results report that separately. - [JsonPropertyName("requiredCapabilities")] - public IList RequiredCapabilities { get => field ??= []; set; } + /// Maximum number of output/completion tokens. + [JsonPropertyName("max_output_tokens")] + public long? MaxOutputTokens { get; set; } + + /// Maximum number of prompt/input tokens. + [JsonPropertyName("max_prompt_tokens")] + public long? MaxPromptTokens { get; set; } + + /// Vision-specific limits. + [JsonPropertyName("vision")] + public ModelCapabilitiesLimitsVision? Vision { get; set; } } -/// What an install plan is computed from: a candidate handle from a previous search, or a card supplied directly. -/// Polymorphic base type discriminated by kind. +/// Feature flags indicating what the model supports. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpPlanInstallSourceCandidate), "candidate")] -[JsonDerivedType(typeof(McpPlanInstallSourceCard), "card")] -public partial class McpPlanInstallSource +public sealed class ModelCapabilitiesSupports { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Resolved Anthropic adaptive-thinking capability — unsupported / optional / required / adaptive_only. 'required' models reject thinking.type='enabled' with HTTP 400 but still accept 'disabled' (e.g. opus-4.7/4.8/5, sonnet-5); 'adaptive_only' models accept nothing but 'adaptive' (e.g. fable, mythos). + [JsonPropertyName("adaptive_thinking")] + public AdaptiveThinkingSupport? AdaptiveThinking { get; set; } + /// Whether this model supports reasoning effort configuration. + [JsonPropertyName("reasoningEffort")] + public bool? ReasoningEffort { get; set; } -/// Plan from a candidate returned by a previous catalog search. -/// The candidate variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallSourceCandidate : McpPlanInstallSource -{ - /// - [JsonIgnore] - public override string Kind => "candidate"; + /// Whether the model supports provider-native thinking. Independent of configurable reasoning effort; omission means unknown. + [JsonPropertyName("thinking")] + public bool? Thinking { get; set; } - /// Single-use candidate handle. Consumed by this call, so a replay of the same handle is rejected. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(256)] - [JsonPropertyName("candidateHandle")] - public required string CandidateHandle { get; set; } + /// Whether this model supports canonical tool calling. + [JsonPropertyName("toolCalls")] + public bool? ToolCalls { get; set; } - /// The runtime- or authority-minted `searchId` returned with the search that produced this candidate. Planning verifies the private correlation and atomically consumes a matching candidate before downstream work, including attempts that subsequently fail or report unavailable. A mismatched search does not consume the candidate. It identifies a search rather than a person and must never be joined with user identity to re-identify anyone. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(64)] - [JsonPropertyName("searchId")] - public required string SearchId { get; set; } + /// Whether this model supports vision/image input. + [JsonPropertyName("vision")] + public bool? Vision { get; set; } } -/// A card supplied directly by the caller. Exactly one of a URL or embedded data, encoded structurally so neither both nor neither can be expressed. -/// Polymorphic base type discriminated by kind. +/// Model capabilities and limits. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpServerCardReferenceUrl), "url")] -[JsonDerivedType(typeof(McpServerCardReferenceEmbedded), "embedded")] -public partial class McpServerCardReference +public sealed class ModelCapabilities { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Token limits for prompts, outputs, and context window. + [JsonPropertyName("limits")] + public ModelCapabilitiesLimits? Limits { get; set; } + /// Feature flags indicating what the model supports. + [JsonPropertyName("supports")] + public ModelCapabilitiesSupports? Supports { get; set; } +} -/// An MCP server card to be retrieved from a URL through the runtime's hardened fetch boundary. -/// The url variant of . +/// A service-published message about a model, carrying a stable machine-readable code alongside human-readable text. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpServerCardReferenceUrl : McpServerCardReference +public sealed class ModelMessage { - /// - [JsonIgnore] - public override string Kind => "url"; - - /// Media type the card is expected to conform to. - [JsonPropertyName("mediaType")] - public required McpServerCardMediaType MediaType { get; set; } + /// Stable machine-readable identifier for the message, such as `client_version_deprecated`. Hosts can key custom presentation off this; unrecognized codes should fall back to displaying `message`. + [JsonPropertyName("code")] + public string Code { get; set; } = string.Empty; - /// Card URL. Retrieved only through the runtime's hardened boundary, with scheme, credential, address-range, redirect, timeout, and response-size controls applied. Never logged. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(2048)] - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Human-readable message text intended for display to the user. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; } -/// An MCP server card supplied inline as an inert document. -/// The embedded variant of . +/// Policy state (if applicable). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpServerCardReferenceEmbedded : McpServerCardReference +public sealed class ModelPolicy { - /// - [JsonIgnore] - public override string Kind => "embedded"; - - /// The card document verbatim, treated as inert untrusted bytes. The runtime parses and validates it; the host is not expected to interpret it. Never logged. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(1048576)] - [JsonPropertyName("data")] - public required string Data { get; set; } + /// Current policy state for this model. + [JsonPropertyName("state")] + public ModelPolicyState State { get; set; } - /// Media type the card is expected to conform to. - [JsonPropertyName("mediaType")] - public required McpServerCardMediaType MediaType { get; set; } + /// Usage terms or conditions for this model. + [JsonPropertyName("terms")] + public string? Terms { get; set; } } -/// Plan from a card supplied directly by the caller, without a preceding search. -/// The card variant of . +/// Service-published warning text that hosts should display when presenting a model. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpPlanInstallSourceCard : McpPlanInstallSource +public sealed class ModelWarningText { - /// - [JsonIgnore] - public override string Kind => "card"; - - /// The card to plan from: exactly one of a URL or embedded data. - [JsonPropertyName("card")] - public required McpServerCardReference Card { get; set; } + /// Data-retention warning for the model. The text may contain Markdown links and should be rendered as Markdown when supported. + [JsonPropertyName("dataRetention")] + public string? DataRetention { get; set; } } -/// A side-effect-free request for an MCP install plan. Computing a plan never writes configuration, stores a secret, or reloads MCP servers. +/// Copilot model metadata, including identifier, display name, capabilities, policy, billing, reasoning efforts, and picker categories. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPlanInstallRequest +public sealed class Model { - /// Protocol version and capabilities the caller requires. - [JsonPropertyName("contract")] - public required CatalogClientContract Contract { get; set; } + /// Billing information. + [JsonPropertyName("billing")] + public ModelBilling? Billing { get; set; } - /// The same existing attached session that owns the original catalogue candidate. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(256)] - [JsonPropertyName("policySessionId")] - public string? PolicySessionId { get; set; } + /// Model capabilities and limits. + [JsonPropertyName("capabilities")] + public ModelCapabilities Capabilities { get => field ??= new(); set; } - /// Configuration scope the plan targets. Defaults to user scope when omitted. - [JsonPropertyName("scope")] - public McpPlanScope? Scope { get; set; } + /// Default reasoning effort level (only present if model supports reasoning effort). + [JsonPropertyName("defaultReasoningEffort")] + public string? DefaultReasoningEffort { get; set; } - /// What to plan: either a candidate handle from a previous search, or a card supplied directly. - [JsonPropertyName("source")] - public required McpPlanInstallSource Source { get; set; } -} + /// Model identifier (e.g., "claude-sonnet-4.5"). + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; -/// Management result with contract receipt, or a typed request/negotiation refusal. -/// Polymorphic base type discriminated by kind. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpInstallationManagementResultOutcome), "outcome")] -[JsonDerivedType(typeof(McpInstallationManagementResultNegotiationRefused), "negotiation-refused")] -[JsonDerivedType(typeof(McpInstallationManagementResultInvalidRequest), "invalid-request")] -public partial class McpInstallationManagementResult -{ - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Informational notices the service published for this model, such as an upcoming change or a recommended alternative. Present only when the service published at least one notice. Hosts should surface these without implying anything is wrong with the model. + [JsonPropertyName("infoMessages")] + public IList? InfoMessages { get; set; } + /// Provider-supplied model metadata. Keys and JSON-compatible values are preserved unchanged. This is factual metadata published by the model provider; it carries no picker or UX semantics. + [JsonPropertyName("metadata")] + public IDictionary? Metadata { get; set; } -/// Read-only or recovery management result, never permission to activate or replay. -/// Polymorphic base type discriminated by kind. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpInstallationManagementOutcomeRecoveryRequired), "recovery-required")] -[JsonDerivedType(typeof(McpInstallationManagementOutcomeInstallPrepared), "install-prepared")] -[JsonDerivedType(typeof(McpInstallationManagementOutcomeListed), "listed")] -[JsonDerivedType(typeof(McpInstallationManagementOutcomeRecovered), "recovered")] -[JsonDerivedType(typeof(McpInstallationManagementOutcomeUninstallPlanned), "uninstall-planned")] -[JsonDerivedType(typeof(McpInstallationManagementOutcomeOperation), "operation")] -[JsonDerivedType(typeof(McpInstallationManagementOutcomeRefused), "refused")] -public partial class McpInstallationManagementOutcome -{ - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Model capability category for grouping in the model picker. + [JsonPropertyName("modelPickerCategory")] + public ModelPickerCategory? ModelPickerCategory { get; set; } + + /// Relative cost tier for token-based billing users. + [JsonPropertyName("modelPickerPriceCategory")] + public ModelPickerPriceCategory? ModelPickerPriceCategory { get; set; } + /// Display name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; -/// Already-confirmed durable work must be reconciled before new mutations or inventory. -/// The recovery-required variant of . + /// Policy state (if applicable). + [JsonPropertyName("policy")] + public ModelPolicy? Policy { get; set; } + + /// The model provider that produced this model, as a neutral reference (opaque id, human-readable label, and provider kind). Present on models returned by `session.model.list`, which resolves provider attribution from the session's account roster; absent on the flat `server.models.list`, which does not resolve a session roster. The model picker groups by this reference. + [JsonPropertyName("provider")] + public ModelProviderRef? Provider { get; set; } + + /// Context-window tiers this model offers, when the provider advertises them independently of tiered token pricing. Copilot models carry their tiers in `billing.tokenPrices`; a provider that has no pricing to publish (an agent host reached over AHP, for example) declares them here instead, so the model picker can still offer the tier toggle. + [JsonPropertyName("supportedContextTiers")] + public IList? SupportedContextTiers { get; set; } + + /// Supported reasoning effort levels (only present if model supports reasoning effort). + [JsonPropertyName("supportedReasoningEfforts")] + public IList? SupportedReasoningEfforts { get; set; } + + /// Model vendor as the Copilot API reports it, for example "Anthropic" or "Azure OpenAI". Open vocabulary, passed through unchanged. It can name the vendor that serves the model instead of the one that built it, or a label that is not a vendor, such as "Experimental". Absent when the Copilot API reports no vendor. + [JsonPropertyName("vendor")] + public string? Vendor { get; set; } + + /// Warnings the service published for this model, such as a deprecated client version. Present only when the service published at least one warning. The model remains usable; hosts should surface these as advisory rather than blocking. + [JsonPropertyName("warningMessages")] + public IList? WarningMessages { get; set; } + + /// Warning text the service requires hosts to surface for this model. Present only when the service published at least one warning. + [JsonPropertyName("warningText")] + public ModelWarningText? WarningText { get; set; } +} + +/// List of Copilot models available to the resolved user, including capabilities and billing metadata. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationManagementOutcomeRecoveryRequired : McpInstallationManagementOutcome +public sealed class ModelList { - /// - [JsonIgnore] - public override string Kind => "recovery-required"; + /// List of available models with full metadata. + [JsonPropertyName("models")] + public IList Models { get => field ??= []; set; } } -/// Inert, runtime-owned admission. The operation ID is known before confirmation or effects. +/// RPC data type for ModelsList operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPreparedInstall +internal sealed class ModelsListRequest { - /// Original plan expiry in Unix epoch milliseconds; preparation does not extend it. - [JsonPropertyName("expiresAtEpochMs")] - public long ExpiresAtEpochMs { get; set; } + /// GitHub token accepted for compatibility with existing SDK clients. When provided, resolves this token instead of using the current account. + [JsonPropertyName("gitHubToken")] + public string? GitHubToken { get; set; } - /// Original connection-owned operation, known before the first confirmation callback. - [JsonPropertyName("operationId")] - public string OperationId { get; set; } = string.Empty; + /// Opaque account identifier returned by `account.getAllUsers`. When omitted, the current account is used. + [JsonPropertyName("selectionId")] + public string? SelectionId { get; set; } } -/// The install-prepared variant of . +/// A well-known model in the runtime's built-in catalog. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationManagementOutcomeInstallPrepared : McpInstallationManagementOutcome +public sealed class BuiltInModelCatalogEntry { - /// - [JsonIgnore] - public override string Kind => "install-prepared"; - - /// Known original operation identity, returned before callback or effects. - [JsonPropertyName("operation")] - public required McpPreparedInstall Operation { get; set; } + /// Well-known runtime model ID suitable for provider or provider-model metadata. This is not necessarily the provider-facing deployment or model name and does not indicate CAPI entitlement or provider availability. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; } -/// A versioned, bounded trust observation carried unchanged with a catalog candidate and its private handle context. Current observations require a recognised T1/T2 tier; every non-current state structurally forbids a tier. Eligibility remains `unknown` while Agent Finder supplies no exposure decision, and states absent from its current wire are never inferred from age, relevance, popularity, or a tier transition. -/// Polymorphic base type discriminated by status. +/// The running runtime's complete catalog of well-known built-in model IDs, including supported models and additional IDs with built-in metadata. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "status", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(CatalogTrustSnapshotCurrent), "current")] -[JsonDerivedType(typeof(CatalogTrustSnapshotAbsent), "absent")] -[JsonDerivedType(typeof(CatalogTrustSnapshotStale), "stale")] -[JsonDerivedType(typeof(CatalogTrustSnapshotDowngraded), "downgraded")] -[JsonDerivedType(typeof(CatalogTrustSnapshotRevoked), "revoked")] -[JsonDerivedType(typeof(CatalogTrustSnapshotUnsupported), "unsupported")] -[JsonDerivedType(typeof(CatalogTrustSnapshotMalformed), "malformed")] -public partial class CatalogTrustSnapshot +public sealed class BuiltInModelCatalog { - /// The type discriminator. - [JsonPropertyName("status")] - public virtual string Status { get; set; } = string.Empty; + /// Built-in model entries. + [JsonPropertyName("models")] + public IList Models { get => field ??= []; set; } } - -/// Where and when the runtime observed the trust metadata. Observation time is not the authority's evaluation time and must not be used to infer staleness. +/// Built-in tool metadata with identifier, optional namespaced name, description, input-parameter schema, and usage instructions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CatalogTrustProvenance +public sealed class Tool { - /// ISO 8601 timestamp with a timezone offset at which the runtime observed the search result carrying this trust field. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(20)] - [MaxLength(64)] - [JsonPropertyName("observedAt")] - public DateTimeOffset ObservedAt { get; set; } + /// Description of what the tool does. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// Bounded authority that supplied the trust field. - [JsonPropertyName("source")] - public CatalogTrustSource Source { get; set; } -} - -/// A recognised current Agent Finder T1 or T2 trust tier. -/// The current variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogTrustSnapshotCurrent : CatalogTrustSnapshot -{ - /// - [JsonIgnore] - public override string Status => "current"; + /// Optional instructions for how to use this tool effectively. + [JsonPropertyName("instructions")] + public string? Instructions { get; set; } - /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. - [JsonPropertyName("eligibility")] - public required CatalogTrustEligibility Eligibility { get; set; } + /// Tool identifier (e.g., "bash", "grep", "str_replace_editor"). + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. - [JsonPropertyName("provenance")] - public required CatalogTrustProvenance Provenance { get; set; } + /// Optional namespaced name for declarative filtering (e.g., "playwright/navigate" for MCP tools). + [JsonPropertyName("namespacedName")] + public string? NamespacedName { get; set; } - /// Schema version of this runtime-owned snapshot envelope. - [JsonPropertyName("schemaVersion")] - public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } + /// JSON Schema for the tool's input parameters. + [JsonPropertyName("parameters")] + public IDictionary? Parameters { get; set; } - /// Service-computed T1 or T2 trust tier. - [JsonPropertyName("tier")] - public required CatalogTrustTier Tier { get; set; } + /// Telemetry-safety policy for the tool name and input names, not input values. Treat omitted metadata as unsafe. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + [JsonPropertyName("safeForTelemetry")] + public JsonElement? SafeForTelemetry { get; set; } } -/// Discriminator: the authority omitted trust metadata. -/// The absent variant of . +/// Built-in tools available for the requested model, with their parameters and instructions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogTrustSnapshotAbsent : CatalogTrustSnapshot +public sealed class ToolList { - /// - [JsonIgnore] - public override string Status => "absent"; - - /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. - [JsonPropertyName("eligibility")] - public required CatalogTrustEligibility Eligibility { get; set; } - - /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. - [JsonPropertyName("provenance")] - public required CatalogTrustProvenance Provenance { get; set; } + /// List of available built-in tools with metadata. + [JsonPropertyName("tools")] + public IList Tools { get => field ??= []; set; } +} - /// Schema version of this runtime-owned snapshot envelope. - [JsonPropertyName("schemaVersion")] - public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } +/// Optional model identifier whose tool overrides should be applied to the listing. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ToolsListRequest +{ + /// Optional model ID — when provided, the returned tool list reflects model-specific overrides. + [JsonPropertyName("model")] + public string? Model { get; set; } } -/// Discriminator: the authority explicitly marked the assessment stale. -/// The stale variant of . +/// Quota usage snapshot for a Copilot quota type, including entitlement, used requests, overage, reset date, and remaining percentage. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogTrustSnapshotStale : CatalogTrustSnapshot +public sealed class AccountQuotaSnapshot { - /// - [JsonIgnore] - public override string Status => "stale"; + /// Number of requests included in the entitlement, or -1 for unlimited entitlements. + [JsonPropertyName("entitlementRequests")] + public long EntitlementRequests { get; set; } - /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. - [JsonPropertyName("eligibility")] - public required CatalogTrustEligibility Eligibility { get; set; } + /// Whether the user has an unlimited usage entitlement. + [JsonPropertyName("isUnlimitedEntitlement")] + public bool IsUnlimitedEntitlement { get; set; } - /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. - [JsonPropertyName("provenance")] - public required CatalogTrustProvenance Provenance { get; set; } + /// Number of additional usage requests made this period. + [JsonPropertyName("overage")] + public double Overage { get; set; } - /// Schema version of this runtime-owned snapshot envelope. - [JsonPropertyName("schemaVersion")] - public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } -} + /// Whether additional usage is allowed when quota is exhausted. + [JsonPropertyName("overageAllowedWithExhaustedQuota")] + public bool OverageAllowedWithExhaustedQuota { get; set; } -/// Discriminator: the authority explicitly reported a downgraded assessment. -/// The downgraded variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogTrustSnapshotDowngraded : CatalogTrustSnapshot -{ - /// - [JsonIgnore] - public override string Status => "downgraded"; + /// Percentage of entitlement remaining. + [JsonPropertyName("remainingPercentage")] + public double RemainingPercentage { get; set; } - /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. - [JsonPropertyName("eligibility")] - public required CatalogTrustEligibility Eligibility { get; set; } + /// Date when the quota resets (ISO 8601 string). + [JsonPropertyName("resetDate")] + public DateTimeOffset? ResetDate { get; set; } - /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. - [JsonPropertyName("provenance")] - public required CatalogTrustProvenance Provenance { get; set; } + /// Whether usage is still permitted after quota exhaustion. + [JsonPropertyName("usageAllowedWithExhaustedQuota")] + public bool UsageAllowedWithExhaustedQuota { get; set; } - /// Schema version of this runtime-owned snapshot envelope. - [JsonPropertyName("schemaVersion")] - public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } + /// Number of requests used so far this period. + [JsonPropertyName("usedRequests")] + public long UsedRequests { get; set; } } -/// Discriminator: the authority explicitly revoked the assessment. -/// The revoked variant of . +/// Quota usage snapshots for the resolved user, keyed by quota type. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogTrustSnapshotRevoked : CatalogTrustSnapshot +public sealed class AccountGetQuotaResult { - /// - [JsonIgnore] - public override string Status => "revoked"; + /// Quota snapshots keyed by type (e.g., chat, completions, premium_interactions). + [JsonPropertyName("quotaSnapshots")] + public IDictionary QuotaSnapshots { get => field ??= new Dictionary(); set; } +} - /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. - [JsonPropertyName("eligibility")] - public required CatalogTrustEligibility Eligibility { get; set; } +/// RPC data type for AccountGetQuota operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AccountGetQuotaRequest +{ + /// GitHub token accepted for compatibility with existing SDK clients. When provided, resolves this token instead of using the current account. + [JsonPropertyName("gitHubToken")] + public string? GitHubToken { get; set; } - /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. - [JsonPropertyName("provenance")] - public required CatalogTrustProvenance Provenance { get; set; } + /// Opaque account identifier returned by `account.getAllUsers`. When omitted, the current account is used. + [JsonPropertyName("selectionId")] + public string? SelectionId { get; set; } +} - /// Schema version of this runtime-owned snapshot envelope. - [JsonPropertyName("schemaVersion")] - public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } +/// Authentication credentials accepted only at native protocol ingress. Runtime outputs use credential-free `AuthIdentity` metadata. +/// Polymorphic base type discriminated by type. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "type", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(AuthInfoHmac), "hmac")] +[JsonDerivedType(typeof(AuthInfoEnv), "env")] +[JsonDerivedType(typeof(AuthInfoToken), "token")] +[JsonDerivedType(typeof(AuthInfoTokenProvider), "token-provider")] +[JsonDerivedType(typeof(AuthInfoCopilotApiToken), "copilot-api-token")] +[JsonDerivedType(typeof(AuthInfoUser), "user")] +[JsonDerivedType(typeof(AuthInfoAccount), "account")] +[JsonDerivedType(typeof(AuthInfoGhCli), "gh-cli")] +[JsonDerivedType(typeof(AuthInfoApiKey), "api-key")] +public partial class AuthInfo +{ + /// The type discriminator. + [JsonPropertyName("type")] + public virtual string Type { get; set; } = string.Empty; } -/// Discriminator: the authority supplied a bounded trust value this runtime does not understand. -/// The unsupported variant of . + +/// Endpoint URLs from the raw Copilot `/copilot_internal/v2/token` user-response passthrough. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogTrustSnapshotUnsupported : CatalogTrustSnapshot +public sealed class CopilotUserResponseEndpoints { - /// - [JsonIgnore] - public override string Status => "unsupported"; + /// Copilot API endpoint URL. + [JsonPropertyName("api")] + public string? Api { get; set; } - /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. - [JsonPropertyName("eligibility")] - public required CatalogTrustEligibility Eligibility { get; set; } + /// Experimental-service endpoint URL. + [JsonPropertyName("exp")] + public string? Exp { get; set; } - /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. - [JsonPropertyName("provenance")] - public required CatalogTrustProvenance Provenance { get; set; } + /// Origin-tracker endpoint URL. + [JsonPropertyName("origin-tracker")] + public string? OriginTracker { get; set; } - /// Schema version of this runtime-owned snapshot envelope. - [JsonPropertyName("schemaVersion")] - public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } + /// Copilot proxy endpoint URL. + [JsonPropertyName("proxy")] + public string? Proxy { get; set; } + + /// Copilot telemetry endpoint URL. + [JsonPropertyName("telemetry")] + public string? Telemetry { get; set; } } -/// Discriminator: the trust field was empty, unbounded, or had the wrong JSON type. -/// The malformed variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogTrustSnapshotMalformed : CatalogTrustSnapshot +/// RPC data type for CopilotUserResponseEnterpriseListItem operations. +public sealed class CopilotUserResponseEnterpriseListItem { - /// - [JsonIgnore] - public override string Status => "malformed"; + /// JavaScript-safe numeric database ID of the enterprise. + [JsonPropertyName("id")] + public long? Id { get; set; } +} - /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. - [JsonPropertyName("eligibility")] - public required CatalogTrustEligibility Eligibility { get; set; } +/// RPC data type for CopilotUserResponseOrganizationListItem operations. +public sealed class CopilotUserResponseOrganizationListItem +{ + /// Numeric database ID of the organization. + [JsonPropertyName("id")] + public double? Id { get; set; } - /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. - [JsonPropertyName("provenance")] - public required CatalogTrustProvenance Provenance { get; set; } + /// GitHub login of the organization. + [JsonPropertyName("login")] + public string? Login { get; set; } - /// Schema version of this runtime-owned snapshot envelope. - [JsonPropertyName("schemaVersion")] - public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } + /// Display name of the organization. + [JsonPropertyName("name")] + public string? Name { get; set; } } -/// Catalogue identity retained from a bound candidate or plan at installation time. +/// Chat quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class InstallationCatalogueIdentity +public sealed class CopilotUserResponseQuotaSnapshotsChat { - /// Catalogue description retained at install planning time. - [JsonPropertyName("description")] - public string? Description { get; set; } + /// Number of requests/units included in the entitlement for this period; `-1` denotes an unlimited entitlement. + [JsonPropertyName("entitlement")] + public double? Entitlement { get; set; } - /// Human display name retained from the catalogue candidate. - [JsonPropertyName("displayName")] - public string DisplayName { get; set; } = string.Empty; + /// Whether the user currently has quota available; when `false` and not unlimited, further requests are blocked until the quota resets. + [JsonPropertyName("has_quota")] + public bool? HasQuota { get; set; } - /// Catalogue item URL when supplied by the authority. - [JsonPropertyName("itemUrl")] - public string? ItemUrl { get; set; } + /// Count of additional pay-per-request usage consumed this period beyond the entitlement. + [JsonPropertyName("overage_count")] + public double? OverageCount { get; set; } - /// Catalogue publisher retained at install planning time. - [JsonPropertyName("publisher")] - public string? Publisher { get; set; } + /// Whether usage may continue at pay-per-request rates once the entitlement is exhausted. + [JsonPropertyName("overage_permitted")] + public bool? OveragePermitted { get; set; } - /// Authority resource identifier when supplied by the catalogue. - [JsonPropertyName("resourceId")] - public string? ResourceId { get; set; } + /// Percentage of the entitlement remaining at the snapshot timestamp. + [JsonPropertyName("percent_remaining")] + public double? PercentRemaining { get; set; } - /// Catalogue authority/source string that supplied the candidate. - [JsonPropertyName("source")] - public string Source { get; set; } = string.Empty; + /// Identifier of the quota bucket this snapshot describes. + [JsonPropertyName("quota_id")] + public string? QuotaId { get; set; } - /// Catalogue trust observation retained at install planning time. - [JsonPropertyName("trustAtInstall")] - public CatalogTrustSnapshot? TrustAtInstall { get; set; } + /// Amount of quota remaining at the snapshot timestamp. + [JsonPropertyName("quota_remaining")] + public double? QuotaRemaining { get; set; } - /// Catalogue version retained at install planning time. - [JsonPropertyName("version")] - public string? Version { get; set; } + /// Unix epoch time, in seconds, when this quota next resets. + [JsonPropertyName("quota_reset_at")] + public double? QuotaResetAt { get; set; } + + /// Remaining entitlement/quota amount at the snapshot timestamp. + [JsonPropertyName("remaining")] + public double? Remaining { get; set; } + + /// UTC timestamp when this snapshot was captured. + [JsonPropertyName("timestamp_utc")] + public string? TimestampUtc { get; set; } + + /// Whether this category uses usage-based (token/AI-credit) billing rather than a fixed premium-request count. + [JsonPropertyName("token_based_billing")] + public bool? TokenBasedBilling { get; set; } + + /// Whether the entitlement for this category is unlimited. + [JsonPropertyName("unlimited")] + public bool? Unlimited { get; set; } } -/// Durable configuration ownership is distinct from session-specific usability. +/// Completions quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpInstallationSummary +public sealed class CopilotUserResponseQuotaSnapshotsCompletions { - /// Catalogue identity retained from the installed plan when available. - [JsonPropertyName("catalogue")] - public InstallationCatalogueIdentity? Catalogue { get; set; } + /// Number of requests/units included in the entitlement for this period; `-1` denotes an unlimited entitlement. + [JsonPropertyName("entitlement")] + public double? Entitlement { get; set; } - /// Exact alternative retained in the installing receipt. - [JsonPropertyName("choiceId")] - public string ChoiceId { get; set; } = string.Empty; + /// Whether the user currently has quota available; when `false` and not unlimited, further requests are blocked until the quota resets. + [JsonPropertyName("has_quota")] + public bool? HasQuota { get; set; } - /// Identity retained from the validated original plan. - [JsonPropertyName("identity")] - public McpPlanResourceIdentity Identity { get => field ??= new(); set; } + /// Count of additional pay-per-request usage consumed this period beyond the entitlement. + [JsonPropertyName("overage_count")] + public double? OverageCount { get; set; } - /// Exact durable installation receipt identity. - [JsonPropertyName("installationId")] - public string InstallationId { get; set; } = string.Empty; + /// Whether usage may continue at pay-per-request rates once the entitlement is exhausted. + [JsonPropertyName("overage_permitted")] + public bool? OveragePermitted { get; set; } - /// ISO 8601 wall-clock installation time when available. - [JsonPropertyName("installedAt")] - public string? InstalledAt { get; set; } + /// Percentage of the entitlement remaining at the snapshot timestamp. + [JsonPropertyName("percent_remaining")] + public double? PercentRemaining { get; set; } - /// Original installing operation, not a fresh management operation. - [JsonPropertyName("operationId")] - public string OperationId { get; set; } = string.Empty; + /// Identifier of the quota bucket this snapshot describes. + [JsonPropertyName("quota_id")] + public string? QuotaId { get; set; } - /// Ownership or setup state, never inferred proof of tool usability. - [JsonPropertyName("state")] - public McpInstallationState State { get; set; } -} + /// Amount of quota remaining at the snapshot timestamp. + [JsonPropertyName("quota_remaining")] + public double? QuotaRemaining { get; set; } -/// The listed variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationManagementOutcomeListed : McpInstallationManagementOutcome -{ - /// - [JsonIgnore] - public override string Kind => "listed"; + /// Unix epoch time, in seconds, when this quota next resets. + [JsonPropertyName("quota_reset_at")] + public double? QuotaResetAt { get; set; } - /// Owned receipts visible to the selected account and host. - [JsonPropertyName("installations")] - public required IList Installations { get; set; } -} + /// Remaining entitlement/quota amount at the snapshot timestamp. + [JsonPropertyName("remaining")] + public double? Remaining { get; set; } -/// The recovered variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationManagementOutcomeRecovered : McpInstallationManagementOutcome -{ - /// - [JsonIgnore] - public override string Kind => "recovered"; + /// UTC timestamp when this snapshot was captured. + [JsonPropertyName("timestamp_utc")] + public string? TimestampUtc { get; set; } - /// Freshly inspected receipts after successful durable reconciliation. - [JsonPropertyName("installations")] - public required IList Installations { get; set; } + /// Whether this category uses usage-based (token/AI-credit) billing rather than a fixed premium-request count. + [JsonPropertyName("token_based_billing")] + public bool? TokenBasedBilling { get; set; } + + /// Whether the entitlement for this category is unlimited. + [JsonPropertyName("unlimited")] + public bool? Unlimited { get; set; } } -/// Exact inert removal plan. No configuration or credentials have changed. +/// Premium-interactions quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpUninstallPlan +public sealed class CopilotUserResponseQuotaSnapshotsPremiumInteractions { - /// Original wall-clock expiry in milliseconds. Applying never renews it. - [JsonPropertyName("expiresAtEpochMs")] - public long ExpiresAtEpochMs { get; set; } + /// Number of requests/units included in the entitlement for this period; `-1` denotes an unlimited entitlement. + [JsonPropertyName("entitlement")] + public double? Entitlement { get; set; } - /// Original owned receipt being removed. - [JsonPropertyName("installation")] - public McpInstallationSummary Installation { get => field ??= new(); set; } + /// Whether the user currently has quota available; when `false` and not unlimited, further requests are blocked until the quota resets. + [JsonPropertyName("has_quota")] + public bool? HasQuota { get; set; } - /// The original operation, inspectable and cancellable on this same connection. - [JsonPropertyName("operationId")] - public string OperationId { get; set; } = string.Empty; + /// Count of additional pay-per-request usage consumed this period beyond the entitlement. + [JsonPropertyName("overage_count")] + public double? OverageCount { get; set; } - /// Exact configured input slots owned by this installation, never shared OAuth tokens. - [JsonPropertyName("ownedSecretCount")] - public long OwnedSecretCount { get; set; } + /// Whether usage may continue at pay-per-request rates once the entitlement is exhausted. + [JsonPropertyName("overage_permitted")] + public bool? OveragePermitted { get; set; } - /// One-use original connection and authority-bound plan handle. - [JsonPropertyName("planHandle")] - public string PlanHandle { get; set; } = string.Empty; + /// Percentage of the entitlement remaining at the snapshot timestamp. + [JsonPropertyName("percent_remaining")] + public double? PercentRemaining { get; set; } - /// Shared authentication is deliberately retained; revocation is a separate action. - [JsonPropertyName("preservesSharedAuthentication")] - public bool PreservesSharedAuthentication { get; set; } + /// Identifier of the quota bucket this snapshot describes. + [JsonPropertyName("quota_id")] + public string? QuotaId { get; set; } - /// Whether removal restores a protected earlier configuration. - [JsonPropertyName("restoresPreviousConfiguration")] - public bool RestoresPreviousConfiguration { get; set; } + /// Amount of quota remaining at the snapshot timestamp. + [JsonPropertyName("quota_remaining")] + public double? QuotaRemaining { get; set; } + + /// Unix epoch time, in seconds, when this quota next resets. + [JsonPropertyName("quota_reset_at")] + public double? QuotaResetAt { get; set; } + + /// Remaining entitlement/quota amount at the snapshot timestamp. + [JsonPropertyName("remaining")] + public double? Remaining { get; set; } + + /// UTC timestamp when this snapshot was captured. + [JsonPropertyName("timestamp_utc")] + public string? TimestampUtc { get; set; } + + /// Whether this category uses usage-based (token/AI-credit) billing rather than a fixed premium-request count. + [JsonPropertyName("token_based_billing")] + public bool? TokenBasedBilling { get; set; } + + /// Whether the entitlement for this category is unlimited. + [JsonPropertyName("unlimited")] + public bool? Unlimited { get; set; } } -/// The uninstall-planned variant of . +/// Quota snapshot map from the raw Copilot user-response passthrough, with chat, completions, premium-interactions, and other entries. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationManagementOutcomeUninstallPlanned : McpInstallationManagementOutcome +public sealed class CopilotUserResponseQuotaSnapshots { - /// - [JsonIgnore] - public override string Kind => "uninstall-planned"; + /// Chat quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. + [JsonPropertyName("chat")] + public CopilotUserResponseQuotaSnapshotsChat? Chat { get; set; } - /// Original owned removal plan and operation. - [JsonPropertyName("plan")] - public required McpUninstallPlan Plan { get; set; } + /// Completions quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. + [JsonPropertyName("completions")] + public CopilotUserResponseQuotaSnapshotsCompletions? Completions { get; set; } + + /// Premium-interactions quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields. + [JsonPropertyName("premium_interactions")] + public CopilotUserResponseQuotaSnapshotsPremiumInteractions? PremiumInteractions { get; set; } } -/// Status snapshot from the original connection, independent of new-work account availability. -/// Polymorphic base type discriminated by phase. +/// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "phase", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpInstallationOperationStatusPreparing), "preparing")] -[JsonDerivedType(typeof(McpInstallationOperationStatusPrepared), "prepared")] -[JsonDerivedType(typeof(McpInstallationOperationStatusAwaitingConfirmation), "awaiting-confirmation")] -[JsonDerivedType(typeof(McpInstallationOperationStatusRevalidating), "revalidating")] -[JsonDerivedType(typeof(McpInstallationOperationStatusApplying), "applying")] -[JsonDerivedType(typeof(McpInstallationOperationStatusCompleted), "completed")] -public partial class McpInstallationOperationStatus +public sealed class CopilotUserResponse { - /// The type discriminator. - [JsonPropertyName("phase")] - public virtual string Phase { get; set; } = string.Empty; -} + /// Copilot access SKU identifier (e.g. `free_limited_copilot`, `copilot_for_business_seat_quota`) used to gate model and feature access. + [JsonPropertyName("access_type_sku")] + public string? AccessTypeSku { get; set; } + /// Opaque analytics tracking identifier for the user, forwarded from the Copilot API. + [JsonPropertyName("analytics_tracking_id")] + public string? AnalyticsTrackingId { get; set; } -/// The preparing variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOperationStatusPreparing : McpInstallationOperationStatus -{ - /// - [JsonIgnore] - public override string Phase => "preparing"; - - /// Whether cancellation has been requested, not proof that a write was undone. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } - - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } -} + /// Date the Copilot seat was assigned to the user, if applicable. + [JsonPropertyName("assigned_date")] + public string? AssignedDate { get; set; } -/// The prepared variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOperationStatusPrepared : McpInstallationOperationStatus -{ - /// - [JsonIgnore] - public override string Phase => "prepared"; + /// Whether the user is eligible to sign up for the free/limited Copilot tier. + [JsonPropertyName("can_signup_for_limited")] + public bool? CanSignupForLimited { get; set; } - /// Whether the inert prepared operation was asked to cancel. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } + /// Whether the user is able to upgrade their Copilot plan. + [JsonPropertyName("can_upgrade_plan")] + public bool? CanUpgradePlan { get; set; } - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } -} + /// Whether Copilot chat is enabled for the user. + [JsonPropertyName("chat_enabled")] + public bool? ChatEnabled { get; set; } -/// The awaiting-confirmation variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOperationStatusAwaitingConfirmation : McpInstallationOperationStatus -{ - /// - [JsonIgnore] - public override string Phase => "awaiting-confirmation"; + /// Whether CLI remote control is enabled for the user. + [JsonPropertyName("cli_remote_control_enabled")] + public bool? CliRemoteControlEnabled { get; set; } - /// Whether the pending human callback was asked to cancel. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } + /// Whether cloud session storage is enabled for the user. + [JsonPropertyName("cloud_session_storage_enabled")] + public bool? CloudSessionStorageEnabled { get; set; } - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } -} + /// Whether the Codex agent is enabled for the user. + [JsonPropertyName("codex_agent_enabled")] + public bool? CodexAgentEnabled { get; set; } -/// The revalidating variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOperationStatusRevalidating : McpInstallationOperationStatus -{ - /// - [JsonIgnore] - public override string Phase => "revalidating"; + /// Copilot plan name for the user (e.g. `individual`, `business`, `enterprise`). + [JsonPropertyName("copilot_plan")] + public string? CopilotPlan { get; set; } - /// Whether source or authority revalidation was asked to cancel. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } + /// Whether `.copilotignore` content-exclusion support is enabled for the user. + [JsonPropertyName("copilotignore_enabled")] + public bool? CopilotignoreEnabled { get; set; } - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } -} + /// Endpoint URLs from the raw Copilot `/copilot_internal/v2/token` user-response passthrough. + [JsonPropertyName("endpoints")] + public CopilotUserResponseEndpoints? Endpoints { get; set; } -/// The applying variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOperationStatusApplying : McpInstallationOperationStatus -{ - /// - [JsonIgnore] - public override string Phase => "applying"; + /// Enterprises that provide the user's Copilot license; malformed entries are normalized to null or ID-less shapes. + [JsonPropertyName("enterprise_list")] + public IList? EnterpriseList { get; set; } - /// Whether applying was asked to cancel; already-started effects retain their lease. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } + /// Whether MCP (Model Context Protocol) support is enabled for the user. + [JsonPropertyName("is_mcp_enabled")] + public bool? IsMcpEnabled { get; set; } - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } -} + /// Whether the user is a GitHub/Microsoft staff member. + [JsonPropertyName("is_staff")] + public bool? IsStaff { get; set; } -/// Terminal mutation result. Uncertainty is not approval, rollback or permission to replay. -/// Polymorphic base type discriminated by kind. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpInstallationOutcomeInstalled), "installed")] -[JsonDerivedType(typeof(McpInstallationOutcomeUninstalled), "uninstalled")] -[JsonDerivedType(typeof(McpInstallationOutcomeRolledBack), "rolled-back")] -[JsonDerivedType(typeof(McpInstallationOutcomeRecoveryRequired), "recovery-required")] -[JsonDerivedType(typeof(McpInstallationOutcomeDeclined), "declined")] -[JsonDerivedType(typeof(McpInstallationOutcomeCancelled), "cancelled")] -[JsonDerivedType(typeof(McpInstallationOutcomeRefused), "refused")] -public partial class McpInstallationOutcome -{ - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Per-category quota allotments for free/limited-tier users, keyed by quota category. + [JsonPropertyName("limited_user_quotas")] + public IDictionary? LimitedUserQuotas { get; set; } + /// Date the free/limited-tier user's quotas next reset, as a raw string from the Copilot API. + [JsonPropertyName("limited_user_reset_date")] + public string? LimitedUserResetDate { get; set; } -/// The installed variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOutcomeInstalled : McpInstallationOutcome -{ - /// - [JsonIgnore] - public override string Kind => "installed"; + /// GitHub login of the authenticated user. + [JsonPropertyName("login")] + public string? Login { get; set; } - /// Durable installation succeeded but final transaction cleanup remains. - [JsonPropertyName("cleanupPending")] - public required bool CleanupPending { get; set; } + /// Per-category monthly quota allotments, keyed by quota category. + [JsonPropertyName("monthly_quotas")] + public IDictionary? MonthlyQuotas { get; set; } - /// Receipt identity produced by the confirmed transaction. - [JsonPropertyName("installation")] - public required McpInstallationSummary Installation { get; set; } -} + /// Organizations the user belongs to, each with an optional ID, login, and display name. + [JsonPropertyName("organization_list")] + public IList? OrganizationList { get; set; } -/// The uninstalled variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOutcomeUninstalled : McpInstallationOutcome -{ - /// - [JsonIgnore] - public override string Kind => "uninstalled"; + /// Logins of the organizations the user belongs to. + [JsonPropertyName("organization_login_list")] + public IList? OrganizationLoginList { get; set; } - /// Durable removal succeeded but final cleanup remains. - [JsonPropertyName("cleanupPending")] - public required bool CleanupPending { get; set; } + /// Date the user's usage quota next resets, as a raw string from the Copilot API; see `quota_reset_date_utc` for the UTC-normalized value. + [JsonPropertyName("quota_reset_date")] + public string? QuotaResetDate { get; set; } - /// Exact removed receipt identity. - [JsonPropertyName("installationId")] - public required string InstallationId { get; set; } + /// UTC-normalized form of `quota_reset_date` (the date the user's usage quota next resets). + [JsonPropertyName("quota_reset_date_utc")] + public string? QuotaResetDateUtc { get; set; } - /// Original removal operation. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// Quota snapshot map from the raw Copilot user-response passthrough, with chat, completions, premium-interactions, and other entries. + [JsonPropertyName("quota_snapshots")] + public CopilotUserResponseQuotaSnapshots? QuotaSnapshots { get; set; } - /// Any grants in the incumbent shared OAuth store remain unowned and retained. - [JsonPropertyName("preservedSharedAuthentication")] - public required bool PreservedSharedAuthentication { get; set; } + /// Whether the user's telemetry is subject to restricted-data handling. + [JsonPropertyName("restricted_telemetry")] + public bool? RestrictedTelemetry { get; set; } - /// Exact owned input slots removed, excluding shared OAuth credentials. - [JsonPropertyName("removedOwnedSecrets")] - public required long RemovedOwnedSecrets { get; set; } + /// Raw passthrough of the Copilot API `te` flag for the user (an opaque server-side eligibility signal surfaced in telemetry); not otherwise interpreted by the runtime. + [JsonPropertyName("te")] + public bool? Te { get; set; } - /// Whether protected pre-install configuration was restored. - [JsonPropertyName("restoredPreviousConfiguration")] - public required bool RestoredPreviousConfiguration { get; set; } + /// Whether the account is on usage-based (token/AI-credit) billing rather than a fixed premium-request quota. + [JsonPropertyName("token_based_billing")] + public bool? TokenBasedBilling { get; set; } } -/// The durable transaction was aborted or fully compensated. -/// The rolled-back variant of . +/// Authentication-info input variant for GitHub-internal HMAC auth, carrying the public GitHub host and HMAC secret. +/// The hmac variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOutcomeRolledBack : McpInstallationOutcome +public partial class AuthInfoHmac : AuthInfo { /// [JsonIgnore] - public override string Kind => "rolled-back"; + public override string Type => "hmac"; - /// Original connection-owned operation. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } - /// Cause of the fully aborted or compensated operation. - [JsonPropertyName("reason")] - public required McpInstallationFailureReason Reason { get; set; } + /// HMAC secret used to sign requests. + [JsonPropertyName("hmac")] + public required string Hmac { get; set; } + + /// Authentication host. HMAC auth always targets the public GitHub host. + [JsonPropertyName("host")] + public required string Host { get; set; } } -/// A write may have completed. Recover and inspect durable state before retrying. -/// The recovery-required variant of . +/// Authentication-info input variant for a token sourced from an environment variable, with host, optional login, token, and env var name. +/// The env variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOutcomeRecoveryRequired : McpInstallationOutcome +public partial class AuthInfoEnv : AuthInfo { /// [JsonIgnore] - public override string Kind => "recovery-required"; + public override string Type => "env"; - /// Operation whose durable result must be recovered and inspected. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } -} + /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } -/// The declined variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOutcomeDeclined : McpInstallationOutcome -{ - /// - [JsonIgnore] - public override string Kind => "declined"; + /// Name of the environment variable the token was sourced from. + [JsonPropertyName("envVar")] + public required string EnvVar { get; set; } - /// Original operation explicitly declined by the user. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } -} + /// Authentication host (e.g. https://github.com or a GHES host). + [JsonPropertyName("host")] + public required string Host { get; set; } -/// The cancelled variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOutcomeCancelled : McpInstallationOutcome -{ - /// - [JsonIgnore] - public override string Kind => "cancelled"; + /// User login associated with the token. Undefined for server-to-server tokens (those starting with `ghs_`). + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("login")] + public string? Login { get; set; } - /// Original operation cancelled before a terminal application result. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// The token value itself. Treat as a secret. + [JsonPropertyName("token")] + public required string Token { get; set; } } -/// The refused variant of . +/// Authentication-info input variant for SDK-configured token authentication, carrying host and the secret token value. +/// The token variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOutcomeRefused : McpInstallationOutcome +public partial class AuthInfoToken : AuthInfo { /// [JsonIgnore] - public override string Kind => "refused"; + public override string Type => "token"; - /// Present once an operation has been allocated; never a plan handle. + /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("operationId")] - public string? OperationId { get; set; } + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } - /// Specific bounded refusal, never a success-shaped fallback. - [JsonPropertyName("reason")] - public required McpInstallationFailureReason Reason { get; set; } + /// Authentication host. + [JsonPropertyName("host")] + public required string Host { get; set; } + + /// Opaque native GitHub credential registration backing this token identity, when applicable. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("registrationId")] + public string? RegistrationId { get; set; } + + /// The token value itself. Treat as a secret. + [JsonPropertyName("token")] + public required string Token { get; set; } } -/// The completed variant of . +/// Authentication-info variant backed by an SDK GitHub token callback. It carries routing metadata but never a plaintext token. +/// The token-provider variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationOperationStatusCompleted : McpInstallationOperationStatus +public partial class AuthInfoTokenProvider : AuthInfo { /// [JsonIgnore] - public override string Phase => "completed"; + public override string Type => "token-provider"; - /// Whether cancellation was requested before the terminal result. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } + /// Snapshot of the authenticated user's Copilot subscription info, if known. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// Authentication host. + [JsonPropertyName("host")] + public required string Host { get; set; } - /// Immutable terminal receipt. - [JsonPropertyName("outcome")] - public required McpInstallationOutcome Outcome { get; set; } + /// Opaque SDK callback registration identifier. + [JsonPropertyName("registrationId")] + public required string RegistrationId { get; set; } } -/// The operation variant of . +/// Authentication-info variant for direct Copilot API token auth sourced from environment variables, with public GitHub host. +/// The copilot-api-token variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationManagementOutcomeOperation : McpInstallationManagementOutcome +public partial class AuthInfoCopilotApiToken : AuthInfo { /// [JsonIgnore] - public override string Kind => "operation"; + public override string Type => "copilot-api-token"; - /// Original-connection operation snapshot. - [JsonPropertyName("operation")] - public required McpInstallationOperationStatus Operation { get; set; } + /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } + + /// Authentication host (always the public GitHub host). + [JsonPropertyName("host")] + public required string Host { get; set; } } -/// The refused variant of . +/// Authentication-info variant for OAuth user auth, with host and login; the token remains in the runtime secret store. +/// The user variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationManagementOutcomeRefused : McpInstallationManagementOutcome +public partial class AuthInfoUser : AuthInfo { /// [JsonIgnore] - public override string Kind => "refused"; + public override string Type => "user"; - /// Specific bounded refusal. - [JsonPropertyName("reason")] - public required McpInstallationFailureReason Reason { get; set; } + /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } + + /// Authentication host. + [JsonPropertyName("host")] + public required string Host { get; set; } + + /// OAuth user login. + [JsonPropertyName("login")] + public required string Login { get; set; } } -/// The outcome variant of . +/// An interactive account whose model provider owns its credentials. It carries no GitHub credential. +/// The account variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationManagementResultOutcome : McpInstallationManagementResult +public partial class AuthInfoAccount : AuthInfo { /// [JsonIgnore] - public override string Kind => "outcome"; + public override string Type => "account"; - /// Capabilities actually honoured for this request. - [JsonPropertyName("negotiated")] - public required CatalogNegotiatedContract Negotiated { get; set; } + /// Host coordinate owned by the account's model provider. + [JsonPropertyName("host")] + public required string Host { get; set; } - /// Observed management outcome. - [JsonPropertyName("outcome")] - public required McpInstallationManagementOutcome Outcome { get; set; } + /// Login identifying the provider-owned account. + [JsonPropertyName("login")] + public required string Login { get; set; } } -/// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. -/// The negotiation-refused variant of . +/// Authentication-info input variant for GitHub CLI credentials, carrying host, login, and the `gh auth token` value. +/// The gh-cli variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationManagementResultNegotiationRefused : McpInstallationManagementResult +public partial class AuthInfoGhCli : AuthInfo { /// [JsonIgnore] - public override string Kind => "negotiation-refused"; - - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } - - /// Lowest caller protocol version this runtime will serve. - [JsonPropertyName("minimumSupportedProtocolVersion")] - public required long MinimumSupportedProtocolVersion { get; set; } + public override string Type => "gh-cli"; - /// Whether the version or the capability set was the problem. - [JsonPropertyName("reason")] - public required CatalogNegotiationRefusedReason Reason { get; set; } + /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } - /// Protocol version of the runtime that refused the request. - [JsonPropertyName("runtimeProtocolVersion")] - public required long RuntimeProtocolVersion { get; set; } + /// Authentication host. + [JsonPropertyName("host")] + public required string Host { get; set; } - /// Capabilities this runtime can safely advertise to this caller. The complete five-capability protocol-3 legacy set is always present; every capability added after that baseline appears only when the caller required it, so an older closed-enum decoder can still consume a refusal. This list does not imply that every deployment has enabled every operation. - [JsonPropertyName("supportedCapabilities")] - public required IList SupportedCapabilities { get; set; } + /// User login as reported by `gh auth status`. + [JsonPropertyName("login")] + public required string Login { get; set; } - /// The subset of the caller's bounded extensible capability identifiers this runtime cannot honour. - [JsonPropertyName("unsupportedCapabilities")] - public required IList UnsupportedCapabilities { get; set; } + /// The token returned by `gh auth token`. Treat as a secret. + [JsonPropertyName("token")] + public required string Token { get; set; } } -/// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. -/// The invalid-request variant of . +/// Authentication-info input variant for API-key authentication to a non-GitHub LLM provider, carrying the secret `apiKey` and host. +/// The api-key variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationManagementResultInvalidRequest : McpInstallationManagementResult +public partial class AuthInfoApiKey : AuthInfo { /// [JsonIgnore] - public override string Kind => "invalid-request"; + public override string Type => "api-key"; - /// Which request field was rejected. - [JsonPropertyName("field")] - public required CatalogInvalidRequestField Field { get; set; } + /// The API key. Treat as a secret. + [JsonPropertyName("apiKey")] + public required string ApiKey { get; set; } - /// Human-readable explanation, safe to surface. Never echoes the offending value, nor a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } + + /// Authentication host. + [JsonPropertyName("host")] + public required string Host { get; set; } } -/// One Registry string-valued configuration entry for the selected transport. +/// Current authentication state. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpInstallationInput +public sealed class AccountGetCurrentAuthResult { - /// Exact category declared by the selected choice. - [JsonPropertyName("category")] - public McpPlanValueCategory Category { get; set; } - - /// Exact key declared by the selected choice. - [JsonPropertyName("key")] - public string Key { get; set; } = string.Empty; + /// Authentication errors from the last auth attempt, if any. + [JsonPropertyName("authErrors")] + public IList? AuthErrors { get; set; } - /// Explicit non-secret value. Secret placeholders use a separate input channel. - [JsonPropertyName("value")] - public string Value { get; set; } = string.Empty; + /// Current authentication information, if authenticated. + [JsonPropertyName("authInfo")] + public AuthInfo? AuthInfo { get; set; } } -/// A request-local value for one exact reviewed placeholder. Never logged or persisted in a plan. +/// Authenticated account entry returned by `account.getAllUsers`. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpInstallationSecret +public sealed class AccountAllUsers { - /// Exact placeholder from the selected choice, not a caller-chosen backend identifier. - [JsonPropertyName("placeholder")] - public string Placeholder { get; set; } = string.Empty; + /// Authentication information for this user. + [JsonPropertyName("authInfo")] + public AuthInfo AuthInfo { get => field ??= new(); set; } - /// Fresh explicit secret value. It is omitted from confirmation reviews and telemetry. - [JsonPropertyName("value")] - public string Value { get; set; } = string.Empty; + /// Opaque identifier accepted by account and model selection APIs. + [JsonPropertyName("selectionId")] + public string? SelectionId { get; set; } + + /// Associated token, if available. + [JsonPropertyName("token")] + public string? Token { get; set; } } -/// Side-effect-free preparation of one original bound remote MCP choice. +/// Result of a successful login; throws on failure. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpPrepareInstallRequest +public sealed class AccountLoginResult { - /// Exact selected alternative from that plan. - [JsonPropertyName("choiceId")] - public string ChoiceId { get; set; } = string.Empty; - - /// Required bound catalogue and confirmed remote installation capabilities. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } - - /// - /// Declared non-secret values. Non-empty only when the caller requires - /// `mcp-configured-remote-installation`; omitted values use the card default. - /// - [JsonPropertyName("inputs")] - public IList Inputs { get => field ??= []; set; } - - /// Original single-use bound plan, never a client-authored configuration. - [JsonPropertyName("planHandle")] - public string PlanHandle { get; set; } = string.Empty; - - /// An existing local session attached to this connection, not permission to attach one. - [JsonPropertyName("policySessionId")] - public string PolicySessionId { get; set; } = string.Empty; + /// Whether the credential was persisted to a secure store (system keychain, or the config file when plaintext storage is enabled). False when no secure store was available and the token was not saved, so the consumer can decide how to proceed. + [JsonPropertyName("storedInVault")] + public bool StoredInVault { get; set; } +} - /// - /// One entry per declared secret placeholder of the selected choice. Non-empty - /// only when the caller requires `mcp-configured-remote-installation`. - /// - [JsonPropertyName("secrets")] - public IList Secrets { get => field ??= []; set; } +/// Credentials to validate and store. Omit login to resolve the authenticated user from the token. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AccountLoginRequest +{ + /// GitHub host URL. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; - /// The trusted host presents this choice alongside the exact secret placeholders. - [JsonPropertyName("secretStorage")] - public McpInstallationSecretStorage SecretStorage { get; set; } + /// User login/username. When omitted, the runtime validates the token and resolves the login from GitHub. + [JsonPropertyName("login")] + public string? Login { get; set; } - /// The exact original source, used transiently only after confirmation. - [JsonPropertyName("source")] - public McpServerCardReference Source { get => field ??= new(); set; } + /// GitHub authentication token. + [JsonPropertyName("token")] + public string Token { get; set; } = string.Empty; } -/// An installation result together with the exact honoured contract, or a negotiation refusal. -/// Polymorphic base type discriminated by kind. +/// Logout result indicating if more users remain. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpInstallationResultOutcome), "outcome")] -[JsonDerivedType(typeof(McpInstallationResultNegotiationRefused), "negotiation-refused")] -[JsonDerivedType(typeof(McpInstallationResultInvalidRequest), "invalid-request")] -public partial class McpInstallationResult +public sealed class AccountLogoutResult { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; + /// Whether other authenticated users remain after logout. + [JsonPropertyName("hasMoreUsers")] + public bool HasMoreUsers { get; set; } } - -/// The outcome variant of . +/// User to log out. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationResultOutcome : McpInstallationResult +internal sealed class AccountLogoutRequest { - /// - [JsonIgnore] - public override string Kind => "outcome"; - - /// Capabilities actually honoured for this request. - [JsonPropertyName("negotiated")] - public required CatalogNegotiatedContract Negotiated { get; set; } + /// Authentication information for the user to log out. + [JsonPropertyName("authInfo")] + public AuthInfo? AuthInfo { get; set; } - /// Terminal result of the original operation. - [JsonPropertyName("outcome")] - public required McpInstallationOutcome Outcome { get; set; } + /// Opaque account identifier returned by `account.getAllUsers`. + [JsonPropertyName("selectionId")] + public string? SelectionId { get; set; } } -/// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. -/// The negotiation-refused variant of . +/// The wording the runtime uses for an authentication identity. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationResultNegotiationRefused : McpInstallationResult +internal sealed class AccountDescribeAuthInfoResult { - /// - [JsonIgnore] - public override string Kind => "negotiation-refused"; + /// One-line description of the identity, suitable after a verb such as "Switched to". + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] + /// Sign-in banner announcing the authenticated user. [JsonPropertyName("message")] - public required string Message { get; set; } - - /// Lowest caller protocol version this runtime will serve. - [JsonPropertyName("minimumSupportedProtocolVersion")] - public required long MinimumSupportedProtocolVersion { get; set; } - - /// Whether the version or the capability set was the problem. - [JsonPropertyName("reason")] - public required CatalogNegotiationRefusedReason Reason { get; set; } - - /// Protocol version of the runtime that refused the request. - [JsonPropertyName("runtimeProtocolVersion")] - public required long RuntimeProtocolVersion { get; set; } - - /// Capabilities this runtime can safely advertise to this caller. The complete five-capability protocol-3 legacy set is always present; every capability added after that baseline appears only when the caller required it, so an older closed-enum decoder can still consume a refusal. This list does not imply that every deployment has enabled every operation. - [JsonPropertyName("supportedCapabilities")] - public required IList SupportedCapabilities { get; set; } - - /// The subset of the caller's bounded extensible capability identifiers this runtime cannot honour. - [JsonPropertyName("unsupportedCapabilities")] - public required IList UnsupportedCapabilities { get; set; } + public string Message { get; set; } = string.Empty; } -/// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. -/// The invalid-request variant of . +/// Credential-free authentication identity safe to expose to hosts and user interfaces. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationResultInvalidRequest : McpInstallationResult +public sealed class AuthIdentity { - /// - [JsonIgnore] - public override string Kind => "invalid-request"; + /// Snapshot of the authenticated user's Copilot subscription info, if known. + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } - /// Which request field was rejected. - [JsonPropertyName("field")] - public required CatalogInvalidRequestField Field { get; set; } + /// Name of the environment variable that supplied the credential, when applicable. + [JsonPropertyName("envVar")] + public string? EnvVar { get; set; } - /// Human-readable explanation, safe to surface. Never echoes the offending value, nor a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } -} + /// Authentication host. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; -/// Applies exactly one previously prepared operation on its original connection. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpApplyInstallRequest -{ - /// Capabilities required by the original prepared operation. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// Authenticated login, when available. + [JsonPropertyName("login")] + public string? Login { get; set; } - /// Runtime-issued ID already returned by prepareInstall, never reused or rebound. - [JsonPropertyName("operationId")] - public string OperationId { get; set; } = string.Empty; + /// Opaque SDK GitHub credential registration backing this identity. Routing metadata only; never a credential. + [JsonPropertyName("registrationId")] + public string? RegistrationId { get; set; } - /// Same existing attached or privately borrowed session as preparation. - [JsonPropertyName("policySessionId")] - public string PolicySessionId { get; set; } = string.Empty; + /// Authentication type. + [JsonPropertyName("type")] + public AuthInfoType Type { get; set; } } -/// Read-only preparation of one owned removal under fresh selected-session authority. +/// The authentication identity whose shared wording should be rendered. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpPlanUninstallRequest +internal sealed class AccountDescribeAuthInfoRequest { - /// Required authenticated bound installation capabilities. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } - - /// Exact receipt to inspect, not a server-name guess. - [JsonPropertyName("installationId")] - public string InstallationId { get; set; } = string.Empty; - - /// Existing selected session on the original connection. - [JsonPropertyName("policySessionId")] - public string PolicySessionId { get; set; } = string.Empty; + /// Identity to describe. + [JsonPropertyName("identity")] + public AuthIdentity Identity { get => field ??= new(); set; } } -/// One-use application of the exact retained removal plan. +/// Whether the identity can create gists, and why not when it cannot. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpApplyUninstallRequest +internal sealed class AccountGetGistSupportResult { - /// Required authenticated bound installation capabilities. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// Machine-readable reason category when unsupported. + [JsonPropertyName("kind")] + public string? Kind { get; set; } - /// Opaque original removal plan, consumed once. - [JsonPropertyName("planHandle")] - public string PlanHandle { get; set; } = string.Empty; + /// Human-readable explanation to show where the gist action would have been. + [JsonPropertyName("reason")] + public string? Reason { get; set; } - /// Same existing selected session as removal preparation. - [JsonPropertyName("policySessionId")] - public string PolicySessionId { get; set; } = string.Empty; + /// True when the identity can create gists. + [JsonPropertyName("supported")] + public bool Supported { get; set; } } -/// User-configured MCP servers, keyed by server name. +/// The authentication identity whose gist support should be reported. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpConfigList +internal sealed class AccountGetGistSupportRequest { - /// All MCP servers from user config, keyed by name. - [JsonPropertyName("servers")] - public IDictionary Servers { get => field ??= new Dictionary(); set; } + /// Identity to evaluate. + [JsonPropertyName("identity")] + public AuthIdentity Identity { get => field ??= new(); set; } } -/// MCP server name and configuration to add to user configuration. +/// An absolute URL on the identity's GitHub host. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpConfigAddRequest +internal sealed class AccountGetWebUrlResult { - /// MCP server configuration (stdio process or remote HTTP/SSE). - [JsonPropertyName("config")] - public JsonElement Config { get; set; } - - /// Unique name for the MCP server. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Absolute URL for the requested path. + [JsonPropertyName("url")] + public string Url { get; set; } = string.Empty; } -/// MCP server name and replacement configuration to write to user configuration. +/// A path to resolve against the GitHub host an identity is signed in to. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpConfigUpdateRequest +internal sealed class AccountGetWebUrlRequest { - /// MCP server configuration (stdio process or remote HTTP/SSE). - [JsonPropertyName("config")] - public JsonElement Config { get; set; } + /// Identity whose host the path resolves against. Omit to resolve against the public github.com host. + [JsonPropertyName("identity")] + public AuthIdentity? Identity { get; set; } - /// Name of the MCP server to update. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + /// Host-relative path, without a leading slash, for example `settings/copilot/features`. [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] [MinLength(1)] - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; } -/// MCP server name to remove from user configuration. +/// The environment variable supplying a classic personal access token, when one is set. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpConfigRemoveRequest +internal sealed class AccountGetTokenEnvVarResult { - /// OAuth Client ID Metadata Document URL whose persisted credentials should also be removed. - [JsonPropertyName("authClientIdMetadataUrl")] - public string? AuthClientIdMetadataUrl { get; set; } - - /// Name of the MCP server to remove. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] + /// Variable name, for example `GH_TOKEN`. Absent when no classic token is present in the environment. [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + public string? Name { get; set; } } -/// MCP server names to enable for new sessions. +/// Confirmation that the secret values were registered. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpConfigEnableRequest +public sealed class SecretsAddFilterValuesResult { - /// Names of MCP servers to enable. Each server is removed from the persisted disabled list so new sessions spawn it. Unknown or already-enabled names are ignored. - [JsonPropertyName("names")] - public IList Names { get => field ??= []; set; } + /// Whether the values were successfully registered. + [JsonPropertyName("ok")] + public bool Ok { get; set; } } -/// MCP server names to disable for new sessions. +/// Secret values to add to the redaction filter. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpConfigDisableRequest +internal sealed class SecretsAddFilterValuesRequest { - /// Names of MCP servers to disable. Each server is added to the persisted disabled list so new sessions skip it. Already-disabled names are ignored. Active sessions keep their current connections until they end. - [JsonPropertyName("names")] - public IList Names { get => field ??= []; set; } + /// Raw secret values to register for redaction. + [JsonPropertyName("values")] + public IList Values { get => field ??= []; set; } } -/// Request id naming a cancellable registry search. +/// Concrete configuration file containing an MCP server declaration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpRegistryRequestIdResult +public sealed class McpSourceFile { - /// Request ID for `mcp.registry.search` and `mcp.registry.cancel`. It serves one search. Allocation can reclaim unused IDs at the 1,024-ID reservation limit. - [JsonPropertyName("requestId")] - public long RequestId { get; set; } -} + /// RFC 6901 JSON Pointer to the server declaration, when known. + [JsonPropertyName("jsonPointer")] + public string? JsonPointer { get; set; } -/// Servers selected from the registry response. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpRegistrySearchResult -{ - /// The server objects, carried opaquely. The runtime follows pages, keeps the newest entry per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub stars. Each server object remains unchanged because the registry owns that shape. - [JsonPropertyName("servers")] - public JsonElement Servers { get; set; } + /// Canonical file URI for the configuration document. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("uri")] + public string Uri { get; set; } = string.Empty; } -/// Registry search terms, the credential to search under, and the request id that makes the search cancellable. +/// Plugin identity associated with an MCP server declaration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpRegistrySearchRequest +public sealed class McpSourcePlugin { - /// The credential the search runs under, carried opaquely. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. - [JsonPropertyName("authInfo")] - public JsonElement AuthInfo { get; set; } - - /// Maximum number of servers to return. - [JsonPropertyName("limit")] - public long Limit { get; set; } - - /// Free-text query. Omitted or empty asks the registry for its top servers rather than searching. A value that is not a string is refused. - [JsonPropertyName("query")] - public string? Query { get; set; } - - /// Repository used for the policy lookup, as `owner/name`. The policy selects the registry URL and whether the user token goes to the registry. The registry receives this repository only when the policy entry lists it as required context. A value that is not a string is refused. - [JsonPropertyName("repository")] - public string? Repository { get; set; } + /// Canonical plugin identity. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Request ID from `mcp.registry.allocateRequestId`. The search refuses unknown, reclaimed, or canceled IDs and IDs that another search or request already uses. - [JsonPropertyName("requestId")] - public long RequestId { get; set; } -} + /// Human-readable plugin name, when available. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("name")] + public string? Name { get; set; } -/// Whether the cancel reached a live search. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpRegistryCancelResult -{ - /// True when the cancel stopped a running search. False for unknown or reclaimed IDs, completed or canceled searches, and unused reservations. The cancel releases an unused reservation. - [JsonPropertyName("canceled")] - public bool Canceled { get; set; } + /// Plugin version, when available. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("version")] + public string? Version { get; set; } } -/// Registry search to abandon. +/// Canonical identity and location of the effective MCP server declaration. The declaration is uniquely addressed by this source id together with the discovered server name. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpRegistryCancelRequest +public sealed class McpSourceRef { - /// Request ID from `mcp.registry.allocateRequestId` that the search uses. - [JsonPropertyName("requestId")] - public long RequestId { get; set; } -} + /// Open semantic editability identifier. Known values are editable and read-only. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("editability")] + public string Editability { get; set; } = string.Empty; -/// New-work inventory or recovery request under an explicitly selected existing session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpInstallationsRequest -{ - /// Required authenticated bound installation contract. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// Configuration file location, when the declaration is file-backed. + [JsonPropertyName("file")] + public McpSourceFile? File { get; set; } - /// Existing selected local session on this connection. - [JsonPropertyName("policySessionId")] - public string PolicySessionId { get; set; } = string.Empty; -} + /// Opaque stable identity for the configuration source. Clients must not parse this value. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; -/// Existing-operation control. A new session selector is deliberately not accepted. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpInstallationOperationRequest -{ - /// Original installation wire capability; new-work authentication is not reacquired. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// Open source-kind identifier. Known values include user, workspace, invocation, plugin, builtin, and device-registry. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("kind")] + public string Kind { get; set; } = string.Empty; - /// Exact runtime-issued operation ID on the original connection. - [JsonPropertyName("operationId")] - public string OperationId { get; set; } = string.Empty; + /// Plugin identity, when the declaration is plugin-provided. + [JsonPropertyName("plugin")] + public McpSourcePlugin? Plugin { get; set; } } -/// Installed plugin that contributes a discovered extension. +/// MCP server discovered by `mcp.discover`, with config source, optional plugin source, transport type, and enabled state. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DiscoveredExtensionPlugin +public sealed class DiscoveredMcpServer { - /// Installed plugin name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; -} + /// Canonical identity and location of the effective server declaration. + [JsonPropertyName("effectiveSource")] + public McpSourceRef? EffectiveSource { get; set; } -/// Discovered extension metadata and persistent enablement state. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DiscoveredExtension -{ - /// Whether this extension's persistent per-ID preference is enabled. + /// Whether the server is enabled (not in the disabled list). [JsonPropertyName("enabled")] public bool Enabled { get; set; } - /// Source-qualified ID accepted by both server and session extension enablement methods. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - - /// Human-readable extension name. + /// Server name (config key). + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; - /// Absolute path to the extension entry module, suitable for revealing it in a file manager. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Configuration source: user, workspace, plugin, or builtin. + [JsonPropertyName("source")] + public McpServerSource Source { get; set; } - /// Containing plugin metadata for plugin-contributed extensions. - [JsonPropertyName("plugin")] - public DiscoveredExtensionPlugin? Plugin { get; set; } + /// Plugin name that provided this server, when source is plugin. + [JsonPropertyName("sourcePlugin")] + public string? SourcePlugin { get; set; } - /// Discovery source. - [JsonPropertyName("source")] - public DiscoveredExtensionSource Source { get; set; } + /// Plugin version that provided this server, when source is plugin. + [JsonPropertyName("sourcePluginVersion")] + public string? SourcePluginVersion { get; set; } + + /// Server transport type: stdio, http, sse (deprecated), or memory. + [JsonPropertyName("type")] + public DiscoveredMcpServerType? Type { get; set; } } -/// Extensions discovered from persisted Copilot home state and their effective loading mode. Launch-scoped additional plugins are not included. +/// MCP servers discovered from user, workspace, plugin, and built-in sources. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DiscoveredExtensions +public sealed class McpDiscoverResult { - /// Discovered user and enabled installed-plugin extensions from persisted Copilot home state. - [JsonPropertyName("extensions")] - public IList Extensions { get => field ??= []; set; } - - /// Effective extension loading mode. Defaults to load_and_augment when unset. - [JsonPropertyName("mode")] - public DiscoveredExtensionMode Mode { get; set; } + /// MCP servers discovered from all sources. + [JsonPropertyName("servers")] + public IList Servers { get => field ??= []; set; } } -/// Source-qualified extension identifiers to persistently enable for future sessions. +/// Optional working directory used as context for MCP server discovery. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class DiscoveredExtensionsEnableRequest +internal sealed class McpDiscoverRequest { - /// Source-qualified user or plugin extension IDs to enable. - [JsonPropertyName("ids")] - public IList Ids { get => field ??= []; set; } + /// Whether to include canonical effectiveSource metadata for each discovered server. Callers must opt in so protocol-3 clients retain the legacy closed response shape. + [JsonPropertyName("includeEffectiveSource")] + public bool? IncludeEffectiveSource { get; set; } + + /// Working directory used as context for discovery (e.g., plugin resolution). + [JsonPropertyName("workingDirectory")] + public string? WorkingDirectory { get; set; } } -/// Source-qualified extension identifiers to persistently disable for future sessions. +/// Names of the MCP servers the runtime supplies itself. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class DiscoveredExtensionsDisableRequest +internal sealed class McpListBuiltinServerNamesResult { - /// Source-qualified user or plugin extension IDs to disable. - [JsonPropertyName("ids")] - public IList Ids { get => field ??= []; set; } + /// Every built-in server name. A host disabling the built-ins wholesale suppresses exactly this set. + [JsonPropertyName("names")] + public IList Names { get => field ??= []; set; } } -/// The prompt the init command runs. +/// Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by the request. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class InstructionsInitPromptResult +internal sealed class McpShouldExcludeGitHubToolsResult { - /// Prompt text authoring repository instructions. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; + /// True only when both halves hold: the session's filters still reach the platform shell tool, and the host actually has the `gh` those tools would be replaced by. Feed it straight back as the `excludeGhReplaceableTools` build option. + [JsonPropertyName("excludeGhReplaceableTools")] + public bool ExcludeGhReplaceableTools { get; set; } } -/// Loaded instruction source for a session, including path, content, category, location, applicability, and optional description. +/// The session tool filters that decide whether the session still has a shell to run `gh` with. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class InstructionSource +internal sealed class McpShouldExcludeGitHubToolsRequest { - /// Glob pattern(s) from frontmatter — when set, this instruction applies only to matching files. - [JsonPropertyName("applyTo")] - public IList? ApplyTo { get; set; } + /// The session's tool allowlist, when it set one. Omitted means the session constrains nothing this way. + [JsonPropertyName("availableTools")] + public IList? AvailableTools { get; set; } - /// Raw content of the instruction file. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; - - /// When true, this source starts disabled and must be toggled on by the user. - [JsonPropertyName("defaultDisabled")] - public bool? DefaultDisabled { get; set; } - - /// Short description (body after frontmatter) for use in instruction tables. - [JsonPropertyName("description")] - public string? Description { get; set; } - - /// Unique identifier for this source (used for toggling). - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - - /// Human-readable label. - [JsonPropertyName("label")] - public string Label { get; set; } = string.Empty; - - /// Where this source lives — used for UI grouping. - [JsonPropertyName("location")] - public InstructionSourceLocation Location { get; set; } - - /// The project path this source was discovered from. Only set by sessionless discovery for repository, working-directory, and project-scoped plugin sources, where it disambiguates sources across multiple workspace roots. The session-scoped getSources leaves it unset. - [JsonPropertyName("projectPath")] - public string? ProjectPath { get; set; } - - /// File path relative to repo or absolute for home. - [JsonPropertyName("sourcePath")] - public string SourcePath { get; set; } = string.Empty; + /// The session's tool denylist, when it set one. Omitted means the session constrains nothing this way. + [JsonPropertyName("excludedTools")] + public IList? ExcludedTools { get; set; } - /// Category of instruction source — used for merge logic. - [JsonPropertyName("type")] - public InstructionSourceType Type { get; set; } + /// How the allowlist and denylist combine when both are set. Omitted means the default every session gets, so a caller that never chose a precedence is answered as its sessions behave. + [JsonPropertyName("toolFilterPrecedence")] + public OptionsUpdateToolFilterPrecedence? ToolFilterPrecedence { get; set; } } -/// Instruction sources discovered across user, repository, and plugin sources. +/// Outcome of an mcp.planInstall call: either a normalised plan, or one typed refusal. Nothing is written in either case. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerInstructionSourceList +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(McpPlanInstallResultPlanned), "planned")] +[JsonDerivedType(typeof(McpPlanInstallResultNegotiationRefused), "negotiation-refused")] +[JsonDerivedType(typeof(McpPlanInstallResultHandleRejected), "handle-rejected")] +[JsonDerivedType(typeof(McpPlanInstallResultInvalidRequest), "invalid-request")] +[JsonDerivedType(typeof(McpPlanInstallResultAuthenticationRequired), "authentication-required")] +[JsonDerivedType(typeof(McpPlanInstallResultPolicyRejected), "policy-rejected")] +[JsonDerivedType(typeof(McpPlanInstallResultNetworkFailure), "network-failure")] +[JsonDerivedType(typeof(McpPlanInstallResultUnsafeRetrieval), "unsafe-retrieval")] +[JsonDerivedType(typeof(McpPlanInstallResultMalformedCard), "malformed-card")] +[JsonDerivedType(typeof(McpPlanInstallResultContractViolation), "contract-violation")] +[JsonDerivedType(typeof(McpPlanInstallResultUnavailableTransport), "unavailable-transport")] +[JsonDerivedType(typeof(McpPlanInstallResultNotInstallable), "not-installable")] +[JsonDerivedType(typeof(McpPlanInstallResultUnavailable), "unavailable")] +public partial class McpPlanInstallResult { - /// All discovered instruction sources. - [JsonPropertyName("sources")] - public IList Sources { get => field ??= []; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Optional project paths to include in instruction discovery. + +/// The protocol version and capability set the runtime actually honoured for a successful catalog operation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class InstructionsDiscoverRequest +public sealed class CatalogNegotiatedContract { - /// When true, omit the host's instruction sources (user/home-level files and plugin rules), leaving only repository and working-directory sources. For multitenant deployments. - [JsonPropertyName("excludeHostInstructions")] - public bool? ExcludeHostInstructions { get; set; } - - /// Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without ambient discovery, subject to instruction/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. - [JsonPropertyName("instructionDirectories")] - public IList? InstructionDirectories { get; set; } + /// Wire features the runtime understood for this operation. Includes the five original catalog capabilities and only explicitly requested supported additions, in supported order without duplicates. Capabilities that introduce new success-union variants or operations are therefore included only when explicitly required, preserving older protocol-v3 clients. Always a superset of the caller's required features, because any shortfall is a refusal instead. Operation availability remains a separate typed result. + [JsonPropertyName("grantedCapabilities")] + public IList GrantedCapabilities { get => field ??= []; set; } - /// Optional list of project directory paths to scan for repository/working-directory instruction sources. When omitted or empty, only user-level and plugin instruction sources are returned (no project scan). - [JsonPropertyName("projectPaths")] - public IList? ProjectPaths { get; set; } + /// Protocol version of the runtime that served the request. + [JsonPropertyName("runtimeProtocolVersion")] + public long RuntimeProtocolVersion { get; set; } } -/// Explicit discovery arguments for one location, supplied by the caller rather than derived from a session. +/// The configuration-change alternative for the transportChoices entry at the same index. Only the selected alternative is applied; entries are not cumulative. The payload stays behind the runtime boundary. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class InstructionsDiscoverRepoSourcesRequest +public sealed class McpPlanConfigurationChange { - /// Extra directories to scan alongside instruction directories configured in the runtime environment. - [JsonPropertyName("additionalDirs")] - public IList? AdditionalDirs { get; set; } - - /// Copilot configuration directory for user-level sources. An omitted or empty value uses the server's configuration home. - [JsonPropertyName("configDir")] - public string? ConfigDir { get; set; } + /// Names of the configuration fields the change would set, without their values. + [JsonPropertyName("changedFields")] + public IList ChangedFields { get => field ??= []; set; } - /// Working directory whose instruction sources should also be included. Omission adds no separate working-directory scope. - [JsonPropertyName("cwdPath")] - public string? CwdPath { get; set; } + /// Configuration key the change applies to. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("configKey")] + public string ConfigKey { get; set; } = string.Empty; - /// When true, also discover instruction files nested below the location. - [JsonPropertyName("enableChildInstructions")] - public bool? EnableChildInstructions { get; set; } + /// Whether the change would create a new entry or modify an existing one. + [JsonPropertyName("operation")] + public McpPlanConfigurationOperation Operation { get; set; } - /// When true, include the sources a command-line host reads. Hosts that are not the CLI omit it. - [JsonPropertyName("isCli")] - public bool? IsCli { get; set; } + /// Scope the change would be written to. + [JsonPropertyName("scope")] + public McpPlanScope Scope { get; set; } - /// Repository location to discover. An empty string selects no repository scope; cwdPath can still supply working-directory sources. - [JsonPropertyName("location")] - public string Location { get; set; } = string.Empty; + /// Secret placeholders the written configuration would reference. The constrained placeholder type cannot carry a literal secret value. + [JsonPropertyName("secretReferences")] + public IList SecretReferences { get => field ??= []; set; } } -/// Canonical file or directory where custom instructions can be discovered or created, with location, kind, preference, and project path. +/// Normalised identity of the MCP server a plan targets, independent of how the card spelled it. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class InstructionDiscoveryPath +public sealed class McpPlanResourceIdentity { - /// Whether the target is a single file or a directory of instruction files. - [JsonPropertyName("kind")] - public InstructionDiscoveryPathKind Kind { get; set; } + /// Canonical, normalised name of the server, for example `io.github.owner/server`. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("canonicalName")] + public string CanonicalName { get; set; } = string.Empty; - /// Which tier this target belongs to. - [JsonPropertyName("location")] - public InstructionDiscoveryPathLocation Location { get; set; } + /// Registry identifier of the server, when it came from a registry. + [JsonPropertyName("registryId")] + public string? RegistryId { get; set; } - /// Absolute path of the file or directory (may not exist on disk yet). - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Local configuration key the server would be recorded under. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; - /// Whether this is the canonical target to create new instructions in its tier. At most one entry per tier is preferred. - [JsonPropertyName("preferredForCreation")] - public bool PreferredForCreation { get; set; } + /// Version advertised by the card, when it declares one. + [JsonPropertyName("version")] + public string? Version { get; set; } +} - /// The input project path this target was derived from (only for repository targets). - [JsonPropertyName("projectPath")] - public string? ProjectPath { get; set; } +/// Outcome of evaluating the planned server against registry and enterprise policy. Evaluation is read-only. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpPlanPolicyResult +{ + /// What policy decided for this server. + [JsonPropertyName("decision")] + public McpPlanPolicyDecision Decision { get; set; } + + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("reason")] + public string? Reason { get; set; } + + /// Which authority produced the decision. + [JsonPropertyName("source")] + public McpPlanPolicySource Source { get; set; } } -/// Canonical files and directories where custom instructions can be created so the runtime will recognize them. +/// Semantic digest of a strictly parsed and schema-validated JSON MCP card. Both URL-backed and embedded cards are canonicalised with RFC 8785 JSON Canonicalization Scheme, encoded as UTF-8, and hashed with SHA-256. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class InstructionDiscoveryPathList +public sealed class CardDigest { - /// Canonical instruction create/discovery files and directories, in priority order. - [JsonPropertyName("paths")] - public IList Paths { get => field ??= []; set; } + /// Digest algorithm and canonical representation. + [JsonPropertyName("algorithm")] + public CardDigestAlgorithm Algorithm { get; set; } + + /// SHA-256 digest of the RFC 8785 canonical UTF-8 bytes, encoded as exactly 64 lowercase hexadecimal characters. + [RegularExpression("^[0-9a-f]{64}$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(64)] + [MaxLength(64)] + [JsonPropertyName("value")] + public string Value { get; set; } = string.Empty; } -/// Optional project paths to include when enumerating instruction discovery targets. +/// Provenance of the exact validated JSON MCP card content bound privately to a completed plan and its opaque handle. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class InstructionsGetDiscoveryPathsRequest +public sealed class McpPlanProvenance { - /// When true, omit the host's user-level instruction targets, leaving only repository targets. For multitenant deployments (mirrors `discover`'s `excludeHostInstructions`). - [JsonPropertyName("excludeHostInstructions")] - public bool? ExcludeHostInstructions { get; set; } + /// Authority associated with the validated card, without path, query, or credentials. Inert untrusted data. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("authority")] + public string Authority { get; set; } = string.Empty; - /// Explicit discovery-only instruction roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. - [JsonPropertyName("instructionDirectories")] - public IList? InstructionDirectories { get; set; } + /// Semantic digest of the exact validated JSON content bound to the plan handle. + [JsonPropertyName("cardDigest")] + public CardDigest CardDigest { get => field ??= new(); set; } - /// Optional list of project directory paths. When omitted or empty, only the user-level targets are returned. - [JsonPropertyName("projectPaths")] - public IList? ProjectPaths { get; set; } + /// JSON MCP media type the validated card was interpreted as. + [JsonPropertyName("mediaType")] + public McpServerCardMediaType MediaType { get; set; } + + /// ISO 8601 timestamp at which the runtime completed strict parsing and schema validation of the card content. + [JsonPropertyName("validatedAt")] + public string ValidatedAt { get; set; } = string.Empty; } -/// Skill installation management result with the honoured contract, or a typed refusal. -/// Polymorphic base type discriminated by kind. +/// Where a plan would be written. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpPlanTarget +{ + /// Configuration key the server would be recorded under within that scope. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("configKey")] + public string ConfigKey { get; set; } = string.Empty; + + /// Configuration scope the plan targets. + [JsonPropertyName("scope")] + public McpPlanScope Scope { get; set; } +} + +/// One eligible way to run the server, represented as a tagged package or remote variant so package identity and endpoint states cannot contradict the install method. +/// Polymorphic base type discriminated by installMethod. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", + TypeDiscriminatorPropertyName = "installMethod", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(SkillInstallationManagementResultOutcome), "outcome")] -[JsonDerivedType(typeof(SkillInstallationManagementResultNegotiationRefused), "negotiation-refused")] -[JsonDerivedType(typeof(SkillInstallationManagementResultInvalidRequest), "invalid-request")] -public partial class SkillInstallationManagementResult +[JsonDerivedType(typeof(McpPlanTransportChoicePackage), "package")] +[JsonDerivedType(typeof(McpPlanTransportChoiceRemote), "remote")] +public partial class McpPlanTransportChoice { /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; + [JsonPropertyName("installMethod")] + public virtual string InstallMethod { get; set; } = string.Empty; } -/// Management outcome for verified Skill inventory, planning and removal. +/// One non-secret value a transport choice needs, represented as a scalar or enumerated variant so enum values cannot be missing or attached to another type. /// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( TypeDiscriminatorPropertyName = "kind", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(SkillInstallationManagementOutcomeRecoveryRequired), "recovery-required")] -[JsonDerivedType(typeof(SkillInstallationManagementOutcomeInstallPlanned), "install-planned")] -[JsonDerivedType(typeof(SkillInstallationManagementOutcomeListed), "listed")] -[JsonDerivedType(typeof(SkillInstallationManagementOutcomeRecovered), "recovered")] -[JsonDerivedType(typeof(SkillInstallationManagementOutcomeRolledBack), "rolled-back")] -[JsonDerivedType(typeof(SkillInstallationManagementOutcomeUninstallPlanned), "uninstall-planned")] -[JsonDerivedType(typeof(SkillInstallationManagementOutcomeOperation), "operation")] -[JsonDerivedType(typeof(SkillInstallationManagementOutcomeEnabledChanged), "enabled-changed")] -[JsonDerivedType(typeof(SkillInstallationManagementOutcomeRefused), "refused")] -public partial class SkillInstallationManagementOutcome +[JsonDerivedType(typeof(McpPlanRequiredValueScalar), "scalar")] +[JsonDerivedType(typeof(McpPlanRequiredValueEnum), "enum")] +public partial class McpPlanRequiredValue { /// The type discriminator. [JsonPropertyName("kind")] @@ -4623,488 +4670,578 @@ public partial class SkillInstallationManagementOutcome } -/// Already-confirmed durable work must be reconciled before new mutations or inventory. -/// The recovery-required variant of . +/// One non-secret scalar value a transport choice needs before it can be applied. +/// The scalar variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementOutcomeRecoveryRequired : SkillInstallationManagementOutcome +public partial class McpPlanRequiredValueScalar : McpPlanRequiredValue { /// [JsonIgnore] - public override string Kind => "recovery-required"; -} + public override string Kind => "scalar"; -/// Safe verified Skill review fields. No raw credential, candidate handle or plan handle. -/// Polymorphic base type discriminated by action. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "action", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(SkillInstallationReviewInstall), "install")] -[JsonDerivedType(typeof(SkillInstallationReviewUninstall), "uninstall")] -public partial class SkillInstallationReview -{ - /// The type discriminator. - [JsonPropertyName("action")] - public virtual string Action { get; set; } = string.Empty; -} + /// Where the value is applied when the server is launched. + [JsonPropertyName("category")] + public required McpPlanValueCategory Category { get; set; } + /// Default supplied by the card, when the value can be resolved without input. Presence is the authoritative indication that a default exists. Inert untrusted data. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("defaultValue")] + public string? DefaultValue { get; set; } -/// One reviewed Skill file. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillInstallationFileReview -{ - /// SHA-256 digest of the exact file bytes. - [JsonPropertyName("digest")] - public string Digest { get; set; } = string.Empty; + /// Human-readable explanation from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } - /// Whether the file is installed with executable permissions. - [JsonPropertyName("executable")] - public bool Executable { get; set; } + /// Whether the value may be supplied more than once. + [JsonPropertyName("isRepeated")] + public required bool IsRepeated { get; set; } - /// Declared media type for the file. - [JsonPropertyName("mediaType")] - public string MediaType { get; set; } = string.Empty; + /// Key the value is supplied under. Inert untrusted data. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("key")] + public required string Key { get; set; } - /// Relative file path within the Skill root. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Whether the value must be present for the plan to be applicable. + [JsonPropertyName("required")] + public required bool Required { get; set; } - /// Exact reviewed file size in bytes. - [JsonPropertyName("sizeBytes")] - public long SizeBytes { get; set; } + /// Human-readable label from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(200)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("title")] + public string? Title { get; set; } + + /// Scalar type the value must conform to. + [JsonPropertyName("valueType")] + public required McpPlanScalarValueType ValueType { get; set; } } -/// Source identity retained from Agent Finder and the pinned GitHub descriptor. +/// One enumerated non-secret value a transport choice needs before it can be applied. The permitted values are structurally required. +/// The enum variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillInstallationSource +public partial class McpPlanRequiredValueEnum : McpPlanRequiredValue { - /// Digest of the descriptor's bundle manifest. - [JsonPropertyName("bundleDigest")] - public string BundleDigest { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "enum"; - /// Agent Finder materialisation revision identifier. - [JsonPropertyName("catalogRevisionId")] - public string CatalogRevisionId { get; set; } = string.Empty; + /// Where the value is applied when the server is launched. + [JsonPropertyName("category")] + public required McpPlanValueCategory Category { get; set; } - /// Digest of the canonical materialisation descriptor. - [JsonPropertyName("descriptorDigest")] - public string DescriptorDigest { get; set; } = string.Empty; + /// Default supplied by the card, when the value can be resolved without input. Presence is the authoritative indication that a default exists. Inert untrusted data. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("defaultValue")] + public string? DefaultValue { get; set; } - /// Repository full name, for example owner/name. - [JsonPropertyName("repository")] - public string Repository { get; set; } = string.Empty; + /// Human-readable explanation from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } - /// GitHub repository database identifier. - [JsonPropertyName("repositoryId")] - public string RepositoryId { get; set; } = string.Empty; + /// Non-empty permitted value set. Inert untrusted data. + [JsonPropertyName("enumValues")] + public required IList EnumValues { get; set; } - /// Agent Finder resource identifier. - [JsonPropertyName("resourceId")] - public string ResourceId { get; set; } = string.Empty; + /// Whether the value may be supplied more than once. + [JsonPropertyName("isRepeated")] + public required bool IsRepeated { get; set; } - /// Pinned Git commit revision. - [JsonPropertyName("revision")] - public string Revision { get; set; } = string.Empty; + /// Key the value is supplied under. Inert untrusted data. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("key")] + public required string Key { get; set; } - /// Root path within the pinned repository. - [JsonPropertyName("root")] - public string Root { get; set; } = string.Empty; + /// Whether the value must be present for the plan to be applicable. + [JsonPropertyName("required")] + public required bool Required { get; set; } + + /// Human-readable label from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(200)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("title")] + public string? Title { get; set; } + + /// Discriminator: the value must be one of `enumValues`. + [JsonPropertyName("valueType")] + public required McpPlanEnumValueType ValueType { get; set; } } -/// A user-facing personal Skill installation location without absolute host paths. +/// A secret a transport choice needs, referenced by placeholder. No secret value ever appears in a plan, and the placeholder resolves against the keychain only when a plan is applied. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillInstallationLocation +public sealed class McpPlanSecretPlaceholder { - /// Diagnostics-only absolute host path. Hosts must not display it by default. - [JsonPropertyName("diagnosticsAbsolutePath")] - public string? DiagnosticsAbsolutePath { get; set; } - - /// Safe display label, for example ~/.copilot/skills/run-checks. - [JsonPropertyName("displayLabel")] - public string DisplayLabel { get; set; } = string.Empty; + /// Key the secret is supplied under. Inert untrusted data. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("key")] + public string Key { get; set; } = string.Empty; - /// Path relative to the Copilot home. - [JsonPropertyName("relativePath")] - public string RelativePath { get; set; } = string.Empty; + /// The runtime-assigned `${secret:<id>}` placeholder written into configuration in place of the value. + [JsonPropertyName("placeholder")] + public string Placeholder { get; set; } = string.Empty; - /// Installation scope. Agent Finder Skills are installed in the user's personal Copilot home. - [JsonPropertyName("scope")] - public SkillInstallationScope Scope { get; set; } + /// Human-readable label from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(200)] + [JsonPropertyName("title")] + public string? Title { get; set; } } -/// Review for installing a verified Skill. -/// The install variant of . +/// An eligible local-package transport choice. Package identity is required and a remote endpoint cannot be represented. +/// The package variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationReviewInstall : SkillInstallationReview +public partial class McpPlanTransportChoicePackage : McpPlanTransportChoice { /// [JsonIgnore] - public override string Action => "install"; - - /// Catalogue identity retained from the bound candidate before consent. - [JsonPropertyName("catalogue")] - public required InstallationCatalogueIdentity Catalogue { get; set; } + public override string InstallMethod => "package"; - /// Skill description from SKILL.md when present. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } + /// Stable identifier for this choice within the plan, used to select it when the plan is applied. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(128)] + [JsonPropertyName("choiceId")] + public required string ChoiceId { get; set; } - /// - /// Complete verified SKILL.md content. Planning refuses with review-too-large - /// when this exceeds 262144 UTF-8 bytes; it is never truncated. - /// - [JsonPropertyName("entrypointContent")] - public required string EntrypointContent { get; set; } + /// Package identifier. Inert untrusted data. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(512)] + [JsonPropertyName("packageIdentifier")] + public required string PackageIdentifier { get; set; } - /// Relative path of the verified Skill entrypoint. - [JsonPropertyName("entrypointPath")] - public required string EntrypointPath { get; set; } + /// Packaging ecosystem, for example `oci` or `npm`. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(64)] + [JsonPropertyName("packageType")] + public required string PackageType { get; set; } - /// Reviewed files and digests. - [JsonPropertyName("files")] - public required IList Files { get; set; } + /// Typed values this choice requires, excluding secrets. + [JsonPropertyName("requiredValues")] + public required IList RequiredValues { get; set; } - /// Installing never grants immediate use; the Skill is written disabled. - [JsonPropertyName("installsDisabled")] - public required bool InstallsDisabled { get; set; } + /// Secrets this choice requires, referenced by placeholder only. + [JsonPropertyName("secretPlaceholders")] + public required IList SecretPlaceholders { get; set; } - /// Skill invocation name from SKILL.md. - [JsonPropertyName("name")] - public required string Name { get; set; } + /// Local process transport this package choice would use. + [JsonPropertyName("transport")] + public required McpPlanPackageTransport Transport { get; set; } +} - /// Exact verified source identity. - [JsonPropertyName("source")] - public required SkillInstallationSource Source { get; set; } +/// An eligible remote-endpoint transport choice. The endpoint is required and package identity cannot be represented. +/// The remote variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class McpPlanTransportChoiceRemote : McpPlanTransportChoice +{ + /// + [JsonIgnore] + public override string InstallMethod => "remote"; - /// Exact user-scope target location without an absolute host path. - [JsonPropertyName("target")] - public required SkillInstallationLocation Target { get; set; } + /// Stable identifier for this choice within the plan, used to select it when the plan is applied. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(128)] + [JsonPropertyName("choiceId")] + public required string ChoiceId { get; set; } - /// Total reviewed payload size in bytes. - [JsonPropertyName("totalBytes")] - public required long TotalBytes { get; set; } + /// Endpoint URL. Inert untrusted data. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(2048)] + [JsonPropertyName("endpoint")] + public required string Endpoint { get; set; } + + /// Typed values this choice requires, excluding secrets. + [JsonPropertyName("requiredValues")] + public required IList RequiredValues { get; set; } + + /// Secrets this choice requires, referenced by placeholder only. + [JsonPropertyName("secretPlaceholders")] + public required IList SecretPlaceholders { get; set; } + + /// Endpoint transport this remote choice would use. + [JsonPropertyName("transport")] + public required McpPlanRemoteTransport Transport { get; set; } } -/// Durable verified Skill ownership summary. +/// A normalised, inert description of what installing an MCP server would involve. Carries no raw card, no install specification, and no secret value. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillInstallationSummary +public sealed class McpInstallPlan { - /// Catalogue identity retained at install time. - [JsonPropertyName("catalogue")] - public InstallationCatalogueIdentity Catalogue { get => field ??= new(); set; } + /// Alternative configuration changes, with exactly one entry for each transportChoices entry in the same order. Only the entry for the subsequently selected transport applies; these are not cumulative writes. Payloads remain behind the runtime boundary. + [JsonPropertyName("configurationChanges")] + public IList ConfigurationChanges { get => field ??= []; set; } - /// Persisted enablement requested for this installation. - [JsonPropertyName("configuredEnabled")] - public bool ConfiguredEnabled { get; set; } + /// Normalised identity of the server the plan would install. + [JsonPropertyName("identity")] + public McpPlanResourceIdentity Identity { get => field ??= new(); set; } - /// Exact durable installation receipt identity. - [JsonPropertyName("installationId")] - public string InstallationId { get; set; } = string.Empty; + /// Opaque, runtime-instance scoped, TTL-bound, single-use handle for this plan. Rejected when stale, replayed, or presented to a different runtime instance. Never logged. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("planHandle")] + public string PlanHandle { get; set; } = string.Empty; - /// ISO 8601 wall-clock installation time. - [JsonPropertyName("installedAt")] - public string InstalledAt { get; set; } = string.Empty; + /// ISO 8601 timestamp after which the plan handle is stale and will be rejected. Abandoning a plan needs no call: an unused handle simply expires, so cancellation before commit is side-effect free. + [JsonPropertyName("planHandleExpiresAt")] + public string PlanHandleExpiresAt { get; set; } = string.Empty; - /// Skill invocation name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Outcome of evaluating the server against registry and enterprise policy. + [JsonPropertyName("policy")] + public McpPlanPolicyResult Policy { get => field ??= new(); set; } - /// Operation that installed this Skill. - [JsonPropertyName("operationId")] - public string OperationId { get; set; } = string.Empty; + /// Origin and semantic digest of the exact validated JSON MCP card content bound to this plan. + [JsonPropertyName("provenance")] + public McpPlanProvenance Provenance { get => field ??= new(); set; } - /// Ownership state observed from files and receipts. - [JsonPropertyName("ownershipState")] - public SkillInstallationOwnershipState OwnershipState { get; set; } + /// Identifier of the choice the runtime would pick by default. Omitted when there is no eligible transport, or when the runtime expresses no preference. + [JsonPropertyName("recommendedTransportChoiceId")] + public string? RecommendedTransportChoiceId { get; set; } - /// Bound-session load observation. - [JsonPropertyName("sessionState")] - public SkillInstallationSessionState SessionState { get; set; } + /// Whether applying this plan would require an MCP reload to take effect. Planning itself never reloads. + [JsonPropertyName("reloadRequired")] + public bool ReloadRequired { get; set; } - /// Exact retained verified source identity. - [JsonPropertyName("source")] - public SkillInstallationSource Source { get => field ??= new(); set; } + /// True only when every eligible transport choice needs additional values or secrets. False means at least one choice needs no additional configuration, not that every choice is ready. A later apply operation must validate the selected choice's own inputs, secrets and policy after explicit confirmation. + [JsonPropertyName("requiresInteractiveConfiguration")] + public bool RequiresInteractiveConfiguration { get; set; } - /// User-facing installation location without an absolute host path. + /// Configuration scope and key the plan would write to. [JsonPropertyName("target")] - public SkillInstallationLocation Target { get => field ??= new(); set; } + public McpPlanTarget Target { get => field ??= new(); set; } + + /// Every eligible transport, so a host can present an explicit choice. A completed plan always has at least one; when none is eligible, planning returns `CatalogUnavailableTransportError` instead. + [JsonPropertyName("transportChoices")] + public IList TransportChoices { get => field ??= []; set; } } -/// Review for uninstalling an owned verified Skill. -/// The uninstall variant of . +/// A computed MCP install plan. Nothing has been applied: the plan describes what installing would change, and the plan handle is what a later apply operation would consume. +/// The planned variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationReviewUninstall : SkillInstallationReview +public partial class McpPlanInstallResultPlanned : McpPlanInstallResult { /// [JsonIgnore] - public override string Action => "uninstall"; - - /// Catalogue identity retained at install time. - [JsonPropertyName("catalogue")] - public required InstallationCatalogueIdentity Catalogue { get; set; } - - /// Files recorded by the installation receipt. - [JsonPropertyName("files")] - public required IList Files { get; set; } - - /// Whether current files differ from the receipt. Apply refuses drift. - [JsonPropertyName("filesModified")] - public required bool FilesModified { get; set; } + public override string Kind => "planned"; - /// Owned installation being removed. - [JsonPropertyName("installation")] - public required SkillInstallationSummary Installation { get; set; } + /// Protocol version and capabilities the runtime honoured. + [JsonPropertyName("negotiated")] + public required CatalogNegotiatedContract Negotiated { get; set; } - /// Total receipt-owned payload size in bytes. - [JsonPropertyName("totalBytes")] - public required long TotalBytes { get; set; } + /// The normalised plan. + [JsonPropertyName("plan")] + public required McpInstallPlan Plan { get; set; } } -/// A computed Skill install plan. Nothing has been applied. +/// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. +/// The negotiation-refused variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillInstallPlan +public partial class McpPlanInstallResultNegotiationRefused : McpPlanInstallResult { - /// Original wall-clock expiry as an ISO 8601 timestamp. - [JsonPropertyName("expiresAt")] - public string ExpiresAt { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "negotiation-refused"; - /// Original operation identifier returned before confirmation. - [JsonPropertyName("operationId")] - public string OperationId { get; set; } = string.Empty; + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// One-use plan handle, bound to the original candidate authority. - [JsonPropertyName("planHandle")] - public string PlanHandle { get; set; } = string.Empty; + /// Lowest caller protocol version this runtime will serve. + [JsonPropertyName("minimumSupportedProtocolVersion")] + public required long MinimumSupportedProtocolVersion { get; set; } - /// Safe review to present before applying the plan. - [JsonPropertyName("review")] - public SkillInstallationReview Review { get => field ??= new(); set; } + /// Whether the version or the capability set was the problem. + [JsonPropertyName("reason")] + public required CatalogNegotiationRefusedReason Reason { get; set; } + + /// Protocol version of the runtime that refused the request. + [JsonPropertyName("runtimeProtocolVersion")] + public required long RuntimeProtocolVersion { get; set; } + + /// Capabilities this runtime can safely advertise to this caller. The complete five-capability protocol-3 legacy set is always present; every capability added after that baseline appears only when the caller required it, so an older closed-enum decoder can still consume a refusal. This list does not imply that every deployment has enabled every operation. + [JsonPropertyName("supportedCapabilities")] + public required IList SupportedCapabilities { get; set; } + + /// The subset of the caller's bounded extensible capability identifiers this runtime cannot honour. + [JsonPropertyName("unsupportedCapabilities")] + public required IList UnsupportedCapabilities { get; set; } } -/// A verified Skill installation plan was prepared. -/// The install-planned variant of . +/// A presented handle was not accepted. Handles are runtime-instance scoped, TTL-bound, and single-use, so each way of failing is reported distinctly. +/// The handle-rejected variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementOutcomeInstallPlanned : SkillInstallationManagementOutcome +public partial class McpPlanInstallResultHandleRejected : McpPlanInstallResult { /// [JsonIgnore] - public override string Kind => "install-planned"; + public override string Kind => "handle-rejected"; - /// Prepared install plan. - [JsonPropertyName("plan")] - public required SkillInstallPlan Plan { get; set; } + /// Which kind of handle was presented. + [JsonPropertyName("handleType")] + public required CatalogHandleType HandleType { get; set; } + + /// Human-readable explanation, safe to surface. Never contains the handle itself, nor a query, URL, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// Why the handle was rejected. + [JsonPropertyName("reason")] + public required CatalogHandleRejectionReason Reason { get; set; } } -/// Owned Skill installations were listed. -/// The listed variant of . +/// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. +/// The invalid-request variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementOutcomeListed : SkillInstallationManagementOutcome +public partial class McpPlanInstallResultInvalidRequest : McpPlanInstallResult { /// [JsonIgnore] - public override string Kind => "listed"; + public override string Kind => "invalid-request"; - /// Owned Skill installation summaries. - [JsonPropertyName("installations")] - public required IList Installations { get; set; } + /// Which request field was rejected. + [JsonPropertyName("field")] + public required CatalogInvalidRequestField Field { get; set; } + + /// Human-readable explanation, safe to surface. Never echoes the offending value, nor a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } } -/// Recovery completed and inventory was inspected. -/// The recovered variant of . +/// An optional catalog authentication exchange did not establish the caller's identity. Anonymous search remains supported; this refusal is reserved for an operation that cannot continue after the attempted exchange. It is distinct from `policy-rejected` and from a network failure, and the reason identifies the recovery action. +/// The authentication-required variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementOutcomeRecovered : SkillInstallationManagementOutcome +public partial class McpPlanInstallResultAuthenticationRequired : McpPlanInstallResult { /// [JsonIgnore] - public override string Kind => "recovered"; + public override string Kind => "authentication-required"; - /// Owned Skill installation summaries after recovery. - [JsonPropertyName("installations")] - public required IList Installations { get; set; } + /// Human-readable explanation, safe to surface. Never contains a credential or token, nor a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// Why authentication failed. Only an expired credential justifies attempting a silent refresh; an absent or rejected credential requires sign-in. + [JsonPropertyName("reason")] + public required CatalogAuthenticationRequiredReason Reason { get; set; } } -/// Interrupted work was safely compensated and the pending marker was cleared. -/// The rolled-back variant of . +/// Registry or enterprise policy refused the operation. +/// The policy-rejected variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementOutcomeRolledBack : SkillInstallationManagementOutcome +public partial class McpPlanInstallResultPolicyRejected : McpPlanInstallResult { /// [JsonIgnore] - public override string Kind => "rolled-back"; + public override string Kind => "policy-rejected"; - /// Original operation identity. - [JsonPropertyName("operation_id")] - public required string OperationId { get; set; } + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Cause of the compensation. - [JsonPropertyName("reason")] - public required SkillInstallationFailureReason Reason { get; set; } + /// Which authority produced the decision. + [JsonPropertyName("source")] + public required McpPlanPolicySource Source { get; set; } } -/// A computed Skill uninstall plan. Nothing has been removed. +/// The runtime could not reach the catalog authority or retrieve a card. Covers being offline as well as transport-level failure. +/// The network-failure variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillUninstallPlan +public partial class McpPlanInstallResultNetworkFailure : McpPlanInstallResult { - /// Original wall-clock expiry as an ISO 8601 timestamp. - [JsonPropertyName("expiresAt")] - public string ExpiresAt { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "network-failure"; - /// Owned Skill installation being removed. - [JsonPropertyName("installation")] - public SkillInstallationSummary Installation { get => field ??= new(); set; } + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Original removal operation identifier returned before confirmation. - [JsonPropertyName("operationId")] - public string OperationId { get; set; } = string.Empty; + /// Categorised failure, low cardinality so it can be aggregated without carrying a URL. + [JsonPropertyName("reason")] + public required CatalogNetworkFailureReason Reason { get; set; } - /// One-use uninstall plan handle. - [JsonPropertyName("planHandle")] - public string PlanHandle { get; set; } = string.Empty; + /// Bounded cooldown in seconds before another catalog request should be attempted, when the authority supplied a numeric Retry-After value or the runtime applied its documented fallback. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("retryAfterSeconds")] + public int? RetryAfterSeconds { get; set; } - /// Safe review to present before applying removal. - [JsonPropertyName("review")] - public SkillInstallationReview Review { get => field ??= new(); set; } + /// HTTP status code, when the failure was a rejected response. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("statusCode")] + public int? StatusCode { get; set; } } -/// An owned Skill uninstall plan was prepared. -/// The uninstall-planned variant of . +/// Retrieval was refused by the runtime's hardened fetch boundary before any request left the process, or before a redirect was followed. +/// The unsafe-retrieval variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementOutcomeUninstallPlanned : SkillInstallationManagementOutcome +public partial class McpPlanInstallResultUnsafeRetrieval : McpPlanInstallResult { /// [JsonIgnore] - public override string Kind => "uninstall-planned"; + public override string Kind => "unsafe-retrieval"; - /// Prepared uninstall plan. - [JsonPropertyName("plan")] - public required SkillUninstallPlan Plan { get; set; } -} + /// Human-readable explanation, safe to surface. Never contains the refused URL, nor a query, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } -/// Status snapshot from the original connection, independent of new-work account availability. -/// Polymorphic base type discriminated by phase. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "phase", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(SkillInstallationOperationStatusPreparing), "preparing")] -[JsonDerivedType(typeof(SkillInstallationOperationStatusPrepared), "prepared")] -[JsonDerivedType(typeof(SkillInstallationOperationStatusAwaitingConfirmation), "awaiting-confirmation")] -[JsonDerivedType(typeof(SkillInstallationOperationStatusRevalidating), "revalidating")] -[JsonDerivedType(typeof(SkillInstallationOperationStatusApplying), "applying")] -[JsonDerivedType(typeof(SkillInstallationOperationStatusCompleted), "completed")] -public partial class SkillInstallationOperationStatus -{ - /// The type discriminator. - [JsonPropertyName("phase")] - public virtual string Phase { get; set; } = string.Empty; + /// Which control refused the retrieval, low cardinality so it can be aggregated without carrying a URL. + [JsonPropertyName("reason")] + public required CatalogUnsafeRetrievalReason Reason { get; set; } } - -/// Original operation progress discriminator. -/// The preparing variant of . +/// A card could not be parsed or did not satisfy its declared media type's schema. +/// The malformed-card variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOperationStatusPreparing : SkillInstallationOperationStatus +public partial class McpPlanInstallResultMalformedCard : McpPlanInstallResult { /// [JsonIgnore] - public override string Phase => "preparing"; + public override string Kind => "malformed-card"; - /// Whether cancellation has been requested. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } + /// Media type the card was interpreted as, when it declared one this runtime recognises. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("mediaType")] + public CatalogMediaType? MediaType { get; set; } - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// Human-readable explanation, safe to surface. Never echoes card content, nor a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// How the card failed validation. + [JsonPropertyName("reason")] + public required CatalogMalformedCardReason Reason { get; set; } } -/// Original operation progress discriminator. -/// The prepared variant of . +/// An upstream catalog response broke the wire contract. Most importantly, every result must carry exactly one of a URL or embedded data: a result carrying both, or neither, is refused here rather than being guessed at. +/// The contract-violation variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOperationStatusPrepared : SkillInstallationOperationStatus +public partial class McpPlanInstallResultContractViolation : McpPlanInstallResult { /// [JsonIgnore] - public override string Phase => "prepared"; + public override string Kind => "contract-violation"; - /// Whether cancellation has been requested. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } + /// Human-readable explanation, safe to surface. Never echoes response content, nor a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// Which rule the response broke. + [JsonPropertyName("reason")] + public required CatalogContractViolationReason Reason { get; set; } } -/// Original operation progress discriminator. -/// The awaiting-confirmation variant of . +/// No transport this runtime can use is available for the requested server. +/// The unavailable-transport variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOperationStatusAwaitingConfirmation : SkillInstallationOperationStatus +public partial class McpPlanInstallResultUnavailableTransport : McpPlanInstallResult { /// [JsonIgnore] - public override string Phase => "awaiting-confirmation"; + public override string Kind => "unavailable-transport"; - /// Whether cancellation has been requested. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// Why no transport could be offered. + [JsonPropertyName("reason")] + public required CatalogUnavailableTransportReason Reason { get; set; } } -/// Original operation progress discriminator. -/// The revalidating variant of . +/// The candidate is discoverable but cannot be installed. `application/ai-skill` resolves here, because it stays searchable while remaining typed non-installable. +/// The not-installable variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOperationStatusRevalidating : SkillInstallationOperationStatus +public partial class McpPlanInstallResultNotInstallable : McpPlanInstallResult { /// [JsonIgnore] - public override string Phase => "revalidating"; + public override string Kind => "not-installable"; - /// Whether cancellation has been requested. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// Why the candidate cannot be installed. + [JsonPropertyName("reason")] + public required CatalogNotInstallableReason Reason { get; set; } } -/// Original operation progress discriminator. -/// The applying variant of . +/// The operation is not available on this runtime. Distinct from a network failure: nothing was attempted. +/// The unavailable variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOperationStatusApplying : SkillInstallationOperationStatus +public partial class McpPlanInstallResultUnavailable : McpPlanInstallResult { /// [JsonIgnore] - public override string Phase => "applying"; + public override string Kind => "unavailable"; - /// Whether cancellation has been requested; already-started effects require recovery. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Original runtime-issued operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// Why the operation is unavailable. + [JsonPropertyName("reason")] + public required CatalogUnavailableReason Reason { get; set; } } -/// Terminal verified Skill mutation result. +/// The protocol version and capability set a caller requires, supplied on every catalog request so negotiation cannot be skipped by omission. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class CatalogClientContract +{ + /// SDK protocol version the caller was generated against. A caller below the runtime's minimum supported version is refused rather than served a partial result. + [JsonPropertyName("protocolVersion")] + public long ProtocolVersion { get; set; } + + /// Wire features the caller requires the runtime to understand. Identifiers are bounded but extensible so a newer caller can negotiate with an older runtime. Requiring an unknown feature yields a typed refusal listing what is understood, never a partial grant. A grant does not promise that a deployment has enabled the operation; typed unavailable results report that separately. + [JsonPropertyName("requiredCapabilities")] + public IList RequiredCapabilities { get => field ??= []; set; } +} + +/// What an install plan is computed from: a candidate handle from a previous search, or a card supplied directly. /// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( TypeDiscriminatorPropertyName = "kind", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(SkillInstallationOutcomeInstalled), "installed")] -[JsonDerivedType(typeof(SkillInstallationOutcomeUninstalled), "uninstalled")] -[JsonDerivedType(typeof(SkillInstallationOutcomeRolledBack), "rolled-back")] -[JsonDerivedType(typeof(SkillInstallationOutcomeRecoveryRequired), "recovery-required")] -[JsonDerivedType(typeof(SkillInstallationOutcomeDeclined), "declined")] -[JsonDerivedType(typeof(SkillInstallationOutcomeCancelled), "cancelled")] -[JsonDerivedType(typeof(SkillInstallationOutcomeRefused), "refused")] -public partial class SkillInstallationOutcome +[JsonDerivedType(typeof(McpPlanInstallSourceCandidate), "candidate")] +[JsonDerivedType(typeof(McpPlanInstallSourceCard), "card")] +public partial class McpPlanInstallSource { /// The type discriminator. [JsonPropertyName("kind")] @@ -5112,629 +5249,656 @@ public partial class SkillInstallationOutcome } -/// The verified Skill was installed disabled. -/// The installed variant of . +/// Plan from a candidate returned by a previous catalog search. +/// The candidate variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOutcomeInstalled : SkillInstallationOutcome +public partial class McpPlanInstallSourceCandidate : McpPlanInstallSource { /// [JsonIgnore] - public override string Kind => "installed"; + public override string Kind => "candidate"; - /// Durable installed Skill summary. - [JsonPropertyName("installation")] - public required SkillInstallationSummary Installation { get; set; } + /// Single-use candidate handle. Consumed by this call, so a replay of the same handle is rejected. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(256)] + [JsonPropertyName("candidateHandle")] + public required string CandidateHandle { get; set; } + + /// The runtime- or authority-minted `searchId` returned with the search that produced this candidate. Planning verifies the private correlation and atomically consumes a matching candidate before downstream work, including attempts that subsequently fail or report unavailable. A mismatched search does not consume the candidate. It identifies a search rather than a person and must never be joined with user identity to re-identify anyone. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(64)] + [JsonPropertyName("searchId")] + public required string SearchId { get; set; } } -/// The owned Skill was removed. -/// The uninstalled variant of . +/// A card supplied directly by the caller. Exactly one of a URL or embedded data, encoded structurally so neither both nor neither can be expressed. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOutcomeUninstalled : SkillInstallationOutcome +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(McpServerCardReferenceUrl), "url")] +[JsonDerivedType(typeof(McpServerCardReferenceEmbedded), "embedded")] +public partial class McpServerCardReference { - /// - [JsonIgnore] - public override string Kind => "uninstalled"; - - /// Removed installation identity. - [JsonPropertyName("installationId")] - public required string InstallationId { get; set; } - - /// Original removal operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// The durable transaction was aborted or fully compensated. -/// The rolled-back variant of . + +/// An MCP server card to be retrieved from a URL through the runtime's hardened fetch boundary. +/// The url variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOutcomeRolledBack : SkillInstallationOutcome +public partial class McpServerCardReferenceUrl : McpServerCardReference { /// [JsonIgnore] - public override string Kind => "rolled-back"; + public override string Kind => "url"; - /// Original operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// Media type the card is expected to conform to. + [JsonPropertyName("mediaType")] + public required McpServerCardMediaType MediaType { get; set; } - /// Cause of the fully aborted or compensated operation. - [JsonPropertyName("reason")] - public required SkillInstallationFailureReason Reason { get; set; } + /// Card URL. Retrieved only through the runtime's hardened boundary, with scheme, credential, address-range, redirect, timeout, and response-size controls applied. Never logged. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(2048)] + [JsonPropertyName("url")] + public required string Url { get; set; } } -/// A write may have completed. Recover and inspect durable state before retrying. -/// The recovery-required variant of . +/// An MCP server card supplied inline as an inert document. +/// The embedded variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOutcomeRecoveryRequired : SkillInstallationOutcome +public partial class McpServerCardReferenceEmbedded : McpServerCardReference { /// [JsonIgnore] - public override string Kind => "recovery-required"; + public override string Kind => "embedded"; - /// Operation whose durable result must be recovered and inspected. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// The card document verbatim, treated as inert untrusted bytes. The runtime parses and validates it; the host is not expected to interpret it. Never logged. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(1048576)] + [JsonPropertyName("data")] + public required string Data { get; set; } + + /// Media type the card is expected to conform to. + [JsonPropertyName("mediaType")] + public required McpServerCardMediaType MediaType { get; set; } } -/// The user declined the confirmation request. -/// The declined variant of . +/// Plan from a card supplied directly by the caller, without a preceding search. +/// The card variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOutcomeDeclined : SkillInstallationOutcome +public partial class McpPlanInstallSourceCard : McpPlanInstallSource { /// [JsonIgnore] - public override string Kind => "declined"; + public override string Kind => "card"; - /// Original operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// The card to plan from: exactly one of a URL or embedded data. + [JsonPropertyName("card")] + public required McpServerCardReference Card { get; set; } } -/// The operation was cancelled before a terminal mutation. -/// The cancelled variant of . +/// A side-effect-free request for an MCP install plan. Computing a plan never writes configuration, stores a secret, or reloads MCP servers. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOutcomeCancelled : SkillInstallationOutcome +public sealed class McpPlanInstallRequest { - /// - [JsonIgnore] - public override string Kind => "cancelled"; + /// Protocol version and capabilities the caller requires. + [JsonPropertyName("contract")] + public required CatalogClientContract Contract { get; set; } - /// Original operation identity. - [JsonPropertyName("operationId")] - public required string OperationId { get; set; } + /// The same existing attached session that owns the original catalogue candidate. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(256)] + [JsonPropertyName("policySessionId")] + public string? PolicySessionId { get; set; } + + /// Configuration scope the plan targets. Defaults to user scope when omitted. + [JsonPropertyName("scope")] + public McpPlanScope? Scope { get; set; } + + /// What to plan: either a candidate handle from a previous search, or a card supplied directly. + [JsonPropertyName("source")] + public required McpPlanInstallSource Source { get; set; } } -/// The operation was refused without applying changes. -/// The refused variant of . +/// Management result with contract receipt, or a typed request/negotiation refusal. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOutcomeRefused : SkillInstallationOutcome +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(McpInstallationManagementResultOutcome), "outcome")] +[JsonDerivedType(typeof(McpInstallationManagementResultNegotiationRefused), "negotiation-refused")] +[JsonDerivedType(typeof(McpInstallationManagementResultInvalidRequest), "invalid-request")] +public partial class McpInstallationManagementResult { - /// - [JsonIgnore] - public override string Kind => "refused"; + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} - /// Present once an operation has been allocated. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("operationId")] - public string? OperationId { get; set; } - /// Bounded refusal reason. - [JsonPropertyName("reason")] - public required SkillInstallationFailureReason Reason { get; set; } +/// Read-only or recovery management result, never permission to activate or replay. +/// Polymorphic base type discriminated by kind. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(McpInstallationManagementOutcomeRecoveryRequired), "recovery-required")] +[JsonDerivedType(typeof(McpInstallationManagementOutcomeInstallPrepared), "install-prepared")] +[JsonDerivedType(typeof(McpInstallationManagementOutcomeListed), "listed")] +[JsonDerivedType(typeof(McpInstallationManagementOutcomeRecovered), "recovered")] +[JsonDerivedType(typeof(McpInstallationManagementOutcomeUninstallPlanned), "uninstall-planned")] +[JsonDerivedType(typeof(McpInstallationManagementOutcomeOperation), "operation")] +[JsonDerivedType(typeof(McpInstallationManagementOutcomeRefused), "refused")] +public partial class McpInstallationManagementOutcome +{ + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Original operation progress discriminator. -/// The completed variant of . + +/// Already-confirmed durable work must be reconciled before new mutations or inventory. +/// The recovery-required variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationOperationStatusCompleted : SkillInstallationOperationStatus +public partial class McpInstallationManagementOutcomeRecoveryRequired : McpInstallationManagementOutcome { /// [JsonIgnore] - public override string Phase => "completed"; + public override string Kind => "recovery-required"; +} - /// Whether cancellation was requested before the terminal result. - [JsonPropertyName("cancellationRequested")] - public required bool CancellationRequested { get; set; } +/// Inert, runtime-owned admission. The operation ID is known before confirmation or effects. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpPreparedInstall +{ + /// Original plan expiry in Unix epoch milliseconds; preparation does not extend it. + [JsonPropertyName("expiresAtEpochMs")] + public long ExpiresAtEpochMs { get; set; } - /// Original runtime-issued operation identity. + /// Original connection-owned operation, known before the first confirmation callback. [JsonPropertyName("operationId")] - public required string OperationId { get; set; } - - /// Immutable terminal receipt. - [JsonPropertyName("outcome")] - public required SkillInstallationOutcome Outcome { get; set; } + public string OperationId { get; set; } = string.Empty; } -/// Original-connection operation snapshot. -/// The operation variant of . +/// The install-prepared variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementOutcomeOperation : SkillInstallationManagementOutcome +public partial class McpInstallationManagementOutcomeInstallPrepared : McpInstallationManagementOutcome { /// [JsonIgnore] - public override string Kind => "operation"; + public override string Kind => "install-prepared"; - /// Operation status. + /// Known original operation identity, returned before callback or effects. [JsonPropertyName("operation")] - public required SkillInstallationOperationStatus Operation { get; set; } + public required McpPreparedInstall Operation { get; set; } } -/// Enablement changed and the selected session was reconciled. -/// The enabled-changed variant of . +/// A versioned, bounded trust observation carried unchanged with a catalog candidate and its private handle context. Current observations require a recognised T1/T2 tier; every non-current state structurally forbids a tier. Eligibility remains `unknown` while Agent Finder supplies no exposure decision, and states absent from its current wire are never inferred from age, relevance, popularity, or a tier transition. +/// Polymorphic base type discriminated by status. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementOutcomeEnabledChanged : SkillInstallationManagementOutcome +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "status", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(CatalogTrustSnapshotCurrent), "current")] +[JsonDerivedType(typeof(CatalogTrustSnapshotAbsent), "absent")] +[JsonDerivedType(typeof(CatalogTrustSnapshotStale), "stale")] +[JsonDerivedType(typeof(CatalogTrustSnapshotDowngraded), "downgraded")] +[JsonDerivedType(typeof(CatalogTrustSnapshotRevoked), "revoked")] +[JsonDerivedType(typeof(CatalogTrustSnapshotUnsupported), "unsupported")] +[JsonDerivedType(typeof(CatalogTrustSnapshotMalformed), "malformed")] +public partial class CatalogTrustSnapshot { - /// - [JsonIgnore] - public override string Kind => "enabled-changed"; - - /// Safe reload or reconciliation diagnostics. - [JsonPropertyName("diagnostics")] - public required IList Diagnostics { get; set; } - - /// Updated installation summary. - [JsonPropertyName("installation")] - public required SkillInstallationSummary Installation { get; set; } + /// The type discriminator. + [JsonPropertyName("status")] + public virtual string Status { get; set; } = string.Empty; } -/// The management request was refused. -/// The refused variant of . + +/// Where and when the runtime observed the trust metadata. Observation time is not the authority's evaluation time and must not be used to infer staleness. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementOutcomeRefused : SkillInstallationManagementOutcome +public sealed class CatalogTrustProvenance { - /// - [JsonIgnore] - public override string Kind => "refused"; + /// ISO 8601 timestamp with a timezone offset at which the runtime observed the search result carrying this trust field. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(20)] + [MaxLength(64)] + [JsonPropertyName("observedAt")] + public DateTimeOffset ObservedAt { get; set; } - /// Bounded refusal reason. - [JsonPropertyName("reason")] - public required SkillInstallationFailureReason Reason { get; set; } + /// Bounded authority that supplied the trust field. + [JsonPropertyName("source")] + public CatalogTrustSource Source { get; set; } } -/// The outcome variant of . +/// A recognised current Agent Finder T1 or T2 trust tier. +/// The current variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementResultOutcome : SkillInstallationManagementResult +public partial class CatalogTrustSnapshotCurrent : CatalogTrustSnapshot { /// [JsonIgnore] - public override string Kind => "outcome"; + public override string Status => "current"; - /// Capabilities honoured for this request. - [JsonPropertyName("negotiated")] - public required CatalogNegotiatedContract Negotiated { get; set; } + /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. + [JsonPropertyName("eligibility")] + public required CatalogTrustEligibility Eligibility { get; set; } - /// Observed management outcome. - [JsonPropertyName("outcome")] - public required SkillInstallationManagementOutcome Outcome { get; set; } + /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. + [JsonPropertyName("provenance")] + public required CatalogTrustProvenance Provenance { get; set; } + + /// Schema version of this runtime-owned snapshot envelope. + [JsonPropertyName("schemaVersion")] + public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } + + /// Service-computed T1 or T2 trust tier. + [JsonPropertyName("tier")] + public required CatalogTrustTier Tier { get; set; } } -/// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. -/// The negotiation-refused variant of . +/// Discriminator: the authority omitted trust metadata. +/// The absent variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementResultNegotiationRefused : SkillInstallationManagementResult +public partial class CatalogTrustSnapshotAbsent : CatalogTrustSnapshot { /// [JsonIgnore] - public override string Kind => "negotiation-refused"; - - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } - - /// Lowest caller protocol version this runtime will serve. - [JsonPropertyName("minimumSupportedProtocolVersion")] - public required long MinimumSupportedProtocolVersion { get; set; } - - /// Whether the version or the capability set was the problem. - [JsonPropertyName("reason")] - public required CatalogNegotiationRefusedReason Reason { get; set; } + public override string Status => "absent"; - /// Protocol version of the runtime that refused the request. - [JsonPropertyName("runtimeProtocolVersion")] - public required long RuntimeProtocolVersion { get; set; } + /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. + [JsonPropertyName("eligibility")] + public required CatalogTrustEligibility Eligibility { get; set; } - /// Capabilities this runtime can safely advertise to this caller. The complete five-capability protocol-3 legacy set is always present; every capability added after that baseline appears only when the caller required it, so an older closed-enum decoder can still consume a refusal. This list does not imply that every deployment has enabled every operation. - [JsonPropertyName("supportedCapabilities")] - public required IList SupportedCapabilities { get; set; } + /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. + [JsonPropertyName("provenance")] + public required CatalogTrustProvenance Provenance { get; set; } - /// The subset of the caller's bounded extensible capability identifiers this runtime cannot honour. - [JsonPropertyName("unsupportedCapabilities")] - public required IList UnsupportedCapabilities { get; set; } + /// Schema version of this runtime-owned snapshot envelope. + [JsonPropertyName("schemaVersion")] + public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } } -/// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. -/// The invalid-request variant of . +/// Discriminator: the authority explicitly marked the assessment stale. +/// The stale variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationManagementResultInvalidRequest : SkillInstallationManagementResult +public partial class CatalogTrustSnapshotStale : CatalogTrustSnapshot { /// [JsonIgnore] - public override string Kind => "invalid-request"; + public override string Status => "stale"; - /// Which request field was rejected. - [JsonPropertyName("field")] - public required CatalogInvalidRequestField Field { get; set; } + /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. + [JsonPropertyName("eligibility")] + public required CatalogTrustEligibility Eligibility { get; set; } - /// Human-readable explanation, safe to surface. Never echoes the offending value, nor a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. + [JsonPropertyName("provenance")] + public required CatalogTrustProvenance Provenance { get; set; } + + /// Schema version of this runtime-owned snapshot envelope. + [JsonPropertyName("schemaVersion")] + public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } } -/// Side-effect-free planning of one verified Agent Finder Skill candidate. +/// Discriminator: the authority explicitly reported a downgraded assessment. +/// The downgraded variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillPlanInstallRequest +public partial class CatalogTrustSnapshotDowngraded : CatalogTrustSnapshot { - /// Fresh single-use AI skill candidate handle returned by a bound catalogue search. - [JsonPropertyName("candidateHandle")] - public string CandidateHandle { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Status => "downgraded"; - /// Required authenticated bound catalogue and Skill installation capabilities. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. + [JsonPropertyName("eligibility")] + public required CatalogTrustEligibility Eligibility { get; set; } - /// Existing local session attached to this connection. - [JsonPropertyName("policySessionId")] - public string PolicySessionId { get; set; } = string.Empty; -} + /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. + [JsonPropertyName("provenance")] + public required CatalogTrustProvenance Provenance { get; set; } -/// Skill installation result with the honoured contract, or a typed request/negotiation refusal. -/// Polymorphic base type discriminated by kind. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(SkillInstallationResultOutcome), "outcome")] -[JsonDerivedType(typeof(SkillInstallationResultNegotiationRefused), "negotiation-refused")] -[JsonDerivedType(typeof(SkillInstallationResultInvalidRequest), "invalid-request")] -public partial class SkillInstallationResult -{ - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; + /// Schema version of this runtime-owned snapshot envelope. + [JsonPropertyName("schemaVersion")] + public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } } - -/// The outcome variant of . +/// Discriminator: the authority explicitly revoked the assessment. +/// The revoked variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationResultOutcome : SkillInstallationResult +public partial class CatalogTrustSnapshotRevoked : CatalogTrustSnapshot { /// [JsonIgnore] - public override string Kind => "outcome"; + public override string Status => "revoked"; - /// Capabilities honoured for this request. - [JsonPropertyName("negotiated")] - public required CatalogNegotiatedContract Negotiated { get; set; } + /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. + [JsonPropertyName("eligibility")] + public required CatalogTrustEligibility Eligibility { get; set; } - /// Terminal operation outcome. - [JsonPropertyName("outcome")] - public required SkillInstallationOutcome Outcome { get; set; } + /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. + [JsonPropertyName("provenance")] + public required CatalogTrustProvenance Provenance { get; set; } + + /// Schema version of this runtime-owned snapshot envelope. + [JsonPropertyName("schemaVersion")] + public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } } -/// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. -/// The negotiation-refused variant of . +/// Discriminator: the authority supplied a bounded trust value this runtime does not understand. +/// The unsupported variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationResultNegotiationRefused : SkillInstallationResult +public partial class CatalogTrustSnapshotUnsupported : CatalogTrustSnapshot { /// [JsonIgnore] - public override string Kind => "negotiation-refused"; - - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } - - /// Lowest caller protocol version this runtime will serve. - [JsonPropertyName("minimumSupportedProtocolVersion")] - public required long MinimumSupportedProtocolVersion { get; set; } - - /// Whether the version or the capability set was the problem. - [JsonPropertyName("reason")] - public required CatalogNegotiationRefusedReason Reason { get; set; } + public override string Status => "unsupported"; - /// Protocol version of the runtime that refused the request. - [JsonPropertyName("runtimeProtocolVersion")] - public required long RuntimeProtocolVersion { get; set; } + /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. + [JsonPropertyName("eligibility")] + public required CatalogTrustEligibility Eligibility { get; set; } - /// Capabilities this runtime can safely advertise to this caller. The complete five-capability protocol-3 legacy set is always present; every capability added after that baseline appears only when the caller required it, so an older closed-enum decoder can still consume a refusal. This list does not imply that every deployment has enabled every operation. - [JsonPropertyName("supportedCapabilities")] - public required IList SupportedCapabilities { get; set; } + /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. + [JsonPropertyName("provenance")] + public required CatalogTrustProvenance Provenance { get; set; } - /// The subset of the caller's bounded extensible capability identifiers this runtime cannot honour. - [JsonPropertyName("unsupportedCapabilities")] - public required IList UnsupportedCapabilities { get; set; } + /// Schema version of this runtime-owned snapshot envelope. + [JsonPropertyName("schemaVersion")] + public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } } -/// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. -/// The invalid-request variant of . +/// Discriminator: the trust field was empty, unbounded, or had the wrong JSON type. +/// The malformed variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SkillInstallationResultInvalidRequest : SkillInstallationResult +public partial class CatalogTrustSnapshotMalformed : CatalogTrustSnapshot { /// [JsonIgnore] - public override string Kind => "invalid-request"; + public override string Status => "malformed"; - /// Which request field was rejected. - [JsonPropertyName("field")] - public required CatalogInvalidRequestField Field { get; set; } + /// Service-computed exposure eligibility. `unknown` is required while Agent Finder returns no explicit eligibility field. + [JsonPropertyName("eligibility")] + public required CatalogTrustEligibility Eligibility { get; set; } - /// Human-readable explanation, safe to surface. Never echoes the offending value, nor a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Bounded source and observation time for this snapshot. This is distinct from evidence used by the authority to calculate trust. + [JsonPropertyName("provenance")] + public required CatalogTrustProvenance Provenance { get; set; } + + /// Schema version of this runtime-owned snapshot envelope. + [JsonPropertyName("schemaVersion")] + public required CatalogTrustSnapshotSchemaVersion SchemaVersion { get; set; } } -/// Applies exactly one retained verified Skill installation plan. +/// Catalogue identity retained from a bound candidate or plan at installation time. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillApplyInstallRequest +public sealed class InstallationCatalogueIdentity { - /// Required authenticated bound catalogue and Skill installation capabilities. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// Catalogue description retained at install planning time. + [JsonPropertyName("description")] + public string? Description { get; set; } - /// Opaque original plan, consumed once. - [JsonPropertyName("planHandle")] - public string PlanHandle { get; set; } = string.Empty; + /// Human display name retained from the catalogue candidate. + [JsonPropertyName("displayName")] + public string DisplayName { get; set; } = string.Empty; - /// Same existing selected session as planning. - [JsonPropertyName("policySessionId")] - public string PolicySessionId { get; set; } = string.Empty; -} + /// Catalogue item URL when supplied by the authority. + [JsonPropertyName("itemUrl")] + public string? ItemUrl { get; set; } -/// Read-only preparation of one owned Skill removal under fresh selected-session authority. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillPlanUninstallRequest -{ - /// Required authenticated bound installation contract. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// Catalogue publisher retained at install planning time. + [JsonPropertyName("publisher")] + public string? Publisher { get; set; } - /// Exact receipt to inspect. - [JsonPropertyName("installationId")] - public string InstallationId { get; set; } = string.Empty; + /// Authority resource identifier when supplied by the catalogue. + [JsonPropertyName("resourceId")] + public string? ResourceId { get; set; } - /// Existing selected local session on this connection. - [JsonPropertyName("policySessionId")] - public string PolicySessionId { get; set; } = string.Empty; -} - -/// One-use application of the exact retained Skill removal plan. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillApplyUninstallRequest -{ - /// Required authenticated bound installation contract. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// Catalogue authority/source string that supplied the candidate. + [JsonPropertyName("source")] + public string Source { get; set; } = string.Empty; - /// Opaque original removal plan, consumed once. - [JsonPropertyName("planHandle")] - public string PlanHandle { get; set; } = string.Empty; + /// Catalogue trust observation retained at install planning time. + [JsonPropertyName("trustAtInstall")] + public CatalogTrustSnapshot? TrustAtInstall { get; set; } - /// Same existing selected session as removal preparation. - [JsonPropertyName("policySessionId")] - public string PolicySessionId { get; set; } = string.Empty; + /// Catalogue version retained at install planning time. + [JsonPropertyName("version")] + public string? Version { get; set; } } -/// Server-side skill metadata, including name, description, source, enabled/invocable state, path, project path, and argument hint. +/// Durable configuration ownership is distinct from session-specific usability. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerSkill +public sealed class McpInstallationSummary { - /// Optional freeform hint describing the skill's expected arguments, from the `argument-hint` frontmatter field. - [JsonPropertyName("argumentHint")] - public string? ArgumentHint { get; set; } + /// Catalogue identity retained from the installed plan when available. + [JsonPropertyName("catalogue")] + public InstallationCatalogueIdentity? Catalogue { get; set; } - /// Canonical slash command name used to invoke the skill, without the leading '/'. - [JsonPropertyName("commandName")] - public string? CommandName { get; set; } + /// Exact alternative retained in the installing receipt. + [JsonPropertyName("choiceId")] + public string ChoiceId { get; set; } = string.Empty; - /// Description of what the skill does. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; + /// Identity retained from the validated original plan. + [JsonPropertyName("identity")] + public McpPlanResourceIdentity Identity { get => field ??= new(); set; } - /// Whether the skill is currently enabled (based on global config). - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// Exact durable installation receipt identity. + [JsonPropertyName("installationId")] + public string InstallationId { get; set; } = string.Empty; - /// Unique identifier for the skill. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// ISO 8601 wall-clock installation time when available. + [JsonPropertyName("installedAt")] + public string? InstalledAt { get; set; } - /// Absolute path to the skill file. - [JsonPropertyName("path")] - public string? Path { get; set; } + /// Original installing operation, not a fresh management operation. + [JsonPropertyName("operationId")] + public string OperationId { get; set; } = string.Empty; - /// The project path this skill belongs to (only for project/inherited skills). - [JsonPropertyName("projectPath")] - public string? ProjectPath { get; set; } + /// Ownership or setup state, never inferred proof of tool usability. + [JsonPropertyName("state")] + public McpInstallationState State { get; set; } +} - /// Source location type (e.g., project, personal-copilot, plugin, builtin). - [JsonPropertyName("source")] - public SkillSource Source { get; set; } +/// The listed variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class McpInstallationManagementOutcomeListed : McpInstallationManagementOutcome +{ + /// + [JsonIgnore] + public override string Kind => "listed"; - /// Whether the skill can be invoked by the user as a slash command. - [JsonPropertyName("userInvocable")] - public bool UserInvocable { get; set; } + /// Owned receipts visible to the selected account and host. + [JsonPropertyName("installations")] + public required IList Installations { get; set; } } -/// Skills discovered across global and project sources. +/// The recovered variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerSkillList +public partial class McpInstallationManagementOutcomeRecovered : McpInstallationManagementOutcome { - /// Messages for skills that failed to load (e.g. malformed SKILL.md). Empty when host skills are excluded so host-local paths are not disclosed to multitenant callers. - [JsonPropertyName("errors")] - public IList? Errors { get; set; } + /// + [JsonIgnore] + public override string Kind => "recovered"; - /// All discovered skills across all sources. - [JsonPropertyName("skills")] - public IList Skills { get => field ??= []; set; } + /// Freshly inspected receipts after successful durable reconciliation. + [JsonPropertyName("installations")] + public required IList Installations { get; set; } } -/// Optional project paths and additional skill directories to include in discovery. +/// Exact inert removal plan. No configuration or credentials have changed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillsDiscoverRequest +public sealed class McpUninstallPlan { - /// When true, omit skills from the host's global sources (personal, custom, plugin, and built-in), returning only project-scoped skills. For multitenant deployments. - [JsonPropertyName("excludeHostSkills")] - public bool? ExcludeHostSkills { get; set; } + /// Original wall-clock expiry in milliseconds. Applying never renews it. + [JsonPropertyName("expiresAtEpochMs")] + public long ExpiresAtEpochMs { get; set; } - /// Optional skill scan paths to exclude from discovery. - [JsonPropertyName("ignoredSkillsLocations")] - public IList? IgnoredSkillsLocations { get; set; } + /// Original owned receipt being removed. + [JsonPropertyName("installation")] + public McpInstallationSummary Installation { get => field ??= new(); set; } - /// Optional list of project directory paths to scan for project-scoped skills. - [JsonPropertyName("projectPaths")] - public IList? ProjectPaths { get; set; } + /// The original operation, inspectable and cancellable on this same connection. + [JsonPropertyName("operationId")] + public string OperationId { get; set; } = string.Empty; - /// Explicit discovery-only skill roots, not filesystem grants. Available without ambient discovery, subject to skill/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. - [JsonPropertyName("skillDirectories")] - public IList? SkillDirectories { get; set; } + /// Exact configured input slots owned by this installation, never shared OAuth tokens. + [JsonPropertyName("ownedSecretCount")] + public long OwnedSecretCount { get; set; } + + /// One-use original connection and authority-bound plan handle. + [JsonPropertyName("planHandle")] + public string PlanHandle { get; set; } = string.Empty; + + /// Shared authentication is deliberately retained; revocation is a separate action. + [JsonPropertyName("preservesSharedAuthentication")] + public bool PreservesSharedAuthentication { get; set; } + + /// Whether removal restores a protected earlier configuration. + [JsonPropertyName("restoresPreviousConfiguration")] + public bool RestoresPreviousConfiguration { get; set; } } -/// Canonical directory where skills can be discovered or created, with scope, preference, and optional project path. +/// The uninstall-planned variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillDiscoveryPath +public partial class McpInstallationManagementOutcomeUninstallPlanned : McpInstallationManagementOutcome { - /// Absolute path of the create/discovery target (may not exist on disk yet). - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; - - /// Whether this is the canonical directory to create a new skill in its tier. At most one entry per tier is preferred; the `personal-agents` and `custom` scopes are never preferred. - [JsonPropertyName("preferredForCreation")] - public bool PreferredForCreation { get; set; } - - /// The input project path this directory was derived from (only for project scope). - [JsonPropertyName("projectPath")] - public string? ProjectPath { get; set; } + /// + [JsonIgnore] + public override string Kind => "uninstall-planned"; - /// Which tier this directory belongs to. - [JsonPropertyName("scope")] - public SkillDiscoveryScope Scope { get; set; } + /// Original owned removal plan and operation. + [JsonPropertyName("plan")] + public required McpUninstallPlan Plan { get; set; } } -/// Canonical locations where skills can be created so the runtime will recognize them. +/// Status snapshot from the original connection, independent of new-work account availability. +/// Polymorphic base type discriminated by phase. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillDiscoveryPathList +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "phase", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(McpInstallationOperationStatusPreparing), "preparing")] +[JsonDerivedType(typeof(McpInstallationOperationStatusPrepared), "prepared")] +[JsonDerivedType(typeof(McpInstallationOperationStatusAwaitingConfirmation), "awaiting-confirmation")] +[JsonDerivedType(typeof(McpInstallationOperationStatusRevalidating), "revalidating")] +[JsonDerivedType(typeof(McpInstallationOperationStatusApplying), "applying")] +[JsonDerivedType(typeof(McpInstallationOperationStatusCompleted), "completed")] +public partial class McpInstallationOperationStatus { - /// Canonical skill create/discovery directories, in priority order. - [JsonPropertyName("paths")] - public IList Paths { get => field ??= []; set; } + /// The type discriminator. + [JsonPropertyName("phase")] + public virtual string Phase { get; set; } = string.Empty; } -/// Optional project paths to enumerate. + +/// The preparing variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillsGetDiscoveryPathsRequest +public partial class McpInstallationOperationStatusPreparing : McpInstallationOperationStatus { - /// When true, omit the host's personal and custom skill directories, leaving only project directories. For multitenant deployments. - [JsonPropertyName("excludeHostSkills")] - public bool? ExcludeHostSkills { get; set; } - - /// Optional skill scan paths to exclude from discovery. - [JsonPropertyName("ignoredSkillsLocations")] - public IList? IgnoredSkillsLocations { get; set; } + /// + [JsonIgnore] + public override string Phase => "preparing"; - /// Optional list of project directory paths. When omitted or empty, only personal and custom directories are returned. - [JsonPropertyName("projectPaths")] - public IList? ProjectPaths { get; set; } + /// Whether cancellation has been requested, not proof that a write was undone. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } - /// Explicit discovery-only skill roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. - [JsonPropertyName("skillDirectories")] - public IList? SkillDirectories { get; set; } + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// Inventory request under an explicitly selected existing session. +/// The prepared variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillInstallationsRequest +public partial class McpInstallationOperationStatusPrepared : McpInstallationOperationStatus { - /// Required authenticated bound installation contract. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// + [JsonIgnore] + public override string Phase => "prepared"; - /// Existing selected local session on this connection. - [JsonPropertyName("policySessionId")] - public string PolicySessionId { get; set; } = string.Empty; + /// Whether the inert prepared operation was asked to cancel. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } + + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// Existing-operation control. A new session selector is deliberately not accepted. +/// The awaiting-confirmation variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillInstallationOperationRequest +public partial class McpInstallationOperationStatusAwaitingConfirmation : McpInstallationOperationStatus { - /// Required authenticated bound Skill installation capability. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// + [JsonIgnore] + public override string Phase => "awaiting-confirmation"; - /// Exact runtime-issued operation ID on the original connection. + /// Whether the pending human callback was asked to cancel. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } + + /// Original runtime-issued operation identity. [JsonPropertyName("operationId")] - public string OperationId { get; set; } = string.Empty; + public required string OperationId { get; set; } } -/// Persisted enablement update for one owned Skill installation. +/// The revalidating variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillSetEnabledRequest +public partial class McpInstallationOperationStatusRevalidating : McpInstallationOperationStatus { - /// Required authenticated bound Skill installation capability. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } - - /// Persisted enablement value. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// + [JsonIgnore] + public override string Phase => "revalidating"; - /// Exact receipt identity to update. - [JsonPropertyName("installationId")] - public string InstallationId { get; set; } = string.Empty; + /// Whether source or authority revalidation was asked to cancel. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } - /// Existing selected local session to reconcile after persistence. - [JsonPropertyName("policySessionId")] - public string PolicySessionId { get; set; } = string.Empty; + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// Skill names to mark as disabled in global configuration, replacing any previous list. +/// The applying variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillsConfigSetDisabledSkillsRequest +public partial class McpInstallationOperationStatusApplying : McpInstallationOperationStatus { - /// List of skill names to disable. - [JsonPropertyName("disabledSkills")] - public IList DisabledSkills { get => field ??= []; set; } -} + /// + [JsonIgnore] + public override string Phase => "applying"; -/// Adds or removes a single skill from the global disabled list, leaving every other entry untouched. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillsConfigSetSkillDisabledRequest -{ - /// True to disable the skill, false to enable it. - [JsonPropertyName("disabled")] - public bool Disabled { get; set; } + /// Whether applying was asked to cancel; already-started effects retain their lease. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } - /// Name of the skill to add to or remove from the disabled list. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// Outcome of a catalog.search call: either bounded inert candidates, or one typed refusal. Never a partial success. +/// Terminal mutation result. Uncertainty is not approval, rollback or permission to replay. /// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( TypeDiscriminatorPropertyName = "kind", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(CatalogSearchResultSucceeded), "succeeded")] -[JsonDerivedType(typeof(CatalogSearchResultNegotiationRefused), "negotiation-refused")] -[JsonDerivedType(typeof(CatalogSearchResultUnsupportedKind), "unsupported-kind")] -[JsonDerivedType(typeof(CatalogSearchResultInvalidRequest), "invalid-request")] -[JsonDerivedType(typeof(CatalogSearchResultAuthenticationRequired), "authentication-required")] -[JsonDerivedType(typeof(CatalogSearchResultPolicyRejected), "policy-rejected")] -[JsonDerivedType(typeof(CatalogSearchResultNetworkFailure), "network-failure")] -[JsonDerivedType(typeof(CatalogSearchResultUnsafeRetrieval), "unsafe-retrieval")] -[JsonDerivedType(typeof(CatalogSearchResultMalformedCard), "malformed-card")] -[JsonDerivedType(typeof(CatalogSearchResultContractViolation), "contract-violation")] -[JsonDerivedType(typeof(CatalogSearchResultUnavailable), "unavailable")] -public partial class CatalogSearchResult +[JsonDerivedType(typeof(McpInstallationOutcomeInstalled), "installed")] +[JsonDerivedType(typeof(McpInstallationOutcomeUninstalled), "uninstalled")] +[JsonDerivedType(typeof(McpInstallationOutcomeRolledBack), "rolled-back")] +[JsonDerivedType(typeof(McpInstallationOutcomeRecoveryRequired), "recovery-required")] +[JsonDerivedType(typeof(McpInstallationOutcomeDeclined), "declined")] +[JsonDerivedType(typeof(McpInstallationOutcomeCancelled), "cancelled")] +[JsonDerivedType(typeof(McpInstallationOutcomeRefused), "refused")] +public partial class McpInstallationOutcome { /// The type discriminator. [JsonPropertyName("kind")] @@ -5742,402 +5906,363 @@ public partial class CatalogSearchResult } -/// One inert catalog result, represented as an MCP server, discovery-only AI skill, or opt-in Agent Plugin variant so kind, media type, provenance, and available operations cannot contradict each other. -/// Polymorphic base type discriminated by kind. +/// The installed variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(CatalogCandidateMcpServer), "mcp-server")] -[JsonDerivedType(typeof(CatalogCandidateAiSkill), "ai-skill")] -[JsonDerivedType(typeof(CatalogCandidatePlugin), "plugin")] -public partial class CatalogCandidate +public partial class McpInstallationOutcomeInstalled : McpInstallationOutcome { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// + [JsonIgnore] + public override string Kind => "installed"; + /// Durable installation succeeded but final transaction cleanup remains. + [JsonPropertyName("cleanupPending")] + public required bool CleanupPending { get; set; } -/// Where and when an MCP server catalog reference was observed. Discovery provenance deliberately carries no content digest because search does not establish the exact validated content a later plan will bind. + /// Receipt identity produced by the confirmed transaction. + [JsonPropertyName("installation")] + public required McpInstallationSummary Installation { get; set; } +} + +/// The uninstalled variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CatalogMcpServerCandidateProvenance +public partial class McpInstallationOutcomeUninstalled : McpInstallationOutcome { - /// Host of the catalog authority that advertised the reference, without path, query, or credentials. Inert untrusted data. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("authority")] - public string Authority { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "uninstalled"; - /// JSON MCP media type advertised for the referenced card. - [JsonPropertyName("mediaType")] - public McpServerCardMediaType MediaType { get; set; } + /// Durable removal succeeded but final cleanup remains. + [JsonPropertyName("cleanupPending")] + public required bool CleanupPending { get; set; } - /// ISO 8601 timestamp at which the runtime observed the catalog reference. This is not a retrieval or validation timestamp. - [JsonPropertyName("observedAt")] - public string ObservedAt { get; set; } = string.Empty; + /// Exact removed receipt identity. + [JsonPropertyName("installationId")] + public required string InstallationId { get; set; } + + /// Original removal operation. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } + + /// Any grants in the incumbent shared OAuth store remain unowned and retained. + [JsonPropertyName("preservedSharedAuthentication")] + public required bool PreservedSharedAuthentication { get; set; } + + /// Exact owned input slots removed, excluding shared OAuth credentials. + [JsonPropertyName("removedOwnedSecrets")] + public required long RemovedOwnedSecrets { get; set; } + + /// Whether protected pre-install configuration was restored. + [JsonPropertyName("restoredPreviousConfiguration")] + public required bool RestoredPreviousConfiguration { get; set; } } -/// Where a candidate's card came from. Exactly one of a URL or embedded data: the union has no variant carrying both, and no variant carrying neither, so the rule holds structurally rather than by validation. -/// Polymorphic base type discriminated by kind. +/// The durable transaction was aborted or fully compensated. +/// The rolled-back variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(CatalogCandidateSourceUrl), "url")] -[JsonDerivedType(typeof(CatalogCandidateSourceEmbedded), "embedded")] -public partial class CatalogCandidateSource +public partial class McpInstallationOutcomeRolledBack : McpInstallationOutcome { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "rolled-back"; + + /// Original connection-owned operation. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } + + /// Cause of the fully aborted or compensated operation. + [JsonPropertyName("reason")] + public required McpInstallationFailureReason Reason { get; set; } } +/// A write may have completed. Recover and inspect durable state before retrying. +/// The recovery-required variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class McpInstallationOutcomeRecoveryRequired : McpInstallationOutcome +{ + /// + [JsonIgnore] + public override string Kind => "recovery-required"; + + /// Operation whose durable result must be recovered and inspected. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } +} -/// Candidate whose card is retrieved from a URL through the runtime's hardened fetch boundary. -/// The url variant of . +/// The declined variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogCandidateSourceUrl : CatalogCandidateSource +public partial class McpInstallationOutcomeDeclined : McpInstallationOutcome { /// [JsonIgnore] - public override string Kind => "url"; + public override string Kind => "declined"; - /// Card URL as advertised. Inert untrusted data: the runtime retrieves it only through its own hardened boundary, and it is never logged. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Original operation explicitly declined by the user. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// Candidate whose card reference arrived inline. The document and its content-derived properties stay behind the runtime boundary. -/// The embedded variant of . +/// The cancelled variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogCandidateSourceEmbedded : CatalogCandidateSource +public partial class McpInstallationOutcomeCancelled : McpInstallationOutcome { /// [JsonIgnore] - public override string Kind => "embedded"; + public override string Kind => "cancelled"; + + /// Original operation cancelled before a terminal application result. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// An inert MCP server catalog result. Every free-text field is untrusted external data and must never be treated as an instruction, and the handle is the only way to refer to the candidate in a later operation. -/// The mcp-server variant of . +/// The refused variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogCandidateMcpServer : CatalogCandidate +public partial class McpInstallationOutcomeRefused : McpInstallationOutcome { /// [JsonIgnore] - public override string Kind => "mcp-server"; + public override string Kind => "refused"; - /// Description taken verbatim from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] + /// Present once an operation has been allocated; never a plan handle. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } + [JsonPropertyName("operationId")] + public string? OperationId { get; set; } - /// Display name taken verbatim from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(200)] - [JsonPropertyName("displayName")] - public required string DisplayName { get; set; } + /// Specific bounded refusal, never a success-shaped fallback. + [JsonPropertyName("reason")] + public required McpInstallationFailureReason Reason { get; set; } +} - /// Opaque, runtime-instance scoped, TTL-bound, single-use handle for this candidate. Carries no readable information and is rejected when stale, replayed, or presented to a different runtime instance. Never logged. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("handle")] - public required string Handle { get; set; } +/// The completed variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class McpInstallationOperationStatusCompleted : McpInstallationOperationStatus +{ + /// + [JsonIgnore] + public override string Phase => "completed"; - /// ISO 8601 timestamp after which the handle is stale and will be rejected. - [JsonPropertyName("handleExpiresAt")] - public required string HandleExpiresAt { get; set; } + /// Whether cancellation was requested before the terminal result. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } - /// Whether this MCP server can be planned for installation, and if policy prevents it. - [JsonPropertyName("installability")] - public required CatalogMcpServerInstallability Installability { get; set; } + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } - /// JSON MCP media type of the underlying card. - [JsonPropertyName("mediaType")] - public required McpServerCardMediaType MediaType { get; set; } + /// Immutable terminal receipt. + [JsonPropertyName("outcome")] + public required McpInstallationOutcome Outcome { get; set; } +} - /// Where the catalog reference was observed, without the card itself or any content digest. - [JsonPropertyName("provenance")] - public required CatalogMcpServerCandidateProvenance Provenance { get; set; } +/// The operation variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class McpInstallationManagementOutcomeOperation : McpInstallationManagementOutcome +{ + /// + [JsonIgnore] + public override string Kind => "operation"; - /// Publisher taken verbatim from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(200)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("publisher")] - public string? Publisher { get; set; } + /// Original-connection operation snapshot. + [JsonPropertyName("operation")] + public required McpInstallationOperationStatus Operation { get; set; } +} - /// Where the card came from: exactly one of a URL or embedded data, encoded as a tagged union so neither both nor neither can be represented. - [JsonPropertyName("source")] - public required CatalogCandidateSource Source { get; set; } +/// The refused variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class McpInstallationManagementOutcomeRefused : McpInstallationManagementOutcome +{ + /// + [JsonIgnore] + public override string Kind => "refused"; - /// Versioned trust metadata observed from the catalog authority. Optional for protocol-3 compatibility with runtimes that predate trust snapshots. A trust-capable runtime emits an explicit snapshot even when the authority omitted or malformed its trust field. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("trust")] - public CatalogTrustSnapshot? Trust { get; set; } + /// Specific bounded refusal. + [JsonPropertyName("reason")] + public required McpInstallationFailureReason Reason { get; set; } } -/// Where and when an AI skill catalog reference was observed. Discovery provenance deliberately carries no content digest because search does not establish the exact validated content a later plan will bind. +/// The outcome variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CatalogAiSkillCandidateProvenance +public partial class McpInstallationManagementResultOutcome : McpInstallationManagementResult { - /// Host of the catalog authority that advertised the reference, without path, query, or credentials. Inert untrusted data. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("authority")] - public string Authority { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "outcome"; - /// Media type advertised for the referenced AI skill card. - [JsonPropertyName("mediaType")] - public CatalogAiSkillMediaType MediaType { get; set; } + /// Capabilities actually honoured for this request. + [JsonPropertyName("negotiated")] + public required CatalogNegotiatedContract Negotiated { get; set; } - /// ISO 8601 timestamp at which the runtime observed the catalog reference. This is not a retrieval or validation timestamp. - [JsonPropertyName("observedAt")] - public string ObservedAt { get; set; } = string.Empty; + /// Observed management outcome. + [JsonPropertyName("outcome")] + public required McpInstallationManagementOutcome Outcome { get; set; } } -/// An inert AI skill catalog result. Verified Skill candidates may be installable only when the runtime reports installability and the selected session is permitted to plan installation. -/// The ai-skill variant of . +/// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. +/// The negotiation-refused variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogCandidateAiSkill : CatalogCandidate +public partial class McpInstallationManagementResultNegotiationRefused : McpInstallationManagementResult { /// [JsonIgnore] - public override string Kind => "ai-skill"; + public override string Kind => "negotiation-refused"; - /// Description taken verbatim from the card. Inert untrusted text. + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] [MaxLength(1000)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } - - /// Display name taken verbatim from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(200)] - [JsonPropertyName("displayName")] - public required string DisplayName { get; set; } + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Opaque, runtime-instance scoped, TTL-bound, single-use handle for this candidate. Carries no readable information and is rejected when stale, replayed, or presented to a different runtime instance. Never logged. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("handle")] - public required string Handle { get; set; } + /// Lowest caller protocol version this runtime will serve. + [JsonPropertyName("minimumSupportedProtocolVersion")] + public required long MinimumSupportedProtocolVersion { get; set; } - /// ISO 8601 timestamp after which the handle is stale and will be rejected. - [JsonPropertyName("handleExpiresAt")] - public required string HandleExpiresAt { get; set; } + /// Whether the version or the capability set was the problem. + [JsonPropertyName("reason")] + public required CatalogNegotiationRefusedReason Reason { get; set; } - /// Whether this AI skill candidate can be planned for verified installation in the selected session. - [JsonPropertyName("installability")] - public required CatalogAiSkillInstallability Installability { get; set; } + /// Protocol version of the runtime that refused the request. + [JsonPropertyName("runtimeProtocolVersion")] + public required long RuntimeProtocolVersion { get; set; } - /// Media type of the underlying AI skill card. - [JsonPropertyName("mediaType")] - public required CatalogAiSkillMediaType MediaType { get; set; } + /// Capabilities this runtime can safely advertise to this caller. The complete five-capability protocol-3 legacy set is always present; every capability added after that baseline appears only when the caller required it, so an older closed-enum decoder can still consume a refusal. This list does not imply that every deployment has enabled every operation. + [JsonPropertyName("supportedCapabilities")] + public required IList SupportedCapabilities { get; set; } - /// Where the catalog reference was observed, without the card itself or any content digest. - [JsonPropertyName("provenance")] - public required CatalogAiSkillCandidateProvenance Provenance { get; set; } + /// The subset of the caller's bounded extensible capability identifiers this runtime cannot honour. + [JsonPropertyName("unsupportedCapabilities")] + public required IList UnsupportedCapabilities { get; set; } +} - /// Publisher taken verbatim from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(200)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("publisher")] - public string? Publisher { get; set; } +/// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. +/// The invalid-request variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class McpInstallationManagementResultInvalidRequest : McpInstallationManagementResult +{ + /// + [JsonIgnore] + public override string Kind => "invalid-request"; - /// Where the card came from: exactly one of a URL or embedded data, encoded as a tagged union so neither both nor neither can be represented. - [JsonPropertyName("source")] - public required CatalogCandidateSource Source { get; set; } + /// Which request field was rejected. + [JsonPropertyName("field")] + public required CatalogInvalidRequestField Field { get; set; } - /// Versioned trust metadata observed from the catalog authority. Optional for protocol-3 compatibility with runtimes that predate trust snapshots. A trust-capable runtime emits an explicit snapshot even when the authority omitted or malformed its trust field. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("trust")] - public CatalogTrustSnapshot? Trust { get; set; } + /// Human-readable explanation, safe to surface. Never echoes the offending value, nor a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } } -/// Where and when an Agent Plugin catalog reference was observed. Discovery provenance deliberately carries no descriptor URL, raw data, candidate handle, or content digest. +/// One Registry string-valued configuration entry for the selected transport. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CatalogAgentPluginCandidateProvenance +public sealed class McpInstallationInput { - /// Host of the catalog authority that advertised the reference, without path, query, or credentials. Inert untrusted data. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("authority")] - public string Authority { get; set; } = string.Empty; + /// Exact category declared by the selected choice. + [JsonPropertyName("category")] + public McpPlanValueCategory Category { get; set; } - /// Canonical Agent Plugin media type. - [JsonPropertyName("mediaType")] - public CatalogAgentPluginMediaType MediaType { get; set; } + /// Exact key declared by the selected choice. + [JsonPropertyName("key")] + public string Key { get; set; } = string.Empty; - /// ISO 8601 timestamp at which the runtime observed the catalog reference. This is not a retrieval or validation timestamp. - [JsonPropertyName("observedAt")] - public string ObservedAt { get; set; } = string.Empty; + /// Explicit non-secret value. Secret placeholders use a separate input channel. + [JsonPropertyName("value")] + public string Value { get; set; } = string.Empty; } -/// Syntactically validated GitHub repository provenance declared by catalog metadata. This is a source claim rather than proof that the descriptor URL resolves to the repository. +/// A request-local value for one exact reviewed placeholder. Never logged or persisted in a plan. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CatalogPluginRepositorySource +public sealed class McpInstallationSecret { - /// Case-preserving safe relative POSIX path derived from metadata.repoPath. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(256)] - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Exact placeholder from the selected choice, not a caller-chosen backend identifier. + [JsonPropertyName("placeholder")] + public string Placeholder { get; set; } = string.Empty; - /// Canonical lowercase owner/repository name derived from metadata.sourceSet. - [RegularExpression("^[a-z0-9_.-]+/[a-z0-9_.-]+$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(3)] - [MaxLength(256)] - [JsonPropertyName("repository")] - public string Repository { get; set; } = string.Empty; + /// Fresh explicit secret value. It is omitted from confirmation reviews and telemetry. + [JsonPropertyName("value")] + public string Value { get; set; } = string.Empty; } -/// An inert Agent Plugin catalog result. Its canonical catalog identity, declared version, repository source claim, and explicit compatibility tags are safe to correlate, while its descriptor, URL, raw data, and installed-plugin state remain runtime-private. This contract-only variant does not mint or expose a candidate handle. -/// The plugin variant of . +/// Side-effect-free preparation of one original bound remote MCP choice. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogCandidatePlugin : CatalogCandidate +internal sealed class McpPrepareInstallRequest { - /// - [JsonIgnore] - public override string Kind => "plugin"; - - /// Explicit validated compatibility tags, in canonical order. An empty list means the source declared no recognised compatibility; clients must not infer compatibility from other fields. `canvas-only` requires both `canvas` and `github-copilot`. - [JsonPropertyName("compatibilityTags")] - public required IList CompatibilityTags { get; set; } + /// Exact selected alternative from that plan. + [JsonPropertyName("choiceId")] + public string ChoiceId { get; set; } = string.Empty; - /// Description taken verbatim from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } + /// Required bound catalogue and confirmed remote installation capabilities. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// Display name taken verbatim from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(200)] - [JsonPropertyName("displayName")] - public required string DisplayName { get; set; } + /// + /// Declared non-secret values. Non-empty only when the caller requires + /// `mcp-configured-remote-installation`; omitted values use the card default. + /// + [JsonPropertyName("inputs")] + public IList Inputs { get => field ??= []; set; } - /// Validated, normalised catalogue resource URN. This identity comes only from the catalog identifier and is never inferred from display text or installed-plugin state. - [JsonPropertyName("identity")] - public required string Identity { get; set; } + /// Original single-use bound plan, never a client-authored configuration. + [JsonPropertyName("planHandle")] + public string PlanHandle { get; set; } = string.Empty; - /// Canonical Agent Plugin media type. - [JsonPropertyName("mediaType")] - public required CatalogAgentPluginMediaType MediaType { get; set; } + /// An existing local session attached to this connection, not permission to attach one. + [JsonPropertyName("policySessionId")] + public string PolicySessionId { get; set; } = string.Empty; - /// Where the Agent Plugin catalog reference was observed, without its descriptor, URL, raw data, or content digest. - [JsonPropertyName("provenance")] - public required CatalogAgentPluginCandidateProvenance Provenance { get; set; } + /// + /// One entry per declared secret placeholder of the selected choice. Non-empty + /// only when the caller requires `mcp-configured-remote-installation`. + /// + [JsonPropertyName("secrets")] + public IList Secrets { get => field ??= []; set; } - /// Publisher taken verbatim from the card. Inert untrusted text. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(200)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("publisher")] - public string? Publisher { get; set; } + /// The trusted host presents this choice alongside the exact secret placeholders. + [JsonPropertyName("secretStorage")] + public McpInstallationSecretStorage SecretStorage { get; set; } - /// Bounded repository provenance declared through the catalog's sourceSet and repoPath metadata. It contains no descriptor URL. + /// The exact original source, used transiently only after confirmation. [JsonPropertyName("source")] - public required CatalogPluginRepositorySource Source { get; set; } - - /// Versioned trust metadata observed from the catalog authority. Optional for protocol-3 compatibility and emitted only when the caller also requires the trust-snapshot capability. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("trust")] - public CatalogTrustSnapshot? Trust { get; set; } - - /// Optional version declared by the catalog source. Omitted rather than guessed when the source supplies no version. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("version")] - public string? Version { get; set; } + public McpServerCardReference Source { get => field ??= new(); set; } } -/// Authority-reported navigation metadata, returned only to callers requiring catalog-search-pagination and only when a supported token is present. Tokenless first-page and continuation responses omit this object; no counts are inferred from candidates. The opaque token may be retained for previous or numbered navigation even when hasNextPage is false. +/// An installation result together with the exact honoured contract, or a negotiation refusal. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CatalogSearchPagination +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(McpInstallationResultOutcome), "outcome")] +[JsonDerivedType(typeof(McpInstallationResultNegotiationRefused), "negotiation-refused")] +[JsonDerivedType(typeof(McpInstallationResultInvalidRequest), "invalid-request")] +public partial class McpInstallationResult { - /// One-based page returned by the authority. - [JsonPropertyName("currentPage")] - public int CurrentPage { get; set; } - - /// Whether the authority token advertises a valid next target within the navigation window. Not inferred from token presence, truncated, or currentPage being less than pageCount. - [JsonPropertyName("hasNextPage")] - public bool HasNextPage { get; set; } - - /// Navigation window ceiling ceil(1000 / pageSize), not the number of existing pages. Legal targets must not exceed this ceiling or the token's signed pageCount. - [JsonPropertyName("maxPage")] - public int MaxPage { get; set; } - - /// Backend-reported page count, which may exceed maxPage. Present pagination metadata always describes a multi-page result; zero- and single-page responses omit pagination. Navigation targets must also be within the signed pageCount carried by the supplied token. - [JsonPropertyName("pageCount")] - public long PageCount { get; set; } - - /// Page size bound to the search, equal to the effective request limit. - [JsonPropertyName("pageSize")] - public int PageSize { get; set; } - - /// Opaque pagination token. Session-bound search returns an expiring runtime-owned reference retaining the exact private authority token, original search and authority. Legacy unbound search returns the authority token unchanged, without a runtime-created expiry. Only the runtime unwraps tokens or changes targetPage; SDK consumers must not decode, modify or log them. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(4096)] - [JsonPropertyName("token")] - public string Token { get; set; } = string.Empty; - - /// Backend-reported count for this response, not the number of returned candidates. Its relationship to the full query result set is unknown. - [JsonPropertyName("totalCount")] - public long TotalCount { get; set; } - - /// The relationship of totalCount to the complete query result set is unknown; neither exactness nor a lower-bound guarantee is implied. - [JsonPropertyName("totalCountRelation")] - public CatalogSearchTotalCountRelation TotalCountRelation { get; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// A completed catalog search containing inert candidate summaries. MCP server and AI skill variants carry a single-use handle; the Agent Plugin variant is handleless. -/// The succeeded variant of . + +/// The outcome variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSearchResultSucceeded : CatalogSearchResult +public partial class McpInstallationResultOutcome : McpInstallationResult { /// [JsonIgnore] - public override string Kind => "succeeded"; - - /// Matching candidates, never more than the requested limit. All text is inert untrusted data. - [JsonPropertyName("candidates")] - public required IList Candidates { get; set; } + public override string Kind => "outcome"; - /// Protocol version and capabilities the runtime honoured. + /// Capabilities actually honoured for this request. [JsonPropertyName("negotiated")] public required CatalogNegotiatedContract Negotiated { get; set; } - /// Navigation metadata for callers explicitly requiring catalog-search-pagination. Omitted when the authority returns no token, including tokenless first-page and continuation responses. Counts are never substituted from candidates.length. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("pagination")] - public CatalogSearchPagination? Pagination { get; set; } - - /// Pseudonymous identifier for this search, issued by the runtime or by the catalog authority it queried and never by the caller, so it cannot be forged or replayed to attribute an install to a search that never happened. Always present on a success, so a result set can be tied to the installs it leads to. It identifies a search rather than a person: it is derived from no user, account, device, or query data, and must never be joined with user identity to re-identify anyone. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(64)] - [JsonPropertyName("searchId")] - public required string SearchId { get; set; } - - /// Legacy indication that the authority returned a page token. Preserved for compatibility; this is not a has-next-page indicator. Use pagination.hasNextPage when pagination metadata is present. - [JsonPropertyName("truncated")] - public required bool Truncated { get; set; } + /// Terminal result of the original operation. + [JsonPropertyName("outcome")] + public required McpInstallationOutcome Outcome { get; set; } } /// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. -/// The negotiation-refused variant of . +/// The negotiation-refused variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSearchResultNegotiationRefused : CatalogSearchResult +public partial class McpInstallationResultNegotiationRefused : McpInstallationResult { /// [JsonIgnore] @@ -6170,34 +6295,10 @@ public partial class CatalogSearchResultNegotiationRefused : CatalogSearchResult public required IList UnsupportedCapabilities { get; set; } } -/// The request asked for a candidate kind this runtime does not serve. -/// The unsupported-kind variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSearchResultUnsupportedKind : CatalogSearchResult -{ - /// - [JsonIgnore] - public override string Kind => "unsupported-kind"; - - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } - - /// The kinds from the request that are not supported. - [JsonPropertyName("requestedKinds")] - public required IList RequestedKinds { get; set; } - - /// Every candidate kind this runtime can serve. - [JsonPropertyName("supportedKinds")] - public required IList SupportedKinds { get; set; } -} - /// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. -/// The invalid-request variant of . +/// The invalid-request variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSearchResultInvalidRequest : CatalogSearchResult +public partial class McpInstallationResultInvalidRequest : McpInstallationResult { /// [JsonIgnore] @@ -6214,11158 +6315,11248 @@ public partial class CatalogSearchResultInvalidRequest : CatalogSearchResult public required string Message { get; set; } } -/// An optional catalog authentication exchange did not establish the caller's identity. Anonymous search remains supported; this refusal is reserved for an operation that cannot continue after the attempted exchange. It is distinct from `policy-rejected` and from a network failure, and the reason identifies the recovery action. -/// The authentication-required variant of . +/// Applies exactly one previously prepared operation on its original connection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSearchResultAuthenticationRequired : CatalogSearchResult +internal sealed class McpApplyInstallRequest { - /// - [JsonIgnore] - public override string Kind => "authentication-required"; + /// Capabilities required by the original prepared operation. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// Human-readable explanation, safe to surface. Never contains a credential or token, nor a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Runtime-issued ID already returned by prepareInstall, never reused or rebound. + [JsonPropertyName("operationId")] + public string OperationId { get; set; } = string.Empty; - /// Why authentication failed. Only an expired credential justifies attempting a silent refresh; an absent or rejected credential requires sign-in. - [JsonPropertyName("reason")] - public required CatalogAuthenticationRequiredReason Reason { get; set; } + /// Same existing attached or privately borrowed session as preparation. + [JsonPropertyName("policySessionId")] + public string PolicySessionId { get; set; } = string.Empty; } -/// Registry or enterprise policy refused the operation. -/// The policy-rejected variant of . +/// Read-only preparation of one owned removal under fresh selected-session authority. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSearchResultPolicyRejected : CatalogSearchResult +internal sealed class McpPlanUninstallRequest { - /// - [JsonIgnore] - public override string Kind => "policy-rejected"; + /// Required authenticated bound installation capabilities. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Exact receipt to inspect, not a server-name guess. + [JsonPropertyName("installationId")] + public string InstallationId { get; set; } = string.Empty; - /// Which authority produced the decision. - [JsonPropertyName("source")] - public required McpPlanPolicySource Source { get; set; } + /// Existing selected session on the original connection. + [JsonPropertyName("policySessionId")] + public string PolicySessionId { get; set; } = string.Empty; } -/// The runtime could not reach the catalog authority or retrieve a card. Covers being offline as well as transport-level failure. -/// The network-failure variant of . +/// One-use application of the exact retained removal plan. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSearchResultNetworkFailure : CatalogSearchResult +internal sealed class McpApplyUninstallRequest { - /// - [JsonIgnore] - public override string Kind => "network-failure"; - - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Required authenticated bound installation capabilities. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// Categorised failure, low cardinality so it can be aggregated without carrying a URL. - [JsonPropertyName("reason")] - public required CatalogNetworkFailureReason Reason { get; set; } + /// Opaque original removal plan, consumed once. + [JsonPropertyName("planHandle")] + public string PlanHandle { get; set; } = string.Empty; - /// Bounded cooldown in seconds before another catalog request should be attempted, when the authority supplied a numeric Retry-After value or the runtime applied its documented fallback. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("retryAfterSeconds")] - public int? RetryAfterSeconds { get; set; } + /// Same existing selected session as removal preparation. + [JsonPropertyName("policySessionId")] + public string PolicySessionId { get; set; } = string.Empty; +} - /// HTTP status code, when the failure was a rejected response. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("statusCode")] - public int? StatusCode { get; set; } +/// User-configured MCP servers, keyed by server name. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpConfigList +{ + /// All MCP servers from user config, keyed by name. + [JsonPropertyName("servers")] + public IDictionary Servers { get => field ??= new Dictionary(); set; } } -/// Retrieval was refused by the runtime's hardened fetch boundary before any request left the process, or before a redirect was followed. -/// The unsafe-retrieval variant of . +/// MCP server name and configuration to add to user configuration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSearchResultUnsafeRetrieval : CatalogSearchResult +internal sealed class McpConfigAddRequest { - /// - [JsonIgnore] - public override string Kind => "unsafe-retrieval"; + /// MCP server configuration (stdio process or remote HTTP/SSE). + [JsonPropertyName("config")] + public JsonElement Config { get; set; } - /// Human-readable explanation, safe to surface. Never contains the refused URL, nor a query, handle, or secret. + /// Unique name for the MCP server. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } - - /// Which control refused the retrieval, low cardinality so it can be aggregated without carrying a URL. - [JsonPropertyName("reason")] - public required CatalogUnsafeRetrievalReason Reason { get; set; } + [MinLength(1)] + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// A card could not be parsed or did not satisfy its declared media type's schema. -/// The malformed-card variant of . +/// MCP server name and replacement configuration to write to user configuration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSearchResultMalformedCard : CatalogSearchResult +internal sealed class McpConfigUpdateRequest { - /// - [JsonIgnore] - public override string Kind => "malformed-card"; + /// MCP server configuration (stdio process or remote HTTP/SSE). + [JsonPropertyName("config")] + public JsonElement Config { get; set; } - /// Media type the card was interpreted as, when it declared one this runtime recognises. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("mediaType")] - public CatalogMediaType? MediaType { get; set; } - - /// Human-readable explanation, safe to surface. Never echoes card content, nor a query, URL, handle, or secret. + /// Name of the MCP server to update. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } - - /// How the card failed validation. - [JsonPropertyName("reason")] - public required CatalogMalformedCardReason Reason { get; set; } + [MinLength(1)] + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// An upstream catalog response broke the wire contract. Most importantly, every result must carry exactly one of a URL or embedded data: a result carrying both, or neither, is refused here rather than being guessed at. -/// The contract-violation variant of . +/// MCP server name to remove from user configuration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSearchResultContractViolation : CatalogSearchResult +internal sealed class McpConfigRemoveRequest { - /// - [JsonIgnore] - public override string Kind => "contract-violation"; + /// OAuth Client ID Metadata Document URL whose persisted credentials should also be removed. + [JsonPropertyName("authClientIdMetadataUrl")] + public string? AuthClientIdMetadataUrl { get; set; } - /// Human-readable explanation, safe to surface. Never echoes response content, nor a query, URL, handle, or secret. + /// Name of the MCP server to remove. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } - - /// Which rule the response broke. - [JsonPropertyName("reason")] - public required CatalogContractViolationReason Reason { get; set; } + [MinLength(1)] + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// The operation is not available on this runtime. Distinct from a network failure: nothing was attempted. -/// The unavailable variant of . +/// MCP server names to enable for new sessions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSearchResultUnavailable : CatalogSearchResult +internal sealed class McpConfigEnableRequest { - /// - [JsonIgnore] - public override string Kind => "unavailable"; - - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } - - /// Why the operation is unavailable. - [JsonPropertyName("reason")] - public required CatalogUnavailableReason Reason { get; set; } + /// Names of MCP servers to enable. Each server is removed from the persisted disabled list so new sessions spawn it. Unknown or already-enabled names are ignored. + [JsonPropertyName("names")] + public IList Names { get => field ??= []; set; } } -/// An explicit numbered-page request. SDK consumers treat the token as opaque. For bound search, the runtime unwraps an expiring owner-bound reference to the private authority token; only the runtime changes the authority token's targetPage. Legacy unbound navigation keeps its authority-issued token semantics. No snapshot stability is promised. +/// MCP server names to disable for new sessions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CatalogSearchPage +internal sealed class McpConfigDisableRequest { - /// Requested one-based page. Must not exceed either the token's signed pageCount or the navigation window ceil(1000 / pageSize). Repeat the search without page to discover newly available pages beyond that signed pageCount. - [JsonPropertyName("number")] - public int Number { get; set; } + /// Names of MCP servers to disable. Each server is added to the persisted disabled list so new sessions skip it. Already-disabled names are ignored. Active sessions keep their current connections until they end. + [JsonPropertyName("names")] + public IList Names { get => field ??= []; set; } +} - /// Opaque pagination token from an earlier response, owner-bound when session-bound search was requested. Never decode, modify or log it in an SDK consumer. Expired or foreign bound references require a fresh bound search, not a legacy retry. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(4096)] - [JsonPropertyName("token")] - public string Token { get; set; } = string.Empty; +/// Request id naming a cancellable registry search. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpRegistryRequestIdResult +{ + /// Request ID for `mcp.registry.search` and `mcp.registry.cancel`. It serves one search. Allocation can reclaim unused IDs at the 1,024-ID reservation limit. + [JsonPropertyName("requestId")] + public long RequestId { get; set; } } -/// A bounded catalog search. Both the query length and the result count are capped by the schema so a caller cannot request an unbounded scan. +/// Servers selected from the registry response. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CatalogSearchRequest +internal sealed class McpRegistrySearchResult { - /// Protocol version and capabilities the caller requires. - [JsonPropertyName("contract")] - public required CatalogClientContract Contract { get; set; } + /// The server objects, carried opaquely. The runtime follows pages, keeps the newest entry per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub stars. Each server object remains unchanged because the registry owns that shape. + [JsonPropertyName("servers")] + public JsonElement Servers { get; set; } +} - /// Restrict results to these candidate kinds. Agent Plugins are opt-in and require the `agent-plugin-discovery` capability so protocol-v3 clients generated before that variant cannot receive an unknown result; when omitted, the backwards-compatible MCP server and AI skill kinds are searched. - [JsonPropertyName("kinds")] - public IList? Kinds { get; set; } +/// Registry search terms, the credential to search under, and the request id that makes the search cancellable. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpRegistrySearchRequest +{ + /// The credential the search runs under, carried opaquely. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. + [JsonPropertyName("authInfo")] + public JsonElement AuthInfo { get; set; } - /// Maximum number of candidates to return. Defaults to 10 when omitted. + /// Maximum number of servers to return. [JsonPropertyName("limit")] - public int? Limit { get; set; } + public long Limit { get; set; } - /// Numbered navigation using metadata from an earlier response. Requires catalog-search-pagination and the same query, kinds and effective limit. Omit for a fresh first-page search. - [JsonPropertyName("page")] - public CatalogSearchPage? Page { get; set; } + /// Free-text query. Omitted or empty asks the registry for its top servers rather than searching. A value that is not a string is refused. + [JsonPropertyName("query")] + public string? Query { get; set; } - /// - /// Select an existing attached local session. Requires authenticated, session-bound search. - /// The runtime never creates, resumes or reconfigures a session to honour this selector. - /// - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(256)] - [JsonPropertyName("policySessionId")] - public string? PolicySessionId { get; set; } + /// Repository used for the policy lookup, as `owner/name`. The policy selects the registry URL and whether the user token goes to the registry. The registry receives this repository only when the policy entry lists it as required context. A value that is not a string is refused. + [JsonPropertyName("repository")] + public string? Repository { get; set; } - /// Free-text search query. Persisted as tool input for session continuity, but omitted from telemetry. - [RegularExpression("\\S")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(256)] - [JsonPropertyName("query")] - public required string Query { get; set; } + /// Request ID from `mcp.registry.allocateRequestId`. The search refuses unknown, reclaimed, or canceled IDs and IDs that another search or request already uses. + [JsonPropertyName("requestId")] + public long RequestId { get; set; } } -/// Typed outcome of catalog.select. Only the selected host result carries a fresh candidate handle; the model-facing projection removes both that handle and searchId. -/// Polymorphic base type discriminated by kind. +/// Whether the cancel reached a live search. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(CatalogSelectionResultSelected), "selected")] -[JsonDerivedType(typeof(CatalogSelectionResultDeclined), "declined")] -[JsonDerivedType(typeof(CatalogSelectionResultCancelled), "cancelled")] -[JsonDerivedType(typeof(CatalogSelectionResultTimedOut), "timed-out")] -[JsonDerivedType(typeof(CatalogSelectionResultInvalid), "invalid")] -[JsonDerivedType(typeof(CatalogSelectionResultStale), "stale")] -[JsonDerivedType(typeof(CatalogSelectionResultReplayed), "replayed")] -[JsonDerivedType(typeof(CatalogSelectionResultForeign), "foreign")] -[JsonDerivedType(typeof(CatalogSelectionResultWrongKind), "wrong-kind")] -[JsonDerivedType(typeof(CatalogSelectionResultNegotiationRefused), "negotiation-refused")] -[JsonDerivedType(typeof(CatalogSelectionResultInvalidRequest), "invalid-request")] -[JsonDerivedType(typeof(CatalogSelectionResultUnavailable), "unavailable")] -public partial class CatalogSelectionResult +internal sealed class McpRegistryCancelResult { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; + /// True when the cancel stopped a running search. False for unknown or reclaimed IDs, completed or canceled searches, and unused reservations. The cancel releases an unused reservation. + [JsonPropertyName("canceled")] + public bool Canceled { get; set; } } - -/// The chosen candidate was transferred into a fresh bounded single-use handle for a later explicit planning request. -/// The selected variant of . +/// Registry search to abandon. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultSelected : CatalogSelectionResult +internal sealed class McpRegistryCancelRequest { - /// - [JsonIgnore] - public override string Kind => "selected"; - - /// Fresh single-use candidate handle accepted by mcp.planInstall. Returned only to the native host and never included in model-tool output. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(256)] - [JsonPropertyName("candidateHandle")] - public required string CandidateHandle { get; set; } - - /// The exact search identifier privately bound to the selected candidate. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(64)] - [JsonPropertyName("searchId")] - public required string SearchId { get; set; } + /// Request ID from `mcp.registry.allocateRequestId` that the search uses. + [JsonPropertyName("requestId")] + public long RequestId { get; set; } } -/// The caller explicitly declined every candidate and the retained search state was released. -/// The declined variant of . +/// New-work inventory or recovery request under an explicitly selected existing session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultDeclined : CatalogSelectionResult +internal sealed class McpInstallationsRequest { - /// - [JsonIgnore] - public override string Kind => "declined"; + /// Required authenticated bound installation contract. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// The search identifier privately bound to the released selection group. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(64)] - [JsonPropertyName("searchId")] - public required string SearchId { get; set; } + /// Existing selected local session on this connection. + [JsonPropertyName("policySessionId")] + public string PolicySessionId { get; set; } = string.Empty; } -/// The caller cancelled the selection interaction and the retained search state was released. -/// The cancelled variant of . +/// Existing-operation control. A new session selector is deliberately not accepted. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultCancelled : CatalogSelectionResult +internal sealed class McpInstallationOperationRequest { - /// - [JsonIgnore] - public override string Kind => "cancelled"; + /// Original installation wire capability; new-work authentication is not reacquired. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// The search identifier privately bound to the released selection group. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(64)] - [JsonPropertyName("searchId")] - public required string SearchId { get; set; } + /// Exact runtime-issued operation ID on the original connection. + [JsonPropertyName("operationId")] + public string OperationId { get; set; } = string.Empty; } -/// The host declared that its live selection interaction timed out, and the retained search state was released. -/// The timed-out variant of . +/// Installed plugin that contributes a discovered extension. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultTimedOut : CatalogSelectionResult +public sealed class DiscoveredExtensionPlugin { - /// - [JsonIgnore] - public override string Kind => "timed-out"; - - /// The search identifier privately bound to the released selection group. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(64)] - [JsonPropertyName("searchId")] - public required string SearchId { get; set; } + /// Installed plugin name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// The selection reference was malformed or unknown. -/// The invalid variant of . +/// Discovered extension metadata and persistent enablement state. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultInvalid : CatalogSelectionResult +public sealed class DiscoveredExtension { - /// - [JsonIgnore] - public override string Kind => "invalid"; + /// Whether this extension's persistent per-ID preference is enabled. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } - /// Human-readable explanation safe to surface. Never contains the presented reference or private candidate state. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Source-qualified ID accepted by both server and session extension enablement methods. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + /// Human-readable extension name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Absolute path to the extension entry module, suitable for revealing it in a file manager. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// Containing plugin metadata for plugin-contributed extensions. + [JsonPropertyName("plugin")] + public DiscoveredExtensionPlugin? Plugin { get; set; } + + /// Discovery source. + [JsonPropertyName("source")] + public DiscoveredExtensionSource Source { get; set; } } -/// The runtime-enforced selection reference lifetime elapsed before the request arrived. -/// The stale variant of . +/// Extensions discovered from persisted Copilot home state and their effective loading mode. Launch-scoped additional plugins are not included. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultStale : CatalogSelectionResult +public sealed class DiscoveredExtensions { - /// - [JsonIgnore] - public override string Kind => "stale"; + /// Discovered user and enabled installed-plugin extensions from persisted Copilot home state. + [JsonPropertyName("extensions")] + public IList Extensions { get => field ??= []; set; } - /// Human-readable explanation safe to surface. Never contains the presented reference or private candidate state. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Effective extension loading mode. Defaults to load_and_augment when unset. + [JsonPropertyName("mode")] + public DiscoveredExtensionMode Mode { get; set; } } -/// The selection group was already terminated or its pending host hand-off was already claimed. -/// The replayed variant of . +/// Source-qualified extension identifiers to persistently enable for future sessions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultReplayed : CatalogSelectionResult +internal sealed class DiscoveredExtensionsEnableRequest { - /// - [JsonIgnore] - public override string Kind => "replayed"; - - /// Human-readable explanation safe to surface. Never contains the presented reference or private candidate state. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Source-qualified user or plugin extension IDs to enable. + [JsonPropertyName("ids")] + public IList Ids { get => field ??= []; set; } } -/// The selection reference belongs to another runtime instance or session. -/// The foreign variant of . +/// Source-qualified extension identifiers to persistently disable for future sessions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultForeign : CatalogSelectionResult +internal sealed class DiscoveredExtensionsDisableRequest { - /// - [JsonIgnore] - public override string Kind => "foreign"; - - /// Human-readable explanation safe to surface. Never contains the presented reference or private candidate state. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Source-qualified user or plugin extension IDs to disable. + [JsonPropertyName("ids")] + public IList Ids { get => field ??= []; set; } } -/// The presented opaque handle was issued for another catalog operation. -/// The wrong-kind variant of . +/// The prompt the init command runs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultWrongKind : CatalogSelectionResult +internal sealed class InstructionsInitPromptResult { - /// - [JsonIgnore] - public override string Kind => "wrong-kind"; - - /// Human-readable explanation safe to surface. Never contains the presented reference or private candidate state. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Prompt text authoring repository instructions. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; } -/// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. -/// The negotiation-refused variant of . +/// Loaded instruction source for a session, including path, content, category, location, applicability, and optional description. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultNegotiationRefused : CatalogSelectionResult +public sealed class InstructionSource { - /// - [JsonIgnore] - public override string Kind => "negotiation-refused"; + /// Glob pattern(s) from frontmatter — when set, this instruction applies only to matching files. + [JsonPropertyName("applyTo")] + public IList? ApplyTo { get; set; } - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Raw content of the instruction file. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; - /// Lowest caller protocol version this runtime will serve. - [JsonPropertyName("minimumSupportedProtocolVersion")] - public required long MinimumSupportedProtocolVersion { get; set; } + /// When true, this source starts disabled and must be toggled on by the user. + [JsonPropertyName("defaultDisabled")] + public bool? DefaultDisabled { get; set; } - /// Whether the version or the capability set was the problem. - [JsonPropertyName("reason")] - public required CatalogNegotiationRefusedReason Reason { get; set; } + /// Short description (body after frontmatter) for use in instruction tables. + [JsonPropertyName("description")] + public string? Description { get; set; } - /// Protocol version of the runtime that refused the request. - [JsonPropertyName("runtimeProtocolVersion")] - public required long RuntimeProtocolVersion { get; set; } + /// Unique identifier for this source (used for toggling). + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Capabilities this runtime can safely advertise to this caller. The complete five-capability protocol-3 legacy set is always present; every capability added after that baseline appears only when the caller required it, so an older closed-enum decoder can still consume a refusal. This list does not imply that every deployment has enabled every operation. - [JsonPropertyName("supportedCapabilities")] - public required IList SupportedCapabilities { get; set; } + /// Human-readable label. + [JsonPropertyName("label")] + public string Label { get; set; } = string.Empty; - /// The subset of the caller's bounded extensible capability identifiers this runtime cannot honour. - [JsonPropertyName("unsupportedCapabilities")] - public required IList UnsupportedCapabilities { get; set; } + /// Where this source lives — used for UI grouping. + [JsonPropertyName("location")] + public InstructionSourceLocation Location { get; set; } + + /// The project path this source was discovered from. Only set by sessionless discovery for repository, working-directory, and project-scoped plugin sources, where it disambiguates sources across multiple workspace roots. The session-scoped getSources leaves it unset. + [JsonPropertyName("projectPath")] + public string? ProjectPath { get; set; } + + /// File path relative to repo or absolute for home. + [JsonPropertyName("sourcePath")] + public string SourcePath { get; set; } = string.Empty; + + /// Category of instruction source — used for merge logic. + [JsonPropertyName("type")] + public InstructionSourceType Type { get; set; } } -/// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. -/// The invalid-request variant of . +/// Instruction sources discovered across user, repository, and plugin sources. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultInvalidRequest : CatalogSelectionResult +public sealed class ServerInstructionSourceList { - /// - [JsonIgnore] - public override string Kind => "invalid-request"; - - /// Which request field was rejected. - [JsonPropertyName("field")] - public required CatalogInvalidRequestField Field { get; set; } - - /// Human-readable explanation, safe to surface. Never echoes the offending value, nor a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// All discovered instruction sources. + [JsonPropertyName("sources")] + public IList Sources { get => field ??= []; set; } } -/// The operation is not available on this runtime. Distinct from a network failure: nothing was attempted. -/// The unavailable variant of . +/// Optional project paths to include in instruction discovery. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class CatalogSelectionResultUnavailable : CatalogSelectionResult +public sealed class InstructionsDiscoverRequest { - /// - [JsonIgnore] - public override string Kind => "unavailable"; + /// When true, omit the host's instruction sources (user/home-level files and plugin rules), leaving only repository and working-directory sources. For multitenant deployments. + [JsonPropertyName("excludeHostInstructions")] + public bool? ExcludeHostInstructions { get; set; } - /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(1000)] - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without ambient discovery, subject to instruction/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + [JsonPropertyName("instructionDirectories")] + public IList? InstructionDirectories { get; set; } - /// Why the operation is unavailable. - [JsonPropertyName("reason")] - public required CatalogUnavailableReason Reason { get; set; } + /// Optional list of project directory paths to scan for repository/working-directory instruction sources. When omitted or empty, only user-level and plugin instruction sources are returned (no project scan). + [JsonPropertyName("projectPaths")] + public IList? ProjectPaths { get; set; } } -/// Terminates one retained catalog selection group through an opaque reference previously returned by the model-safe search projection. +/// Explicit discovery arguments for one location, supplied by the caller rather than derived from a session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CatalogSelectionRequest +internal sealed class InstructionsDiscoverRepoSourcesRequest { - /// Protocol version and capabilities the caller requires. - [JsonPropertyName("contract")] - public CatalogClientContract Contract { get => field ??= new(); set; } + /// Extra directories to scan alongside instruction directories configured in the runtime environment. + [JsonPropertyName("additionalDirs")] + public IList? AdditionalDirs { get; set; } - /// The terminal outcome declared by the caller. Timed-out means the host's live interaction deadline elapsed; a reference whose runtime TTL elapsed is rejected separately as stale. - [JsonPropertyName("outcome")] - public CatalogSelectionDecision Outcome { get; set; } + /// Copilot configuration directory for user-level sources. An omitted or empty value uses the server's configuration home. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } - /// Opaque runtime-instance scoped reference to one visible candidate. For a non-selected outcome, any candidate reference from the same search closes that search's retained group. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(256)] - [JsonPropertyName("selectionRef")] - public string SelectionRef { get; set; } = string.Empty; + /// Working directory whose instruction sources should also be included. Omission adds no separate working-directory scope. + [JsonPropertyName("cwdPath")] + public string? CwdPath { get; set; } - /// Locally owned root session whose retained search state is being resolved. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(256)] - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// When true, also discover instruction files nested below the location. + [JsonPropertyName("enableChildInstructions")] + public bool? EnableChildInstructions { get; set; } + + /// When true, include the sources a command-line host reads. Hosts that are not the CLI omit it. + [JsonPropertyName("isCli")] + public bool? IsCli { get; set; } + + /// Repository location to discover. An empty string selects no repository scope; cwdPath can still supply working-directory sources. + [JsonPropertyName("location")] + public string Location { get; set; } = string.Empty; } -/// Information about an installed plugin tracked in global state. +/// Canonical file or directory where custom instructions can be discovered or created, with location, kind, preference, and project path. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class InstalledPluginInfo +public sealed class InstructionDiscoveryPath { - /// Opaque, stable hash identifying a direct (non-marketplace) install source. Present only for direct repo / URL / local installs; absent for marketplace plugins. Same source yields the same id; distinct sources never collide. - [JsonPropertyName("directSourceId")] - public string? DirectSourceId { get; set; } + /// Whether the target is a single file or a directory of instruction files. + [JsonPropertyName("kind")] + public InstructionDiscoveryPathKind Kind { get; set; } - /// Whether the plugin is currently enabled for new sessions. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } - - /// Whether the managed desired plugin currently has an installed or live record. Set to false for a managed desired entry retained in the listing after installation or reconciliation failed. - [JsonPropertyName("installed")] - public bool? Installed { get; set; } - - /// Absolute path of the marketplace directory a live plugin was resolved from. Present only on live, never-persisted records — a plugin belonging to a directory/local marketplace, which is loaded from its real directory on every pass instead of a copy under the installed-plugins cache. Its presence is what marks a listed plugin as live: such a plugin is always present on disk, so `enabled` is its only meaningful state and it is never "not installed". - [JsonPropertyName("installedFrom")] - public string? InstalledFrom { get; set; } - - /// Whether enterprise managed settings control this plugin's enabled state. - [JsonPropertyName("managed")] - public bool? Managed { get; set; } - - /// The enabled state required by enterprise managed settings, when this plugin spec is managed. - [JsonPropertyName("managedDesiredEnabled")] - public bool? ManagedDesiredEnabled { get; set; } - - /// Marketplace the plugin came from. Empty string ("") for direct repo / URL / local installs. - [JsonPropertyName("marketplace")] - public string Marketplace { get; set; } = string.Empty; + /// Which tier this target belongs to. + [JsonPropertyName("location")] + public InstructionDiscoveryPathLocation Location { get; set; } - /// Plugin name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Absolute path of the file or directory (may not exist on disk yet). + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Runtime-reported plugin provenance. Currently set to "builtin" only for plugins registered through the trusted host built-in boundary; absent for installed, marketplace, direct, and live plugins. - [JsonPropertyName("source")] - public string? Source { get; set; } + /// Whether this is the canonical target to create new instructions in its tier. At most one entry per tier is preferred. + [JsonPropertyName("preferredForCreation")] + public bool PreferredForCreation { get; set; } - /// Installed version (when reported by the plugin manifest). - [JsonPropertyName("version")] - public string? Version { get; set; } + /// The input project path this target was derived from (only for repository targets). + [JsonPropertyName("projectPath")] + public string? ProjectPath { get; set; } } -/// Plugins installed in user/global state. +/// Canonical files and directories where custom instructions can be created so the runtime will recognize them. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PluginListResult +public sealed class InstructionDiscoveryPathList { - /// Installed plugins. - [JsonPropertyName("plugins")] - public IList Plugins { get => field ??= []; set; } + /// Canonical instruction create/discovery files and directories, in priority order. + [JsonPropertyName("paths")] + public IList Paths { get => field ??= []; set; } } -/// Result of installing a plugin. +/// Optional project paths to include when enumerating instruction discovery targets. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PluginInstallResult +public sealed class InstructionsGetDiscoveryPathsRequest { - /// Set when the install path is deprecated (e.g. direct repo / URL / local installs). Callers should surface this to end users. - [JsonPropertyName("deprecationWarning")] - public string? DeprecationWarning { get; set; } - - /// The newly installed plugin's metadata. - [JsonPropertyName("plugin")] - public InstalledPluginInfo Plugin { get => field ??= new(); set; } - - /// Optional post-install message provided by the plugin (e.g. setup instructions). - [JsonPropertyName("postInstallMessage")] - public string? PostInstallMessage { get; set; } + /// When true, omit the host's user-level instruction targets, leaving only repository targets. For multitenant deployments (mirrors `discover`'s `excludeHostInstructions`). + [JsonPropertyName("excludeHostInstructions")] + public bool? ExcludeHostInstructions { get; set; } - /// Number of skills discovered and installed from the plugin. - [JsonPropertyName("skillsInstalled")] - public long SkillsInstalled { get; set; } + /// Explicit discovery-only instruction roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + [JsonPropertyName("instructionDirectories")] + public IList? InstructionDirectories { get; set; } - /// Where the completed plugin tree was staged before atomic promotion. - [JsonPropertyName("stagingMode")] - public PluginInstallStagingMode? StagingMode { get; set; } + /// Optional list of project directory paths. When omitted or empty, only the user-level targets are returned. + [JsonPropertyName("projectPaths")] + public IList? ProjectPaths { get; set; } } -/// Plugin source and optional working directory for relative-path resolution. +/// Skill installation management result with the honoured contract, or a typed refusal. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsInstallRequest +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(SkillInstallationManagementResultOutcome), "outcome")] +[JsonDerivedType(typeof(SkillInstallationManagementResultNegotiationRefused), "negotiation-refused")] +[JsonDerivedType(typeof(SkillInstallationManagementResultInvalidRequest), "invalid-request")] +public partial class SkillInstallationManagementResult { - /// Plugin install spec. Accepts the same forms as the CLI: "plugin@marketplace" (marketplace install), "owner/repo" or "owner/repo:subpath" (GitHub direct), an http/https/ssh URL, or a local path. Direct (non-marketplace) installs are deprecated and will produce a deprecationWarning in the result. - [JsonPropertyName("source")] - public string Source { get; set; } = string.Empty; - - /// Working directory used to resolve relative local paths in `source`. Defaults to the server's current working directory. - [JsonPropertyName("workingDirectory")] - public string? WorkingDirectory { get; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Name (or spec) of the plugin to uninstall. + +/// Management outcome for verified Skill inventory, planning and removal. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsUninstallRequest +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(SkillInstallationManagementOutcomeRecoveryRequired), "recovery-required")] +[JsonDerivedType(typeof(SkillInstallationManagementOutcomeInstallPlanned), "install-planned")] +[JsonDerivedType(typeof(SkillInstallationManagementOutcomeListed), "listed")] +[JsonDerivedType(typeof(SkillInstallationManagementOutcomeRecovered), "recovered")] +[JsonDerivedType(typeof(SkillInstallationManagementOutcomeRolledBack), "rolled-back")] +[JsonDerivedType(typeof(SkillInstallationManagementOutcomeUninstallPlanned), "uninstall-planned")] +[JsonDerivedType(typeof(SkillInstallationManagementOutcomeOperation), "operation")] +[JsonDerivedType(typeof(SkillInstallationManagementOutcomeEnabledChanged), "enabled-changed")] +[JsonDerivedType(typeof(SkillInstallationManagementOutcomeRefused), "refused")] +public partial class SkillInstallationManagementOutcome { - /// Stable source identity for a direct (non-marketplace) install. Disambiguates uninstall when multiple installed plugins share the same name. - [JsonPropertyName("directSourceId")] - public string? DirectSourceId { get; set; } - - /// Plugin name or "plugin@marketplace" spec to uninstall. When ambiguous, prefer the fully-qualified spec. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Result of updating a single plugin. + +/// Already-confirmed durable work must be reconciled before new mutations or inventory. +/// The recovery-required variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PluginUpdateResult +public partial class SkillInstallationManagementOutcomeRecoveryRequired : SkillInstallationManagementOutcome { - /// Version after the update, when reported by the plugin manifest. - [JsonPropertyName("newVersion")] - public string? NewVersion { get; set; } - - /// Version that was previously installed, when available. - [JsonPropertyName("previousVersion")] - public string? PreviousVersion { get; set; } - - /// Number of skills discovered and installed after the update. - [JsonPropertyName("skillsInstalled")] - public long SkillsInstalled { get; set; } + /// + [JsonIgnore] + public override string Kind => "recovery-required"; } -/// Name (or spec) of the plugin to update. +/// Safe verified Skill review fields. No raw credential, candidate handle or plan handle. +/// Polymorphic base type discriminated by action. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsUpdateRequest +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "action", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(SkillInstallationReviewInstall), "install")] +[JsonDerivedType(typeof(SkillInstallationReviewUninstall), "uninstall")] +public partial class SkillInstallationReview { - /// Plugin name or "plugin@marketplace" spec to update. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// The type discriminator. + [JsonPropertyName("action")] + public virtual string Action { get; set; } = string.Empty; } -/// Per-plugin result from updating all plugins, with versions, skills installed, success flag, and optional error. + +/// One reviewed Skill file. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PluginUpdateAllEntry +public sealed class SkillInstallationFileReview { - /// Error message (failure only). - [JsonPropertyName("error")] - public string? Error { get; set; } - - /// Marketplace the plugin came from. Empty string ("") for direct installs. - [JsonPropertyName("marketplace")] - public string Marketplace { get; set; } = string.Empty; - - /// Plugin name that was updated. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// SHA-256 digest of the exact file bytes. + [JsonPropertyName("digest")] + public string Digest { get; set; } = string.Empty; - /// Version after the update, when available. - [JsonPropertyName("newVersion")] - public string? NewVersion { get; set; } + /// Whether the file is installed with executable permissions. + [JsonPropertyName("executable")] + public bool Executable { get; set; } - /// Previously installed version, when available. - [JsonPropertyName("previousVersion")] - public string? PreviousVersion { get; set; } + /// Declared media type for the file. + [JsonPropertyName("mediaType")] + public string MediaType { get; set; } = string.Empty; - /// Number of skills installed after the update (success only). - [JsonPropertyName("skillsInstalled")] - public long? SkillsInstalled { get; set; } + /// Relative file path within the Skill root. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Whether the update succeeded for this plugin. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Exact reviewed file size in bytes. + [JsonPropertyName("sizeBytes")] + public long SizeBytes { get; set; } } -/// Result of updating all installed plugins. +/// Source identity retained from Agent Finder and the pinned GitHub descriptor. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PluginUpdateAllResult +public sealed class SkillInstallationSource { - /// Per-plugin update results in deterministic order. - [JsonPropertyName("results")] - public IList Results { get => field ??= []; set; } -} + /// Digest of the descriptor's bundle manifest. + [JsonPropertyName("bundleDigest")] + public string BundleDigest { get; set; } = string.Empty; -/// Plugin names (or specs) to enable, plus the optional working directory the repository-controlled guard is evaluated against. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsEnableRequest -{ - /// Plugin names or "plugin@marketplace" specs to enable. Unknown names are ignored. Non-marketplace direct installs are always enabled and cannot be toggled via this API. - [JsonPropertyName("names")] - public IList Names { get => field ??= []; set; } + /// Agent Finder materialisation revision identifier. + [JsonPropertyName("catalogRevisionId")] + public string CatalogRevisionId { get; set; } = string.Empty; - /// Working directory whose repository `enabledPlugins` overlay decides whether this mutation is repository-controlled. Hosts that serve sessions across several repositories (the SDK server) should pass the session's directory; otherwise the guard is evaluated against the server process's own working directory, which may belong to a different repository. Defaults to the server's current working directory. - [JsonPropertyName("workingDirectory")] - public string? WorkingDirectory { get; set; } -} + /// Digest of the canonical materialisation descriptor. + [JsonPropertyName("descriptorDigest")] + public string DescriptorDigest { get; set; } = string.Empty; -/// Plugin names (or specs) to disable, plus the optional working directory the repository-controlled guard is evaluated against. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsDisableRequest -{ - /// Plugin names or "plugin@marketplace" specs to disable. Unknown names are ignored. Non-marketplace direct installs cannot be disabled via this API; uninstall them instead. Plugin-owned MCP servers are stopped in active sessions immediately; other plugin contributions remain available until each session reloads plugins. - [JsonPropertyName("names")] - public IList Names { get => field ??= []; set; } + /// Repository full name, for example owner/name. + [JsonPropertyName("repository")] + public string Repository { get; set; } = string.Empty; - /// Working directory whose repository `enabledPlugins` overlay decides whether this mutation is repository-controlled. Hosts that serve sessions across several repositories (the SDK server) should pass the session's directory; otherwise the guard is evaluated against the server process's own working directory, which may belong to a different repository. Defaults to the server's current working directory. - [JsonPropertyName("workingDirectory")] - public string? WorkingDirectory { get; set; } + /// GitHub repository database identifier. + [JsonPropertyName("repositoryId")] + public string RepositoryId { get; set; } = string.Empty; + + /// Agent Finder resource identifier. + [JsonPropertyName("resourceId")] + public string ResourceId { get; set; } = string.Empty; + + /// Pinned Git commit revision. + [JsonPropertyName("revision")] + public string Revision { get; set; } = string.Empty; + + /// Root path within the pinned repository. + [JsonPropertyName("root")] + public string Root { get; set; } = string.Empty; } -/// Trusted built-in plugin directories to use for this runtime process. +/// A user-facing personal Skill installation location without absolute host paths. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsBuiltinSetRequest +public sealed class SkillInstallationLocation { - /// Complete replacement set of trusted built-in plugin directories. Every entry must be an absolute local filesystem path no longer than 4096 characters. - [JsonPropertyName("paths")] - public IList Paths { get => field ??= []; set; } + /// Diagnostics-only absolute host path. Hosts must not display it by default. + [JsonPropertyName("diagnosticsAbsolutePath")] + public string? DiagnosticsAbsolutePath { get; set; } + + /// Safe display label, for example ~/.copilot/skills/run-checks. + [JsonPropertyName("displayLabel")] + public string DisplayLabel { get; set; } = string.Empty; + + /// Path relative to the Copilot home. + [JsonPropertyName("relativePath")] + public string RelativePath { get; set; } = string.Empty; + + /// Installation scope. Agent Finder Skills are installed in the user's personal Copilot home. + [JsonPropertyName("scope")] + public SkillInstallationScope Scope { get; set; } } -/// Registered marketplace summary. +/// Review for installing a verified Skill. +/// The install variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MarketplaceInfo +public partial class SkillInstallationReviewInstall : SkillInstallationReview { - /// Whether the managed marketplace currently resolved into the runtime marketplace registry. Set to false when the desired managed entry is retained for governance visibility after loading or reconciliation failed. - [JsonPropertyName("available")] - public bool? Available { get; set; } + /// + [JsonIgnore] + public override string Action => "install"; - /// True when this is a default marketplace shipped with the runtime. Defaults are not removable. - [JsonPropertyName("isDefault")] - public bool? IsDefault { get; set; } + /// Catalogue identity retained from the bound candidate before consent. + [JsonPropertyName("catalogue")] + public required InstallationCatalogueIdentity Catalogue { get; set; } - /// Whether enterprise managed settings provide and control this marketplace entry. - [JsonPropertyName("managed")] - public bool? Managed { get; set; } + /// Skill description from SKILL.md when present. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } - /// Marketplace name (matches the @marketplace suffix in plugin specs). + /// + /// Complete verified SKILL.md content. Planning refuses with review-too-large + /// when this exceeds 262144 UTF-8 bytes; it is never truncated. + /// + [JsonPropertyName("entrypointContent")] + public required string EntrypointContent { get; set; } + + /// Relative path of the verified Skill entrypoint. + [JsonPropertyName("entrypointPath")] + public required string EntrypointPath { get; set; } + + /// Reviewed files and digests. + [JsonPropertyName("files")] + public required IList Files { get; set; } + + /// Installing never grants immediate use; the Skill is written disabled. + [JsonPropertyName("installsDisabled")] + public required bool InstallsDisabled { get; set; } + + /// Skill invocation name from SKILL.md. [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + public required string Name { get; set; } - /// Human-readable description of where the marketplace data is fetched from (e.g. "GitHub: owner/repo"). + /// Exact verified source identity. [JsonPropertyName("source")] - public string Source { get; set; } = string.Empty; -} + public required SkillInstallationSource Source { get; set; } -/// All registered marketplaces, including built-in defaults. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MarketplaceListResult -{ - /// Registered marketplaces. - [JsonPropertyName("marketplaces")] - public IList Marketplaces { get => field ??= []; set; } + /// Exact user-scope target location without an absolute host path. + [JsonPropertyName("target")] + public required SkillInstallationLocation Target { get; set; } + + /// Total reviewed payload size in bytes. + [JsonPropertyName("totalBytes")] + public required long TotalBytes { get; set; } } -/// Result of registering a new marketplace. +/// Durable verified Skill ownership summary. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MarketplaceAddResult +public sealed class SkillInstallationSummary { - /// Final name of the marketplace as resolved from its manifest. + /// Catalogue identity retained at install time. + [JsonPropertyName("catalogue")] + public InstallationCatalogueIdentity Catalogue { get => field ??= new(); set; } + + /// Persisted enablement requested for this installation. + [JsonPropertyName("configuredEnabled")] + public bool ConfiguredEnabled { get; set; } + + /// Exact durable installation receipt identity. + [JsonPropertyName("installationId")] + public string InstallationId { get; set; } = string.Empty; + + /// ISO 8601 wall-clock installation time. + [JsonPropertyName("installedAt")] + public string InstalledAt { get; set; } = string.Empty; + + /// Skill invocation name. [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; -} -/// Marketplace source and optional working directory for relative-path resolution. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsMarketplacesAddRequest -{ - /// Marketplace source. Accepts the same forms as the CLI: "owner/repo" or "owner/repo#ref" (GitHub), an http/https/ssh URL (optionally with #ref), a git scp-style URL (user@host:path), or a local path. The marketplace's own name (from its manifest) is used as the registration key. + /// Operation that installed this Skill. + [JsonPropertyName("operationId")] + public string OperationId { get; set; } = string.Empty; + + /// Ownership state observed from files and receipts. + [JsonPropertyName("ownershipState")] + public SkillInstallationOwnershipState OwnershipState { get; set; } + + /// Bound-session load observation. + [JsonPropertyName("sessionState")] + public SkillInstallationSessionState SessionState { get; set; } + + /// Exact retained verified source identity. [JsonPropertyName("source")] - public string Source { get; set; } = string.Empty; + public SkillInstallationSource Source { get => field ??= new(); set; } - /// Working directory used to resolve relative local paths in `source`. Defaults to the server's current working directory. - [JsonPropertyName("workingDirectory")] - public string? WorkingDirectory { get; set; } + /// User-facing installation location without an absolute host path. + [JsonPropertyName("target")] + public SkillInstallationLocation Target { get => field ??= new(); set; } } -/// Outcome of the remove attempt, including dependent-plugin info when applicable. +/// Review for uninstalling an owned verified Skill. +/// The uninstall variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MarketplaceRemoveResult +public partial class SkillInstallationReviewUninstall : SkillInstallationReview { - /// Names of installed plugins that prevented removal. Populated only when `removed=false`. - [JsonPropertyName("dependentPlugins")] - public IList? DependentPlugins { get; set; } + /// + [JsonIgnore] + public override string Action => "uninstall"; - /// True when the marketplace was actually removed. False when removal was skipped because the marketplace has dependent plugins and `force` was not set. - [JsonPropertyName("removed")] - public bool Removed { get; set; } + /// Catalogue identity retained at install time. + [JsonPropertyName("catalogue")] + public required InstallationCatalogueIdentity Catalogue { get; set; } + + /// Files recorded by the installation receipt. + [JsonPropertyName("files")] + public required IList Files { get; set; } + + /// Whether current files differ from the receipt. Apply refuses drift. + [JsonPropertyName("filesModified")] + public required bool FilesModified { get; set; } + + /// Owned installation being removed. + [JsonPropertyName("installation")] + public required SkillInstallationSummary Installation { get; set; } + + /// Total receipt-owned payload size in bytes. + [JsonPropertyName("totalBytes")] + public required long TotalBytes { get; set; } } -/// Name of the marketplace to remove and an optional force flag. +/// A computed Skill install plan. Nothing has been applied. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsMarketplacesRemoveRequest +public sealed class SkillInstallPlan { - /// When true, also uninstall every plugin sourced from this marketplace. When false (default), removal is a no-op if any plugin from this marketplace is installed and the dependent plugin names are returned in the result. - [JsonPropertyName("force")] - public bool? Force { get; set; } + /// Original wall-clock expiry as an ISO 8601 timestamp. + [JsonPropertyName("expiresAt")] + public string ExpiresAt { get; set; } = string.Empty; - /// Marketplace name to remove. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Original operation identifier returned before confirmation. + [JsonPropertyName("operationId")] + public string OperationId { get; set; } = string.Empty; + + /// One-use plan handle, bound to the original candidate authority. + [JsonPropertyName("planHandle")] + public string PlanHandle { get; set; } = string.Empty; + + /// Safe review to present before applying the plan. + [JsonPropertyName("review")] + public SkillInstallationReview Review { get => field ??= new(); set; } } -/// Plugin entry advertised by a marketplace. +/// A verified Skill installation plan was prepared. +/// The install-planned variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MarketplacePluginInfo +public partial class SkillInstallationManagementOutcomeInstallPlanned : SkillInstallationManagementOutcome { - /// Short description from the marketplace catalog, when present. - [JsonPropertyName("description")] - public string? Description { get; set; } + /// + [JsonIgnore] + public override string Kind => "install-planned"; - /// Plugin name as listed in the marketplace catalog. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Prepared install plan. + [JsonPropertyName("plan")] + public required SkillInstallPlan Plan { get; set; } } -/// Plugins advertised by the marketplace. +/// Owned Skill installations were listed. +/// The listed variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MarketplaceBrowseResult +public partial class SkillInstallationManagementOutcomeListed : SkillInstallationManagementOutcome { - /// Plugins advertised by the marketplace. - [JsonPropertyName("plugins")] - public IList Plugins { get => field ??= []; set; } + /// + [JsonIgnore] + public override string Kind => "listed"; + + /// Owned Skill installation summaries. + [JsonPropertyName("installations")] + public required IList Installations { get; set; } } -/// Name of the marketplace whose plugin catalog to fetch. +/// Recovery completed and inventory was inspected. +/// The recovered variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsMarketplacesBrowseRequest +public partial class SkillInstallationManagementOutcomeRecovered : SkillInstallationManagementOutcome { - /// Marketplace name to browse. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "recovered"; + + /// Owned Skill installation summaries after recovery. + [JsonPropertyName("installations")] + public required IList Installations { get; set; } } -/// Per-marketplace refresh result, including marketplace name, success flag, and optional failure error. +/// Interrupted work was safely compensated and the pending marker was cleared. +/// The rolled-back variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MarketplaceRefreshEntry +public partial class SkillInstallationManagementOutcomeRolledBack : SkillInstallationManagementOutcome { - /// Error message (failure only). - [JsonPropertyName("error")] - public string? Error { get; set; } + /// + [JsonIgnore] + public override string Kind => "rolled-back"; - /// Marketplace name that was refreshed. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Original operation identity. + [JsonPropertyName("operation_id")] + public required string OperationId { get; set; } - /// Whether the refresh succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Cause of the compensation. + [JsonPropertyName("reason")] + public required SkillInstallationFailureReason Reason { get; set; } } -/// Result of refreshing one or more marketplace catalogs. +/// A computed Skill uninstall plan. Nothing has been removed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MarketplaceRefreshResult +public sealed class SkillUninstallPlan { - /// Per-marketplace refresh results in deterministic order. - [JsonPropertyName("results")] - public IList Results { get => field ??= []; set; } + /// Original wall-clock expiry as an ISO 8601 timestamp. + [JsonPropertyName("expiresAt")] + public string ExpiresAt { get; set; } = string.Empty; + + /// Owned Skill installation being removed. + [JsonPropertyName("installation")] + public SkillInstallationSummary Installation { get => field ??= new(); set; } + + /// Original removal operation identifier returned before confirmation. + [JsonPropertyName("operationId")] + public string OperationId { get; set; } = string.Empty; + + /// One-use uninstall plan handle. + [JsonPropertyName("planHandle")] + public string PlanHandle { get; set; } = string.Empty; + + /// Safe review to present before applying removal. + [JsonPropertyName("review")] + public SkillInstallationReview Review { get => field ??= new(); set; } } -/// RPC data type for PluginsMarketplacesRefresh operations. +/// An owned Skill uninstall plan was prepared. +/// The uninstall-planned variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsMarketplacesRefreshRequest +public partial class SkillInstallationManagementOutcomeUninstallPlanned : SkillInstallationManagementOutcome { - /// Marketplace name to refresh. When omitted, every registered marketplace is refreshed. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// + [JsonIgnore] + public override string Kind => "uninstall-planned"; + + /// Prepared uninstall plan. + [JsonPropertyName("plan")] + public required SkillUninstallPlan Plan { get; set; } } -/// Agent metadata, including identifiers, display details, source, tools, model, models, reasoning effort, MCP servers, skills, and file path. +/// Status snapshot from the original connection, independent of new-work account availability. +/// Polymorphic base type discriminated by phase. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AgentInfo +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "phase", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(SkillInstallationOperationStatusPreparing), "preparing")] +[JsonDerivedType(typeof(SkillInstallationOperationStatusPrepared), "prepared")] +[JsonDerivedType(typeof(SkillInstallationOperationStatusAwaitingConfirmation), "awaiting-confirmation")] +[JsonDerivedType(typeof(SkillInstallationOperationStatusRevalidating), "revalidating")] +[JsonDerivedType(typeof(SkillInstallationOperationStatusApplying), "applying")] +[JsonDerivedType(typeof(SkillInstallationOperationStatusCompleted), "completed")] +public partial class SkillInstallationOperationStatus { - /// Description of the agent's purpose. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; - - /// Whether model-driven invocation is disabled for this agent. - [JsonPropertyName("disableModelInvocation")] - public bool? DisableModelInvocation { get; set; } - - /// Human-readable display name. - [JsonPropertyName("displayName")] - public string DisplayName { get; set; } = string.Empty; - - /// Declarative hook actions keyed by event name, executed only while this agent is active. - [JsonPropertyName("hooks")] - public IDictionary>? Hooks { get; set; } - - /// Stable identifier for selection. For most agents this is the same as `name`; for plugin/builtin agents it may differ. Always populated; defaults to `name` when no distinct id was assigned. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - - /// MCP server configurations attached to this agent, keyed by server name. Server config shape mirrors the MCP `mcpServers` schema. - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] - [JsonPropertyName("mcpServers")] - public IDictionary? McpServers { get; set; } - - /// Authored preferred model id for this agent. Runtime model selection may choose a different model; omitted means no authored preference. - [JsonPropertyName("model")] - public string? Model { get; set; } - - /// Whether authored models are preferences or required constraints. - [JsonPropertyName("modelPolicy")] - public AgentModelPolicy? ModelPolicy { get; set; } - - /// Authored preferred model ids for this agent, in priority order. Runtime model selection chooses the first available model; omitted means no authored preference. - [JsonPropertyName("models")] - public IList? Models { get; set; } - - /// Name of the agent. Use `id` as the stable selection identifier. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// The type discriminator. + [JsonPropertyName("phase")] + public virtual string Phase { get; set; } = string.Empty; +} - /// Absolute local file path of the agent definition. Only set for file-based agents loaded from disk; remote agents do not have a path. - [JsonPropertyName("path")] - public string? Path { get; set; } - /// Authored base prompt for the agent. Runtime prompt assembly may add dynamic context at invocation time. Omitted from `session.agent.list` unless `includePrompt` is true. - [JsonPropertyName("prompt")] - public string? Prompt { get; set; } +/// Original operation progress discriminator. +/// The preparing variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class SkillInstallationOperationStatusPreparing : SkillInstallationOperationStatus +{ + /// + [JsonIgnore] + public override string Phase => "preparing"; - /// Authored reasoning effort for this agent. Applied on selection to models that support it; omitted means no authored preference. - [JsonPropertyName("reasoningEffort")] - public string? ReasoningEffort { get; set; } + /// Whether cancellation has been requested. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } - /// Skill names preloaded into this agent's context. Omitted means none. - [JsonPropertyName("skills")] - public IList? Skills { get; set; } + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } +} - /// Where the agent definition was loaded from. - [JsonPropertyName("source")] - public AgentInfoSource? Source { get; set; } +/// Original operation progress discriminator. +/// The prepared variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class SkillInstallationOperationStatusPrepared : SkillInstallationOperationStatus +{ + /// + [JsonIgnore] + public override string Phase => "prepared"; - /// Allowed tool names for this agent. Empty array means none; omitted means inherit defaults. - [JsonPropertyName("tools")] - public IList? Tools { get; set; } + /// Whether cancellation has been requested. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } - /// Whether the agent can be selected directly by the user. Agents marked `false` are subagent-only. - [JsonPropertyName("userInvocable")] - public bool? UserInvocable { get; set; } + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// Agents discovered across user, project, plugin, and remote sources. +/// Original operation progress discriminator. +/// The awaiting-confirmation variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerAgentList +public partial class SkillInstallationOperationStatusAwaitingConfirmation : SkillInstallationOperationStatus { - /// All discovered agents across all sources. - [JsonPropertyName("agents")] - public IList Agents { get => field ??= []; set; } + /// + [JsonIgnore] + public override string Phase => "awaiting-confirmation"; + + /// Whether cancellation has been requested. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } + + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// Optional project paths to include in agent discovery. +/// Original operation progress discriminator. +/// The revalidating variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AgentsDiscoverRequest +public partial class SkillInstallationOperationStatusRevalidating : SkillInstallationOperationStatus { - /// Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without ambient discovery, subject to managed/source disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. - [JsonPropertyName("agentDirectories")] - public IList? AgentDirectories { get; set; } + /// + [JsonIgnore] + public override string Phase => "revalidating"; - /// When true, omit the host's agents (the user-level agent directory and all plugin agents), leaving only project and remote agents. For multitenant deployments. - [JsonPropertyName("excludeHostAgents")] - public bool? ExcludeHostAgents { get; set; } + /// Whether cancellation has been requested. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } - /// Optional list of project directory paths to scan for project-scoped agents. When omitted or empty, only user/plugin/remote-independent agents are returned (no project scan). - [JsonPropertyName("projectPaths")] - public IList? ProjectPaths { get; set; } + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// Canonical directory where custom agents can be discovered or created, with scope, preference, and optional project path. +/// Original operation progress discriminator. +/// The applying variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AgentDiscoveryPath +public partial class SkillInstallationOperationStatusApplying : SkillInstallationOperationStatus { - /// Absolute path of the search/create directory (may not exist on disk yet). - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; - - /// Whether this is the canonical directory to create a new agent in its tier. At most one entry per tier is preferred. - [JsonPropertyName("preferredForCreation")] - public bool PreferredForCreation { get; set; } + /// + [JsonIgnore] + public override string Phase => "applying"; - /// The input project path this directory was derived from (only for project scope). - [JsonPropertyName("projectPath")] - public string? ProjectPath { get; set; } + /// Whether cancellation has been requested; already-started effects require recovery. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } - /// Which tier this directory belongs to. - [JsonPropertyName("scope")] - public AgentDiscoveryPathScope Scope { get; set; } + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// Canonical locations where custom agents can be created so the runtime will recognize them. +/// Terminal verified Skill mutation result. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AgentDiscoveryPathList +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(SkillInstallationOutcomeInstalled), "installed")] +[JsonDerivedType(typeof(SkillInstallationOutcomeUninstalled), "uninstalled")] +[JsonDerivedType(typeof(SkillInstallationOutcomeRolledBack), "rolled-back")] +[JsonDerivedType(typeof(SkillInstallationOutcomeRecoveryRequired), "recovery-required")] +[JsonDerivedType(typeof(SkillInstallationOutcomeDeclined), "declined")] +[JsonDerivedType(typeof(SkillInstallationOutcomeCancelled), "cancelled")] +[JsonDerivedType(typeof(SkillInstallationOutcomeRefused), "refused")] +public partial class SkillInstallationOutcome { - /// Canonical agent create/discovery directories, in priority order. - [JsonPropertyName("paths")] - public IList Paths { get => field ??= []; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Optional project paths to include when enumerating agent discovery directories. + +/// The verified Skill was installed disabled. +/// The installed variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AgentsGetDiscoveryPathsRequest +public partial class SkillInstallationOutcomeInstalled : SkillInstallationOutcome { - /// Explicit discovery-only agent roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. - [JsonPropertyName("agentDirectories")] - public IList? AgentDirectories { get; set; } - - /// When true, omit the host's user-level agent directory, leaving only project directories. For multitenant deployments (mirrors `discover`'s `excludeHostAgents`). - [JsonPropertyName("excludeHostAgents")] - public bool? ExcludeHostAgents { get; set; } + /// + [JsonIgnore] + public override string Kind => "installed"; - /// Optional list of project directory paths. When omitted or empty, only the user-level directory is returned. - [JsonPropertyName("projectPaths")] - public IList? ProjectPaths { get; set; } + /// Durable installed Skill summary. + [JsonPropertyName("installation")] + public required SkillInstallationSummary Installation { get; set; } } -/// The agents this runtime ships, named so a consumer can tell them apart from authored ones. +/// The owned Skill was removed. +/// The uninstalled variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AgentsGetBuiltinsResult +public partial class SkillInstallationOutcomeUninstalled : SkillInstallationOutcome { - /// The subset of `names` a user is allowed to turn off. A shipped agent outside this list is always active and a client should not offer a toggle for it. - [JsonPropertyName("disableableNames")] - public IList DisableableNames { get => field ??= []; set; } + /// + [JsonIgnore] + public override string Kind => "uninstalled"; - /// Every agent name this runtime ships. - [JsonPropertyName("names")] - public IList Names { get => field ??= []; set; } + /// Removed installation identity. + [JsonPropertyName("installationId")] + public required string InstallationId { get; set; } - /// The subset of `names` defined by a shipped YAML definition. The remainder are special-cased in code and have no definition to load. - [JsonPropertyName("yamlBasedNames")] - public IList YamlBasedNames { get => field ??= []; set; } + /// Original removal operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// A shipped agent, named and described. +/// The durable transaction was aborted or fully compensated. +/// The rolled-back variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class BuiltinAgentSummary +public partial class SkillInstallationOutcomeRolledBack : SkillInstallationOutcome { - /// One-line description of what the agent does. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "rolled-back"; - /// The agent name, as it appears in `getBuiltins`. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Original operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } + + /// Cause of the fully aborted or compensated operation. + [JsonPropertyName("reason")] + public required SkillInstallationFailureReason Reason { get; set; } } -/// The shipped agents available under the requested flags. +/// A write may have completed. Recover and inspect durable state before retrying. +/// The recovery-required variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AgentsGetAvailableBuiltinsResult +public partial class SkillInstallationOutcomeRecoveryRequired : SkillInstallationOutcome { - /// Available shipped agents, in the runtime's own order. - [JsonPropertyName("agents")] - public IList Agents { get => field ??= []; set; } + /// + [JsonIgnore] + public override string Kind => "recovery-required"; + + /// Operation whose durable result must be recovered and inspected. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// The feature flags to evaluate shipped agents against. +/// The user declined the confirmation request. +/// The declined variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AgentsGetAvailableBuiltinsRequest +public partial class SkillInstallationOutcomeDeclined : SkillInstallationOutcome { - /// The surface asking, which gates agents that only apply to one client. Omit or pass null to apply no client filter. - [JsonPropertyName("context")] - public string? Context { get; set; } - - /// Feature flag values keyed by name, evaluated with the runtime's truthiness rules. Omit or pass null for no flags. - [JsonPropertyName("featureFlags")] - public IDictionary? FeatureFlags { get; set; } + /// + [JsonIgnore] + public override string Kind => "declined"; - /// Flag overrides keyed by name. A null entry uses the corresponding base flag; false explicitly disables it. Omit or pass null for no overrides. - [JsonPropertyName("overrides")] - public IDictionary? Overrides { get; set; } + /// Original operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// One shipped agent's definition. +/// The operation was cancelled before a terminal mutation. +/// The cancelled variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AgentsGetBuiltinDefinitionResult +public partial class SkillInstallationOutcomeCancelled : SkillInstallationOutcome { - /// The agent's definition, serialized as JSON. It carries the authored keys plus the runtime's projected `__nativeCustomAgent` view of the same agent. It is a string rather than an object because the runtime parses it with the agent schema's tolerant shape, which accepts keys this contract does not name. - [JsonPropertyName("definitionJson")] - public string DefinitionJson { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "cancelled"; + + /// Original operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } } -/// The shipped agent whose definition to load. +/// The operation was refused without applying changes. +/// The refused variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AgentsGetBuiltinDefinitionRequest +public partial class SkillInstallationOutcomeRefused : SkillInstallationOutcome { - /// The agent name, which must be one of `getBuiltins`'s `yamlBasedNames`. A name outside that list is special-cased in code and has no definition, and is reported as an error rather than as an empty definition. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "refused"; + + /// Present once an operation has been allocated. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("operationId")] + public string? OperationId { get; set; } + + /// Bounded refusal reason. + [JsonPropertyName("reason")] + public required SkillInstallationFailureReason Reason { get; set; } } -/// One shipped agent, projected for a listing. +/// Original operation progress discriminator. +/// The completed variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AgentsGetBuiltinListingDefinitionResult +public partial class SkillInstallationOperationStatusCompleted : SkillInstallationOperationStatus { - /// The agent projected as a custom agent, serialized as JSON. It is a string rather than an object for the same reason as `getBuiltinDefinition`: the runtime parses the underlying definition with the agent schema's tolerant shape, which accepts keys this contract does not name. - [JsonPropertyName("definitionJson")] - public string DefinitionJson { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Phase => "completed"; + + /// Whether cancellation was requested before the terminal result. + [JsonPropertyName("cancellationRequested")] + public required bool CancellationRequested { get; set; } + + /// Original runtime-issued operation identity. + [JsonPropertyName("operationId")] + public required string OperationId { get; set; } + + /// Immutable terminal receipt. + [JsonPropertyName("outcome")] + public required SkillInstallationOutcome Outcome { get; set; } } -/// The shipped agent whose listing entry to load. +/// Original-connection operation snapshot. +/// The operation variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AgentsGetBuiltinListingDefinitionRequest +public partial class SkillInstallationManagementOutcomeOperation : SkillInstallationManagementOutcome { - /// The agent name, taken from `getAvailableBuiltins`. Unlike `getBuiltinDefinition`, the agent that `getBuiltins` reports as special-cased rather than YAML-based is answered here too, from its in-code definition. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "operation"; + + /// Operation status. + [JsonPropertyName("operation")] + public required SkillInstallationOperationStatus Operation { get; set; } } -/// The model to switch to, and the warning to show when the agent's preference could not be met. +/// Enablement changed and the selected session was reconciled. +/// The enabled-changed variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AgentsCustomAgentInitialModelDecisionResult +public partial class SkillInstallationManagementOutcomeEnabledChanged : SkillInstallationManagementOutcome { - /// The reasoning effort attached to the selected model preference. Absent when that preference does not specify an effort. - [JsonPropertyName("reasoningEffort")] - public string? ReasoningEffort { get; set; } + /// + [JsonIgnore] + public override string Kind => "enabled-changed"; - /// The first available model that matches the agent's preferences. Absent when none of the requested models is available. - [JsonPropertyName("targetModel")] - public string? TargetModel { get; set; } + /// Safe reload or reconciliation diagnostics. + [JsonPropertyName("diagnostics")] + public required IList Diagnostics { get; set; } - /// What to tell the user about an unmet preference. Absent when the preference was met. A warning with no `targetModel` means the agent's models are all unavailable. - [JsonPropertyName("warning")] - public string? Warning { get; set; } + /// Updated installation summary. + [JsonPropertyName("installation")] + public required SkillInstallationSummary Installation { get; set; } } -/// The models a custom agent asks for, and the models actually available. +/// The management request was refused. +/// The refused variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AgentsCustomAgentInitialModelDecisionParams +public partial class SkillInstallationManagementOutcomeRefused : SkillInstallationManagementOutcome { - /// The agent's declared `model:` entry, serialized. A single name or an ordered list of acceptable names. - [JsonPropertyName("agentModelsJson")] - public string AgentModelsJson { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "refused"; - /// The models available to this session, serialized in the shape the model list carries. - [JsonPropertyName("availableModelsJson")] - public string AvailableModelsJson { get; set; } = string.Empty; + /// Bounded refusal reason. + [JsonPropertyName("reason")] + public required SkillInstallationFailureReason Reason { get; set; } } -/// Installed plugin record from global state, with marketplace, version, install time, enabled state, cache path, and source. +/// The outcome variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class InstalledPlugin +public partial class SkillInstallationManagementResultOutcome : SkillInstallationManagementResult { - /// Path where the plugin is cached locally. - [JsonPropertyName("cache_path")] - public string? CachePath { get; set; } - - /// Whether the plugin is currently enabled. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// + [JsonIgnore] + public override string Kind => "outcome"; - /// Installation timestamp. - [JsonPropertyName("installed_at")] - public string InstalledAt { get; set; } = string.Empty; + /// Capabilities honoured for this request. + [JsonPropertyName("negotiated")] + public required CatalogNegotiatedContract Negotiated { get; set; } - /// Absolute path of the marketplace directory a live plugin was resolved from. Present only on live, never-persisted records — those synthesized at session start for a directory/local marketplace, whose cache_path points at the real plugin directory on disk rather than a copy under the installed-plugins cache. Its presence is what marks a record as live, and no record carrying it is ever written to the persisted installedPlugins key. - [JsonPropertyName("installed_from")] - public string? InstalledFrom { get; set; } + /// Observed management outcome. + [JsonPropertyName("outcome")] + public required SkillInstallationManagementOutcome Outcome { get; set; } +} - /// Marketplace the plugin came from (empty string for direct repo installs). - [JsonPropertyName("marketplace")] - public string Marketplace { get; set; } = string.Empty; +/// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. +/// The negotiation-refused variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class SkillInstallationManagementResultNegotiationRefused : SkillInstallationManagementResult +{ + /// + [JsonIgnore] + public override string Kind => "negotiation-refused"; - /// Plugin name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Source for direct repo installs (when marketplace is empty). - [JsonPropertyName("source")] - public JsonElement? Source { get; set; } + /// Lowest caller protocol version this runtime will serve. + [JsonPropertyName("minimumSupportedProtocolVersion")] + public required long MinimumSupportedProtocolVersion { get; set; } - /// Per-plugin source fingerprint (a SHA-256 hash of the plugin's catalog source spec plus its resolved source subtree — NOT a Git commit SHA) captured at marketplace install/update time. Auto-update compares it against the freshly recomputed fingerprint to detect a content change that does not bump the version. Absent for pre-existing installs and for direct (non-marketplace) installs. - [JsonPropertyName("source_sha")] - public string? SourceSha { get; set; } + /// Whether the version or the capability set was the problem. + [JsonPropertyName("reason")] + public required CatalogNegotiationRefusedReason Reason { get; set; } - /// Version installed (if available). - [JsonPropertyName("version")] - public string? Version { get; set; } + /// Protocol version of the runtime that refused the request. + [JsonPropertyName("runtimeProtocolVersion")] + public required long RuntimeProtocolVersion { get; set; } + + /// Capabilities this runtime can safely advertise to this caller. The complete five-capability protocol-3 legacy set is always present; every capability added after that baseline appears only when the caller required it, so an older closed-enum decoder can still consume a refusal. This list does not imply that every deployment has enabled every operation. + [JsonPropertyName("supportedCapabilities")] + public required IList SupportedCapabilities { get; set; } + + /// The subset of the caller's bounded extensible capability identifiers this runtime cannot honour. + [JsonPropertyName("unsupportedCapabilities")] + public required IList UnsupportedCapabilities { get; set; } } -/// An account the host has signed in to, identified by the server it lives on and the login it uses there. The same person can appear more than once when they use both github.com and an Enterprise server. +/// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. +/// The invalid-request variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class LoggedInUser +public partial class SkillInstallationManagementResultInvalidRequest : SkillInstallationManagementResult { - /// Source account this account was derived from, when one was recorded. - [JsonPropertyName("derivedFrom")] - public string? DerivedFrom { get; set; } - - /// Host the account belongs to, such as `github.com` or an Enterprise server. - [JsonPropertyName("host")] - public string Host { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "invalid-request"; - /// Account kind, when the host recorded one. Consumers must tolerate new strings. - [JsonPropertyName("kind")] - public string? Kind { get; set; } + /// Which request field was rejected. + [JsonPropertyName("field")] + public required CatalogInvalidRequestField Field { get; set; } - /// Account login on that host. - [JsonPropertyName("login")] - public string Login { get; set; } = string.Empty; + /// Human-readable explanation, safe to surface. Never echoes the offending value, nor a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } } -/// The host's machine-wide state. Every field is optional because a fresh install has recorded nothing yet, so a reader must treat an absent field as `not yet`, never as a negative answer. Stored credentials are deliberately absent from this shape. +/// Side-effect-free planning of one verified Agent Finder Skill candidate. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class GlobalStateLoadResult +internal sealed class SkillPlanInstallRequest { - /// Whether the app tip has been shown. - [JsonPropertyName("appTipShown")] - public bool? AppTipShown { get; set; } - - /// Terminals the user has already been asked to set up, so the host does not ask twice. - [JsonPropertyName("askedSetupTerminals")] - public IList? AskedSetupTerminals { get; set; } - - /// When the Auto-feedback hint was last shown, as an ISO 8601 timestamp. It enforces the once-per-day cap for non-staff users across restarts. - [JsonPropertyName("autoFeedbackLastPromptedAt")] - public string? AutoFeedbackLastPromptedAt { get; set; } - - /// When the host first ran on this machine. - [JsonPropertyName("firstLaunchAt")] - public string? FirstLaunchAt { get; set; } - - /// Plugins installed on this machine. - [JsonPropertyName("installedPlugins")] - public IList? InstalledPlugins { get; set; } + /// Fresh single-use AI skill candidate handle returned by a bound catalogue search. + [JsonPropertyName("candidateHandle")] + public string CandidateHandle { get; set; } = string.Empty; - /// Account used for the most recent sign-in. - [JsonPropertyName("lastLoggedInUser")] - public LoggedInUser? LastLoggedInUser { get; set; } + /// Required authenticated bound catalogue and Skill installation capabilities. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// Every account the host has signed in to on this machine. - [JsonPropertyName("loggedInUsers")] - public IList? LoggedInUsers { get; set; } + /// Existing local session attached to this connection. + [JsonPropertyName("policySessionId")] + public string PolicySessionId { get; set; } = string.Empty; +} - /// Whether the one-off cleanup of stored reasoning summaries has run. - [JsonPropertyName("reasoningSummariesCleanupDone")] - public bool? ReasoningSummariesCleanupDone { get; set; } +/// Skill installation result with the honoured contract, or a typed request/negotiation refusal. +/// Polymorphic base type discriminated by kind. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(SkillInstallationResultOutcome), "outcome")] +[JsonDerivedType(typeof(SkillInstallationResultNegotiationRefused), "negotiation-refused")] +[JsonDerivedType(typeof(SkillInstallationResultInvalidRequest), "invalid-request")] +public partial class SkillInstallationResult +{ + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} - /// Models the user selected recently, most recent first. - [JsonPropertyName("recentModelIds")] - public IList? RecentModelIds { get; set; } - /// Whether the user declined to trust the sandbox credential proxy CA. - [JsonPropertyName("sandboxCredentialProxyCaDeclined")] - public bool? SandboxCredentialProxyCaDeclined { get; set; } +/// The outcome variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class SkillInstallationResultOutcome : SkillInstallationResult +{ + /// + [JsonIgnore] + public override string Kind => "outcome"; - /// Whether the sandbox onboarding has been shown. - [JsonPropertyName("sandboxOnboardingShown")] - public bool? SandboxOnboardingShown { get; set; } + /// Capabilities honoured for this request. + [JsonPropertyName("negotiated")] + public required CatalogNegotiatedContract Negotiated { get; set; } - /// Whether the user is a GitHub or Microsoft staff member, which unlocks internal-only behavior. - [JsonPropertyName("staff")] - public bool? Staff { get; set; } + /// Terminal operation outcome. + [JsonPropertyName("outcome")] + public required SkillInstallationOutcome Outcome { get; set; } +} - /// Whether the user was recognized as GitHub staff. - [JsonPropertyName("staffGithub")] - public bool? StaffGitHub { get; set; } +/// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. +/// The negotiation-refused variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class SkillInstallationResultNegotiationRefused : SkillInstallationResult +{ + /// + [JsonIgnore] + public override string Kind => "negotiation-refused"; - /// When the staff-only log level migration last ran. - [JsonPropertyName("staffLogLevelMigrationAt")] - public string? StaffLogLevelMigrationAt { get; set; } + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Whether the user was recognized as Microsoft staff. - [JsonPropertyName("staffMicrosoft")] - public bool? StaffMicrosoft { get; set; } + /// Lowest caller protocol version this runtime will serve. + [JsonPropertyName("minimumSupportedProtocolVersion")] + public required long MinimumSupportedProtocolVersion { get; set; } - /// When the staff-only model reset last ran. - [JsonPropertyName("staffModelResetAt")] - public string? StaffModelResetAt { get; set; } + /// Whether the version or the capability set was the problem. + [JsonPropertyName("reason")] + public required CatalogNegotiationRefusedReason Reason { get; set; } - /// When the staff-only update channel migration last ran. - [JsonPropertyName("staffUpdateChannelMigrationAt")] - public string? StaffUpdateChannelMigrationAt { get; set; } + /// Protocol version of the runtime that refused the request. + [JsonPropertyName("runtimeProtocolVersion")] + public required long RuntimeProtocolVersion { get; set; } - /// Folders where the user declined the init prompt, so it stays hidden there. - [JsonPropertyName("suppressInitFolders")] - public IList? SuppressInitFolders { get; set; } + /// Capabilities this runtime can safely advertise to this caller. The complete five-capability protocol-3 legacy set is always present; every capability added after that baseline appears only when the caller required it, so an older closed-enum decoder can still consume a refusal. This list does not imply that every deployment has enabled every operation. + [JsonPropertyName("supportedCapabilities")] + public required IList SupportedCapabilities { get; set; } - /// Folders the user has marked as trusted. - [JsonPropertyName("trustedFolders")] - public IList? TrustedFolders { get; set; } + /// The subset of the caller's bounded extensible capability identifiers this runtime cannot honour. + [JsonPropertyName("unsupportedCapabilities")] + public required IList UnsupportedCapabilities { get; set; } } -/// Selects the configuration directory whose machine-wide state to read. +/// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. +/// The invalid-request variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class GlobalStateLoadForConfigDirRequest +public partial class SkillInstallationResultInvalidRequest : SkillInstallationResult { - /// Copilot configuration directory to read the state document from, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to read the directory the server resolved for itself. - [JsonPropertyName("configDir")] - public string? ConfigDir { get; set; } + /// + [JsonIgnore] + public override string Kind => "invalid-request"; + + /// Which request field was rejected. + [JsonPropertyName("field")] + public required CatalogInvalidRequestField Field { get; set; } + + /// Human-readable explanation, safe to surface. Never echoes the offending value, nor a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } } -/// A single top-level key to record in the host's machine-wide state. The write replaces only that key and leaves the rest of the document untouched, so two writers recording different one-off flags do not overwrite each other. The stored credential keys cannot be written through this method. +/// Applies exactly one retained verified Skill installation plan. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class GlobalStateWriteKeyRequest +internal sealed class SkillApplyInstallRequest { - /// Copilot configuration directory to write the state document in, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to write the directory the server resolved for itself. Mirrors `globalState.loadForConfigDir`, so a caller can read and write the same directory. - [JsonPropertyName("configDir")] - public string? ConfigDir { get; set; } + /// Required authenticated bound catalogue and Skill installation capabilities. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// Top-level key to write, named as it appears in the result of `globalState.load`. It must be one of the writable keys that `globalState.writeKey` lists. - [JsonPropertyName("key")] - public string Key { get; set; } = string.Empty; + /// Opaque original plan, consumed once. + [JsonPropertyName("planHandle")] + public string PlanHandle { get; set; } = string.Empty; - /// Value to store for the key. Omit it, or pass null, to remove the key instead. - [JsonPropertyName("value")] - public JsonElement? Value { get; set; } + /// Same existing selected session as planning. + [JsonPropertyName("policySessionId")] + public string PolicySessionId { get; set; } = string.Empty; } -/// A literal choice the command input accepts, with a human-facing description. +/// Read-only preparation of one owned Skill removal under fresh selected-session authority. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SlashCommandInputChoice +internal sealed class SkillPlanUninstallRequest { - /// Human-readable description shown alongside the choice. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; + /// Required authenticated bound installation contract. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// The literal choice value (e.g. 'on', 'off', 'show'). - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Exact receipt to inspect. + [JsonPropertyName("installationId")] + public string InstallationId { get; set; } = string.Empty; + + /// Existing selected local session on this connection. + [JsonPropertyName("policySessionId")] + public string PolicySessionId { get; set; } = string.Empty; } -/// Optional unstructured input hint. +/// One-use application of the exact retained Skill removal plan. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SlashCommandInput +internal sealed class SkillApplyUninstallRequest { - /// Optional literal choices the input accepts, each with a human-facing description; clients may render these as selectable options. - [JsonPropertyName("choices")] - public IList? Choices { get; set; } - - /// Optional completion hint for the input (e.g. 'directory' for filesystem path completion). - [JsonPropertyName("completion")] - public SlashCommandInputCompletion? Completion { get; set; } - - /// Hint to display when command input has not been provided. - [JsonPropertyName("hint")] - public string Hint { get; set; } = string.Empty; + /// Required authenticated bound installation contract. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// When true, clients should pass the full text after the command name as a single argument rather than splitting on whitespace. - [JsonPropertyName("preserveMultilineInput")] - public bool? PreserveMultilineInput { get; set; } + /// Opaque original removal plan, consumed once. + [JsonPropertyName("planHandle")] + public string PlanHandle { get; set; } = string.Empty; - /// When true, the command requires non-empty input; clients should render the input hint as required. - [JsonPropertyName("required")] - public bool? Required { get; set; } + /// Same existing selected session as removal preparation. + [JsonPropertyName("policySessionId")] + public string PolicySessionId { get; set; } = string.Empty; } -/// Slash-command metadata with name, aliases, description, kind, input hint, execution allowance, and schedulability. +/// Server-side skill metadata, including name, description, source, enabled/invocable state, path, project path, and argument hint. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SlashCommandInfo +public sealed class ServerSkill { - /// Canonical aliases without leading slashes. - [JsonPropertyName("aliases")] - public IList? Aliases { get; set; } + /// Optional freeform hint describing the skill's expected arguments, from the `argument-hint` frontmatter field. + [JsonPropertyName("argumentHint")] + public string? ArgumentHint { get; set; } - /// Whether the command may run while an agent turn is active. - [JsonPropertyName("allowDuringAgentExecution")] - public bool AllowDuringAgentExecution { get; set; } + /// Canonical slash command name used to invoke the skill, without the leading '/'. + [JsonPropertyName("commandName")] + public string? CommandName { get; set; } - /// Human-readable command description. + /// Description of what the skill does. [JsonPropertyName("description")] public string Description { get; set; } = string.Empty; - /// Whether the command is experimental. - [JsonPropertyName("experimental")] - public bool? Experimental { get; set; } - - /// Optional unstructured input hint. - [JsonPropertyName("input")] - public SlashCommandInput? Input { get; set; } - - /// Coarse command category for grouping and behavior: runtime built-in, skill-backed command, or SDK/client-owned command. - [JsonPropertyName("kind")] - public SlashCommandKind Kind { get; set; } + /// Whether the skill is currently enabled (based on global config). + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } - /// Canonical command name without a leading slash. + /// Unique identifier for the skill. [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; - /// Whether the command may be the target of `/every` / `/after` schedules. Resolution happens at every tick, so only set this when the command is safe to re-invoke and produces an agent prompt. - [JsonPropertyName("schedulable")] - public bool? Schedulable { get; set; } + /// Absolute path to the skill file. + [JsonPropertyName("path")] + public string? Path { get; set; } + + /// The project path this skill belongs to (only for project/inherited skills). + [JsonPropertyName("projectPath")] + public string? ProjectPath { get; set; } + + /// Source location type (e.g., project, personal-copilot, plugin, builtin). + [JsonPropertyName("source")] + public SkillSource Source { get; set; } + + /// Whether the skill can be invoked by the user as a slash command. + [JsonPropertyName("userInvocable")] + public bool UserInvocable { get; set; } } -/// Slash commands available in the session, after applying any include/exclude filters. +/// Skills discovered across global and project sources. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CommandList +public sealed class ServerSkillList { - /// Commands available in this session. - [JsonPropertyName("commands")] - public IList Commands { get => field ??= []; set; } + /// Messages for skills that failed to load (e.g. malformed SKILL.md). Empty when host skills are excluded so host-local paths are not disclosed to multitenant callers. + [JsonPropertyName("errors")] + public IList? Errors { get; set; } + + /// All discovered skills across all sources. + [JsonPropertyName("skills")] + public IList Skills { get => field ??= []; set; } } -/// A single user setting's effective value alongside its default, so consumers can render settings left at their default. +/// Optional project paths and additional skill directories to include in discovery. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UserSettingMetadata +internal sealed class SkillsDiscoverRequest { - /// The centrally-known default for this setting (null when no default is registered). - [JsonPropertyName("default")] - public JsonElement Default { get; set; } + /// When true, omit skills from the host's global sources (personal, custom, plugin, and built-in), returning only project-scoped skills. For multitenant deployments. + [JsonPropertyName("excludeHostSkills")] + public bool? ExcludeHostSkills { get; set; } - /// True when the user has not set an explicit value for this setting (i.e. it is left at its default). Reflects whether the user has overridden the key, not whether the effective value happens to equal the default — a key explicitly set to a value identical to the default still reports false. - [JsonPropertyName("isDefault")] - public bool IsDefault { get; set; } + /// Optional skill scan paths to exclude from discovery. + [JsonPropertyName("ignoredSkillsLocations")] + public IList? IgnoredSkillsLocations { get; set; } - /// The effective value: the user's value if set, otherwise the default. - [JsonPropertyName("value")] - public JsonElement Value { get; set; } -} + /// Optional list of project directory paths to scan for project-scoped skills. + [JsonPropertyName("projectPaths")] + public IList? ProjectPaths { get; set; } -/// Per-key metadata for every known user setting in settings.json, including settings left at their default. Excludes repository- and enterprise-managed overrides. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UserSettingsGetResult -{ - /// Every known user setting keyed by setting name, each with its effective value, default, and whether it is at the default. - [JsonPropertyName("settings")] - public IDictionary Settings { get => field ??= new Dictionary(); set; } + /// Explicit discovery-only skill roots, not filesystem grants. Available without ambient discovery, subject to skill/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + [JsonPropertyName("skillDirectories")] + public IList? SkillDirectories { get; set; } } -/// On-disk locations of the settings files this runtime reads. A path is reported whether or not the file exists. +/// Canonical directory where skills can be discovered or created, with scope, preference, and optional project path. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UserSettingsGetPathsResult +public sealed class SkillDiscoveryPath { - /// The repository's local, untracked settings file, or null when no repository root was supplied. - [JsonPropertyName("repoLocalSettings")] - public string? RepoLocalSettings { get; set; } + /// Absolute path of the create/discovery target (may not exist on disk yet). + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// The repository's checked-in settings file, or null when no repository root was supplied. - [JsonPropertyName("repoSettings")] - public string? RepoSettings { get; set; } + /// Whether this is the canonical directory to create a new skill in its tier. At most one entry per tier is preferred; the `personal-agents` and `custom` scopes are never preferred. + [JsonPropertyName("preferredForCreation")] + public bool PreferredForCreation { get; set; } - /// The user settings file: `settings.json` under the resolved Copilot home. This is the file `user.settings.get`, `user.settings.load`, and `user.settings.set` read and write. - [JsonPropertyName("userSettings")] - public string UserSettings { get; set; } = string.Empty; + /// The input project path this directory was derived from (only for project scope). + [JsonPropertyName("projectPath")] + public string? ProjectPath { get; set; } + + /// Which tier this directory belongs to. + [JsonPropertyName("scope")] + public SkillDiscoveryScope Scope { get; set; } } -/// Selects which settings file paths to resolve. +/// Canonical locations where skills can be created so the runtime will recognize them. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UserSettingsGetPathsRequest +public sealed class SkillDiscoveryPathList { - /// Absolute path of a repository root. Supply it to also resolve that repository's two settings file paths; omit it to resolve only the user path. - [JsonPropertyName("repoRoot")] - public string? RepoRoot { get; set; } + /// Canonical skill create/discovery directories, in priority order. + [JsonPropertyName("paths")] + public IList Paths { get => field ??= []; set; } } -/// Partial user settings to write to settings.json. Each top-level key is written individually, replacing the existing value; a key whose value is null is removed. +/// Optional project paths to enumerate. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UserSettingsSetRequest +public sealed class SkillsGetDiscoveryPathsRequest { - /// Partial user settings to write, as a free-form object keyed by setting name. - [JsonPropertyName("settings")] - public JsonElement Settings { get; set; } + /// When true, omit the host's personal and custom skill directories, leaving only project directories. For multitenant deployments. + [JsonPropertyName("excludeHostSkills")] + public bool? ExcludeHostSkills { get; set; } + + /// Optional skill scan paths to exclude from discovery. + [JsonPropertyName("ignoredSkillsLocations")] + public IList? IgnoredSkillsLocations { get; set; } + + /// Optional list of project directory paths. When omitted or empty, only personal and custom directories are returned. + [JsonPropertyName("projectPaths")] + public IList? ProjectPaths { get; set; } + + /// Explicit discovery-only skill roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + [JsonPropertyName("skillDirectories")] + public IList? SkillDirectories { get; set; } } -/// Top-level user-setting keys grouped by who may govern them. +/// Inventory request under an explicitly selected existing session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UserSettingsGovernanceKeysResult +internal sealed class SkillInstallationsRequest { - /// Top-level keys a repository may override through a Claude-compatible repository config. - [JsonPropertyName("claudeRepo")] - public IList ClaudeRepo { get => field ??= []; set; } - - /// Top-level keys an enterprise policy may fix through managed settings. - [JsonPropertyName("managed")] - public IList Managed { get => field ??= []; set; } + /// Required authenticated bound installation contract. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// Top-level keys a repository may override through `.github/copilot/settings.json` or `.github/copilot/settings.local.json`. - [JsonPropertyName("repo")] - public IList Repo { get => field ??= []; set; } + /// Existing selected local session on this connection. + [JsonPropertyName("policySessionId")] + public string PolicySessionId { get; set; } = string.Empty; } -/// Outcome of an atomic user or repository settings edit. +/// Existing-operation control. A new session selector is deliberately not accepted. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SettingsEditResult +internal sealed class SkillInstallationOperationRequest { - /// Changed, unchanged or invalid existing file. Rejected input, validation failures and I/O errors remain RPC errors. - [JsonPropertyName("status")] - public SettingsEditStatus Status { get; set; } + /// Required authenticated bound Skill installation capability. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } + + /// Exact runtime-issued operation ID on the original connection. + [JsonPropertyName("operationId")] + public string OperationId { get; set; } = string.Empty; } -/// One atomic edit of a canonical setting in settings.json. +/// Persisted enablement update for one owned Skill installation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UserSettingsEditRequest +internal sealed class SkillSetEnabledRequest { - /// Nonempty canonical path segments of the setting to edit, starting with its top-level key. - [JsonPropertyName("canonicalPath")] - public IList CanonicalPath { get => field ??= []; set; } + /// Required authenticated bound Skill installation capability. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// Configuration directory to edit. Omitted or empty resolves the server's own home, as in `user.settings.loadForConfigDir`. - [JsonPropertyName("configDir")] - public string? ConfigDir { get; set; } + /// Persisted enablement value. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } - /// Set a scalar, add or remove a string list item, or remove the setting. The handler rejects a missing or incompatible value. - [JsonPropertyName("operation")] - public SettingsEditOperation Operation { get; set; } + /// Exact receipt identity to update. + [JsonPropertyName("installationId")] + public string InstallationId { get; set; } = string.Empty; - /// Required boolean, string or number for set, required string for add-item and remove-item, and forbidden for remove. The runtime rejects all other JSON values. - [JsonPropertyName("value")] - public JsonElement? Value { get; set; } + /// Existing selected local session to reconcile after persistence. + [JsonPropertyName("policySessionId")] + public string PolicySessionId { get; set; } = string.Empty; } -/// Settings object with canonical key names. +/// Skill names to mark as disabled in global configuration, replacing any previous list. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UserSettingsNormalizeResult +internal sealed class SkillsConfigSetDisabledSkillsRequest { - /// The same settings with every legacy or snake_case key renamed to its canonical spelling. - [JsonPropertyName("settings")] - public JsonElement Settings { get; set; } + /// List of skill names to disable. + [JsonPropertyName("disabledSkills")] + public IList DisabledSkills { get => field ??= []; set; } } -/// Settings object whose key names should be canonicalized. +/// Adds or removes a single skill from the global disabled list, leaving every other entry untouched. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UserSettingsNormalizeRequest +internal sealed class SkillsConfigSetSkillDisabledRequest { - /// Free-form settings object, possibly using legacy or snake_case key names. - [JsonPropertyName("settings")] - public JsonElement Settings { get; set; } + /// True to disable the skill, false to enable it. + [JsonPropertyName("disabled")] + public bool Disabled { get; set; } + + /// Name of the skill to add to or remove from the disabled list. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// The settings layer a problem was found in. +/// Outcome of a catalog.search call: either bounded inert candidates, or one typed refusal. Never a partial success. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UserSettingsProblemLocation +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(CatalogSearchResultSucceeded), "succeeded")] +[JsonDerivedType(typeof(CatalogSearchResultNegotiationRefused), "negotiation-refused")] +[JsonDerivedType(typeof(CatalogSearchResultUnsupportedKind), "unsupported-kind")] +[JsonDerivedType(typeof(CatalogSearchResultInvalidRequest), "invalid-request")] +[JsonDerivedType(typeof(CatalogSearchResultAuthenticationRequired), "authentication-required")] +[JsonDerivedType(typeof(CatalogSearchResultPolicyRejected), "policy-rejected")] +[JsonDerivedType(typeof(CatalogSearchResultNetworkFailure), "network-failure")] +[JsonDerivedType(typeof(CatalogSearchResultUnsafeRetrieval), "unsafe-retrieval")] +[JsonDerivedType(typeof(CatalogSearchResultMalformedCard), "malformed-card")] +[JsonDerivedType(typeof(CatalogSearchResultContractViolation), "contract-violation")] +[JsonDerivedType(typeof(CatalogSearchResultUnavailable), "unavailable")] +public partial class CatalogSearchResult { - /// Absolute path of the file backing this layer. - [JsonPropertyName("filePath")] - public string FilePath { get; set; } = string.Empty; - - /// Which layer this is: `user`, `repo`, or `local`. + /// The type discriminator. [JsonPropertyName("kind")] - public string Kind { get; set; } = string.Empty; - - /// The caller-supplied display label for the layer. - [JsonPropertyName("label")] - public string Label { get; set; } = string.Empty; + public virtual string Kind { get; set; } = string.Empty; } -/// One setting that will not take effect, and why. + +/// One inert catalog result, represented as an MCP server, discovery-only AI skill, or opt-in Agent Plugin variant so kind, media type, provenance, and available operations cannot contradict each other. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UserSettingsProblem +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(CatalogCandidateMcpServer), "mcp-server")] +[JsonDerivedType(typeof(CatalogCandidateAiSkill), "ai-skill")] +[JsonDerivedType(typeof(CatalogCandidatePlugin), "plugin")] +public partial class CatalogCandidate { - /// Coarse grouping for the problem, for a caller that presents problems in sections. - [JsonPropertyName("category")] - public string Category { get; set; } = string.Empty; - - /// Why the setting will not take effect. Never contains the setting's value, which may be a token or another secret. - [JsonPropertyName("explanation")] - public string Explanation { get; set; } = string.Empty; + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} - /// Stable identifier for this problem within the reported set, so a caller can track a selection across refreshes. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - /// What is wrong in machine-readable form, for a caller that wants to branch rather than display. - [JsonPropertyName("kind")] - public string Kind { get; set; } = string.Empty; +/// Where and when an MCP server catalog reference was observed. Discovery provenance deliberately carries no content digest because search does not establish the exact validated content a later plan will bind. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class CatalogMcpServerCandidateProvenance +{ + /// Host of the catalog authority that advertised the reference, without path, query, or credentials. Inert untrusted data. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("authority")] + public string Authority { get; set; } = string.Empty; - /// The offending key as written in the file, when the problem is attributable to a single key. Absent when the whole file is at fault. - [JsonPropertyName("rawKey")] - public string? RawKey { get; set; } + /// JSON MCP media type advertised for the referenced card. + [JsonPropertyName("mediaType")] + public McpServerCardMediaType MediaType { get; set; } - /// The settings layer the problem was found in. - [JsonPropertyName("source")] - public UserSettingsProblemLocation Source { get => field ??= new(); set; } + /// ISO 8601 timestamp at which the runtime observed the catalog reference. This is not a retrieval or validation timestamp. + [JsonPropertyName("observedAt")] + public string ObservedAt { get; set; } = string.Empty; } -/// The settings that will not take effect across the given layers. +/// Where a candidate's card came from. Exactly one of a URL or embedded data: the union has no variant carrying both, and no variant carrying neither, so the rule holds structurally rather than by validation. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UserSettingsProblemsResult +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(CatalogCandidateSourceUrl), "url")] +[JsonDerivedType(typeof(CatalogCandidateSourceEmbedded), "embedded")] +public partial class CatalogCandidateSource { - /// Each setting that will not take effect, and why. Empty when every layer is healthy. - [JsonPropertyName("problems")] - public IList? Problems { get; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// One already-loaded settings layer to diagnose. + +/// Candidate whose card is retrieved from a URL through the runtime's hardened fetch boundary. +/// The url variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UserSettingsProblemSource +public partial class CatalogCandidateSourceUrl : CatalogCandidateSource { - /// The layer's settings exactly as loaded, unnormalized. Empty when the file is missing or failed to parse. - [JsonPropertyName("config")] - public IDictionary? Config { get; set; } - - /// Absolute path of the file backing this layer. - [JsonPropertyName("filePath")] - public string FilePath { get; set; } = string.Empty; - - /// True when the file itself failed to parse, so its keys could not be read at all. - [JsonPropertyName("invalid")] - public bool? Invalid { get; set; } - - /// Which layer this is: `user`, `repo`, or `local`. - [JsonPropertyName("kind")] - public string Kind { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "url"; - /// Caller-chosen display label for the layer, echoed back on each problem so a caller can group by layer without re-deriving its own naming. - [JsonPropertyName("label")] - public string Label { get; set; } = string.Empty; + /// Card URL as advertised. Inert untrusted data: the runtime retrieves it only through its own hardened boundary, and it is never logged. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("url")] + public required string Url { get; set; } } -/// The settings layers to diagnose. +/// Candidate whose card reference arrived inline. The document and its content-derived properties stay behind the runtime boundary. +/// The embedded variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UserSettingsProblemsRequest +public partial class CatalogCandidateSourceEmbedded : CatalogCandidateSource { - /// Layers to diagnose, in the precedence order the caller applies them. - [JsonPropertyName("sources")] - public IList? Sources { get; set; } + /// + [JsonIgnore] + public override string Kind => "embedded"; } -/// One problem found while validating a setting value. +/// An inert MCP server catalog result. Every free-text field is untrusted external data and must never be treated as an instruction, and the handle is the only way to refer to the candidate in a later operation. +/// The mcp-server variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UserSettingsValidationIssue +public partial class CatalogCandidateMcpServer : CatalogCandidate { - /// Human-readable description of the problem. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "mcp-server"; - /// Where in the settings tree the problem sits, as object keys and array indices. The first element is the top-level key; a whole-value problem is reported as that single key. - [JsonPropertyName("path")] - public IList Path { get => field ??= []; set; } -} + /// Description taken verbatim from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } -/// Outcome of validating and writing one top-level setting subtree. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UserSettingsApplyTopKeyResult -{ - /// Why the write failed, present only when `status` is `write-error`. - [JsonPropertyName("error")] - public string? Error { get; set; } + /// Display name taken verbatim from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(200)] + [JsonPropertyName("displayName")] + public required string DisplayName { get; set; } - /// Problems found, present only when `status` is `validation-error`. - [JsonPropertyName("issues")] - public IList? Issues { get; set; } + /// Opaque, runtime-instance scoped, TTL-bound, single-use handle for this candidate. Carries no readable information and is rejected when stale, replayed, or presented to a different runtime instance. Never logged. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("handle")] + public required string Handle { get; set; } - /// `ok` when the value was written, `validation-error` when it was rejected before any write, `write-error` when validation passed but the write failed. - [JsonPropertyName("status")] - public string Status { get; set; } = string.Empty; -} + /// ISO 8601 timestamp after which the handle is stale and will be rejected. + [JsonPropertyName("handleExpiresAt")] + public required string HandleExpiresAt { get; set; } -/// A single top-level setting subtree to validate and write. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UserSettingsApplyTopKeyRequest -{ - /// Canonical path of the setting the caller is editing. Currently informational only. - [JsonPropertyName("canonicalPath")] - public IList CanonicalPath { get => field ??= []; set; } + /// Whether this MCP server can be planned for installation, and if policy prevents it. + [JsonPropertyName("installability")] + public required CatalogMcpServerInstallability Installability { get; set; } - /// Records that the user chose an update channel explicitly, so the one-time staff channel migration stops reapplying. Honored only for the `autoUpdatesChannel` key. - [JsonPropertyName("completeStaffUpdateChannelMigration")] - public bool? CompleteStaffUpdateChannelMigration { get; set; } + /// JSON MCP media type of the underlying card. + [JsonPropertyName("mediaType")] + public required McpServerCardMediaType MediaType { get; set; } - /// True to remove the top-level key instead of writing it. - [JsonPropertyName("delete")] - public bool? Delete { get; set; } + /// Where the catalog reference was observed, without the card itself or any content digest. + [JsonPropertyName("provenance")] + public required CatalogMcpServerCandidateProvenance Provenance { get; set; } - /// Top-level setting name to write. - [JsonPropertyName("topKey")] - public string TopKey { get; set; } = string.Empty; + /// Publisher taken verbatim from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(200)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("publisher")] + public string? Publisher { get; set; } - /// Value to write for the whole top-level key. Omitted when `delete` is true. Explicit null is preserved and validated as null. - [JsonPropertyName("value")] - public JsonElement? Value { get; set; } -} + /// Where the card came from: exactly one of a URL or embedded data, encoded as a tagged union so neither both nor neither can be represented. + [JsonPropertyName("source")] + public required CatalogCandidateSource Source { get; set; } -/// The whole content to store in the user settings file. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UserSettingsWriteAllRequest -{ - /// The settings object to store. It replaces the file's entire content, so a key absent here is removed. - [JsonPropertyName("settings")] - public JsonElement Settings { get; set; } + /// Versioned trust metadata observed from the catalog authority. Optional for protocol-3 compatibility with runtimes that predate trust snapshots. A trust-capable runtime emits an explicit snapshot even when the authority omitted or malformed its trust field. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("trust")] + public CatalogTrustSnapshot? Trust { get; set; } } -/// The stored value of the user setting after the merge. +/// Where and when an AI skill catalog reference was observed. Discovery provenance deliberately carries no content digest because search does not establish the exact validated content a later plan will bind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UserSettingsUpdateResult +public sealed class CatalogAiSkillCandidateProvenance { - /// The key's stored value after the write: the merged object when both the stored value and the supplied value are objects, otherwise the supplied value. - [JsonPropertyName("value")] - public JsonElement Value { get; set; } + /// Host of the catalog authority that advertised the reference, without path, query, or credentials. Inert untrusted data. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("authority")] + public string Authority { get; set; } = string.Empty; + + /// Media type advertised for the referenced AI skill card. + [JsonPropertyName("mediaType")] + public CatalogAiSkillMediaType MediaType { get; set; } + + /// ISO 8601 timestamp at which the runtime observed the catalog reference. This is not a retrieval or validation timestamp. + [JsonPropertyName("observedAt")] + public string ObservedAt { get; set; } = string.Empty; } -/// Names the user setting to merge into, and the partial object to merge. +/// An inert AI skill catalog result. Verified Skill candidates may be installable only when the runtime reports installability and the selected session is permitted to plan installation. +/// The ai-skill variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UserSettingsUpdateRequest +public partial class CatalogCandidateAiSkill : CatalogCandidate { - /// Copilot configuration directory to write the settings document in, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to use the directory the server resolved for itself. - [JsonPropertyName("configDir")] - public string? ConfigDir { get; set; } + /// + [JsonIgnore] + public override string Kind => "ai-skill"; - /// Top-level user-setting key to merge into, such as `extensions`. - [JsonPropertyName("key")] - public string Key { get; set; } = string.Empty; + /// Description taken verbatim from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } - /// Single-component name for the settings document at `<configDir>/settings/<subDir>.json`; path separators, `.` and `..` are rejected. Omit it, or pass an empty string, to use the main settings document. - [JsonPropertyName("subDir")] - public string? SubDir { get; set; } + /// Display name taken verbatim from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(200)] + [JsonPropertyName("displayName")] + public required string DisplayName { get; set; } - /// Value to store for `key`. When both the stored value and this value are objects, their fields are shallow-merged and fields this object does not name are preserved. Otherwise this value replaces the stored value. - [JsonPropertyName("value")] - public JsonElement Value { get; set; } -} + /// Opaque, runtime-instance scoped, TTL-bound, single-use handle for this candidate. Carries no readable information and is rejected when stale, replayed, or presented to a different runtime instance. Never logged. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("handle")] + public required string Handle { get; set; } -/// Contents of settings.json as stored, for a caller about to rewrite it. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UserSettingsLoadForEditResult -{ - /// Parsed contents, present only when `status` is `ok`. - [JsonPropertyName("settings")] - public JsonElement? Settings { get; set; } + /// ISO 8601 timestamp after which the handle is stale and will be rejected. + [JsonPropertyName("handleExpiresAt")] + public required string HandleExpiresAt { get; set; } - /// `ok` when the file parsed, `missing` when there is no file yet, `invalid` when the file exists but will not parse. - [JsonPropertyName("status")] - public string Status { get; set; } = string.Empty; -} + /// Whether this AI skill candidate can be planned for verified installation in the selected session. + [JsonPropertyName("installability")] + public required CatalogAiSkillInstallability Installability { get; set; } -/// Outcome of validating one top-level setting subtree. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UserSettingsValidateResult -{ - /// Problems found, empty when `ok` is true. - [JsonPropertyName("issues")] - public IList? Issues { get; set; } + /// Media type of the underlying AI skill card. + [JsonPropertyName("mediaType")] + public required CatalogAiSkillMediaType MediaType { get; set; } - /// True when the subtree is valid. - [JsonPropertyName("ok")] - public bool Ok { get; set; } -} + /// Where the catalog reference was observed, without the card itself or any content digest. + [JsonPropertyName("provenance")] + public required CatalogAiSkillCandidateProvenance Provenance { get; set; } -/// A single top-level setting subtree to validate. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UserSettingsValidateRequest -{ - /// True to validate a removal of this key. The current settings file is not read. - [JsonPropertyName("delete")] - public bool? Delete { get; set; } + /// Publisher taken verbatim from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(200)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("publisher")] + public string? Publisher { get; set; } - /// Top-level setting name to validate. - [JsonPropertyName("topKey")] - public string TopKey { get; set; } = string.Empty; + /// Where the card came from: exactly one of a URL or embedded data, encoded as a tagged union so neither both nor neither can be represented. + [JsonPropertyName("source")] + public required CatalogCandidateSource Source { get; set; } - /// Value to validate. Omitted when `delete` is true. - [JsonPropertyName("value")] - public JsonElement? Value { get; set; } + /// Versioned trust metadata observed from the catalog authority. Optional for protocol-3 compatibility with runtimes that predate trust snapshots. A trust-capable runtime emits an explicit snapshot even when the authority omitted or malformed its trust field. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("trust")] + public CatalogTrustSnapshot? Trust { get; set; } } -/// The declared shape of one feature flag, independent of any caller population. +/// Where and when an Agent Plugin catalog reference was observed. Discovery provenance deliberately carries no descriptor URL, raw data, candidate handle, or content digest. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class FeatureFlagMetadata +public sealed class CatalogAgentPluginCandidateProvenance { - /// The population the flag is declared for before any environment or user-settings override is applied. - [JsonPropertyName("availability")] - public FeatureFlagAvailability Availability { get; set; } - - /// Whether the flag participates in the CAPI sanity suite. - [JsonPropertyName("capiSanity")] - public bool CapiSanity { get; set; } - - /// Text shown to a user choosing whether to turn the flag on in experimental mode. Absent when the flag is not user-facing. - [JsonPropertyName("experimentalDescription")] - public string? ExperimentalDescription { get; set; } - - /// The online-experiment (ExP) flag this maps to, when the flag is assigned by an experiment rather than declared statically. - [JsonPropertyName("expFlag")] - public string? ExpFlag { get; set; } + /// Host of the catalog authority that advertised the reference, without path, query, or credentials. Inert untrusted data. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("authority")] + public string Authority { get; set; } = string.Empty; - /// Environment variable that overrides this flag's experiment assignment locally in the experiment service, not in `featureFlags.resolve`. Present exactly when `expFlag` is, and derived from it, so a caller reads a local override without reproducing the naming rule. - [JsonPropertyName("expFlagEnvVar")] - public string? ExpFlagEnvVar { get; set; } + /// Canonical Agent Plugin media type. + [JsonPropertyName("mediaType")] + public CatalogAgentPluginMediaType MediaType { get; set; } - /// The flag's name, matching the key it is listed under. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// ISO 8601 timestamp at which the runtime observed the catalog reference. This is not a retrieval or validation timestamp. + [JsonPropertyName("observedAt")] + public string ObservedAt { get; set; } = string.Empty; } -/// Every feature flag this runtime declares, with the shape each one was declared with. +/// Syntactically validated GitHub repository provenance declared by catalog metadata. This is a source claim rather than proof that the descriptor URL resolves to the repository. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class FeatureFlagsMetadataResult +public sealed class CatalogPluginRepositorySource { - /// Declared feature flags keyed by flag name. - [JsonPropertyName("flags")] - public IDictionary Flags { get => field ??= new Dictionary(); set; } + /// Case-preserving safe relative POSIX path derived from metadata.repoPath. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(256)] + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// Canonical lowercase owner/repository name derived from metadata.sourceSet. + [RegularExpression("^[a-z0-9_.-]+/[a-z0-9_.-]+$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(3)] + [MaxLength(256)] + [JsonPropertyName("repository")] + public string Repository { get; set; } = string.Empty; } -/// Caller population and overrides for static feature-flag resolution, independent of experiment assignments and active runtime state. +/// An inert Agent Plugin catalog result. Its canonical catalog identity, declared version, repository source claim, and explicit compatibility tags are safe to correlate, while its descriptor, URL, raw data, and installed-plugin state remain runtime-private. This contract-only variant does not mint or expose a candidate handle. +/// The plugin variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class FeatureFlagsResolveRequest +public partial class CatalogCandidatePlugin : CatalogCandidate { - /// Resolve against this already-computed flag set rather than each flag's declared availability. Keyed by flag name. - [JsonPropertyName("baseFlags")] - public IDictionary? BaseFlags { get; set; } + /// + [JsonIgnore] + public override string Kind => "plugin"; - /// User settings to apply, including `enabledFeatureFlags`, legacy `feature_flags.enabled`, and supported convenience settings. - [JsonPropertyName("config")] - public JsonElement? Config { get; set; } + /// Explicit validated compatibility tags, in canonical order. An empty list means the source declared no recognised compatibility; clients must not infer compatibility from other fields. `canvas-only` requires both `canvas` and `github-copilot`. + [JsonPropertyName("compatibilityTags")] + public required IList CompatibilityTags { get; set; } - /// Environment for direct feature-flag overrides and `COPILOT_CLI_ENABLED_FEATURE_FLAGS`. Does not apply `COPILOT_EXP_*` experiment assignments. Defaults to this runtime process's own environment. - [JsonPropertyName("environment")] - public IDictionary? Environment { get; set; } + /// Description taken verbatim from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } - /// Flags forced to a value after every other layer, keyed by flag name. - [JsonPropertyName("flagOverrides")] - public IDictionary? FlagOverrides { get; set; } + /// Display name taken verbatim from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(200)] + [JsonPropertyName("displayName")] + public required string DisplayName { get; set; } - /// Whether the caller is in an experimental population. - [JsonPropertyName("isExperimental")] - public bool IsExperimental { get; set; } + /// Validated, normalised catalogue resource URN. This identity comes only from the catalog identifier and is never inferred from display text or installed-plugin state. + [JsonPropertyName("identity")] + public required string Identity { get; set; } - /// Whether the caller is GitHub or Microsoft staff. - [JsonPropertyName("isStaff")] - public bool IsStaff { get; set; } + /// Canonical Agent Plugin media type. + [JsonPropertyName("mediaType")] + public required CatalogAgentPluginMediaType MediaType { get; set; } - /// GitHub-staff membership. Omit when it was never recorded: a legacy staff account then counts as both staff populations and keeps every staff feature. - [JsonPropertyName("isStaffGithub")] - public bool? IsStaffGitHub { get; set; } + /// Where the Agent Plugin catalog reference was observed, without its descriptor, URL, raw data, or content digest. + [JsonPropertyName("provenance")] + public required CatalogAgentPluginCandidateProvenance Provenance { get; set; } - /// Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. - [JsonPropertyName("isStaffMicrosoft")] - public bool? IsStaffMicrosoft { get; set; } + /// Publisher taken verbatim from the card. Inert untrusted text. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(200)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("publisher")] + public string? Publisher { get; set; } - /// Whether the caller belongs to the team population used by feature availability. - [JsonPropertyName("isTeam")] - public bool IsTeam { get; set; } + /// Bounded repository provenance declared through the catalog's sourceSet and repoPath metadata. It contains no descriptor URL. + [JsonPropertyName("source")] + public required CatalogPluginRepositorySource Source { get; set; } + + /// Versioned trust metadata observed from the catalog authority. Optional for protocol-3 compatibility and emitted only when the caller also requires the trust-snapshot capability. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("trust")] + public CatalogTrustSnapshot? Trust { get; set; } + + /// Optional version declared by the catalog source. Omitted rather than guessed when the source supplies no version. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("version")] + public string? Version { get; set; } } -/// Parsed repository settings without normalization or layering. +/// Authority-reported navigation metadata, returned only to callers requiring catalog-search-pagination and only when a supported token is present. Tokenless first-page and continuation responses omit this object; no counts are inferred from candidates. The opaque token may be retained for previous or numbered navigation even when hasNextPage is false. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class RepoSettingsReadRawResult +public sealed class CatalogSearchPagination { - /// Stored JSON values after the existing JSONC parser and prototype-safety checks. Empty when the file is missing, blank, or invalid. - [JsonPropertyName("config")] - public JsonElement Config { get; set; } + /// One-based page returned by the authority. + [JsonPropertyName("currentPage")] + public int CurrentPage { get; set; } - /// True when the file exists but did not parse, so `config` is empty for that reason rather than because nothing is set. - [JsonPropertyName("invalid")] - public bool Invalid { get; set; } -} + /// Whether the authority token advertises a valid next target within the navigation window. Not inferred from token presence, truncated, or currentPage being less than pageCount. + [JsonPropertyName("hasNextPage")] + public bool HasNextPage { get; set; } -/// Which repository settings file to read. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class RepoSettingsReadRawRequest -{ - /// Absolute path of the repository root. - [JsonPropertyName("repoRoot")] - public string RepoRoot { get; set; } = string.Empty; + /// Navigation window ceiling ceil(1000 / pageSize), not the number of existing pages. Legal targets must not exceed this ceiling or the token's signed pageCount. + [JsonPropertyName("maxPage")] + public int MaxPage { get; set; } - /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. - [JsonPropertyName("scope")] - public string Scope { get; set; } = string.Empty; + /// Backend-reported page count, which may exceed maxPage. Present pagination metadata always describes a multi-page result; zero- and single-page responses omit pagination. Navigation targets must also be within the signed pageCount carried by the supplied token. + [JsonPropertyName("pageCount")] + public long PageCount { get; set; } + + /// Page size bound to the search, equal to the effective request limit. + [JsonPropertyName("pageSize")] + public int PageSize { get; set; } + + /// Opaque pagination token. Session-bound search returns an expiring runtime-owned reference retaining the exact private authority token, original search and authority. Legacy unbound search returns the authority token unchanged, without a runtime-created expiry. Only the runtime unwraps tokens or changes targetPage; SDK consumers must not decode, modify or log them. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(4096)] + [JsonPropertyName("token")] + public string Token { get; set; } = string.Empty; + + /// Backend-reported count for this response, not the number of returned candidates. Its relationship to the full query result set is unknown. + [JsonPropertyName("totalCount")] + public long TotalCount { get; set; } + + /// The relationship of totalCount to the complete query result set is unknown; neither exactness nor a lower-bound guarantee is implied. + [JsonPropertyName("totalCountRelation")] + public CatalogSearchTotalCountRelation TotalCountRelation { get; set; } } -/// One key to write or remove in a repository settings file. +/// A completed catalog search containing inert candidate summaries. MCP server and AI skill variants carry a single-use handle; the Agent Plugin variant is handleless. +/// The succeeded variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class RepoSettingsWriteKeyRequest +public partial class CatalogSearchResultSucceeded : CatalogSearchResult { - /// True to remove the key instead of writing it. - [JsonPropertyName("delete")] - public bool? Delete { get; set; } + /// + [JsonIgnore] + public override string Kind => "succeeded"; - /// Canonical top-level key permitted by the repository settings allowlist. - [JsonPropertyName("key")] - public string Key { get; set; } = string.Empty; + /// Matching candidates, never more than the requested limit. All text is inert untrusted data. + [JsonPropertyName("candidates")] + public required IList Candidates { get; set; } - /// Absolute path of the repository root. - [JsonPropertyName("repoRoot")] - public string RepoRoot { get; set; } = string.Empty; + /// Protocol version and capabilities the runtime honoured. + [JsonPropertyName("negotiated")] + public required CatalogNegotiatedContract Negotiated { get; set; } - /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. - [JsonPropertyName("scope")] - public string Scope { get; set; } = string.Empty; + /// Navigation metadata for callers explicitly requiring catalog-search-pagination. Omitted when the authority returns no token, including tokenless first-page and continuation responses. Counts are never substituted from candidates.length. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("pagination")] + public CatalogSearchPagination? Pagination { get; set; } - /// Value to validate and write. Required unless delete is true; a null value is validated, not treated as deletion. - [JsonPropertyName("value")] - public JsonElement? Value { get; set; } + /// Pseudonymous identifier for this search, issued by the runtime or by the catalog authority it queried and never by the caller, so it cannot be forged or replayed to attribute an install to a search that never happened. Always present on a success, so a result set can be tied to the installs it leads to. It identifies a search rather than a person: it is derived from no user, account, device, or query data, and must never be joined with user identity to re-identify anyone. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(64)] + [JsonPropertyName("searchId")] + public required string SearchId { get; set; } + + /// Legacy indication that the authority returned a page token. Preserved for compatibility; this is not a has-next-page indicator. Use pagination.hasNextPage when pagination metadata is present. + [JsonPropertyName("truncated")] + public required bool Truncated { get; set; } } -/// The complete set of repository-overridable settings to store. +/// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. +/// The negotiation-refused variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class RepoSettingsWriteAllRequest +public partial class CatalogSearchResultNegotiationRefused : CatalogSearchResult { - /// Absolute path of the repository root. - [JsonPropertyName("repoRoot")] - public string RepoRoot { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "negotiation-refused"; - /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. - [JsonPropertyName("scope")] - public string Scope { get; set; } = string.Empty; + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Object of allowed settings to store. Missing allowlisted keys are removed. Other input keys are ignored, while unknown stored keys are preserved. - [JsonPropertyName("settings")] - public JsonElement Settings { get; set; } -} + /// Lowest caller protocol version this runtime will serve. + [JsonPropertyName("minimumSupportedProtocolVersion")] + public required long MinimumSupportedProtocolVersion { get; set; } -/// Owner, name, and host of a GitHub repository, as resolved from a git remote URL. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class GitHubRepositoryIdentity -{ - /// Host the remote points at, for example `github.com` or a GitHub Enterprise hostname. - [JsonPropertyName("host")] - public string Host { get; set; } = string.Empty; + /// Whether the version or the capability set was the problem. + [JsonPropertyName("reason")] + public required CatalogNegotiationRefusedReason Reason { get; set; } - /// Repository name, without the owner prefix or the `.git` suffix. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Protocol version of the runtime that refused the request. + [JsonPropertyName("runtimeProtocolVersion")] + public required long RuntimeProtocolVersion { get; set; } - /// Repository owner login (user or organization). - [JsonPropertyName("owner")] - public string Owner { get; set; } = string.Empty; + /// Capabilities this runtime can safely advertise to this caller. The complete five-capability protocol-3 legacy set is always present; every capability added after that baseline appears only when the caller required it, so an older closed-enum decoder can still consume a refusal. This list does not imply that every deployment has enabled every operation. + [JsonPropertyName("supportedCapabilities")] + public required IList SupportedCapabilities { get; set; } + + /// The subset of the caller's bounded extensible capability identifiers this runtime cannot honour. + [JsonPropertyName("unsupportedCapabilities")] + public required IList UnsupportedCapabilities { get; set; } } -/// The GitHub repository that owns the requested path, when the selected remote (`origin`, else the first) is on a GitHub host. +/// The request asked for a candidate kind this runtime does not serve. +/// The unsupported-kind variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class GitHubRepositoryAtPathResult +public partial class CatalogSearchResultUnsupportedKind : CatalogSearchResult { - /// Resolved repository identity, or null when the selected remote resolves to no GitHub host. - [JsonPropertyName("repository")] - public GitHubRepositoryIdentity? Repository { get; set; } + /// + [JsonIgnore] + public override string Kind => "unsupported-kind"; + + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// The kinds from the request that are not supported. + [JsonPropertyName("requestedKinds")] + public required IList RequestedKinds { get; set; } + + /// Every candidate kind this runtime can serve. + [JsonPropertyName("supportedKinds")] + public required IList SupportedKinds { get; set; } } -/// Working-tree path whose owning GitHub repository should be resolved. +/// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. +/// The invalid-request variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class GitHubRepositoryAtPathRequest +public partial class CatalogSearchResultInvalidRequest : CatalogSearchResult { - /// Absolute path to a directory inside the git working tree to resolve. + /// + [JsonIgnore] + public override string Kind => "invalid-request"; + + /// Which request field was rejected. + [JsonPropertyName("field")] + public required CatalogInvalidRequestField Field { get; set; } + + /// Human-readable explanation, safe to surface. Never echoes the offending value, nor a query, URL, handle, or secret. [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } } -/// A freshly registered request id. Registering it before the listing starts is what lets a cancel that races the request still find the owner listing slot. The id serves one listing only. Long-abandoned unused ids can be released by later allocations. +/// An optional catalog authentication exchange did not establish the caller's identity. Anonymous search remains supported; this refusal is reserved for an operation that cannot continue after the attempted exchange. It is distinct from `policy-rejected` and from a network failure, and the reason identifies the recovery action. +/// The authentication-required variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class GitHubOwnersRequestIdResult +public partial class CatalogSearchResultAuthenticationRequired : CatalogSearchResult { - /// Request id to pass to `gitHubOwners.list` and, to abandon it, `gitHubOwners.cancel`. - [JsonPropertyName("requestId")] - public long RequestId { get; set; } + /// + [JsonIgnore] + public override string Kind => "authentication-required"; + + /// Human-readable explanation, safe to surface. Never contains a credential or token, nor a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// Why authentication failed. Only an expired credential justifies attempting a silent refresh; an absent or rejected credential requires sign-in. + [JsonPropertyName("reason")] + public required CatalogAuthenticationRequiredReason Reason { get; set; } } -/// A GitHub login the authenticated user may act as: their own account, or an organization they belong to. +/// Registry or enterprise policy refused the operation. +/// The policy-rejected variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class GitHubOwnerOption +public partial class CatalogSearchResultPolicyRejected : CatalogSearchResult { - /// The owner's GitHub login. - [JsonPropertyName("login")] - public string Login { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "policy-rejected"; - /// Which kind of owner this is. The authenticated user's own account is always reported as `user`. - [JsonPropertyName("type")] - public string Type { get; set; } = string.Empty; + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// Which authority produced the decision. + [JsonPropertyName("source")] + public required McpPlanPolicySource Source { get; set; } } -/// Outcome of an owner listing. Exactly one of `owners` and `message` is present, except that `throwError` reports a failure the caller is expected to raise rather than render. +/// The runtime could not reach the catalog authority or retrieve a card. Covers being offline as well as transport-level failure. +/// The network-failure variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class GitHubOwnersListResult +public partial class CatalogSearchResultNetworkFailure : CatalogSearchResult { - /// Why no owners could be listed, phrased for a user. Present when the listing failed in a way the caller should render rather than raise. + /// + [JsonIgnore] + public override string Kind => "network-failure"; + + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] [JsonPropertyName("message")] - public string? Message { get; set; } + public required string Message { get; set; } - /// The owners, on success: the authenticated user first, then the organizations they belong to. - [JsonPropertyName("owners")] - public IList? Owners { get; set; } + /// Categorised failure, low cardinality so it can be aggregated without carrying a URL. + [JsonPropertyName("reason")] + public required CatalogNetworkFailureReason Reason { get; set; } - /// A malformed request or an unreadable credential, which the caller raises instead of rendering. Kept a field rather than a dispatch error so it stays distinct from `message`, which the caller renders. - [JsonPropertyName("throwError")] - public string? ThrowError { get; set; } + /// Bounded cooldown in seconds before another catalog request should be attempted, when the authority supplied a numeric Retry-After value or the runtime applied its documented fallback. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("retryAfterSeconds")] + public int? RetryAfterSeconds { get; set; } - /// A line the caller should log. Present only alongside `message`, and only for failures worth recording. - [JsonPropertyName("warning")] - public string? Warning { get; set; } + /// HTTP status code, when the failure was a rejected response. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("statusCode")] + public int? StatusCode { get; set; } } -/// Credential to list owners under, and the request id that makes the listing cancellable. +/// Retrieval was refused by the runtime's hardened fetch boundary before any request left the process, or before a redirect was followed. +/// The unsafe-retrieval variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class GitHubOwnersListRequest +public partial class CatalogSearchResultUnsafeRetrieval : CatalogSearchResult { - /// The credential the listing runs under, carried opaquely because its shape is the host's own and the runtime only resolves a token and a GitHub host from it. No credential travels: this selects one the runtime already holds. - [JsonPropertyName("authInfo")] - public JsonElement AuthInfo { get; set; } + /// + [JsonIgnore] + public override string Kind => "unsafe-retrieval"; - /// Request id from `gitHubOwners.nextRequestId`. An id that was never registered, canceled before use, released after being abandoned, or already used is refused rather than silently running uncancellable. - [JsonPropertyName("requestId")] - public long RequestId { get; set; } + /// Human-readable explanation, safe to surface. Never contains the refused URL, nor a query, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// Which control refused the retrieval, low cardinality so it can be aggregated without carrying a URL. + [JsonPropertyName("reason")] + public required CatalogUnsafeRetrievalReason Reason { get; set; } } -/// Whether the id named a running owner listing. +/// A card could not be parsed or did not satisfy its declared media type's schema. +/// The malformed-card variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class GitHubOwnersCancelResult +public partial class CatalogSearchResultMalformedCard : CatalogSearchResult { - /// True when a listing with the id was running and the cancel stopped it. False when the id was never registered, was registered but unused, was released after being abandoned, or its listing had ended. An unused id is released and cannot start a later listing. - [JsonPropertyName("canceled")] - public bool Canceled { get; set; } + /// + [JsonIgnore] + public override string Kind => "malformed-card"; + + /// Media type the card was interpreted as, when it declared one this runtime recognises. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("mediaType")] + public CatalogMediaType? MediaType { get; set; } + + /// Human-readable explanation, safe to surface. Never echoes card content, nor a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// How the card failed validation. + [JsonPropertyName("reason")] + public required CatalogMalformedCardReason Reason { get; set; } } -/// The owner listing to abandon. +/// An upstream catalog response broke the wire contract. Most importantly, every result must carry exactly one of a URL or embedded data: a result carrying both, or neither, is refused here rather than being guessed at. +/// The contract-violation variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class GitHubOwnersCancelRequest +public partial class CatalogSearchResultContractViolation : CatalogSearchResult { - /// Request id the listing was started with. - [JsonPropertyName("requestId")] - public long RequestId { get; set; } + /// + [JsonIgnore] + public override string Kind => "contract-violation"; + + /// Human-readable explanation, safe to surface. Never echoes response content, nor a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// Which rule the response broke. + [JsonPropertyName("reason")] + public required CatalogContractViolationReason Reason { get; set; } } -/// The remote the checked-out branch tracks. +/// The operation is not available on this runtime. Distinct from a network failure: nothing was attempted. +/// The unavailable variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class GitCurrentBranchRemoteResult +public partial class CatalogSearchResultUnavailable : CatalogSearchResult { - /// Name of the tracked remote. Reports `origin` whenever the working tree has no tracking configuration to read, including on a detached HEAD, so this is never null and never empty. + /// + [JsonIgnore] + public override string Kind => "unavailable"; + + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("remote")] - public string Remote { get; set; } = string.Empty; + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// Why the operation is unavailable. + [JsonPropertyName("reason")] + public required CatalogUnavailableReason Reason { get; set; } } -/// Working-tree path a git query applies to. +/// An explicit numbered-page request. SDK consumers treat the token as opaque. For bound search, the runtime unwraps an expiring owner-bound reference to the private authority token; only the runtime changes the authority token's targetPage. Legacy unbound navigation keeps its authority-issued token semantics. No snapshot stability is promised. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class GitCwdRequest +public sealed class CatalogSearchPage { - /// Absolute path to a directory inside the git working tree to query. + /// Requested one-based page. Must not exceed either the token's signed pageCount or the navigation window ceil(1000 / pageSize). Repeat the search without page to discover newly available pages beyond that signed pageCount. + [JsonPropertyName("number")] + public int Number { get; set; } + + /// Opaque pagination token from an earlier response, owner-bound when session-bound search was requested. Never decode, modify or log it in an SDK consumer. Expired or foreign bound references require a fresh bound search, not a legacy retry. [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] [MinLength(1)] - [JsonPropertyName("cwd")] - public string Cwd { get; set; } = string.Empty; + [MaxLength(4096)] + [JsonPropertyName("token")] + public string Token { get; set; } = string.Empty; } -/// Updated working directory and git context. Emitted as the new payload of `session.context_changed`. +/// A bounded catalog search. Both the query length and the result count are capped by the schema so a caller cannot request an unbounded scan. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionWorkingDirectoryContext +public sealed class CatalogSearchRequest { - /// Merge-base commit SHA (fork point from the remote default branch). - [JsonPropertyName("baseCommit")] - public string? BaseCommit { get; set; } - - /// Current git branch name. - [JsonPropertyName("branch")] - public string? Branch { get; set; } - - /// Current working directory path. - [JsonPropertyName("cwd")] - public string Cwd { get; set; } = string.Empty; + /// Protocol version and capabilities the caller requires. + [JsonPropertyName("contract")] + public required CatalogClientContract Contract { get; set; } - /// Root directory of the git repository, resolved via git rev-parse. - [JsonPropertyName("gitRoot")] - public string? GitRoot { get; set; } + /// Restrict results to these candidate kinds. Agent Plugins are opt-in and require the `agent-plugin-discovery` capability so protocol-v3 clients generated before that variant cannot receive an unknown result; when omitted, the backwards-compatible MCP server and AI skill kinds are searched. + [JsonPropertyName("kinds")] + public IList? Kinds { get; set; } - /// Head commit of the current git branch. - [JsonPropertyName("headCommit")] - public string? HeadCommit { get; set; } + /// Maximum number of candidates to return. Defaults to 10 when omitted. + [JsonPropertyName("limit")] + public int? Limit { get; set; } - /// Hosting platform type of the repository. - [JsonPropertyName("hostType")] - public SessionWorkingDirectoryContextHostType? HostType { get; set; } + /// Numbered navigation using metadata from an earlier response. Requires catalog-search-pagination and the same query, kinds and effective limit. Omit for a fresh first-page search. + [JsonPropertyName("page")] + public CatalogSearchPage? Page { get; set; } - /// Repository identifier derived from the git remote URL ("owner/name" for GitHub, "org/project/repo" for Azure DevOps). - [JsonPropertyName("repository")] - public string? Repository { get; set; } + /// + /// Select an existing attached local session. Requires authenticated, session-bound search. + /// The runtime never creates, resumes or reconfigures a session to honour this selector. + /// + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(256)] + [JsonPropertyName("policySessionId")] + public string? PolicySessionId { get; set; } - /// Raw host string from the git remote URL (e.g. "github.com", "dev.azure.com"). - [JsonPropertyName("repositoryHost")] - public string? RepositoryHost { get; set; } + /// Free-text search query. Persisted as tool input for session continuity, but omitted from telemetry. + [RegularExpression("\\S")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(256)] + [JsonPropertyName("query")] + public required string Query { get; set; } } -/// A GitHub repository one of a working tree's remotes points at. +/// Typed outcome of catalog.select. Only the selected host result carries a fresh candidate handle; the model-facing projection removes both that handle and searchId. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class GitRemoteRepository +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(CatalogSelectionResultSelected), "selected")] +[JsonDerivedType(typeof(CatalogSelectionResultDeclined), "declined")] +[JsonDerivedType(typeof(CatalogSelectionResultCancelled), "cancelled")] +[JsonDerivedType(typeof(CatalogSelectionResultTimedOut), "timed-out")] +[JsonDerivedType(typeof(CatalogSelectionResultInvalid), "invalid")] +[JsonDerivedType(typeof(CatalogSelectionResultStale), "stale")] +[JsonDerivedType(typeof(CatalogSelectionResultReplayed), "replayed")] +[JsonDerivedType(typeof(CatalogSelectionResultForeign), "foreign")] +[JsonDerivedType(typeof(CatalogSelectionResultWrongKind), "wrong-kind")] +[JsonDerivedType(typeof(CatalogSelectionResultNegotiationRefused), "negotiation-refused")] +[JsonDerivedType(typeof(CatalogSelectionResultInvalidRequest), "invalid-request")] +[JsonDerivedType(typeof(CatalogSelectionResultUnavailable), "unavailable")] +public partial class CatalogSelectionResult { - /// GitHub host serving the repository, which is not `github.com` for a GitHub Enterprise remote. - [JsonPropertyName("host")] - public string Host { get; set; } = string.Empty; - - /// Repository name, without the owner. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - - /// Account or organization owning the repository. - [JsonPropertyName("owner")] - public string Owner { get; set; } = string.Empty; - - /// Name of the first remote that produced this distinct repository entry, such as `origin` or `upstream`. - [JsonPropertyName("remoteName")] - public string RemoteName { get; set; } = string.Empty; + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// The GitHub repositories a working tree's remotes point at. + +/// The chosen candidate was transferred into a fresh bounded single-use handle for a later explicit planning request. +/// The selected variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class GitReposFromRemotesResult +public partial class CatalogSelectionResultSelected : CatalogSelectionResult { - /// One entry per distinct GitHub repository, in the order git reports the first remote for each repository. Empty when no remote points at a GitHub host, which a caller should read as `not connected to GitHub`. Failing to read the remotes is an error, not an empty list. - [JsonPropertyName("repositories")] - public IList Repositories { get => field ??= []; set; } + /// + [JsonIgnore] + public override string Kind => "selected"; + + /// Fresh single-use candidate handle accepted by mcp.planInstall. Returned only to the native host and never included in model-tool output. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(256)] + [JsonPropertyName("candidateHandle")] + public required string CandidateHandle { get; set; } + + /// The exact search identifier privately bound to the selected candidate. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(64)] + [JsonPropertyName("searchId")] + public required string SearchId { get; set; } } -/// Git working tree whose GitHub remotes should be listed. +/// The caller explicitly declined every candidate and the retained search state was released. +/// The declined variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class GitReposFromRemotesRequest +public partial class CatalogSelectionResultDeclined : CatalogSelectionResult { - /// Absolute path to the root of the git working tree. + /// + [JsonIgnore] + public override string Kind => "declined"; + + /// The search identifier privately bound to the released selection group. [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] [MinLength(1)] - [JsonPropertyName("gitRoot")] - public string GitRoot { get; set; } = string.Empty; + [MaxLength(64)] + [JsonPropertyName("searchId")] + public required string SearchId { get; set; } } -/// Validated device-managed settings discovered before a session exists. +/// The caller cancelled the selection interaction and the retained search state was released. +/// The cancelled variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsReadResult +public partial class CatalogSelectionResultCancelled : CatalogSelectionResult { - /// Discovery or validation error text when managed settings could not be read safely. - [JsonPropertyName("errorMessage")] - public string? ErrorMessage { get; set; } + /// + [JsonIgnore] + public override string Kind => "cancelled"; - /// Validated, canonical managed-settings JSON. Omitted when no managed settings were discovered or when discovered settings failed validation. - [JsonPropertyName("settingsJson")] - public JsonElement? SettingsJson { get; set; } + /// The search identifier privately bound to the released selection group. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(64)] + [JsonPropertyName("searchId")] + public required string SearchId { get; set; } } -/// One validation finding for a managed-settings document. +/// The host declared that its live selection interaction timed out, and the retained search state was released. +/// The timed-out variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsDiagnostic +public partial class CatalogSelectionResultTimedOut : CatalogSelectionResult { - /// Human-readable description of the finding. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; - - /// Dot-separated path of the offending setting, such as `autoTier.overridable`. Empty for the document as a whole. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "timed-out"; - /// Whether the finding rejects the document. - [JsonPropertyName("severity")] - public ManagedSettingsDiagnosticSeverity Severity { get; set; } + /// The search identifier privately bound to the released selection group. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(64)] + [JsonPropertyName("searchId")] + public required string SearchId { get; set; } } -/// One managed-settings channel and the document it delivered. +/// The selection reference was malformed or unknown. +/// The invalid variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsLayer +public partial class CatalogSelectionResultInvalid : CatalogSelectionResult { - /// Validated managed-settings document this channel delivered. Absent when the channel delivered none. - [JsonPropertyName("settings")] - public JsonElement? Settings { get; set; } + /// + [JsonIgnore] + public override string Kind => "invalid"; - /// Channel identifier: `device` (MDM, plist, registry, or managed file), `server` (account or organization policy), or `policyHelper` (session-local helper output, supported by compose). Treat unknown output values as additional channels; more may be added. - [JsonPropertyName("source")] - public string Source { get; set; } = string.Empty; + /// Human-readable explanation safe to surface. Never contains the presented reference or private candidate state. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } } -/// Lock state and provenance of one managed setting. +/// The runtime-enforced selection reference lifetime elapsed before the request arrived. +/// The stale variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingMeta +public partial class CatalogSelectionResultStale : CatalogSelectionResult { - /// Whether users and repositories may choose a different value. `false` means policy locks the value. - [JsonPropertyName("overridable")] - public bool Overridable { get; set; } - - /// Original managed value when the runtime adjusted it to a supported effective value. Omitted when no adjustment was needed. - [JsonPropertyName("requested")] - public string? Requested { get; set; } + /// + [JsonIgnore] + public override string Kind => "stale"; - /// Channel that supplied this scalar value, matching a `layers[].source`: `device`, `server`, or `policyHelper`. These scalar defaults select one winning channel, not a mixed source. Treat unknown values as additional channels; more may be added. - [JsonPropertyName("source")] - public string Source { get; set; } = string.Empty; + /// Human-readable explanation safe to surface. Never contains the presented reference or private candidate state. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } } -/// Per-key lock state and provenance for `ManagedSettingsValues`, with the same field names. Producers emit each typed key in values and meta together; both outer objects are omitted when no typed key is set. +/// The selection group was already terminated or its pending host hand-off was already claimed. +/// The replayed variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsMeta +public partial class CatalogSelectionResultReplayed : CatalogSelectionResult { - /// Lock state and provenance of `values.autoTier`. - [JsonPropertyName("autoTier")] - public ManagedSettingMeta? AutoTier { get; set; } - - /// Lock state and provenance of `values.contextTier`. - [JsonPropertyName("contextTier")] - public ManagedSettingMeta? ContextTier { get; set; } - - /// Lock state and provenance of `values.effortLevel`. - [JsonPropertyName("effortLevel")] - public ManagedSettingMeta? EffortLevel { get; set; } + /// + [JsonIgnore] + public override string Kind => "replayed"; - /// Lock state and provenance of `values.model`. - [JsonPropertyName("model")] - public ManagedSettingMeta? Model { get; set; } + /// Human-readable explanation safe to surface. Never contains the presented reference or private candidate state. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } } -/// Effective enterprise managed settings and contributing channels. Session events report applied policy; sessionless resolve reports an account/device snapshot, and compose reports a non-applying preview of candidate documents. Device values take precedence over server values, then the policy helper, per ordinary key, while permissions compose restrictively. Session-local SDK-client policy is included only in session results. Marked experimental while the managed-settings surface stabilizes. +/// The selection reference belongs to another runtime instance or session. +/// The foreign variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsResolvedData +public partial class CatalogSelectionResultForeign : CatalogSelectionResult { - /// Whether an explicit enterprise policy restriction disables bypass-permissions ("yolo") mode for this session. Deny-wins across layers; an unresolved policy does not force this on by itself. - [JsonPropertyName("bypassPermissionsDisabled")] - public bool BypassPermissionsDisabled { get; set; } - - /// Whether a session-local permissions layer injected by the SDK host was present. - [JsonPropertyName("clientManaged")] - public bool? ClientManaged { get; set; } - - /// Whether an actual device MDM/plist/registry/file managed-settings layer was present. - [JsonPropertyName("deviceManaged")] - public bool DeviceManaged { get; set; } - - /// Whether managed policy could not be determined (e.g. a failed server fetch) and unresolved-policy safeguards remain active. This does not by itself disable bypass-permissions; `bypassPermissionsDisabled` reports only an explicit policy restriction. - [JsonPropertyName("failClosed")] - public bool FailClosed { get; set; } - - /// The setting keys under enterprise management in the effective managed settings (e.g. `model`, `enabledPlugins`, `permissions`). Empty when no managed settings are in force. - [JsonPropertyName("managedKeys")] - public IList ManagedKeys { get => field ??= []; set; } - - /// Whether at least two managed sources supplied permission allowlists, so enforcement intersects them and the flattened settings payload omits `permissions.allow`. - [JsonPropertyName("permissionsAllowIntersected")] - public bool? PermissionsAllowIntersected { get; set; } - - /// Reusable retained managed permission policy for managedSettings.permissions.evaluate, including source composition and session-local injection. Provided by live session snapshots; absent in older events. Refresh the context when managed policy changes. - [JsonPropertyName("permissionsContext")] - public ManagedPermissionsContext? PermissionsContext { get; set; } - - /// Whether the policy-helper managed-settings layer was present. The policy helper is the weakest channel: it fills keys no enterprise source set and can never replace one. - [JsonPropertyName("policyHelperManaged")] - public bool? PolicyHelperManaged { get; set; } - - /// Whether the effective sandbox policy forces the sandbox on *only* because managed policy could not be determined, rather than because the policy requires it. Lets clients tell a user whose `--no-sandbox` was overridden that the sandbox stayed on as a fail-closed fallback, instead of attributing it to an administrator who set no such policy. - [JsonPropertyName("sandboxEnabledByUndeterminedPolicy")] - public bool? SandboxEnabledByUndeterminedPolicy { get; set; } - - /// Whether the server (account/org) managed-settings layer was present. - [JsonPropertyName("serverManaged")] - public bool ServerManaged { get; set; } - - /// The effective (resolved) managed settings values, so clients can render exactly what is enforced. Absent when no managed policy is in force. - [JsonPropertyName("settings")] - public JsonElement? Settings { get; set; } + /// + [JsonIgnore] + public override string Kind => "foreign"; - /// Channel summary: `server`, `device`, `client`, or `policyHelper` when exactly one channel contributed; `mixed` when multiple channels contributed; otherwise `none`. Consult the per-channel booleans for exact provenance. - [JsonPropertyName("source")] - public ManagedSettingsResolvedSource Source { get; set; } + /// Human-readable explanation safe to surface. Never contains the presented reference or private candidate state. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } } -/// Typed effective values of managed settings. Each field mirrors the managed-settings schema key of the same name; more keys are added as they are typed. +/// The presented opaque handle was issued for another catalog operation. +/// The wrong-kind variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsValues +public partial class CatalogSelectionResultWrongKind : CatalogSelectionResult { - /// Managed Auto routing preference, used when the selected model is `auto`. - [JsonPropertyName("autoTier")] - public AutoTier? AutoTier { get; set; } - - /// Managed context-tier default for the managed concrete model. - [JsonPropertyName("contextTier")] - public ContextTier? ContextTier { get; set; } - - /// Managed reasoning-effort default for the managed concrete model. The runtime clamps it to an entitled effort when model availability is known. - [JsonPropertyName("effortLevel")] - public string? EffortLevel { get; set; } + /// + [JsonIgnore] + public override string Kind => "wrong-kind"; - /// Managed default model identifier. When model availability was resolved, aliases and family names are projected to a concrete available model ID; otherwise the configured value is returned. - [JsonPropertyName("model")] - public string? Model { get; set; } + /// Human-readable explanation safe to surface. Never contains the presented reference or private candidate state. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } } -/// Effective enterprise managed settings for an account, resolved without a session. +/// The caller's protocol version or required capabilities cannot be honoured. Returned instead of a partial or ambiguous success. +/// The negotiation-refused variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsResolveResult +public partial class CatalogSelectionResultNegotiationRefused : CatalogSelectionResult { - /// Printable opaque identity of the account the settings were resolved for, suitable for comparison and storage, not an account selectionId. Absent when no account was available, in which case only device policy is reported. - [JsonPropertyName("account")] - public string? Account { get; set; } + /// + [JsonIgnore] + public override string Kind => "negotiation-refused"; - /// Warnings about unavailable policy sources or a failed refresh served from cache. A cached response is not proof of a successful live fetch; `resolved.failClosed` separately describes enforcement. - [JsonPropertyName("diagnostics")] - public IList Diagnostics { get => field ??= []; set; } + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Each managed-settings channel consulted, strongest first, with the validated document it delivered before merging. `resolved.settings` is the merged result. More channels may be added over time. - [JsonPropertyName("layers")] - public IList Layers { get => field ??= []; set; } + /// Lowest caller protocol version this runtime will serve. + [JsonPropertyName("minimumSupportedProtocolVersion")] + public required long MinimumSupportedProtocolVersion { get; set; } - /// Per-key lock state and provenance for the entries in `values`, using the same key names. - [JsonPropertyName("meta")] - public ManagedSettingsMeta? Meta { get; set; } + /// Whether the version or the capability set was the problem. + [JsonPropertyName("reason")] + public required CatalogNegotiationRefusedReason Reason { get; set; } - /// Reusable source-composed permission policy for managedSettings.permissions.evaluate. Unlike resolved.settings.permissions, this retains every source's allowlist and default-prompt semantics. Refresh through resolve when account/device policy changes. Absent on runtimes that do not support permission evaluation. - [JsonPropertyName("permissionsContext")] - public ManagedPermissionsContext? PermissionsContext { get; set; } + /// Protocol version of the runtime that refused the request. + [JsonPropertyName("runtimeProtocolVersion")] + public required long RuntimeProtocolVersion { get; set; } - /// Effective managed settings from the device and account (server) channels, in the same shape as `session.managedSettings.get`, excluding session-local injection. - [JsonPropertyName("resolved")] - public ManagedSettingsResolvedData Resolved { get => field ??= new(); set; } + /// Capabilities this runtime can safely advertise to this caller. The complete five-capability protocol-3 legacy set is always present; every capability added after that baseline appears only when the caller required it, so an older closed-enum decoder can still consume a refusal. This list does not imply that every deployment has enabled every operation. + [JsonPropertyName("supportedCapabilities")] + public required IList SupportedCapabilities { get; set; } - /// Typed effective values of managed settings, keyed like the managed-settings schema and already resolved across channels, with the `{ "overridable": ... }` wrapper removed. Present when policy sets at least one typed key. Keys not typed here are available in `resolved.settings`. - [JsonPropertyName("values")] - public ManagedSettingsValues? Values { get; set; } + /// The subset of the caller's bounded extensible capability identifiers this runtime cannot honour. + [JsonPropertyName("unsupportedCapabilities")] + public required IList UnsupportedCapabilities { get; set; } } -/// RPC data type for ManagedSettingsResolve operations. +/// The request was rejected because a bounded field fell outside its permitted range or a required field was unusable. Pagination may also be rejected by the authority after a continuation request; repeat the search without page. +/// The invalid-request variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ManagedSettingsResolveRequest +public partial class CatalogSelectionResultInvalidRequest : CatalogSelectionResult { - /// Embedding client identity for server policy requests, as in session creation. Omit for the CLI identity. - [JsonPropertyName("clientName")] - public string? ClientName { get; set; } - - /// GitHub token to resolve instead of the current account. The call fails when the token cannot be resolved. - [JsonPropertyName("gitHubToken")] - public string? GitHubToken { get; set; } + /// + [JsonIgnore] + public override string Kind => "invalid-request"; - /// Opaque account identifier returned by `account.getAllUsers`. When omitted, the current account is used, or device policy only when no account is signed in. - [JsonPropertyName("selectionId")] - public string? SelectionId { get; set; } + /// Which request field was rejected. + [JsonPropertyName("field")] + public required CatalogInvalidRequestField Field { get; set; } - /// Working directory used to run an organization policy helper. When omitted, sessionless resolution does not run the helper. - [JsonPropertyName("workingDirectory")] - public string? WorkingDirectory { get; set; } + /// Human-readable explanation, safe to surface. Never echoes the offending value, nor a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } } -/// The authoring JSON schema for managed settings recognized by this runtime. +/// The operation is not available on this runtime. Distinct from a network failure: nothing was attempted. +/// The unavailable variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsSchemaResult +public partial class CatalogSelectionResultUnavailable : CatalogSelectionResult { - /// Version of the runtime that owns this schema. - [JsonPropertyName("runtimeVersion")] - public string RuntimeVersion { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "unavailable"; - /// JSON schema (draft 2020-12) with descriptive shared `x-composition` annotations, not a complete runtime composition contract. Model, effortLevel, and contextTier remain coupled; use `managedSettings.compose` for the runtime's effective result. - [JsonPropertyName("schema")] - public JsonElement Schema { get; set; } + /// Human-readable explanation, safe to surface. Never contains a query, URL, handle, or secret. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(1000)] + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// Why the operation is unavailable. + [JsonPropertyName("reason")] + public required CatalogUnavailableReason Reason { get; set; } } -/// Result of validating a managed-settings document. +/// Terminates one retained catalog selection group through an opaque reference previously returned by the model-safe search projection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsValidateResult +internal sealed class CatalogSelectionRequest { - /// Errors that reject the document and warnings about content the runtime ignores. - [JsonPropertyName("diagnostics")] - public IList Diagnostics { get => field ??= []; set; } + /// Protocol version and capabilities the caller requires. + [JsonPropertyName("contract")] + public CatalogClientContract Contract { get => field ??= new(); set; } - /// Canonical form of the document the runtime would apply, with unrecognized keys removed. Absent when the document is invalid. - [JsonPropertyName("settings")] - public JsonElement? Settings { get; set; } + /// The terminal outcome declared by the caller. Timed-out means the host's live interaction deadline elapsed; a reference whose runtime TTL elapsed is rejected separately as stale. + [JsonPropertyName("outcome")] + public CatalogSelectionDecision Outcome { get; set; } - /// Whether the runtime would accept the document within the preview resource limits. Always equals whether `settings` is present. An invalid document is rejected as a whole. - [JsonPropertyName("valid")] - public bool Valid { get; set; } + /// Opaque runtime-instance scoped reference to one visible candidate. For a non-selected outcome, any candidate reference from the same search closes that search's retained group. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(256)] + [JsonPropertyName("selectionRef")] + public string SelectionRef { get; set; } = string.Empty; + + /// Locally owned root session whose retained search state is being resolved. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(256)] + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// A candidate managed-settings document to validate without applying it. +/// Information about an installed plugin tracked in global state. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ManagedSettingsValidateRequest +public sealed class InstalledPluginInfo { - /// The document to validate: a JSON object, or a string containing the document's JSON text. Preview documents are limited to 1 MiB and 64 levels of nesting, a stricter resource limit than delivered-policy parsing; violations are returned as diagnostics. - [JsonPropertyName("content")] - public JsonElement Content { get; set; } + /// Opaque, stable hash identifying a direct (non-marketplace) install source. Present only for direct repo / URL / local installs; absent for marketplace plugins. Same source yields the same id; distinct sources never collide. + [JsonPropertyName("directSourceId")] + public string? DirectSourceId { get; set; } - /// Channel the document is meant for (`device`, `server`, or `policyHelper`). Some keys are only honored in some channels; for example, a `policyHelper` registration is ignored in policy-helper output. When omitted, no channel-specific checks run. - [JsonPropertyName("layer")] - public string? Layer { get; set; } -} + /// Whether the plugin is currently enabled for new sessions. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } -/// The effective managed settings the runtime would enforce for the given documents, in the same shape `managedSettings.resolve` returns. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsComposeResult -{ - /// Warnings about ignored content, with paths prefixed by the channel name. - [JsonPropertyName("diagnostics")] - public IList Diagnostics { get => field ??= []; set; } + /// Whether the managed desired plugin currently has an installed or live record. Set to false for a managed desired entry retained in the listing after installation or reconciliation failed. + [JsonPropertyName("installed")] + public bool? Installed { get; set; } - /// Only the supplied channels, strongest first, with canonical documents. Empty canonical documents are represented as absent settings, as in live resolution. - [JsonPropertyName("layers")] - public IList Layers { get => field ??= []; set; } + /// Absolute path of the marketplace directory a live plugin was resolved from. Present only on live, never-persisted records — a plugin belonging to a directory/local marketplace, which is loaded from its real directory on every pass instead of a copy under the installed-plugins cache. Its presence is what marks a listed plugin as live: such a plugin is always present on disk, so `enabled` is its only meaningful state and it is never "not installed". + [JsonPropertyName("installedFrom")] + public string? InstalledFrom { get; set; } - /// Per-key lock state and provenance for `values`. - [JsonPropertyName("meta")] - public ManagedSettingsMeta? Meta { get; set; } + /// Whether enterprise managed settings control this plugin's enabled state. + [JsonPropertyName("managed")] + public bool? Managed { get; set; } - /// Effective managed settings, in the same shape as `session.managedSettings.get`. - [JsonPropertyName("resolved")] - public ManagedSettingsResolvedData Resolved { get => field ??= new(); set; } + /// The enabled state required by enterprise managed settings, when this plugin spec is managed. + [JsonPropertyName("managedDesiredEnabled")] + public bool? ManagedDesiredEnabled { get; set; } - /// Typed effective values, as in `managedSettings.resolve`. - [JsonPropertyName("values")] - public ManagedSettingsValues? Values { get; set; } -} + /// Marketplace the plugin came from. Empty string ("") for direct repo / URL / local installs. + [JsonPropertyName("marketplace")] + public string Marketplace { get; set; } = string.Empty; -/// One candidate channel; absent settings represents a channel that delivered no document. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsComposeLayer -{ - /// Candidate managed-settings document. Omit when the channel delivered none, as in resolve output. - [JsonPropertyName("settings")] - public JsonElement? Settings { get; set; } + /// Plugin name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// The channel whose candidate document is being supplied. + /// Runtime-reported plugin provenance. Currently set to "builtin" only for plugins registered through the trusted host built-in boundary; absent for installed, marketplace, direct, and live plugins. [JsonPropertyName("source")] - public ManagedSettingsChannel Source { get; set; } + public string? Source { get; set; } + + /// Installed version (when reported by the plugin manifest). + [JsonPropertyName("version")] + public string? Version { get; set; } } -/// Candidate managed-settings documents to merge without applying them. +/// Plugins installed in user/global state. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ManagedSettingsComposeRequest +public sealed class PluginListResult { - /// One entry per channel. `source` must be `device`, `server`, or `policyHelper`, each at most once (checked at runtime); order does not matter, because channel precedence is fixed. To preview documents from resolve output, map recognized source strings to ManagedSettingsChannel and copy their settings; generated resolve and compose layer types are distinct. Omitted settings means this channel delivered no document. Supplied documents must be valid within the preview limits; warnings are returned in diagnostics. Compose does not reproduce source-failure state or retained enforcement floors from resolve. - [JsonPropertyName("layers")] - public IList Layers { get => field ??= []; set; } + /// Installed plugins. + [JsonPropertyName("plugins")] + public IList Plugins { get => field ??= []; set; } } -/// Polymorphic base type discriminated by kind. +/// Result of installing a plugin. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(ManagedPermissionOperationUrl), "url")] -public partial class ManagedPermissionOperation +public sealed class PluginInstallResult { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Set when the install path is deprecated (e.g. direct repo / URL / local installs). Callers should surface this to end users. + [JsonPropertyName("deprecationWarning")] + public string? DeprecationWarning { get; set; } + /// The newly installed plugin's metadata. + [JsonPropertyName("plugin")] + public InstalledPluginInfo Plugin { get => field ??= new(); set; } -/// The url variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ManagedPermissionOperationUrl : ManagedPermissionOperation -{ - /// - [JsonIgnore] - public override string Kind => "url"; + /// Optional post-install message provided by the plugin (e.g. setup instructions). + [JsonPropertyName("postInstallMessage")] + public string? PostInstallMessage { get; set; } - /// Absolute HTTP(S) URL with a host. Invalid URLs reject the entire evaluation batch. - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Number of skills discovered and installed from the plugin. + [JsonPropertyName("skillsInstalled")] + public long SkillsInstalled { get; set; } + + /// Where the completed plugin tree was staged before atomic promotion. + [JsonPropertyName("stagingMode")] + public PluginInstallStagingMode? StagingMode { get; set; } } -/// RPC data type for ManagedPermissionEvaluation operations. +/// Plugin source and optional working directory for relative-path resolution. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedPermissionEvaluation +internal sealed class PluginsInstallRequest { - /// Original input operation associated with this verdict. - [JsonPropertyName("operation")] - public ManagedPermissionOperation Operation { get => field ??= new(); set; } + /// Plugin install spec. Accepts the same forms as the CLI: "plugin@marketplace" (marketplace install), "owner/repo" or "owner/repo:subpath" (GitHub direct), an http/https/ssh URL, or a local path. Direct (non-marketplace) installs are deprecated and will produce a deprecationWarning in the result. + [JsonPropertyName("source")] + public string Source { get; set; } = string.Empty; - /// Managed-policy decision only; never bypasses user permissions or other security controls. - [JsonPropertyName("verdict")] - public ManagedPermissionVerdict Verdict { get; set; } + /// Working directory used to resolve relative local paths in `source`. Defaults to the server's current working directory. + [JsonPropertyName("workingDirectory")] + public string? WorkingDirectory { get; set; } } -/// Ordered managed permission verdicts and the supplied policy's fail-closed posture. +/// Name (or spec) of the plugin to uninstall. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedSettingsPermissionsEvaluateResult +internal sealed class PluginsUninstallRequest { - /// Managed permission policy could not be determined; every operation is denied. - [JsonPropertyName("failClosed")] - public bool FailClosed { get; set; } + /// Stable source identity for a direct (non-marketplace) install. Disambiguates uninstall when multiple installed plugins share the same name. + [JsonPropertyName("directSourceId")] + public string? DirectSourceId { get; set; } - /// One verdict per input operation, in the same order, including duplicates. - [JsonPropertyName("results")] - public IList Results { get => field ??= []; set; } + /// Plugin name or "plugin@marketplace" spec to uninstall. When ambiguous, prefer the fully-qualified spec. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// Managed policy context and ordered operations for pure, sessionless evaluation. +/// Result of updating a single plugin. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ManagedSettingsPermissionsEvaluateRequest +public sealed class PluginUpdateResult { - /// Trusted, reusable managed permission policy snapshot; no policy is discovered during evaluation. - [JsonPropertyName("context")] - public ManagedPermissionsContext Context { get; set; } = null!; + /// Version after the update, when reported by the plugin manifest. + [JsonPropertyName("newVersion")] + public string? NewVersion { get; set; } - /// Operations to evaluate, preserving input order and duplicates. An empty batch is valid. - [JsonPropertyName("operations")] - public IList Operations { get => field ??= []; set; } + /// Version that was previously installed, when available. + [JsonPropertyName("previousVersion")] + public string? PreviousVersion { get; set; } + + /// Number of skills discovered and installed after the update. + [JsonPropertyName("skillsInstalled")] + public long SkillsInstalled { get; set; } } -/// Indicates whether the calling client was registered as the session filesystem provider. +/// Name (or spec) of the plugin to update. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsSetProviderResult +internal sealed class PluginsUpdateRequest { - /// Whether the provider was set successfully. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Plugin name or "plugin@marketplace" spec to update. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// Optional capabilities declared by the provider. +/// Per-plugin result from updating all plugins, with versions, skills installed, success flag, and optional error. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsSetProviderCapabilities +public sealed class PluginUpdateAllEntry { - /// Whether the provider supports binary reads and writes through sessionFs.readFileBytes and sessionFs.writeFileBytes. - [JsonPropertyName("binary")] - public bool? Binary { get; set; } + /// Error message (failure only). + [JsonPropertyName("error")] + public string? Error { get; set; } - /// Whether the provider supports SQLite query/exists operations. - [JsonPropertyName("sqlite")] - public bool? Sqlite { get; set; } + /// Marketplace the plugin came from. Empty string ("") for direct installs. + [JsonPropertyName("marketplace")] + public string Marketplace { get; set; } = string.Empty; + + /// Plugin name that was updated. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Version after the update, when available. + [JsonPropertyName("newVersion")] + public string? NewVersion { get; set; } + + /// Previously installed version, when available. + [JsonPropertyName("previousVersion")] + public string? PreviousVersion { get; set; } + + /// Number of skills installed after the update (success only). + [JsonPropertyName("skillsInstalled")] + public long? SkillsInstalled { get; set; } + + /// Whether the update succeeded for this plugin. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Initial working directory, session-state path layout, and path conventions used to register the calling SDK client as the session filesystem provider. A registered provider is authoritative for path interpretation and filesystem facts used by workspace permission validation. Paths are interpreted lexically; home-relative paths (`~` and `~/...`) and Windows drive-relative paths such as `C:foo` are unsupported. Until provider-side canonicalization is supported, providers must not expose symlinks inside allowed roots that escape those roots. +/// Result of updating all installed plugins. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionFsSetProviderRequest +public sealed class PluginUpdateAllResult { - /// Optional capabilities declared by the provider. - [JsonPropertyName("capabilities")] - public SessionFsSetProviderCapabilities? Capabilities { get; set; } - - /// Path conventions used by this filesystem. - [JsonPropertyName("conventions")] - public SessionFsSetProviderConventions Conventions { get; set; } + /// Per-plugin update results in deterministic order. + [JsonPropertyName("results")] + public IList Results { get => field ??= []; set; } +} - /// Absolute initial working directory for sessions. Registering the provider establishes this path as the root of its virtual namespace; the runtime does not require the provider to materialize or stat it before creating a session. - [JsonPropertyName("initialCwd")] - public string InitialCwd { get; set; } = string.Empty; +/// Plugin names (or specs) to enable, plus the optional working directory the repository-controlled guard is evaluated against. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PluginsEnableRequest +{ + /// Plugin names or "plugin@marketplace" specs to enable. Unknown names are ignored. Non-marketplace direct installs are always enabled and cannot be toggled via this API. + [JsonPropertyName("names")] + public IList Names { get => field ??= []; set; } - /// Path within each session's SessionFs where the runtime stores files for that session. - [JsonPropertyName("sessionStatePath")] - public string SessionStatePath { get; set; } = string.Empty; + /// Working directory whose repository `enabledPlugins` overlay decides whether this mutation is repository-controlled. Hosts that serve sessions across several repositories (the SDK server) should pass the session's directory; otherwise the guard is evaluated against the server process's own working directory, which may belong to a different repository. Defaults to the server's current working directory. + [JsonPropertyName("workingDirectory")] + public string? WorkingDirectory { get; set; } } -/// Indicates whether the calling client was registered as the LLM inference provider. +/// Plugin names (or specs) to disable, plus the optional working directory the repository-controlled guard is evaluated against. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class LlmInferenceSetProviderResult +internal sealed class PluginsDisableRequest { - /// Whether the provider was set successfully. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Plugin names or "plugin@marketplace" specs to disable. Unknown names are ignored. Non-marketplace direct installs cannot be disabled via this API; uninstall them instead. Plugin-owned MCP servers are stopped in active sessions immediately; other plugin contributions remain available until each session reloads plugins. + [JsonPropertyName("names")] + public IList Names { get => field ??= []; set; } + + /// Working directory whose repository `enabledPlugins` overlay decides whether this mutation is repository-controlled. Hosts that serve sessions across several repositories (the SDK server) should pass the session's directory; otherwise the guard is evaluated against the server process's own working directory, which may belong to a different repository. Defaults to the server's current working directory. + [JsonPropertyName("workingDirectory")] + public string? WorkingDirectory { get; set; } } -/// Whether the start frame was accepted. +/// Trusted built-in plugin directories to use for this runtime process. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class LlmInferenceHttpResponseStartResult +internal sealed class PluginsBuiltinSetRequest { - /// True when the response start was matched to a pending request; false when unknown. - [JsonPropertyName("accepted")] - public bool Accepted { get; set; } + /// Complete replacement set of trusted built-in plugin directories. Every entry must be an absolute local filesystem path no longer than 4096 characters. + [JsonPropertyName("paths")] + public IList Paths { get => field ??= []; set; } } -/// Response head. +/// Registered marketplace summary. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class LlmInferenceHttpResponseStartRequest +public sealed class MarketplaceInfo { - /// HTTP response headers, preserving multiple values per name. - [JsonPropertyName("headers")] - public IDictionary> Headers { get => field ??= new Dictionary>(); set; } + /// Whether the managed marketplace currently resolved into the runtime marketplace registry. Set to false when the desired managed entry is retained for governance visibility after loading or reconciliation failed. + [JsonPropertyName("available")] + public bool? Available { get; set; } - /// Matches the requestId from the originating httpRequestStart frame. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// True when this is a default marketplace shipped with the runtime. Defaults are not removable. + [JsonPropertyName("isDefault")] + public bool? IsDefault { get; set; } - /// HTTP status code. - [JsonPropertyName("status")] - public long Status { get; set; } + /// Whether enterprise managed settings provide and control this marketplace entry. + [JsonPropertyName("managed")] + public bool? Managed { get; set; } - /// Optional HTTP status reason phrase. - [JsonPropertyName("statusText")] - public string? StatusText { get; set; } + /// Marketplace name (matches the @marketplace suffix in plugin specs). + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Human-readable description of where the marketplace data is fetched from (e.g. "GitHub: owner/repo"). + [JsonPropertyName("source")] + public string Source { get; set; } = string.Empty; } -/// Whether the chunk was accepted. +/// All registered marketplaces, including built-in defaults. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class LlmInferenceHttpResponseChunkResult +public sealed class MarketplaceListResult { - /// True when the chunk was matched to a pending request; false when unknown. - [JsonPropertyName("accepted")] - public bool Accepted { get; set; } + /// Registered marketplaces. + [JsonPropertyName("marketplaces")] + public IList Marketplaces { get => field ??= []; set; } } -/// Set to terminate the response with a transport-level failure. Implies end-of-stream; any further chunks for this requestId are ignored. +/// Result of registering a new marketplace. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class LlmInferenceHttpResponseChunkError +public sealed class MarketplaceAddResult { - /// Optional machine-readable error code. - [JsonPropertyName("code")] - public string? Code { get; set; } - - /// Human-readable failure description. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; + /// Final name of the marketplace as resolved from its manifest. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// A response body chunk or terminal error. +/// Marketplace source and optional working directory for relative-path resolution. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class LlmInferenceHttpResponseChunkRequest +internal sealed class PluginsMarketplacesAddRequest { - /// When true, `data` is base64-encoded bytes. When absent or false, `data` is UTF-8 text. - [JsonPropertyName("binary")] - public bool? Binary { get; set; } - - /// Body byte range. UTF-8 text when `binary` is absent or false; base64-encoded bytes when `binary` is true. May be empty (e.g. when the response body is empty: send a single chunk with empty data and end=true). - [JsonPropertyName("data")] - public string Data { get; set; } = string.Empty; + /// Marketplace source. Accepts the same forms as the CLI: "owner/repo" or "owner/repo#ref" (GitHub), an http/https/ssh URL (optionally with #ref), a git scp-style URL (user@host:path), or a local path. The marketplace's own name (from its manifest) is used as the registration key. + [JsonPropertyName("source")] + public string Source { get; set; } = string.Empty; - /// When true, this is the final body chunk for the response. The runtime treats the response body as complete after receiving an end-marked chunk. - [JsonPropertyName("end")] - public bool? End { get; set; } + /// Working directory used to resolve relative local paths in `source`. Defaults to the server's current working directory. + [JsonPropertyName("workingDirectory")] + public string? WorkingDirectory { get; set; } +} - /// Set to terminate the response with a transport-level failure. Implies end-of-stream; any further chunks for this requestId are ignored. - [JsonPropertyName("error")] - public LlmInferenceHttpResponseChunkError? Error { get; set; } +/// Outcome of the remove attempt, including dependent-plugin info when applicable. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class MarketplaceRemoveResult +{ + /// Names of installed plugins that prevented removal. Populated only when `removed=false`. + [JsonPropertyName("dependentPlugins")] + public IList? DependentPlugins { get; set; } - /// Matches the requestId from the originating httpRequestStart frame. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// True when the marketplace was actually removed. False when removal was skipped because the marketplace has dependent plugins and `force` was not set. + [JsonPropertyName("removed")] + public bool Removed { get; set; } } -/// Pre-resolved working-directory context for session startup. +/// Name of the marketplace to remove and an optional force flag. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionContext +internal sealed class PluginsMarketplacesRemoveRequest { - /// Active git branch. - [JsonPropertyName("branch")] - public string? Branch { get; set; } + /// When true, also uninstall every plugin sourced from this marketplace. When false (default), removal is a no-op if any plugin from this marketplace is installed and the dependent plugin names are returned in the result. + [JsonPropertyName("force")] + public bool? Force { get; set; } - /// Most recent working directory for this session. - [JsonPropertyName("cwd")] - public string Cwd { get; set; } = string.Empty; + /// Marketplace name to remove. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; +} - /// Git repository root, if the cwd was inside a git repo. - [JsonPropertyName("gitRoot")] - public string? GitRoot { get; set; } +/// Plugin entry advertised by a marketplace. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class MarketplacePluginInfo +{ + /// Short description from the marketplace catalog, when present. + [JsonPropertyName("description")] + public string? Description { get; set; } - /// Repository host type. - [JsonPropertyName("hostType")] - public SessionContextHostType? HostType { get; set; } + /// Plugin name as listed in the marketplace catalog. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; +} - /// Repository slug in `owner/name` form, when known. - [JsonPropertyName("repository")] - public string? Repository { get; set; } +/// Plugins advertised by the marketplace. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class MarketplaceBrowseResult +{ + /// Plugins advertised by the marketplace. + [JsonPropertyName("plugins")] + public IList Plugins { get => field ??= []; set; } } -/// GitHub repository the remote session belongs to. +/// Name of the marketplace whose plugin catalog to fetch. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class RemoteSessionMetadataRepository +internal sealed class PluginsMarketplacesBrowseRequest { - /// Branch associated with the remote session. - [JsonPropertyName("branch")] - public string Branch { get; set; } = string.Empty; + /// Marketplace name to browse. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; +} - /// Repository name. +/// Per-marketplace refresh result, including marketplace name, success flag, and optional failure error. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class MarketplaceRefreshEntry +{ + /// Error message (failure only). + [JsonPropertyName("error")] + public string? Error { get; set; } + + /// Marketplace name that was refreshed. [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; - /// Repository owner. - [JsonPropertyName("owner")] - public string Owner { get; set; } = string.Empty; + /// Whether the refresh succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Remote session metadata for the session to hand off (typically obtained from `sessions.list` with `source: "remote"`). +/// Result of refreshing one or more marketplace catalogs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class RemoteSessionMetadataValue +public sealed class MarketplaceRefreshResult { - /// Most recent working directory context. - [JsonPropertyName("context")] - public SessionContext? Context { get; set; } + /// Per-marketplace refresh results in deterministic order. + [JsonPropertyName("results")] + public IList Results { get => field ??= []; set; } +} - /// Host-supplied human description of what the session is doing right now ("running tests", "waiting for approval"). Optional in the protocol and absent on hosts that do not publish it, so never rely on it -- it enriches `hostStatus`, it does not replace it. - [JsonPropertyName("hostActivity")] - public string? HostActivity { get; set; } +/// RPC data type for PluginsMarketplacesRefresh operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PluginsMarketplacesRefreshRequest +{ + /// Marketplace name to refresh. When omitted, every registered marketplace is refreshed. + [JsonPropertyName("name")] + public string? Name { get; set; } +} - /// Live status as the owning host reports it in its session listing, so a row for a session running elsewhere can show that it is running. Absent for hosts that publish no such status (the cloud task managers), which read as idle. - [JsonPropertyName("hostStatus")] - public RemoteSessionHostStatus? HostStatus { get; set; } +/// Agent metadata, including identifiers, display details, source, tools, model, models, reasoning effort, MCP servers, skills, and file path. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class AgentInfo +{ + /// Description of the agent's purpose. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// Always true for remote sessions. - [JsonPropertyName("isRemote")] - public bool IsRemote { get; set; } + /// Whether model-driven invocation is disabled for this agent. + [JsonPropertyName("disableModelInvocation")] + public bool? DisableModelInvocation { get; set; } - /// Last-modified time as an ISO 8601 timestamp. - [JsonPropertyName("modifiedTime")] - public string ModifiedTime { get; set; } = string.Empty; + /// Human-readable display name. + [JsonPropertyName("displayName")] + public string DisplayName { get; set; } = string.Empty; - /// Optional human-friendly name set via /rename. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Declarative hook actions keyed by event name, executed only while this agent is active. + [JsonPropertyName("hooks")] + public IDictionary>? Hooks { get; set; } - /// Pull request number associated with the session. - [JsonPropertyName("pullRequestNumber")] - public long? PullRequestNumber { get; set; } + /// Stable identifier for selection. For most agents this is the same as `name`; for plugin/builtin agents it may differ. Always populated; defaults to `name` when no distinct id was assigned. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Backing remote session IDs (most recent first). - [JsonPropertyName("remoteSessionIds")] - public IList RemoteSessionIds { get => field ??= []; set; } + /// MCP server configurations attached to this agent, keyed by server name. Server config shape mirrors the MCP `mcpServers` schema. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + [JsonPropertyName("mcpServers")] + public IDictionary? McpServers { get; set; } - /// GitHub repository the remote session belongs to. - [JsonPropertyName("repository")] - public RemoteSessionMetadataRepository Repository { get => field ??= new(); set; } + /// Authored preferred model id for this agent. Runtime model selection may choose a different model; omitted means no authored preference. + [JsonPropertyName("model")] + public string? Model { get; set; } - /// Original remote resource identifier (task ID or PR node ID). - [JsonPropertyName("resourceId")] - public string? ResourceId { get; set; } + /// Whether authored models are preferences or required constraints. + [JsonPropertyName("modelPolicy")] + public AgentModelPolicy? ModelPolicy { get; set; } - /// Stable session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Authored preferred model ids for this agent, in priority order. Runtime model selection chooses the first available model; omitted means no authored preference. + [JsonPropertyName("models")] + public IList? Models { get; set; } - /// Deadline (ISO 8601) at which a CLI remote session becomes stale without further heartbeats. - [JsonPropertyName("staleAt")] - public string? StaleAt { get; set; } + /// Name of the agent. Use `id` as the stable selection identifier. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Session creation time as an ISO 8601 timestamp. - [JsonPropertyName("startTime")] - public string StartTime { get; set; } = string.Empty; + /// Absolute local file path of the agent definition. Only set for file-based agents loaded from disk; remote agents do not have a path. + [JsonPropertyName("path")] + public string? Path { get; set; } - /// Server-side task state returned by GitHub. - [JsonPropertyName("state")] - public string? State { get; set; } + /// Authored base prompt for the agent. Runtime prompt assembly may add dynamic context at invocation time. Omitted from `session.agent.list` unless `includePrompt` is true. + [JsonPropertyName("prompt")] + public string? Prompt { get; set; } - /// Short summary of the session, when one has been derived. - [JsonPropertyName("summary")] - public string? Summary { get; set; } + /// Authored reasoning effort for this agent. Applied on selection to models that support it; omitted means no authored preference. + [JsonPropertyName("reasoningEffort")] + public string? ReasoningEffort { get; set; } - /// Whether the remote task originated from CCA or CLI `--remote`. - [JsonPropertyName("taskType")] - public RemoteSessionMetadataTaskType? TaskType { get; set; } + /// Skill names preloaded into this agent's context. Omitted means none. + [JsonPropertyName("skills")] + public IList? Skills { get; set; } + + /// Where the agent definition was loaded from. + [JsonPropertyName("source")] + public AgentInfoSource? Source { get; set; } + + /// Allowed tool names for this agent. Empty array means none; omitted means inherit defaults. + [JsonPropertyName("tools")] + public IList? Tools { get; set; } + + /// Whether the agent can be selected directly by the user. Agents marked `false` are subagent-only. + [JsonPropertyName("userInvocable")] + public bool? UserInvocable { get; set; } } -/// `sessions.open` handoff progress update with step, status, and optional message. +/// Agents discovered across user, project, plugin, and remote sources. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionsOpenProgress +public sealed class ServerAgentList { - /// Optional step message. - [JsonPropertyName("message")] - public string? Message { get; set; } + /// All discovered agents across all sources. + [JsonPropertyName("agents")] + public IList Agents { get => field ??= []; set; } +} - /// Step status. - [JsonPropertyName("status")] - public SessionsOpenProgressStatus Status { get; set; } +/// Optional project paths to include in agent discovery. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class AgentsDiscoverRequest +{ + /// Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without ambient discovery, subject to managed/source disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. + [JsonPropertyName("agentDirectories")] + public IList? AgentDirectories { get; set; } - /// Handoff step. - [JsonPropertyName("step")] - public SessionsOpenProgressStep Step { get; set; } + /// When true, omit the host's agents (the user-level agent directory and all plugin agents), leaving only project and remote agents. For multitenant deployments. + [JsonPropertyName("excludeHostAgents")] + public bool? ExcludeHostAgents { get; set; } + + /// Optional list of project directory paths to scan for project-scoped agents. When omitted or empty, only user/plugin/remote-independent agents are returned (no project scan). + [JsonPropertyName("projectPaths")] + public IList? ProjectPaths { get; set; } } -/// Result of opening a session. +/// Canonical directory where custom agents can be discovered or created, with scope, preference, and optional project path. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionOpenResult +public sealed class AgentDiscoveryPath { - /// Remote session metadata, present when status is `connected`. - [JsonPropertyName("metadata")] - public RemoteSessionMetadataValue? Metadata { get; set; } - - /// Handoff progress steps, present when status is `handed_off`. - [JsonPropertyName("progress")] - public IList? Progress { get; set; } + /// Absolute path of the search/create directory (may not exist on disk yet). + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Remote session ID, present when status is `connected`. - [JsonPropertyName("remoteSessionId")] - public string? RemoteSessionId { get; set; } + /// Whether this is the canonical directory to create a new agent in its tier. At most one entry per tier is preferred. + [JsonPropertyName("preferredForCreation")] + public bool PreferredForCreation { get; set; } - /// Opened session ID. Omitted when status is `not_found`. - [JsonPropertyName("sessionId")] - public string? SessionId { get; set; } + /// The input project path this directory was derived from (only for project scope). + [JsonPropertyName("projectPath")] + public string? ProjectPath { get; set; } - /// Startup prompts queued by user-level hook configs at session creation. Only populated when status is `created`; resumed sessions return an empty array. - [JsonPropertyName("startupPrompts")] - public IList? StartupPrompts { get; set; } + /// Which tier this directory belongs to. + [JsonPropertyName("scope")] + public AgentDiscoveryPathScope Scope { get; set; } +} - /// Outcome of the open request. - [JsonPropertyName("status")] - public SessionsOpenStatus Status { get; set; } +/// Canonical locations where custom agents can be created so the runtime will recognize them. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class AgentDiscoveryPathList +{ + /// Canonical agent create/discovery directories, in priority order. + [JsonPropertyName("paths")] + public IList Paths { get => field ??= []; set; } } -/// Identifier and optional friendly name assigned to the newly forked session. +/// Optional project paths to include when enumerating agent discovery directories. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionsForkResult +public sealed class AgentsGetDiscoveryPathsRequest { - /// Friendly name assigned to the forked session, if any. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Explicit discovery-only agent roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + [JsonPropertyName("agentDirectories")] + public IList? AgentDirectories { get; set; } - /// The new forked session's ID. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// When true, omit the host's user-level agent directory, leaving only project directories. For multitenant deployments (mirrors `discover`'s `excludeHostAgents`). + [JsonPropertyName("excludeHostAgents")] + public bool? ExcludeHostAgents { get; set; } + + /// Optional list of project directory paths. When omitted or empty, only the user-level directory is returned. + [JsonPropertyName("projectPaths")] + public IList? ProjectPaths { get; set; } } -/// Source session identifier to fork from, optional event-ID boundary, and optional friendly name for the new session. +/// The agents this runtime ships, named so a consumer can tell them apart from authored ones. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsForkRequest +internal sealed class AgentsGetBuiltinsResult { - /// Optional friendly name to assign to the forked session. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// The subset of `names` a user is allowed to turn off. A shipped agent outside this list is always active and a client should not offer a toggle for it. + [JsonPropertyName("disableableNames")] + public IList DisableableNames { get => field ??= []; set; } - /// Source session ID to fork from. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Every agent name this runtime ships. + [JsonPropertyName("names")] + public IList Names { get => field ??= []; set; } - /// Optional event ID boundary. When provided, the fork includes only events before this ID (exclusive). When omitted, all events are included. - [JsonPropertyName("toEventId")] - public string? ToEventId { get; set; } + /// The subset of `names` defined by a shipped YAML definition. The remainder are special-cased in code and have no definition to load. + [JsonPropertyName("yamlBasedNames")] + public IList YamlBasedNames { get => field ??= []; set; } } -/// Repository associated with the connected remote session. +/// A shipped agent, named and described. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectedRemoteSessionMetadataRepository +internal sealed class BuiltinAgentSummary { - /// Branch associated with the remote session. - [JsonPropertyName("branch")] - public string Branch { get; set; } = string.Empty; + /// One-line description of what the agent does. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// Repository name. + /// The agent name, as it appears in `getBuiltins`. [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; - - /// Repository owner or organization login. - [JsonPropertyName("owner")] - public string Owner { get; set; } = string.Empty; } -/// Metadata for a connected remote session. +/// The shipped agents available under the requested flags. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectedRemoteSessionMetadata +internal sealed class AgentsGetAvailableBuiltinsResult { - /// Neutral SDK discriminator for the connected remote session kind. - [JsonPropertyName("kind")] - public ConnectedRemoteSessionMetadataKind Kind { get; set; } + /// Available shipped agents, in the runtime's own order. + [JsonPropertyName("agents")] + public IList Agents { get => field ??= []; set; } +} - /// Last session update time as an ISO 8601 string. - [JsonPropertyName("modifiedTime")] - public DateTimeOffset ModifiedTime { get; set; } +/// The feature flags to evaluate shipped agents against. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AgentsGetAvailableBuiltinsRequest +{ + /// The surface asking, which gates agents that only apply to one client. Omit or pass null to apply no client filter. + [JsonPropertyName("context")] + public string? Context { get; set; } - /// Optional friendly session name. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Feature flag values keyed by name, evaluated with the runtime's truthiness rules. Omit or pass null for no flags. + [JsonPropertyName("featureFlags")] + public IDictionary? FeatureFlags { get; set; } - /// Pull request number associated with the session. - [JsonPropertyName("pullRequestNumber")] - public long? PullRequestNumber { get; set; } + /// Flag overrides keyed by name. A null entry uses the corresponding base flag; false explicitly disables it. Omit or pass null for no overrides. + [JsonPropertyName("overrides")] + public IDictionary? Overrides { get; set; } +} - /// Repository associated with the connected remote session. - [JsonPropertyName("repository")] - public ConnectedRemoteSessionMetadataRepository Repository { get => field ??= new(); set; } +/// One shipped agent's definition. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AgentsGetBuiltinDefinitionResult +{ + /// The agent's definition, serialized as JSON. It carries the authored keys plus the runtime's projected `__nativeCustomAgent` view of the same agent. It is a string rather than an object because the runtime parses it with the agent schema's tolerant shape, which accepts keys this contract does not name. + [JsonPropertyName("definitionJson")] + public string DefinitionJson { get; set; } = string.Empty; +} - /// Original remote resource identifier. - [JsonPropertyName("resourceId")] - public string? ResourceId { get; set; } +/// The shipped agent whose definition to load. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AgentsGetBuiltinDefinitionRequest +{ + /// The agent name, which must be one of `getBuiltins`'s `yamlBasedNames`. A name outside that list is special-cased in code and has no definition, and is reported as an error rather than as an empty definition. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; +} - /// SDK session ID for the connected remote session. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; +/// One shipped agent, projected for a listing. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AgentsGetBuiltinListingDefinitionResult +{ + /// The agent projected as a custom agent, serialized as JSON. It is a string rather than an object for the same reason as `getBuiltinDefinition`: the runtime parses the underlying definition with the agent schema's tolerant shape, which accepts keys this contract does not name. + [JsonPropertyName("definitionJson")] + public string DefinitionJson { get; set; } = string.Empty; +} - /// Remote session staleness deadline as an ISO 8601 string. - [JsonPropertyName("staleAt")] - public DateTimeOffset? StaleAt { get; set; } +/// The shipped agent whose listing entry to load. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AgentsGetBuiltinListingDefinitionRequest +{ + /// The agent name, taken from `getAvailableBuiltins`. Unlike `getBuiltinDefinition`, the agent that `getBuiltins` reports as special-cased rather than YAML-based is answered here too, from its in-code definition. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; +} - /// Session start time as an ISO 8601 string. - [JsonPropertyName("startTime")] - public DateTimeOffset StartTime { get; set; } +/// The model to switch to, and the warning to show when the agent's preference could not be met. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AgentsCustomAgentInitialModelDecisionResult +{ + /// The reasoning effort attached to the selected model preference. Absent when that preference does not specify an effort. + [JsonPropertyName("reasoningEffort")] + public string? ReasoningEffort { get; set; } - /// Remote session state returned by the backing service. - [JsonPropertyName("state")] - public string? State { get; set; } + /// The first available model that matches the agent's preferences. Absent when none of the requested models is available. + [JsonPropertyName("targetModel")] + public string? TargetModel { get; set; } - /// Optional session summary. - [JsonPropertyName("summary")] - public string? Summary { get; set; } + /// What to tell the user about an unmet preference. Absent when the preference was met. A warning with no `targetModel` means the agent's models are all unavailable. + [JsonPropertyName("warning")] + public string? Warning { get; set; } } -/// Remote session connection result. +/// The models a custom agent asks for, and the models actually available. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class RemoteSessionConnectionResult +internal sealed class AgentsCustomAgentInitialModelDecisionParams { - /// Metadata for a connected remote session. - [JsonPropertyName("metadata")] - public ConnectedRemoteSessionMetadata Metadata { get => field ??= new(); set; } + /// The agent's declared `model:` entry, serialized. A single name or an ordered list of acceptable names. + [JsonPropertyName("agentModelsJson")] + public string AgentModelsJson { get; set; } = string.Empty; - /// SDK session ID for the connected remote session. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// The models available to this session, serialized in the shape the model list carries. + [JsonPropertyName("availableModelsJson")] + public string AvailableModelsJson { get; set; } = string.Empty; } -/// Remote session connection parameters. +/// Installed plugin record from global state, with marketplace, version, install time, enabled state, cache path, and source. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ConnectRemoteSessionParams +public sealed class InstalledPlugin { - /// Session ID to connect to. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Path where the plugin is cached locally. + [JsonPropertyName("cache_path")] + public string? CachePath { get; set; } + + /// Whether the plugin is currently enabled. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } + + /// Installation timestamp. + [JsonPropertyName("installed_at")] + public string InstalledAt { get; set; } = string.Empty; + + /// Absolute path of the marketplace directory a live plugin was resolved from. Present only on live, never-persisted records — those synthesized at session start for a directory/local marketplace, whose cache_path points at the real plugin directory on disk rather than a copy under the installed-plugins cache. Its presence is what marks a record as live, and no record carrying it is ever written to the persisted installedPlugins key. + [JsonPropertyName("installed_from")] + public string? InstalledFrom { get; set; } + + /// Marketplace the plugin came from (empty string for direct repo installs). + [JsonPropertyName("marketplace")] + public string Marketplace { get; set; } = string.Empty; + + /// Plugin name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Source for direct repo installs (when marketplace is empty). + [JsonPropertyName("source")] + public JsonElement? Source { get; set; } + + /// Per-plugin source fingerprint (a SHA-256 hash of the plugin's catalog source spec plus its resolved source subtree — NOT a Git commit SHA) captured at marketplace install/update time. Auto-update compares it against the freshly recomputed fingerprint to detect a content change that does not bump the version. Absent for pre-existing installs and for direct (non-marketplace) installs. + [JsonPropertyName("source_sha")] + public string? SourceSha { get; set; } + + /// Version installed (if available). + [JsonPropertyName("version")] + public string? Version { get; set; } } -/// Local or remote session metadata entry. Narrow on `isRemote` to access source-specific fields. -/// Data type discriminated by isRemote. +/// An account the host has signed in to, identified by the server it lives on and the login it uses there. The same person can appear more than once when they use both github.com and an Enterprise server. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SessionListEntry +internal sealed class LoggedInUser { - /// The boolean discriminator. - [JsonPropertyName("isRemote")] - public bool IsRemote { get; set; } + /// Source account this account was derived from, when one was recorded. + [JsonPropertyName("derivedFrom")] + public string? DerivedFrom { get; set; } - /// Runtime client name that created/last resumed this session. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("clientName")] - public string? ClientName { get; set; } + /// Host the account belongs to, such as `github.com` or an Enterprise server. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; - /// Pre-resolved working-directory context for session startup. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("context")] - public SessionContext? Context { get; set; } + /// Account kind, when the host recorded one. Consumers must tolerate new strings. + [JsonPropertyName("kind")] + public string? Kind { get; set; } - /// Host-supplied human description of what the session is doing right now ("running tests", "waiting for approval"). Optional in the protocol and absent on hosts that do not publish it, so never rely on it -- it enriches `hostStatus`, it does not replace it. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("hostActivity")] - public string? HostActivity { get; set; } + /// Account login on that host. + [JsonPropertyName("login")] + public string Login { get; set; } = string.Empty; +} - /// Live status as the owning host reports it in its session listing, so a row for a session running elsewhere can show that it is running. Absent for hosts that publish no such status (the cloud task managers), which read as idle. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("hostStatus")] - public RemoteSessionHostStatus? HostStatus { get; set; } +/// The host's machine-wide state. Every field is optional because a fresh install has recorded nothing yet, so a reader must treat an absent field as `not yet`, never as a negative answer. Stored credentials are deliberately absent from this shape. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class GlobalStateLoadResult +{ + /// Whether the app tip has been shown. + [JsonPropertyName("appTipShown")] + public bool? AppTipShown { get; set; } - /// True for detached maintenance sessions that should be hidden from normal resume lists. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("isDetached")] - public bool? IsDetached { get; set; } + /// Terminals the user has already been asked to set up, so the host does not ask twice. + [JsonPropertyName("askedSetupTerminals")] + public IList? AskedSetupTerminals { get; set; } - /// GitHub task ID, when this local session is bound to one. Only present for local sessions exported to remote control. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("mcTaskId")] - public string? McTaskId { get; set; } + /// When the Auto-feedback hint was last shown, as an ISO 8601 timestamp. It enforces the once-per-day cap for non-staff users across restarts. + [JsonPropertyName("autoFeedbackLastPromptedAt")] + public string? AutoFeedbackLastPromptedAt { get; set; } - /// Last-modified time of the session's persisted state, as ISO 8601. - [JsonPropertyName("modifiedTime")] - public required string ModifiedTime { get; set; } + /// When the host first ran on this machine. + [JsonPropertyName("firstLaunchAt")] + public string? FirstLaunchAt { get; set; } - /// Optional human-friendly name set via /rename. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Plugins installed on this machine. + [JsonPropertyName("installedPlugins")] + public IList? InstalledPlugins { get; set; } - /// Pull request number associated with the session. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("pullRequestNumber")] - public long? PullRequestNumber { get; set; } + /// Account used for the most recent sign-in. + [JsonPropertyName("lastLoggedInUser")] + public LoggedInUser? LastLoggedInUser { get; set; } - /// Backing remote session IDs (most recent first). - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("remoteSessionIds")] - public IList? RemoteSessionIds { get; set; } + /// Every account the host has signed in to on this machine. + [JsonPropertyName("loggedInUsers")] + public IList? LoggedInUsers { get; set; } - /// GitHub repository the remote session belongs to. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("repository")] - public RemoteSessionMetadataRepository? Repository { get; set; } + /// Whether the one-off cleanup of stored reasoning summaries has run. + [JsonPropertyName("reasoningSummariesCleanupDone")] + public bool? ReasoningSummariesCleanupDone { get; set; } - /// Original remote resource identifier (task ID or PR node ID). - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("resourceId")] - public string? ResourceId { get; set; } + /// Models the user selected recently, most recent first. + [JsonPropertyName("recentModelIds")] + public IList? RecentModelIds { get; set; } - /// Stable session identifier. - [JsonPropertyName("sessionId")] - public required string SessionId { get; set; } + /// Whether the user declined to trust the sandbox credential proxy CA. + [JsonPropertyName("sandboxCredentialProxyCaDeclined")] + public bool? SandboxCredentialProxyCaDeclined { get; set; } - /// Deadline (ISO 8601) at which a CLI remote session becomes stale without further heartbeats. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("staleAt")] - public string? StaleAt { get; set; } + /// Whether the sandbox onboarding has been shown. + [JsonPropertyName("sandboxOnboardingShown")] + public bool? SandboxOnboardingShown { get; set; } - /// Session creation time as an ISO 8601 timestamp. - [JsonPropertyName("startTime")] - public required string StartTime { get; set; } + /// Whether the user is a GitHub or Microsoft staff member, which unlocks internal-only behavior. + [JsonPropertyName("staff")] + public bool? Staff { get; set; } - /// Server-side task state returned by GitHub. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("state")] - public string? State { get; set; } + /// Whether the user was recognized as GitHub staff. + [JsonPropertyName("staffGithub")] + public bool? StaffGitHub { get; set; } - /// Short summary of the session, when one has been derived. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("summary")] - public string? Summary { get; set; } + /// When the staff-only log level migration last ran. + [JsonPropertyName("staffLogLevelMigrationAt")] + public string? StaffLogLevelMigrationAt { get; set; } - /// Whether the remote task originated from CCA or CLI `--remote`. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("taskType")] - public RemoteSessionMetadataTaskType? TaskType { get; set; } + /// Whether the user was recognized as Microsoft staff. + [JsonPropertyName("staffMicrosoft")] + public bool? StaffMicrosoft { get; set; } + + /// When the staff-only model reset last ran. + [JsonPropertyName("staffModelResetAt")] + public string? StaffModelResetAt { get; set; } + + /// When the staff-only update channel migration last ran. + [JsonPropertyName("staffUpdateChannelMigrationAt")] + public string? StaffUpdateChannelMigrationAt { get; set; } + + /// Folders where the user declined the init prompt, so it stays hidden there. + [JsonPropertyName("suppressInitFolders")] + public IList? SuppressInitFolders { get; set; } + + /// Folders the user has marked as trusted. + [JsonPropertyName("trustedFolders")] + public IList? TrustedFolders { get; set; } } -/// Sessions matching the filter, ordered most-recently-modified first. +/// Selects the configuration directory whose machine-wide state to read. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionList +internal sealed class GlobalStateLoadForConfigDirRequest { - /// Sessions ordered most-recently-modified first. Discriminated by `isRemote`. - [JsonPropertyName("sessions")] - public IList Sessions { get => field ??= []; set; } + /// Copilot configuration directory to read the state document from, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to read the directory the server resolved for itself. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } } -/// Optional filter applied to the returned sessions. +/// A single top-level key to record in the host's machine-wide state. The write replaces only that key and leaves the rest of the document untouched, so two writers recording different one-off flags do not overwrite each other. The stored credential keys cannot be written through this method. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionListFilter +internal sealed class GlobalStateWriteKeyRequest { - /// Match sessions whose context.branch equals this value. - [JsonPropertyName("branch")] - public string? Branch { get; set; } + /// Copilot configuration directory to write the state document in, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to write the directory the server resolved for itself. Mirrors `globalState.loadForConfigDir`, so a caller can read and write the same directory. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } - /// Match sessions whose context.cwd equals this value. - [JsonPropertyName("cwd")] - public string? Cwd { get; set; } + /// Top-level key to write, named as it appears in the result of `globalState.load`. It must be one of the writable keys that `globalState.writeKey` lists. + [JsonPropertyName("key")] + public string Key { get; set; } = string.Empty; - /// Match sessions whose context.gitRoot equals this value. - [JsonPropertyName("gitRoot")] - public string? GitRoot { get; set; } + /// Value to store for the key. Omit it, or pass null, to remove the key instead. + [JsonPropertyName("value")] + public JsonElement? Value { get; set; } +} - /// Match sessions whose context.repository equals this value. - [JsonPropertyName("repository")] - public string? Repository { get; set; } +/// A literal choice the command input accepts, with a human-facing description. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SlashCommandInputChoice +{ + /// Human-readable description shown alongside the choice. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; + + /// The literal choice value (e.g. 'on', 'off', 'show'). + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// Optional source filter, metadata-load limit, and context filter applied to the returned sessions. +/// Optional unstructured input hint. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsListRequest +public sealed class SlashCommandInput { - /// Optional filter applied to the returned sessions. - [JsonPropertyName("filter")] - public SessionListFilter? Filter { get; set; } + /// Optional literal choices the input accepts, each with a human-facing description; clients may render these as selectable options. + [JsonPropertyName("choices")] + public IList? Choices { get; set; } - /// When true, include detached maintenance sessions. Defaults to false for user-facing session lists. - [JsonPropertyName("includeDetached")] - public bool? IncludeDetached { get; set; } + /// Optional completion hint for the input (e.g. 'directory' for filesystem path completion). + [JsonPropertyName("completion")] + public SlashCommandInputCompletion? Completion { get; set; } - /// When provided, only the first N local sessions (sorted by modification time, newest first) load full metadata; remaining sessions return basic info only. Use 0 to return only basic info for every local session. Has no effect on remote entries (which always carry their full shape). - [JsonPropertyName("metadataLimit")] - public long? MetadataLimit { get; set; } + /// Hint to display when command input has not been provided. + [JsonPropertyName("hint")] + public string Hint { get; set; } = string.Empty; - /// Which session sources to include. Defaults to `local` for backward compatibility. - [JsonPropertyName("source")] - public SessionSource? Source { get; set; } + /// When true, clients should pass the full text after the command name as a single argument rather than splitting on whitespace. + [JsonPropertyName("preserveMultilineInput")] + public bool? PreserveMultilineInput { get; set; } - /// Only meaningful when `source` includes remote. When true, propagates errors from the remote service instead of silently returning an empty remote list. Defaults to false. - [JsonPropertyName("throwOnError")] - public bool? ThrowOnError { get; set; } + /// When true, the command requires non-empty input; clients should render the input hint as required. + [JsonPropertyName("required")] + public bool? Required { get; set; } } -/// Persisted local session metadata, including identifiers, timestamps, summary/name, client, context, detached state, and task ID. +/// Slash-command metadata with name, aliases, description, kind, input hint, execution allowance, and schedulability. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class LocalSessionMetadataValue +public sealed class SlashCommandInfo { - /// Runtime client name that created/last resumed this session. - [JsonPropertyName("clientName")] - public string? ClientName { get; set; } + /// Canonical aliases without leading slashes. + [JsonPropertyName("aliases")] + public IList? Aliases { get; set; } - /// Pre-resolved working-directory context for session startup. - [JsonPropertyName("context")] - public SessionContext? Context { get; set; } + /// Whether the command may run while an agent turn is active. + [JsonPropertyName("allowDuringAgentExecution")] + public bool AllowDuringAgentExecution { get; set; } - /// True for detached maintenance sessions that should be hidden from normal resume lists. - [JsonPropertyName("isDetached")] - public bool? IsDetached { get; set; } + /// Human-readable command description. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// Always false for local sessions. - [JsonPropertyName("isRemote")] - public bool IsRemote { get; set; } + /// Whether the command is experimental. + [JsonPropertyName("experimental")] + public bool? Experimental { get; set; } - /// GitHub task ID, when this local session is bound to one. Only present for local sessions exported to remote control. - [JsonPropertyName("mcTaskId")] - public string? McTaskId { get; set; } + /// Optional unstructured input hint. + [JsonPropertyName("input")] + public SlashCommandInput? Input { get; set; } - /// Last-modified time of the session's persisted state, as ISO 8601. - [JsonPropertyName("modifiedTime")] - public string ModifiedTime { get; set; } = string.Empty; + /// Coarse command category for grouping and behavior: runtime built-in, skill-backed command, or SDK/client-owned command. + [JsonPropertyName("kind")] + public SlashCommandKind Kind { get; set; } - /// Optional human-friendly name set via /rename. + /// Canonical command name without a leading slash. [JsonPropertyName("name")] - public string? Name { get; set; } - - /// Stable session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; - - /// Session creation time as an ISO 8601 timestamp. - [JsonPropertyName("startTime")] - public string StartTime { get; set; } = string.Empty; + public string Name { get; set; } = string.Empty; - /// Short summary of the session, when one has been derived. - [JsonPropertyName("summary")] - public string? Summary { get; set; } + /// Whether the command may be the target of `/every` / `/after` schedules. Resolution happens at every tick, so only set this when the command is safe to re-invoke and produces an agent prompt. + [JsonPropertyName("schedulable")] + public bool? Schedulable { get; set; } } -/// Persisted local session metadata when the session exists. +/// Slash commands available in the session, after applying any include/exclude filters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsGetMetadataResult +public sealed class CommandList { - /// Local session metadata, omitted when the session does not exist. - [JsonPropertyName("session")] - public LocalSessionMetadataValue? Session { get; set; } + /// Commands available in this session. + [JsonPropertyName("commands")] + public IList Commands { get => field ??= []; set; } } -/// Session ID whose persisted metadata should be read. +/// Owner, name, and host of a GitHub repository, as resolved from a git remote URL. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsGetMetadataRequest +public sealed class GitHubRepositoryIdentity { - /// Session ID to inspect. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Host the remote points at, for example `github.com` or a GitHub Enterprise hostname. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; + + /// Repository name, without the owner prefix or the `.git` suffix. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Repository owner login (user or organization). + [JsonPropertyName("owner")] + public string Owner { get; set; } = string.Empty; } -/// Client metadata outcome for one requested local session. -/// Polymorphic base type discriminated by status. +/// The GitHub repository that owns the requested path, when the selected remote (`origin`, else the first) is on a GitHub host. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "status", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(SessionsClientMetadataEntryOk), "ok")] -[JsonDerivedType(typeof(SessionsClientMetadataEntryNotFound), "notFound")] -[JsonDerivedType(typeof(SessionsClientMetadataEntryCorrupt), "corrupt")] -[JsonDerivedType(typeof(SessionsClientMetadataEntryUnsupportedVersion), "unsupportedVersion")] -[JsonDerivedType(typeof(SessionsClientMetadataEntryUnavailable), "unavailable")] -public partial class SessionsClientMetadataEntry +internal sealed class GitHubRepositoryAtPathResult { - /// The type discriminator. - [JsonPropertyName("status")] - public virtual string Status { get; set; } = string.Empty; + /// Resolved repository identity, or null when the selected remote resolves to no GitHub host. + [JsonPropertyName("repository")] + public GitHubRepositoryIdentity? Repository { get; set; } } - -/// The ok variant of . +/// Working-tree path whose owning GitHub repository should be resolved. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SessionsClientMetadataEntryOk : SessionsClientMetadataEntry +internal sealed class GitHubRepositoryAtPathRequest { - /// - [JsonIgnore] - public override string Status => "ok"; - - /// Validated client metadata, possibly empty or projected to requested keys. - [JsonPropertyName("metadata")] - public required IDictionary Metadata { get; set; } + /// Absolute path to a directory inside the git working tree to resolve. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; +} - /// Requested session ID. - [JsonPropertyName("sessionId")] - public required string SessionId { get; set; } -} - -/// The notFound variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SessionsClientMetadataEntryNotFound : SessionsClientMetadataEntry -{ - /// - [JsonIgnore] - public override string Status => "notFound"; - - /// Requested session ID. - [JsonPropertyName("sessionId")] - public required string SessionId { get; set; } -} - -/// The corrupt variant of . +/// A freshly registered request id. Registering it before the listing starts is what lets a cancel that races the request still find the owner listing slot. The id serves one listing only. Long-abandoned unused ids can be released by later allocations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SessionsClientMetadataEntryCorrupt : SessionsClientMetadataEntry +internal sealed class GitHubOwnersRequestIdResult { - /// - [JsonIgnore] - public override string Status => "corrupt"; - - /// Requested session ID. - [JsonPropertyName("sessionId")] - public required string SessionId { get; set; } + /// Request id to pass to `gitHubOwners.list` and, to abandon it, `gitHubOwners.cancel`. + [JsonPropertyName("requestId")] + public long RequestId { get; set; } } -/// The unsupportedVersion variant of . +/// A GitHub login the authenticated user may act as: their own account, or an organization they belong to. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SessionsClientMetadataEntryUnsupportedVersion : SessionsClientMetadataEntry +internal sealed class GitHubOwnerOption { - /// - [JsonIgnore] - public override string Status => "unsupportedVersion"; + /// The owner's GitHub login. + [JsonPropertyName("login")] + public string Login { get; set; } = string.Empty; - /// Requested session ID. - [JsonPropertyName("sessionId")] - public required string SessionId { get; set; } + /// Which kind of owner this is. The authenticated user's own account is always reported as `user`. + [JsonPropertyName("type")] + public string Type { get; set; } = string.Empty; } -/// The unavailable variant of . +/// Outcome of an owner listing. Exactly one of `owners` and `message` is present, except that `throwError` reports a failure the caller is expected to raise rather than render. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SessionsClientMetadataEntryUnavailable : SessionsClientMetadataEntry +internal sealed class GitHubOwnersListResult { - /// - [JsonIgnore] - public override string Status => "unavailable"; - - /// Filesystem or provider error code. Clients should not assume every provider uses operating-system error codes. - [JsonPropertyName("code")] - public required string Code { get; set; } - - /// Human-readable diagnostic message. Not stable for programmatic matching. + /// Why no owners could be listed, phrased for a user. Present when the listing failed in a way the caller should render rather than raise. [JsonPropertyName("message")] - public required string Message { get; set; } + public string? Message { get; set; } - /// Requested session ID. - [JsonPropertyName("sessionId")] - public required string SessionId { get; set; } -} + /// The owners, on success: the authenticated user first, then the organizations they belong to. + [JsonPropertyName("owners")] + public IList? Owners { get; set; } -/// Bounded batch request for client-owned metadata from persisted local sessions. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsGetClientMetadataRequest -{ - /// Case-sensitive keys to project from each valid bag. Each key must be non-empty, at most 256 UTF-8 bytes, and outside the reserved `copilot/` and `github/` namespaces. Omit to return every entry. - [JsonPropertyName("keys")] - public IList? Keys { get; set; } + /// A malformed request or an unreadable credential, which the caller raises instead of rendering. Kept a field rather than a dispatch error so it stays distinct from `message`, which the caller renders. + [JsonPropertyName("throwError")] + public string? ThrowError { get; set; } - /// Session IDs to inspect. Results preserve this order. - [JsonPropertyName("sessionIds")] - public IList SessionIds { get => field ??= []; set; } + /// A line the caller should log. Present only alongside `message`, and only for failures worth recording. + [JsonPropertyName("warning")] + public string? Warning { get; set; } } -/// Batch of session events returned by a read, with cursor and continuation metadata. +/// Credential to list owners under, and the request id that makes the listing cancellable. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class EventsReadResult +internal sealed class GitHubOwnersListRequest { - /// Opaque cursor for the next read. Pass back unchanged in the next read.cursor to continue from where this read left off. Always present, even when no events were returned. For a backward read this cursor pages toward OLDER events; keep passing `direction: backward` with it (the cursor is also self-describing, so backward paging continues correctly). - [JsonPropertyName("cursor")] - public string Cursor { get; set; } = string.Empty; - - /// Cursor status: 'ok' means the cursor was applied successfully. For session.eventLog.read, 'expired' means the cursor referred to an event that no longer exists in active history and the read fell back to a boundary of the remaining history: the beginning for a forward read or the newest window for a backward read. That fallback may overlap already rendered events, so active-session consumers should reset, rebase, or deduplicate before continuing. sessions.readPersistedEvents has stricter snapshot semantics: 'expired' returns an empty terminal page and never switches to a replacement journal generation. Other persisted-read I/O failures are RPC errors with diagnostics, not cursor expiry. - [JsonPropertyName("cursorStatus")] - public EventsCursorStatus CursorStatus { get; set; } - - /// Session events for this batch, merged into a single stream in creation order: durable (persisted) events and ephemeral events interleave exactly as they were emitted. Set `includeEphemeral: false` to receive only durable events. Ephemeral events are never replayable once pruned from the in-memory ring, so a consumer that needs them should keep reading with a non-zero `waitMs`. For a backward (tail-first) read, the returned window contains persisted events only, still in chronological (oldest-to-newest) append order. - [JsonPropertyName("events")] - public IList Events { get => field ??= []; set; } + /// The credential the listing runs under, carried opaquely because its shape is the host's own and the runtime only resolves a token and a GitHub host from it. No credential travels: this selects one the runtime already holds. + [JsonPropertyName("authInfo")] + public JsonElement AuthInfo { get; set; } - /// True when more events are available in the read's direction. For a backward read, true means older persisted events remain before the returned window. A persisted-event page may contain fewer than `max` events because of its byte budget while still reporting hasMore true; continue according to this flag rather than the event count. - [JsonPropertyName("hasMore")] - public bool HasMore { get; set; } + /// Request id from `gitHubOwners.nextRequestId`. An id that was never registered, canceled before use, released after being abandoned, or already used is refused rather than silently running uncancellable. + [JsonPropertyName("requestId")] + public long RequestId { get; set; } } -/// Pagination options for reading an inactive or active local session's persisted event journal. +/// Whether the id named a running owner listing. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsReadPersistedEventsRequest +internal sealed class GitHubOwnersCancelResult { - /// Opaque, process-local, single-use cursor returned by the previous persisted-event read. Omit on the first call and issue continuations sequentially; reusing the same cursor returns an expired terminal page. - [JsonPropertyName("cursor")] - public string? Cursor { get; set; } - - /// Direction to page through persisted history. Forward starts at the beginning; backward starts with the newest events. Events in each page remain chronological. This selects the initial read only; a continuation always uses the direction bound into its cursor. - [JsonPropertyName("direction")] - public EventsReadDirection? Direction { get; set; } - - /// Maximum number of events to return in this batch (1–1000, default 200). Pages may contain fewer events to keep the serialized event array within a soft 1 MiB budget including resolved binary assets; one oversized event is returned alone to guarantee progress. - [JsonPropertyName("max")] - public long? Max { get; set; } - - /// Session ID whose persisted event journal should be read. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// True when a listing with the id was running and the cancel stopped it. False when the id was never registered, was registered but unused, was released after being abandoned, or its listing had ended. An unused id is released and cannot start a later listing. + [JsonPropertyName("canceled")] + public bool Canceled { get; set; } } -/// Recent local session IDs that contain user-visible history. +/// The owner listing to abandon. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsListNonEmptySessionIdsResult +internal sealed class GitHubOwnersCancelRequest { - /// Session IDs ordered newest-first. - [JsonPropertyName("sessionIds")] - public IList SessionIds { get => field ??= []; set; } + /// Request id the listing was started with. + [JsonPropertyName("requestId")] + public long RequestId { get; set; } } -/// Limit for non-empty local session IDs. +/// The remote the checked-out branch tracks. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsListNonEmptySessionIdsRequest +internal sealed class GitCurrentBranchRemoteResult { - /// Maximum number of session IDs to return. - [JsonPropertyName("limit")] - public long? Limit { get; set; } + /// Name of the tracked remote. Reports `origin` whenever the working tree has no tracking configuration to read, including on a detached HEAD, so this is never null and never empty. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("remote")] + public string Remote { get; set; } = string.Empty; } -/// ID of the local session bound to the given GitHub task, or omitted when none. +/// Working-tree path a git query applies to. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionsFindByTaskIDResult +internal sealed class GitCwdRequest { - /// Omitted when no local session is bound to that GitHub task. - [JsonPropertyName("sessionId")] - public string? SessionId { get; set; } + /// Absolute path to a directory inside the git working tree to query. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("cwd")] + public string Cwd { get; set; } = string.Empty; } -/// GitHub task ID to look up. +/// Updated working directory and git context. Emitted as the new payload of `session.context_changed`. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsFindByTaskIDRequest +public sealed class SessionWorkingDirectoryContext { - /// GitHub task ID to look up. - [JsonPropertyName("taskId")] - public string TaskId { get; set; } = string.Empty; -} + /// Merge-base commit SHA (fork point from the remote default branch). + [JsonPropertyName("baseCommit")] + public string? BaseCommit { get; set; } -/// Session ID matching the prefix, omitted when no unique match exists. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionsFindByPrefixResult -{ - /// Omitted when no unique session matches the prefix (no match or ambiguous). - [JsonPropertyName("sessionId")] - public string? SessionId { get; set; } -} + /// Current git branch name. + [JsonPropertyName("branch")] + public string? Branch { get; set; } -/// UUID prefix to resolve to a unique session ID. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsFindByPrefixRequest -{ - /// UUID prefix (>=7 hex chars, <36 chars). Returns the unique session ID, or undefined when there is no match or the prefix matches multiple sessions. - [JsonPropertyName("prefix")] - public string Prefix { get; set; } = string.Empty; -} + /// Current working directory path. + [JsonPropertyName("cwd")] + public string Cwd { get; set; } = string.Empty; -/// Most-relevant session ID for the supplied context, or omitted when no sessions exist. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionsGetLastForContextResult -{ - /// Most-relevant session ID for the supplied context, or omitted when no sessions exist. - [JsonPropertyName("sessionId")] - public string? SessionId { get; set; } -} + /// Root directory of the git repository, resolved via git rev-parse. + [JsonPropertyName("gitRoot")] + public string? GitRoot { get; set; } -/// Optional working-directory context used to score session relevance. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsGetLastForContextRequest -{ - /// Optional working-directory context used to score session relevance. When omitted the most-recently-modified session wins. - [JsonPropertyName("context")] - public SessionContext? Context { get; set; } -} + /// Head commit of the current git branch. + [JsonPropertyName("headCommit")] + public string? HeadCommit { get; set; } -/// Absolute path to the session's events.jsonl file on disk. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsGetEventFilePathResult -{ - /// Absolute path to the session's events.jsonl file. - [JsonPropertyName("filePath")] - public string FilePath { get; set; } = string.Empty; + /// Hosting platform type of the repository. + [JsonPropertyName("hostType")] + public SessionWorkingDirectoryContextHostType? HostType { get; set; } + + /// Repository identifier derived from the git remote URL ("owner/name" for GitHub, "org/project/repo" for Azure DevOps). + [JsonPropertyName("repository")] + public string? Repository { get; set; } + + /// Raw host string from the git remote URL (e.g. "github.com", "dev.azure.com"). + [JsonPropertyName("repositoryHost")] + public string? RepositoryHost { get; set; } } -/// Session ID whose event-log file path to compute. +/// A GitHub repository one of a working tree's remotes points at. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsGetEventFilePathRequest +internal sealed class GitRemoteRepository { - /// Session ID whose event-log file path to compute. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// GitHub host serving the repository, which is not `github.com` for a GitHub Enterprise remote. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; + + /// Repository name, without the owner. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Account or organization owning the repository. + [JsonPropertyName("owner")] + public string Owner { get; set; } = string.Empty; + + /// Name of the first remote that produced this distinct repository entry, such as `origin` or `upstream`. + [JsonPropertyName("remoteName")] + public string RemoteName { get; set; } = string.Empty; } -/// Map of sessionId -> on-disk size in bytes for each session's workspace directory. +/// The GitHub repositories a working tree's remotes point at. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionSizes +internal sealed class GitReposFromRemotesResult { - /// Map of sessionId -> on-disk size in bytes for the session's workspace directory. - [JsonPropertyName("sizes")] - public IDictionary Sizes { get => field ??= new Dictionary(); set; } + /// One entry per distinct GitHub repository, in the order git reports the first remote for each repository. Empty when no remote points at a GitHub host, which a caller should read as `not connected to GitHub`. Failing to read the remotes is an error, not an empty list. + [JsonPropertyName("repositories")] + public IList Repositories { get => field ??= []; set; } } -/// Session IDs from the input set that are currently in use by another process. +/// Git working tree whose GitHub remotes should be listed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionsCheckInUseResult +internal sealed class GitReposFromRemotesRequest { - /// Session IDs from the input set that are currently held by another running process via an alive lock file. - [JsonPropertyName("inUse")] - public IList InUse { get => field ??= []; set; } + /// Absolute path to the root of the git working tree. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("gitRoot")] + public string GitRoot { get; set; } = string.Empty; } -/// Session IDs to test for live in-use locks. +/// Indicates whether the calling client was registered as the session filesystem provider. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsCheckInUseRequest +public sealed class SessionFsSetProviderResult { - /// Session IDs to test for live in-use locks. - [JsonPropertyName("sessionIds")] - public IList SessionIds { get => field ??= []; set; } + /// Whether the provider was set successfully. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// The session's persisted remote-steerable flag, or omitted when no value has been persisted. +/// Optional capabilities declared by the provider. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsGetPersistedRemoteSteerableResult +public sealed class SessionFsSetProviderCapabilities { - /// The session's persisted remote-steerable flag if recorded; omitted when no value has been persisted. - [JsonPropertyName("remoteSteerable")] - public bool? RemoteSteerable { get; set; } + /// Whether the provider supports binary reads and writes through sessionFs.readFileBytes and sessionFs.writeFileBytes. + [JsonPropertyName("binary")] + public bool? Binary { get; set; } + + /// Whether the provider supports SQLite query/exists operations. + [JsonPropertyName("sqlite")] + public bool? Sqlite { get; set; } } -/// Session ID to look up the persisted remote-steerable flag for. +/// Initial working directory, session-state path layout, and path conventions used to register the calling SDK client as the session filesystem provider. A registered provider is authoritative for path interpretation and filesystem facts used by workspace permission validation. Paths are interpreted lexically; home-relative paths (`~` and `~/...`) and Windows drive-relative paths such as `C:foo` are unsupported. Until provider-side canonicalization is supported, providers must not expose symlinks inside allowed roots that escape those roots. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsGetPersistedRemoteSteerableRequest +internal sealed class SessionFsSetProviderRequest { - /// Session ID to look up the persisted remote-steerable flag for. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Optional capabilities declared by the provider. + [JsonPropertyName("capabilities")] + public SessionFsSetProviderCapabilities? Capabilities { get; set; } + + /// Path conventions used by this filesystem. + [JsonPropertyName("conventions")] + public SessionFsSetProviderConventions Conventions { get; set; } + + /// Absolute initial working directory for sessions. Registering the provider establishes this path as the root of its virtual namespace; the runtime does not require the provider to materialize or stat it before creating a session. + [JsonPropertyName("initialCwd")] + public string InitialCwd { get; set; } = string.Empty; + + /// Path within each session's SessionFs where the runtime stores files for that session. + [JsonPropertyName("sessionStatePath")] + public string SessionStatePath { get; set; } = string.Empty; } -/// Closes a session: emits shutdown, flushes pending events to disk, releases the in-use lock, disposes the active session. Idempotent: succeeds even if the session is not currently active. +/// Indicates whether the calling client was registered as the LLM inference provider. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionsCloseResult +public sealed class LlmInferenceSetProviderResult { + /// Whether the provider was set successfully. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Session ID to close. +/// Whether the start frame was accepted. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsCloseRequest +public sealed class LlmInferenceHttpResponseStartResult { - /// Session ID to close. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// True when the response start was matched to a pending request; false when unknown. + [JsonPropertyName("accepted")] + public bool Accepted { get; set; } } -/// Map of sessionId -> bytes freed by removing the session's workspace directory. +/// Response head. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionBulkDeleteResult +internal sealed class LlmInferenceHttpResponseStartRequest { - /// Map of sessionId -> bytes freed by removing the session's workspace directory. Sessions whose deletion failed are omitted from this map (failures are logged on the server but not surfaced per-id; check the map for absent IDs to detect them). - [JsonPropertyName("freedBytes")] - public IDictionary FreedBytes { get => field ??= new Dictionary(); set; } + /// HTTP response headers, preserving multiple values per name. + [JsonPropertyName("headers")] + public IDictionary> Headers { get => field ??= new Dictionary>(); set; } + + /// Matches the requestId from the originating httpRequestStart frame. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; + + /// HTTP status code. + [JsonPropertyName("status")] + public long Status { get; set; } + + /// Optional HTTP status reason phrase. + [JsonPropertyName("statusText")] + public string? StatusText { get; set; } } -/// Session IDs to close, deactivate, and delete from disk. +/// Whether the chunk was accepted. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsBulkDeleteRequest +public sealed class LlmInferenceHttpResponseChunkResult { - /// Session IDs to close, deactivate, and delete from disk. - [JsonPropertyName("sessionIds")] - public IList SessionIds { get => field ??= []; set; } + /// True when the chunk was matched to a pending request; false when unknown. + [JsonPropertyName("accepted")] + public bool Accepted { get; set; } } -/// Session ID to delete from disk. +/// Set to terminate the response with a transport-level failure. Implies end-of-stream; any further chunks for this requestId are ignored. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsDeleteRequest +public sealed class LlmInferenceHttpResponseChunkError { - /// Session ID to delete. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Optional machine-readable error code. + [JsonPropertyName("code")] + public string? Code { get; set; } - /// Internal resolved session directory path to delete. - [JsonPropertyName("sessionPath")] - public string? SessionPath { get; set; } + /// Human-readable failure description. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; } -/// Outcome of the prune operation: deleted IDs, dry-run candidates, skipped IDs, total bytes freed, and the dry-run flag. +/// A response body chunk or terminal error. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionPruneResult +internal sealed class LlmInferenceHttpResponseChunkRequest { - /// Session IDs that would be deleted in dry-run mode (always empty otherwise). - [JsonPropertyName("candidates")] - public IList Candidates { get => field ??= []; set; } + /// When true, `data` is base64-encoded bytes. When absent or false, `data` is UTF-8 text. + [JsonPropertyName("binary")] + public bool? Binary { get; set; } - /// Session IDs that were deleted (always empty in dry-run mode). - [JsonPropertyName("deleted")] - public IList Deleted { get => field ??= []; set; } + /// Body byte range. UTF-8 text when `binary` is absent or false; base64-encoded bytes when `binary` is true. May be empty (e.g. when the response body is empty: send a single chunk with empty data and end=true). + [JsonPropertyName("data")] + public string Data { get; set; } = string.Empty; - /// True when no deletions were actually performed. - [JsonPropertyName("dryRun")] - public bool DryRun { get; set; } + /// When true, this is the final body chunk for the response. The runtime treats the response body as complete after receiving an end-marked chunk. + [JsonPropertyName("end")] + public bool? End { get; set; } - /// Total bytes freed (actual when not dry-run, projected when dry-run). - [JsonPropertyName("freedBytes")] - public long FreedBytes { get; set; } + /// Set to terminate the response with a transport-level failure. Implies end-of-stream; any further chunks for this requestId are ignored. + [JsonPropertyName("error")] + public LlmInferenceHttpResponseChunkError? Error { get; set; } - /// Session IDs that were skipped (e.g., named sessions). - [JsonPropertyName("skipped")] - public IList Skipped { get => field ??= []; set; } + /// Matches the requestId from the originating httpRequestStart frame. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; } -/// Age threshold and optional flags controlling which old sessions are pruned (or simulated when dryRun is true). +/// Pre-resolved working-directory context for session startup. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsPruneOldRequest +public sealed class SessionContext { - /// When true, only report what would be deleted without performing any deletion. - [JsonPropertyName("dryRun")] - public bool? DryRun { get; set; } + /// Active git branch. + [JsonPropertyName("branch")] + public string? Branch { get; set; } - /// Session IDs that should never be considered for pruning. - [JsonPropertyName("excludeSessionIds")] - public IList? ExcludeSessionIds { get; set; } + /// Most recent working directory for this session. + [JsonPropertyName("cwd")] + public string Cwd { get; set; } = string.Empty; - /// When true, named sessions (set via /rename) are also eligible for pruning. - [JsonPropertyName("includeNamed")] - public bool? IncludeNamed { get; set; } + /// Git repository root, if the cwd was inside a git repo. + [JsonPropertyName("gitRoot")] + public string? GitRoot { get; set; } - /// Delete sessions whose modifiedTime is at least this many days old. - [JsonPropertyName("olderThanDays")] - public long OlderThanDays { get; set; } -} + /// Repository host type. + [JsonPropertyName("hostType")] + public SessionContextHostType? HostType { get; set; } -/// Flush a session's pending events to disk. No-op when no writer exists for the session (e.g., already closed). -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionsSaveResult -{ + /// Repository slug in `owner/name` form, when known. + [JsonPropertyName("repository")] + public string? Repository { get; set; } } -/// Session ID whose pending events should be flushed to disk. +/// GitHub repository the remote session belongs to. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsSaveRequest +public sealed class RemoteSessionMetadataRepository { - /// Session ID whose pending events should be flushed to disk. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Branch associated with the remote session. + [JsonPropertyName("branch")] + public string Branch { get; set; } = string.Empty; -/// Release the in-use lock held by this process for the given session. No-op when this process does not currently hold a lock for the session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionsReleaseLockResult -{ -} + /// Repository name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; -/// Session ID whose in-use lock should be released. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsReleaseLockRequest -{ - /// Session ID whose in-use lock should be released. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Repository owner. + [JsonPropertyName("owner")] + public string Owner { get; set; } = string.Empty; } -/// The enriched metadata records, with summary and context fields backfilled where available. Sessions confirmed empty and unnamed are omitted. +/// Remote session metadata for the session to hand off (typically obtained from `sessions.list` with `source: "remote"`). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionEnrichMetadataResult +public sealed class RemoteSessionMetadataValue { - /// Enriched records, with summary and context backfilled. Sessions confirmed empty and unnamed may be omitted. - [JsonPropertyName("sessions")] - public IList Sessions { get => field ??= []; set; } -} + /// Most recent working directory context. + [JsonPropertyName("context")] + public SessionContext? Context { get; set; } -/// Session metadata records to enrich with summary and context information. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsEnrichMetadataRequest -{ - /// Session metadata records to enrich. Records that already have summary and context are returned unchanged. - [JsonPropertyName("sessions")] - public IList Sessions { get => field ??= []; set; } -} - -/// The workspace record that was written. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsCreateWorkspaceResult -{ - /// The created workspace record, as JSON. - [JsonPropertyName("workspaceJson")] - public string WorkspaceJson { get; set; } = string.Empty; -} - -/// A working-directory context together with the client that produced it. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionWorkingDirectoryContextWithClient -{ - /// Merge-base commit SHA. - [JsonPropertyName("baseCommit")] - public string? BaseCommit { get; set; } + /// Host-supplied human description of what the session is doing right now ("running tests", "waiting for approval"). Optional in the protocol and absent on hosts that do not publish it, so never rely on it -- it enriches `hostStatus`, it does not replace it. + [JsonPropertyName("hostActivity")] + public string? HostActivity { get; set; } - /// Current git branch name. - [JsonPropertyName("branch")] - public string? Branch { get; set; } + /// Live status as the owning host reports it in its session listing, so a row for a session running elsewhere can show that it is running. Absent for hosts that publish no such status (the cloud task managers), which read as idle. + [JsonPropertyName("hostStatus")] + public RemoteSessionHostStatus? HostStatus { get; set; } - /// Name of the client that created the session. - [JsonPropertyName("clientName")] - public string? ClientName { get; set; } + /// Always true for remote sessions. + [JsonPropertyName("isRemote")] + public bool IsRemote { get; set; } - /// Current working directory path. - [JsonPropertyName("cwd")] - public string Cwd { get; set; } = string.Empty; + /// Last-modified time as an ISO 8601 timestamp. + [JsonPropertyName("modifiedTime")] + public string ModifiedTime { get; set; } = string.Empty; - /// Root directory of the git repository. - [JsonPropertyName("gitRoot")] - public string? GitRoot { get; set; } + /// Optional human-friendly name set via /rename. + [JsonPropertyName("name")] + public string? Name { get; set; } - /// Head commit of the current git branch. - [JsonPropertyName("headCommit")] - public string? HeadCommit { get; set; } + /// Pull request number associated with the session. + [JsonPropertyName("pullRequestNumber")] + public long? PullRequestNumber { get; set; } - /// Hosting platform type of the repository. - [JsonPropertyName("hostType")] - public string? HostType { get; set; } + /// Backing remote session IDs (most recent first). + [JsonPropertyName("remoteSessionIds")] + public IList RemoteSessionIds { get => field ??= []; set; } - /// Repository identifier derived from the git remote URL. + /// GitHub repository the remote session belongs to. [JsonPropertyName("repository")] - public string? Repository { get; set; } + public RemoteSessionMetadataRepository Repository { get => field ??= new(); set; } - /// Raw host string from the git remote URL. - [JsonPropertyName("repositoryHost")] - public string? RepositoryHost { get; set; } -} + /// Original remote resource identifier (task ID or PR node ID). + [JsonPropertyName("resourceId")] + public string? ResourceId { get; set; } -/// Identity, state location and starting context for a workspace record. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsCreateWorkspaceRequest -{ - /// Starting working-directory context. The record keeps `cwd`, `gitRoot`, `repository`, `hostType`, `branch`, and `clientName`. Other fields, including `repositoryHost`, `headCommit`, and `baseCommit`, are ignored. `hostType` must be `github` or `ado`. - [JsonPropertyName("context")] - public SessionWorkingDirectoryContextWithClient? Context { get; set; } + /// Stable session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// `windows` (any letter case) selects Windows path rules. Any other value selects POSIX path rules. - [JsonPropertyName("convention")] - public string Convention { get; set; } = string.Empty; + /// Deadline (ISO 8601) at which a CLI remote session becomes stale without further heartbeats. + [JsonPropertyName("staleAt")] + public string? StaleAt { get; set; } - /// User-supplied display name for the workspace. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Session creation time as an ISO 8601 timestamp. + [JsonPropertyName("startTime")] + public string StartTime { get; set; } = string.Empty; - /// Session ID the workspace record belongs to. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Server-side task state returned by GitHub. + [JsonPropertyName("state")] + public string? State { get; set; } - /// Directory the session's state is written under when no session filesystem provider is configured. Ignored when a provider is configured; the provider's session state path is used instead. - [JsonPropertyName("sessionStatePath")] - public string SessionStatePath { get; set; } = string.Empty; -} + /// Short summary of the session, when one has been derived. + [JsonPropertyName("summary")] + public string? Summary { get; set; } -/// The workspace record on disk, omitted when the session has none. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsLoadWorkspaceResult -{ - /// The workspace record, as JSON. Omitted when the record does not exist. - [JsonPropertyName("workspaceJson")] - public string? WorkspaceJson { get; set; } + /// Whether the remote task originated from CCA or CLI `--remote`. + [JsonPropertyName("taskType")] + public RemoteSessionMetadataTaskType? TaskType { get; set; } } -/// Where the session's state lives, as a root directory and the session ID under it. +/// `sessions.open` handoff progress update with step, status, and optional message. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsLoadWorkspaceRequest +public sealed class SessionsOpenProgress { - /// Session ID naming the state directory under the sessions home. Rejected when it is absolute or contains a parent component, so it cannot escape the sessions home. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Optional step message. + [JsonPropertyName("message")] + public string? Message { get; set; } - /// Root directory every session's state directory sits under. - [JsonPropertyName("sessionsHome")] - public string SessionsHome { get; set; } = string.Empty; -} + /// Step status. + [JsonPropertyName("status")] + public SessionsOpenProgressStatus Status { get; set; } -/// The merge completed. The record carries the supplied workspace-schema fields, but a stored `fork_count` stays. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsUpdateWorkspaceFieldsResult -{ + /// Handoff step. + [JsonPropertyName("step")] + public SessionsOpenProgressStep Step { get; set; } } -/// Where the session's state lives, plus workspace-schema fields to merge into its workspace record. Stored keys outside the schema are not preserved, and a stored `fork_count` is never replaced. +/// Result of opening a session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsUpdateWorkspaceFieldsRequest +public sealed class SessionOpenResult { - /// Workspace-schema fields to merge into the record, as a JSON object. Fields the object omits keep their stored values, except stored keys outside the schema are not preserved and a stored `fork_count` is never replaced. - [JsonPropertyName("fieldsJson")] - public string FieldsJson { get; set; } = string.Empty; + /// Remote session metadata, present when status is `connected`. + [JsonPropertyName("metadata")] + public RemoteSessionMetadataValue? Metadata { get; set; } - /// Session ID naming the state directory under the sessions home. Rejected when it is absolute or contains a parent component, so it cannot escape the sessions home. + /// Handoff progress steps, present when status is `handed_off`. + [JsonPropertyName("progress")] + public IList? Progress { get; set; } + + /// Remote session ID, present when status is `connected`. + [JsonPropertyName("remoteSessionId")] + public string? RemoteSessionId { get; set; } + + /// Opened session ID. Omitted when status is `not_found`. [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + public string? SessionId { get; set; } - /// Root directory every session's state directory sits under. - [JsonPropertyName("sessionsHome")] - public string SessionsHome { get; set; } = string.Empty; -} + /// Startup prompts queued by user-level hook configs at session creation. Only populated when status is `created`; resumed sessions return an empty array. + [JsonPropertyName("startupPrompts")] + public IList? StartupPrompts { get; set; } -/// Reload all hooks (user, plugin, optionally repo) and apply them to the active session. Call after installing or removing plugins so their hooks take effect immediately. No-op when no active session matches the given sessionId. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionsReloadPluginHooksResult -{ + /// Outcome of the open request. + [JsonPropertyName("status")] + public SessionsOpenStatus Status { get; set; } } -/// Active session ID and an optional flag for deferring repo-level hooks until folder trust. +/// Identifier and optional friendly name assigned to the newly forked session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsReloadPluginHooksRequest +public sealed class SessionsForkResult { - /// When true, skip repo-level hooks. Use before folder trust is confirmed; loadDeferredRepoHooks loads them post-trust. - [JsonPropertyName("deferRepoHooks")] - public bool? DeferRepoHooks { get; set; } + /// Friendly name assigned to the forked session, if any. + [JsonPropertyName("name")] + public string? Name { get; set; } - /// Active session ID to reload hooks for. + /// The new forked session's ID. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Queued repo-level startup prompts and the total hook command count after loading. +/// Source session identifier to fork from, optional event-ID boundary, and optional friendly name for the new session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionLoadDeferredRepoHooksResult +internal sealed class SessionsForkRequest { - /// Total hook command count (user + plugin + repo) loaded for the session by this call. Captured atomically with startupPrompts so callers don't need to read a separate counter. - [JsonPropertyName("hookCount")] - public long HookCount { get; set; } - - /// Repo-level startup prompts queued from repo hook configs. Empty on resume, when no repo configs were pending, or when disableAllHooks is set. - [JsonPropertyName("startupPrompts")] - public IList StartupPrompts { get => field ??= []; set; } -} + /// Optional friendly name to assign to the forked session. + [JsonPropertyName("name")] + public string? Name { get; set; } -/// Active session ID whose deferred repo-level hooks should be loaded. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsLoadDeferredRepoHooksRequest -{ - /// Active session ID whose deferred repo-level hooks should be loaded. + /// Source session ID to fork from. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; -} -/// Replace the manager-wide additional plugins. New session creations and subsequent hook reloads see the new set; already-running sessions keep their existing hook installation until the next reload. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionsSetAdditionalPluginsResult -{ + /// Optional event ID boundary. When provided, the fork includes only events before this ID (exclusive). When omitted, all events are included. + [JsonPropertyName("toEventId")] + public string? ToEventId { get; set; } } -/// Manager-wide additional plugins to register; replaces any previously-configured set. +/// Repository associated with the connected remote session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsSetAdditionalPluginsRequest +public sealed class ConnectedRemoteSessionMetadataRepository { - /// Manager-wide additional plugins to register. Replaces any previously-configured set. Pass an empty array to clear. - [JsonPropertyName("plugins")] - public IList Plugins { get => field ??= []; set; } -} + /// Branch associated with the remote session. + [JsonPropertyName("branch")] + public string Branch { get; set; } = string.Empty; -/// Dynamic-context board entry count, when available. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsGetBoardEntryCountResult -{ - /// Board entry count, when available. - [JsonPropertyName("count")] - public long? Count { get; set; } + /// Repository name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Repository owner or organization login. + [JsonPropertyName("owner")] + public string Owner { get; set; } = string.Empty; } -/// Session ID whose board entry count should be returned. +/// Metadata for a connected remote session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsGetBoardEntryCountRequest +public sealed class ConnectedRemoteSessionMetadata { - /// Session ID whose board entry count should be returned. + /// Neutral SDK discriminator for the connected remote session kind. + [JsonPropertyName("kind")] + public ConnectedRemoteSessionMetadataKind Kind { get; set; } + + /// Last session update time as an ISO 8601 string. + [JsonPropertyName("modifiedTime")] + public DateTimeOffset ModifiedTime { get; set; } + + /// Optional friendly session name. + [JsonPropertyName("name")] + public string? Name { get; set; } + + /// Pull request number associated with the session. + [JsonPropertyName("pullRequestNumber")] + public long? PullRequestNumber { get; set; } + + /// Repository associated with the connected remote session. + [JsonPropertyName("repository")] + public ConnectedRemoteSessionMetadataRepository Repository { get => field ??= new(); set; } + + /// Original remote resource identifier. + [JsonPropertyName("resourceId")] + public string? ResourceId { get; set; } + + /// SDK session ID for the connected remote session. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; -} -/// State of the runtime-managed remote-control singleton. -/// Polymorphic base type discriminated by state. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "state", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(RemoteControlStatusOff), "off")] -[JsonDerivedType(typeof(RemoteControlStatusConnecting), "connecting")] -[JsonDerivedType(typeof(RemoteControlStatusActive), "active")] -[JsonDerivedType(typeof(RemoteControlStatusError), "error")] -public partial class RemoteControlStatus -{ - /// The type discriminator. + /// Remote session staleness deadline as an ISO 8601 string. + [JsonPropertyName("staleAt")] + public DateTimeOffset? StaleAt { get; set; } + + /// Session start time as an ISO 8601 string. + [JsonPropertyName("startTime")] + public DateTimeOffset StartTime { get; set; } + + /// Remote session state returned by the backing service. [JsonPropertyName("state")] - public virtual string State { get; set; } = string.Empty; -} + public string? State { get; set; } + /// Optional session summary. + [JsonPropertyName("summary")] + public string? Summary { get; set; } +} -/// Remote control is not connected. -/// The off variant of . +/// Remote session connection result. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class RemoteControlStatusOff : RemoteControlStatus +public sealed class RemoteSessionConnectionResult { - /// - [JsonIgnore] - public override string State => "off"; + /// Metadata for a connected remote session. + [JsonPropertyName("metadata")] + public ConnectedRemoteSessionMetadata Metadata { get => field ??= new(); set; } + + /// SDK session ID for the connected remote session. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Remote control is in the middle of initial setup. -/// The connecting variant of . +/// Remote session connection parameters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class RemoteControlStatusConnecting : RemoteControlStatus +internal sealed class ConnectRemoteSessionParams { - /// - [JsonIgnore] - public override string State => "connecting"; - - /// Session id the connection is attaching to. - [JsonPropertyName("attachedSessionId")] - public required string AttachedSessionId { get; set; } + /// Session ID to connect to. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Remote control is connected to a local session. -/// The active variant of . +/// Local or remote session metadata entry. Narrow on `isRemote` to access source-specific fields. +/// Data type discriminated by isRemote. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class RemoteControlStatusActive : RemoteControlStatus +public partial class SessionListEntry { - /// - [JsonIgnore] - public override string State => "active"; + /// The boolean discriminator. + [JsonPropertyName("isRemote")] + public bool IsRemote { get; set; } - /// Session id remote control is pointed at. - [JsonPropertyName("attachedSessionId")] - public required string AttachedSessionId { get; set; } + /// Runtime client name that created/last resumed this session. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } - /// True while a read-only/session-sync export is deferred, awaiting the first `user.message` before its MC session exists. Marked internal: this field is excluded from the public SDK surface and is populated only on the CLI in-process path. + /// Pre-resolved working-directory context for session startup. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonInclude] - [JsonPropertyName("awaitingFirstMessage")] - internal bool? AwaitingFirstMessage { get; set; } + [JsonPropertyName("context")] + public SessionContext? Context { get; set; } - /// MC frontend URL for this session, when known. + /// Host-supplied human description of what the session is doing right now ("running tests", "waiting for approval"). Optional in the protocol and absent on hosts that do not publish it, so never rely on it -- it enriches `hostStatus`, it does not replace it. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("frontendUrl")] - public string? FrontendUrl { get; set; } + [JsonPropertyName("hostActivity")] + public string? HostActivity { get; set; } - /// Whether the MC session may steer this session. - [JsonPropertyName("isSteerable")] - public required bool IsSteerable { get; set; } -} + /// Live status as the owning host reports it in its session listing, so a row for a session running elsewhere can show that it is running. Absent for hosts that publish no such status (the cloud task managers), which read as idle. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("hostStatus")] + public RemoteSessionHostStatus? HostStatus { get; set; } -/// The last setup attempt failed. The singleton is otherwise off. -/// The error variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class RemoteControlStatusError : RemoteControlStatus -{ - /// - [JsonIgnore] - public override string State => "error"; + /// True for detached maintenance sessions that should be hidden from normal resume lists. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("isDetached")] + public bool? IsDetached { get; set; } - /// Session id the failing setup attempt targeted, when known. + /// GitHub task ID, when this local session is bound to one. Only present for local sessions exported to remote control. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("attachedSessionId")] - public string? AttachedSessionId { get; set; } + [JsonPropertyName("mcTaskId")] + public string? McTaskId { get; set; } - /// Human-readable error message from the last setup attempt. - [JsonPropertyName("error")] - public required string Error { get; set; } -} + /// Last-modified time of the session's persisted state, as ISO 8601. + [JsonPropertyName("modifiedTime")] + public required string ModifiedTime { get; set; } -/// Wrapper for the singleton's current status. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class RemoteControlStatusResult -{ - /// State of the runtime-managed remote-control singleton. - [JsonPropertyName("status")] - public RemoteControlStatus Status { get => field ??= new(); set; } -} + /// Optional human-friendly name set via /rename. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("name")] + public string? Name { get; set; } -/// Reattach to an existing MC session without creating a new one. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class RemoteControlConfigExistingMcSession -{ - /// Existing MC session ID to reattach to. - [JsonPropertyName("mcSessionId")] - public string McSessionId { get; set; } = string.Empty; + /// Pull request number associated with the session. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("pullRequestNumber")] + public long? PullRequestNumber { get; set; } - /// Existing MC task ID for the reattached session. - [JsonPropertyName("mcTaskId")] - public string McTaskId { get; set; } = string.Empty; -} + /// Backing remote session IDs (most recent first). + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("remoteSessionIds")] + public IList? RemoteSessionIds { get; set; } -/// Configuration for the runtime-managed remote-control singleton. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class RemoteControlConfig -{ - /// Reattach to an existing MC session without creating a new one. - [JsonPropertyName("existingMcSession")] - public RemoteControlConfigExistingMcSession? ExistingMcSession { get; set; } + /// GitHub repository the remote session belongs to. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("repository")] + public RemoteSessionMetadataRepository? Repository { get; set; } - /// Whether the user explicitly requested remote (vs. implicit session-sync). Controls warning surfacing for missing-repo cases. - [JsonPropertyName("explicit")] - public bool Explicit { get; set; } + /// Original remote resource identifier (task ID or PR node ID). + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("resourceId")] + public string? ResourceId { get; set; } - /// Whether remote export should be enabled. - [JsonPropertyName("remote")] - public bool Remote { get; set; } + /// Stable session identifier. + [JsonPropertyName("sessionId")] + public required string SessionId { get; set; } - /// When true, suppresses timeline messages on successful setup. - [JsonPropertyName("silent")] - public bool Silent { get; set; } + /// Deadline (ISO 8601) at which a CLI remote session becomes stale without further heartbeats. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("staleAt")] + public string? StaleAt { get; set; } - /// Whether the MC session may steer the local session (write mode). - [JsonPropertyName("steerable")] - public bool Steerable { get; set; } + /// Session creation time as an ISO 8601 timestamp. + [JsonPropertyName("startTime")] + public required string StartTime { get; set; } - /// Existing Mission Control task ID to attach the exported session to. - [JsonPropertyName("taskId")] - public string? TaskId { get; set; } -} + /// Server-side task state returned by GitHub. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("state")] + public string? State { get; set; } -/// Parameters for attaching the remote-control singleton to a session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsStartRemoteControlRequest -{ - /// Configuration for the runtime-managed remote-control singleton. - [JsonPropertyName("config")] - public RemoteControlConfig Config { get => field ??= new(); set; } + /// Short summary of the session, when one has been derived. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("summary")] + public string? Summary { get; set; } - /// Local session id to attach remote control to. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether the remote task originated from CCA or CLI `--remote`. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("taskType")] + public RemoteSessionMetadataTaskType? TaskType { get; set; } } -/// Outcome of a transferRemoteControl call. +/// Sessions matching the filter, ordered most-recently-modified first. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class RemoteControlTransferResult +public sealed class SessionList { - /// State of the runtime-managed remote-control singleton. - [JsonPropertyName("status")] - public RemoteControlStatus Status { get => field ??= new(); set; } - - /// Whether the rebinding actually happened. - [JsonPropertyName("transferred")] - public bool Transferred { get; set; } + /// Sessions ordered most-recently-modified first. Discriminated by `isRemote`. + [JsonPropertyName("sessions")] + public IList Sessions { get => field ??= []; set; } } -/// Parameters for atomically rebinding the remote-control singleton. +/// Optional filter applied to the returned sessions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsTransferRemoteControlRequest +public sealed class SessionListFilter { - /// When provided, the transfer is rejected unless the singleton currently points at this session id (compare-and-swap semantics to avoid clobbering newer state). - [JsonPropertyName("expectedFromSessionId")] - public string? ExpectedFromSessionId { get; set; } + /// Match sessions whose context.branch equals this value. + [JsonPropertyName("branch")] + public string? Branch { get; set; } - /// Local session id to point remote control at. - [JsonPropertyName("toSessionId")] - public string ToSessionId { get; set; } = string.Empty; + /// Match sessions whose context.cwd equals this value. + [JsonPropertyName("cwd")] + public string? Cwd { get; set; } + + /// Match sessions whose context.gitRoot equals this value. + [JsonPropertyName("gitRoot")] + public string? GitRoot { get; set; } + + /// Match sessions whose context.repository equals this value. + [JsonPropertyName("repository")] + public string? Repository { get; set; } } -/// Patch for the singleton's steering state. +/// Optional source filter, metadata-load limit, and context filter applied to the returned sessions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsSetRemoteControlSteeringRequest +internal sealed class SessionsListRequest { - /// Target steering state. Today only `true` is actionable on the underlying exporter; `false` is reserved for future use. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// Optional filter applied to the returned sessions. + [JsonPropertyName("filter")] + public SessionListFilter? Filter { get; set; } + + /// When true, include detached maintenance sessions. Defaults to false for user-facing session lists. + [JsonPropertyName("includeDetached")] + public bool? IncludeDetached { get; set; } + + /// When provided, only the first N local sessions (sorted by modification time, newest first) load full metadata; remaining sessions return basic info only. Use 0 to return only basic info for every local session. Has no effect on remote entries (which always carry their full shape). + [JsonPropertyName("metadataLimit")] + public long? MetadataLimit { get; set; } + + /// Which session sources to include. Defaults to `local` for backward compatibility. + [JsonPropertyName("source")] + public SessionSource? Source { get; set; } + + /// Only meaningful when `source` includes remote. When true, propagates errors from the remote service instead of silently returning an empty remote list. Defaults to false. + [JsonPropertyName("throwOnError")] + public bool? ThrowOnError { get; set; } } -/// Outcome of a stopRemoteControl call. +/// Persisted local session metadata, including identifiers, timestamps, summary/name, client, context, detached state, and task ID. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class RemoteControlStopResult +public sealed class LocalSessionMetadataValue { - /// State of the runtime-managed remote-control singleton. - [JsonPropertyName("status")] - public RemoteControlStatus Status { get => field ??= new(); set; } + /// Runtime client name that created/last resumed this session. + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } - /// Whether the singleton was actually torn down by this call. - [JsonPropertyName("stopped")] - public bool Stopped { get; set; } + /// Pre-resolved working-directory context for session startup. + [JsonPropertyName("context")] + public SessionContext? Context { get; set; } + + /// True for detached maintenance sessions that should be hidden from normal resume lists. + [JsonPropertyName("isDetached")] + public bool? IsDetached { get; set; } + + /// Always false for local sessions. + [JsonPropertyName("isRemote")] + public bool IsRemote { get; set; } + + /// GitHub task ID, when this local session is bound to one. Only present for local sessions exported to remote control. + [JsonPropertyName("mcTaskId")] + public string? McTaskId { get; set; } + + /// Last-modified time of the session's persisted state, as ISO 8601. + [JsonPropertyName("modifiedTime")] + public string ModifiedTime { get; set; } = string.Empty; + + /// Optional human-friendly name set via /rename. + [JsonPropertyName("name")] + public string? Name { get; set; } + + /// Stable session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Session creation time as an ISO 8601 timestamp. + [JsonPropertyName("startTime")] + public string StartTime { get; set; } = string.Empty; + + /// Short summary of the session, when one has been derived. + [JsonPropertyName("summary")] + public string? Summary { get; set; } } -/// RPC data type for SessionsStopRemoteControl operations. +/// Persisted local session metadata when the session exists. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionsStopRemoteControlRequest +internal sealed class SessionsGetMetadataResult { - /// When provided, the stop is rejected unless the singleton currently points at this session id (compare-and-swap semantics). - [JsonPropertyName("expectedSessionId")] - public string? ExpectedSessionId { get; set; } - - /// When true, the singleton is unconditionally torn down regardless of `expectedSessionId`. Use during shutdown or explicit `/remote off`. - [JsonPropertyName("force")] - public bool? Force { get; set; } + /// Local session metadata, omitted when the session does not exist. + [JsonPropertyName("session")] + public LocalSessionMetadataValue? Session { get; set; } } -/// Params to attach or detach an in-process ExtensionController delegate. +/// Session ID whose persisted metadata should be read. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ConfigureSessionExtensionsParams +internal sealed class SessionsGetMetadataRequest { - /// Session to attach the extension controller delegate to. + /// Session ID to inspect. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Outcome of an agentRegistry.spawn call. -/// Polymorphic base type discriminated by kind. +/// Client metadata outcome for one requested local session. +/// Polymorphic base type discriminated by status. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", + TypeDiscriminatorPropertyName = "status", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(AgentRegistrySpawnResultSpawned), "spawned")] -[JsonDerivedType(typeof(AgentRegistrySpawnResultSpawnError), "spawn-error")] -[JsonDerivedType(typeof(AgentRegistrySpawnResultRegistryTimeout), "registry-timeout")] -[JsonDerivedType(typeof(AgentRegistrySpawnResultValidationError), "validation-error")] -public partial class AgentRegistrySpawnResult +[JsonDerivedType(typeof(SessionsClientMetadataEntryOk), "ok")] +[JsonDerivedType(typeof(SessionsClientMetadataEntryNotFound), "notFound")] +[JsonDerivedType(typeof(SessionsClientMetadataEntryCorrupt), "corrupt")] +[JsonDerivedType(typeof(SessionsClientMetadataEntryUnsupportedVersion), "unsupportedVersion")] +[JsonDerivedType(typeof(SessionsClientMetadataEntryUnavailable), "unavailable")] +public partial class SessionsClientMetadataEntry { /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; + [JsonPropertyName("status")] + public virtual string Status { get; set; } = string.Empty; } -/// Full registry entry for the spawned child. Lets the controller call `handleLiveTargetSelected(entry)` directly without re-reading the registry (avoids a TOCTOU window). +/// The ok variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AgentRegistryLiveTargetEntry +public partial class SessionsClientMetadataEntryOk : SessionsClientMetadataEntry { - /// Kind of attention required when status === "attention". Meaningful only when status === "attention". - [JsonPropertyName("attentionKind")] - public AgentRegistryLiveTargetEntryAttentionKind? AttentionKind { get; set; } - - /// Git branch of the session (when known). - [JsonPropertyName("branch")] - public string? Branch { get; set; } - - /// Copilot CLI version that wrote the entry. - [JsonPropertyName("copilotVersion")] - public string CopilotVersion { get; set; } = string.Empty; - - /// Working directory of the session (when known). - [JsonPropertyName("cwd")] - public string? Cwd { get; set; } - - /// Bind host for the entry's JSON-RPC server. - [JsonPropertyName("host")] - public string Host { get; set; } = string.Empty; - - /// Process kind tag for the registry entry. - [JsonPropertyName("kind")] - public AgentRegistryLiveTargetEntryKind Kind { get; set; } - - /// Wall-clock milliseconds since the watcher last observed this entry (heartbeat freshness). - [JsonPropertyName("lastSeenMs")] - public long LastSeenMs { get; set; } - - /// How the most recent turn ended (clean vs aborted). Lets the renderer distinguish done from done_cancelled. - [JsonPropertyName("lastTerminalEvent")] - public AgentRegistryLiveTargetEntryLastTerminalEvent? LastTerminalEvent { get; set; } - - /// Model identifier currently selected for the session. - [JsonPropertyName("model")] - public string? Model { get; set; } - - /// Operating-system pid of the process owning this entry. - [JsonPropertyName("pid")] - public long Pid { get; set; } - - /// TCP port the entry's JSON-RPC server is listening on. - [JsonPropertyName("port")] - public long Port { get; set; } + /// + [JsonIgnore] + public override string Status => "ok"; - /// Registry entry schema version (1 = ui-server, 2 = managed-server). - [JsonPropertyName("schemaVersion")] - public long SchemaVersion { get; set; } + /// Validated client metadata, possibly empty or projected to requested keys. + [JsonPropertyName("metadata")] + public required IDictionary Metadata { get; set; } - /// Session ID of the foreground session for this entry. + /// Requested session ID. [JsonPropertyName("sessionId")] - public string? SessionId { get; set; } - - /// Friendly session name (when set). - [JsonPropertyName("sessionName")] - public string? SessionName { get; set; } - - /// ISO 8601 timestamp captured at registration. - [JsonPropertyName("startedAt")] - public string StartedAt { get; set; } = string.Empty; - - /// Coarse lifecycle status of the foreground session. - [JsonPropertyName("status")] - public AgentRegistryLiveTargetEntryStatus? Status { get; set; } - - /// Monotonic per-publisher revision counter incremented on every status update. Lets watchers detect transient flips. - [JsonPropertyName("statusRevision")] - public long? StatusRevision { get; set; } - - /// Connection token (null when the target is unauthenticated). - [JsonInclude] - [JsonPropertyName("token")] - internal string? Token { get; set; } -} - -/// Canonical process-log discovery outcome; populated from spawnLiveTarget. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AgentRegistryLogCapture -{ - /// Whether a canonical process log was discovered for this managed spawn. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } - - /// Why no canonical process log could be opened for this managed spawn (set only when enabled is false). - [JsonPropertyName("openError")] - public string? OpenError { get; set; } - - /// Categorized reason no canonical process log could be opened (set only when enabled is false). - [JsonPropertyName("openErrorReason")] - public AgentRegistryLogCaptureOpenErrorReason? OpenErrorReason { get; set; } - - /// Absolute path to the managed spawn's process-<timestamp>-<pid>.log file (only set when enabled). - [JsonPropertyName("path")] - public string? Path { get; set; } + public required string SessionId { get; set; } } -/// Managed-server child was spawned and registered successfully. -/// The spawned variant of . +/// The notFound variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AgentRegistrySpawnResultSpawned : AgentRegistrySpawnResult +public partial class SessionsClientMetadataEntryNotFound : SessionsClientMetadataEntry { /// [JsonIgnore] - public override string Kind => "spawned"; - - /// Full registry entry for the spawned child. Lets the controller call `handleLiveTargetSelected(entry)` directly without re-reading the registry (avoids a TOCTOU window). - [JsonPropertyName("entry")] - public required AgentRegistryLiveTargetEntry Entry { get; set; } - - /// If the delegate attempted to send the initial prompt and failed, the categorized error message. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("initialPromptError")] - public string? InitialPromptError { get; set; } - - /// Whether the delegate already sent the initial prompt. Always omitted in the current wiring: the controller sends the prompt post-attach via the standard LocalRpcSession.send path. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("initialPromptSent")] - public bool? InitialPromptSent { get; set; } + public override string Status => "notFound"; - /// Per-spawn log-capture outcome; populated from spawnLiveTarget. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("logCapture")] - public AgentRegistryLogCapture? LogCapture { get; set; } + /// Requested session ID. + [JsonPropertyName("sessionId")] + public required string SessionId { get; set; } } -/// `child_process.spawn` itself failed before the child entered the registry. -/// The spawn-error variant of . +/// The corrupt variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AgentRegistrySpawnResultSpawnError : AgentRegistrySpawnResult +public partial class SessionsClientMetadataEntryCorrupt : SessionsClientMetadataEntry { /// [JsonIgnore] - public override string Kind => "spawn-error"; - - /// Underlying errno code (e.g. ENOENT, EACCES) when available. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("code")] - public string? Code { get; set; } + public override string Status => "corrupt"; - /// Human-readable error message. - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Requested session ID. + [JsonPropertyName("sessionId")] + public required string SessionId { get; set; } } -/// Spawn succeeded but the child did not publish a matching managed-server entry within the timeout. -/// The registry-timeout variant of . +/// The unsupportedVersion variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AgentRegistrySpawnResultRegistryTimeout : AgentRegistrySpawnResult +public partial class SessionsClientMetadataEntryUnsupportedVersion : SessionsClientMetadataEntry { /// [JsonIgnore] - public override string Kind => "registry-timeout"; - - /// Process ID of the orphaned child (so the caller can offer 'kill the pid' guidance). - [JsonPropertyName("childPid")] - public required long ChildPid { get; set; } + public override string Status => "unsupportedVersion"; - /// Per-spawn log-capture outcome; populated from spawnLiveTarget. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("logCapture")] - public AgentRegistryLogCapture? LogCapture { get; set; } + /// Requested session ID. + [JsonPropertyName("sessionId")] + public required string SessionId { get; set; } } -/// Synchronous pre-validation rejected the spawn request. -/// The validation-error variant of . +/// The unavailable variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AgentRegistrySpawnResultValidationError : AgentRegistrySpawnResult +public partial class SessionsClientMetadataEntryUnavailable : SessionsClientMetadataEntry { /// [JsonIgnore] - public override string Kind => "validation-error"; + public override string Status => "unavailable"; - /// Which parameter field was invalid. Omitted when the rejection is not field-specific. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("field")] - public AgentRegistrySpawnValidationErrorField? Field { get; set; } + /// Filesystem or provider error code. Clients should not assume every provider uses operating-system error codes. + [JsonPropertyName("code")] + public required string Code { get; set; } - /// Human-readable explanation; safe to surface in the UI banner. Never logged to unrestricted telemetry. + /// Human-readable diagnostic message. Not stable for programmatic matching. [JsonPropertyName("message")] public required string Message { get; set; } - /// Categorized reason for the rejection. Low-cardinality enum so telemetry can aggregate by reason without leaking raw paths or agent/model names. - [JsonPropertyName("reason")] - public required AgentRegistrySpawnValidationErrorReason Reason { get; set; } + /// Requested session ID. + [JsonPropertyName("sessionId")] + public required string SessionId { get; set; } } -/// Inputs to spawn a managed-server child via the controller's spawn delegate. +/// Bounded batch request for client-owned metadata from persisted local sessions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AgentRegistrySpawnRequest +internal sealed class SessionsGetClientMetadataRequest { - /// Custom or built-in agent name (e.g. 'explore'). When omitted, the child uses its own default. - [JsonPropertyName("agentName")] - public string? AgentName { get; set; } + /// Case-sensitive keys to project from each valid bag. Each key must be non-empty, at most 256 UTF-8 bytes, and outside the reserved `copilot/` and `github/` namespaces. Omit to return every entry. + [JsonPropertyName("keys")] + public IList? Keys { get; set; } - /// Working directory for the spawned child (must be an existing directory). - [JsonPropertyName("cwd")] - public string Cwd { get; set; } = string.Empty; + /// Session IDs to inspect. Results preserve this order. + [JsonPropertyName("sessionIds")] + public IList SessionIds { get => field ??= []; set; } +} - /// Optional first user message. Forwarded to the caller (the CLI's spawn wrapper sends it post-attach via the standard LocalRpcSession.send path). - [JsonPropertyName("initialPrompt")] - public string? InitialPrompt { get; set; } +/// Batch of session events returned by a read, with cursor and continuation metadata. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class EventsReadResult +{ + /// Opaque cursor for the next read. Pass back unchanged in the next read.cursor to continue from where this read left off. Always present, even when no events were returned. For a backward read this cursor pages toward OLDER events; keep passing `direction: backward` with it (the cursor is also self-describing, so backward paging continues correctly). + [JsonPropertyName("cursor")] + public string Cursor { get; set; } = string.Empty; - /// Model identifier to apply to the new session. - [JsonPropertyName("model")] - public string? Model { get; set; } + /// Cursor status: 'ok' means the cursor was applied successfully. For session.eventLog.read, 'expired' means the cursor referred to an event that no longer exists in active history and the read fell back to a boundary of the remaining history: the beginning for a forward read or the newest window for a backward read. That fallback may overlap already rendered events, so active-session consumers should reset, rebase, or deduplicate before continuing. sessions.readPersistedEvents has stricter snapshot semantics: 'expired' returns an empty terminal page and never switches to a replacement journal generation. Other persisted-read I/O failures are RPC errors with diagnostics, not cursor expiry. + [JsonPropertyName("cursorStatus")] + public EventsCursorStatus CursorStatus { get; set; } - /// Friendly session name. Must satisfy validateSessionName: non-empty, no leading/trailing whitespace, <=100 chars, no control chars, no double quotes. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Session events for this batch, merged into a single stream in creation order: durable (persisted) events and ephemeral events interleave exactly as they were emitted. Set `includeEphemeral: false` to receive only durable events. Ephemeral events are never replayable once pruned from the in-memory ring, so a consumer that needs them should keep reading with a non-zero `waitMs`. For a backward (tail-first) read, the returned window contains persisted events only, still in chronological (oldest-to-newest) append order. + [JsonPropertyName("events")] + public IList Events { get => field ??= []; set; } - /// Permission posture for the new session. 'yolo' requires the controller-local session to currently be in allow-all mode. - [JsonPropertyName("permissionMode")] - public AgentRegistrySpawnPermissionMode? PermissionMode { get; set; } + /// True when more events are available in the read's direction. For a backward read, true means older persisted events remain before the returned window. A persisted-event page may contain fewer than `max` events because of its byte budget while still reporting hasMore true; continue according to this flag rather than the event count. + [JsonPropertyName("hasMore")] + public bool HasMore { get; set; } } -/// Feature availability. +/// Pagination options for reading an inactive or active local session's persisted event journal. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorDiscoveryCapabilities +internal sealed class SessionsReadPersistedEventsRequest { - /// API version. - [JsonPropertyName("apiVersion")] - public long ApiVersion { get; set; } + /// Opaque, process-local, single-use cursor returned by the previous persisted-event read. Omit on the first call and issue continuations sequentially; reusing the same cursor returns an expired terminal page. + [JsonPropertyName("cursor")] + public string? Cursor { get; set; } - /// Availability. - [JsonPropertyName("availability")] - public ConnectorDiscoveryAvailability Availability { get; set; } + /// Direction to page through persisted history. Forward starts at the beginning; backward starts with the newest events. Events in each page remain chronological. This selects the initial read only; a continuation always uses the direction bound into its cursor. + [JsonPropertyName("direction")] + public EventsReadDirection? Direction { get; set; } - /// Whether results are cached. - [JsonPropertyName("conditionalCache")] - public bool ConditionalCache { get; set; } + /// Maximum number of events to return in this batch (1–1000, default 200). Pages may contain fewer events to keep the serialized event array within a soft 1 MiB budget including resolved binary assets; one oversized event is returned alone to guarantee progress. + [JsonPropertyName("max")] + public long? Max { get; set; } - /// Whether accounts are selected by opaque ID. - [JsonPropertyName("opaqueAccountSelection")] - public bool OpaqueAccountSelection { get; set; } + /// Session ID whose persisted event journal should be read. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Account metadata. +/// Recent local session IDs that contain user-visible history. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorDiscoveryAuthInfo +internal sealed class SessionsListNonEmptySessionIdsResult { - /// Host. - [JsonPropertyName("host")] - public string Host { get; set; } = string.Empty; - - /// Login. - [JsonPropertyName("login")] - public string Login { get; set; } = string.Empty; - - /// Authentication type. - [JsonPropertyName("type")] - public AuthInfoType Type { get; set; } + /// Session IDs ordered newest-first. + [JsonPropertyName("sessionIds")] + public IList SessionIds { get => field ??= []; set; } } -/// Eligible account. +/// Limit for non-empty local session IDs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorDiscoveryAccount +internal sealed class SessionsListNonEmptySessionIdsRequest { - /// Opaque account ID. - [JsonPropertyName("accountId")] - public string AccountId { get; set; } = string.Empty; - - /// Account metadata. - [JsonPropertyName("authInfo")] - public ConnectorDiscoveryAuthInfo AuthInfo { get => field ??= new(); set; } + /// Maximum number of session IDs to return. + [JsonPropertyName("limit")] + public long? Limit { get; set; } } -/// Eligible accounts. +/// ID of the local session bound to the given GitHub task, or omitted when none. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorDiscoveryAccountList +public sealed class SessionsFindByTaskIDResult { - /// Eligible accounts. - [JsonPropertyName("accounts")] - public IList Accounts { get => field ??= []; set; } - - /// Availability. - [JsonPropertyName("availability")] - public ConnectorDiscoveryAvailability Availability { get; set; } + /// Omitted when no local session is bound to that GitHub task. + [JsonPropertyName("sessionId")] + public string? SessionId { get; set; } } -/// Entry. +/// GitHub task ID to look up. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorDiscoveryCatalogEntry +internal sealed class SessionsFindByTaskIDRequest { - /// Description. - [JsonPropertyName("description")] - public string? Description { get; set; } - - /// Display name. - [JsonPropertyName("displayName")] - public string DisplayName { get; set; } = string.Empty; - - /// Logo. - [JsonPropertyName("logo")] - public string? Logo { get; set; } - - /// Name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - - /// Release tag. - [JsonPropertyName("releaseTag")] - public string? ReleaseTag { get; set; } - - /// Status. - [JsonPropertyName("status")] - public ConnectorCatalogStatus Status { get; set; } - - /// Tier. - [JsonPropertyName("tier")] - public string? Tier { get; set; } + /// GitHub task ID to look up. + [JsonPropertyName("taskId")] + public string TaskId { get; set; } = string.Empty; } -/// Entries for the selected account. +/// Session ID matching the prefix, omitted when no unique match exists. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorDiscoveryCatalogResult +public sealed class SessionsFindByPrefixResult { - /// Opaque account ID. - [JsonPropertyName("accountId")] - public string AccountId { get; set; } = string.Empty; - - /// Entries. - [JsonPropertyName("connectors")] - public IList Connectors { get => field ??= []; set; } - - /// Refresh time in Unix epoch milliseconds. - [JsonPropertyName("refreshedAtMs")] - public long RefreshedAtMs { get; set; } - - /// Revision. - [JsonPropertyName("revision")] - public long Revision { get; set; } + /// Omitted when no unique session matches the prefix (no match or ambiguous). + [JsonPropertyName("sessionId")] + public string? SessionId { get; set; } } -/// Selected account. +/// UUID prefix to resolve to a unique session ID. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ConnectorDiscoveryAccountRequest +internal sealed class SessionsFindByPrefixRequest { - /// Opaque account ID. - [RegularExpression("^\\S+$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(2048)] - [JsonPropertyName("accountId")] - public string AccountId { get; set; } = string.Empty; + /// UUID prefix (>=7 hex chars, <36 chars). Returns the unique session ID, or undefined when there is no match or the prefix matches multiple sessions. + [JsonPropertyName("prefix")] + public string Prefix { get; set; } = string.Empty; } -/// Identifies the target session. +/// Most-relevant session ID for the supplied context, or omitted when no sessions exist. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSuspendRequest +public sealed class SessionsGetLastForContextResult { - /// Target session identifier. + /// Most-relevant session ID for the supplied context, or omitted when no sessions exist. [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + public string? SessionId { get; set; } } -/// Result of sending a user message. +/// Optional working-directory context used to score session relevance. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SendResult +internal sealed class SessionsGetLastForContextRequest { - /// Unique identifier assigned to the message. - [JsonPropertyName("messageId")] - public string MessageId { get; set; } = string.Empty; + /// Optional working-directory context used to score session relevance. When omitted the most-recently-modified session wins. + [JsonPropertyName("context")] + public SessionContext? Context { get; set; } } -/// Provider-native structured output format. JSON Schema is forwarded without rewriting or validating the schema or the generated output. -/// Polymorphic base type discriminated by type. +/// Absolute path to the session's events.jsonl file on disk. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "type", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(ResponseFormatJsonSchema), "json_schema")] -public partial class ResponseFormat +internal sealed class SessionsGetEventFilePathResult { - /// The type discriminator. - [JsonPropertyName("type")] - public virtual string Type { get; set; } = string.Empty; + /// Absolute path to the session's events.jsonl file. + [JsonPropertyName("filePath")] + public string FilePath { get; set; } = string.Empty; } - -/// A JSON Schema output contract. OpenAI receives the name, description, schema and strict setting; Anthropic receives the schema in output_config.format and always uses its native strict enforcement. +/// Session ID whose event-log file path to compute. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class JsonSchemaResponseFormat +internal sealed class SessionsGetEventFilePathRequest { - /// Optional description passed to OpenAI providers. - [JsonPropertyName("description")] - public string? Description { get; set; } + /// Session ID whose event-log file path to compute. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Name of the output schema, subject to the provider's naming restrictions. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; +/// Map of sessionId -> on-disk size in bytes for each session's workspace directory. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionSizes +{ + /// Map of sessionId -> on-disk size in bytes for the session's workspace directory. + [JsonPropertyName("sizes")] + public IDictionary Sizes { get => field ??= new Dictionary(); set; } +} - /// JSON Schema passed unchanged to the inference provider. Schemas larger than 32 MiB when JSON-encoded are rejected before admission, using the runtime's existing request-size ceiling. This is not a guarantee that the entire model request fits. Supported keywords and schema restrictions are determined by the provider. - [JsonPropertyName("schema")] - public JsonElement Schema { get; set; } +/// Session IDs from the input set that are currently in use by another process. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionsCheckInUseResult +{ + /// Session IDs from the input set that are currently held by another running process via an alive lock file. + [JsonPropertyName("inUse")] + public IList InUse { get => field ??= []; set; } +} - /// Optional strict enforcement setting for OpenAI providers. Omitted uses the provider default. Anthropic always enforces its supported schema subset. - [JsonPropertyName("strict")] - public bool? Strict { get; set; } +/// Session IDs to test for live in-use locks. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionsCheckInUseRequest +{ + /// Session IDs to test for live in-use locks. + [JsonPropertyName("sessionIds")] + public IList SessionIds { get => field ??= []; set; } } -/// The json_schema variant of . +/// The session's persisted remote-steerable flag, or omitted when no value has been persisted. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ResponseFormatJsonSchema : ResponseFormat +internal sealed class SessionsGetPersistedRemoteSteerableResult { - /// - [JsonIgnore] - public override string Type => "json_schema"; + /// The session's persisted remote-steerable flag if recorded; omitted when no value has been persisted. + [JsonPropertyName("remoteSteerable")] + public bool? RemoteSteerable { get; set; } +} - /// JSON Schema and provider options for the turn's output. - [JsonPropertyName("jsonSchema")] - public required JsonSchemaResponseFormat JsonSchema { get; set; } +/// Session ID to look up the persisted remote-steerable flag for. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionsGetPersistedRemoteSteerableRequest +{ + /// Session ID to look up the persisted remote-steerable flag for. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Parameters for sending a user message to the session. +/// Closes a session: emits shutdown, flushes pending events to disk, releases the in-use lock, disposes the active session. Idempotent: succeeds even if the session is not currently active. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SendRequest +public sealed class SessionsCloseResult { - /// The UI mode the agent was in when this message was sent. Defaults to the session's current mode. - [JsonPropertyName("agentMode")] - public SendAgentMode? AgentMode { get; set; } +} - /// Optional attachments (files, directories, selections, blobs, GitHub references) to include with the message. - [JsonPropertyName("attachments")] - public IList? Attachments { get; set; } +/// Session ID to close. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionsCloseRequest +{ + /// Session ID to close. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// If false, this message will not trigger a Premium Request Unit charge. User messages default to billable. - [JsonPropertyName("billable")] - public bool? Billable { get; set; } +/// Map of sessionId -> bytes freed by removing the session's workspace directory. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionBulkDeleteResult +{ + /// Map of sessionId -> bytes freed by removing the session's workspace directory. Sessions whose deletion failed are omitted from this map (failures are logged on the server but not surfaced per-id; check the map for absent IDs to detect them). + [JsonPropertyName("freedBytes")] + public IDictionary FreedBytes { get => field ??= new Dictionary(); set; } +} - /// If provided, this is shown in the timeline instead of `prompt`. - [JsonPropertyName("displayPrompt")] - public string? DisplayPrompt { get; set; } +/// Session IDs to close, deactivate, and delete from disk. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionsBulkDeleteRequest +{ + /// Session IDs to close, deactivate, and delete from disk. + [JsonPropertyName("sessionIds")] + public IList SessionIds { get => field ??= []; set; } +} - /// How to deliver the message. `enqueue` (default) appends to the message queue. `immediate` interjects during an in-progress turn. - [JsonPropertyName("mode")] - public SendMode? Mode { get; set; } +/// Session ID to delete from disk. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionsDeleteRequest +{ + /// Session ID to delete. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// If true, adds the message to the front of the queue instead of the end. - [JsonPropertyName("prepend")] - public bool? Prepend { get; set; } + /// Internal resolved session directory path to delete. + [JsonPropertyName("sessionPath")] + public string? SessionPath { get; set; } +} - /// The user message text. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; +/// Outcome of the prune operation: deleted IDs, dry-run candidates, skipped IDs, total bytes freed, and the dry-run flag. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionPruneResult +{ + /// Session IDs that would be deleted in dry-run mode (always empty otherwise). + [JsonPropertyName("candidates")] + public IList Candidates { get => field ??= []; set; } - /// Custom HTTP headers to include in outbound model requests for this turn. Merged with session-level provider headers; per-turn headers augment and overwrite session-level headers with the same key. - [JsonPropertyName("requestHeaders")] - public IDictionary? RequestHeaders { get; set; } + /// Session IDs that were deleted (always empty in dry-run mode). + [JsonPropertyName("deleted")] + public IList Deleted { get => field ??= []; set; } - /// If set, the request will fail if the named tool is not available when this message is among the user messages at the start of the current exchange. - [JsonPropertyName("requiredTool")] - public string? RequiredTool { get; set; } + /// True when no deletions were actually performed. + [JsonPropertyName("dryRun")] + public bool DryRun { get; set; } - /// Provider-native output format for this turn, including all tool-call iterations. Not inherited by later turns or subagents. Ordinary steering inherits the active format; specifying responseFormat with mode: immediate is an error, even while idle. Returned assistant content remains text; the runtime does not parse or validate it. Unsupported models or schemas produce provider errors. - [JsonPropertyName("responseFormat")] - public ResponseFormat? ResponseFormat { get; set; } + /// Total bytes freed (actual when not dry-run, projected when dry-run). + [JsonPropertyName("freedBytes")] + public long FreedBytes { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Session IDs that were skipped (e.g., named sessions). + [JsonPropertyName("skipped")] + public IList Skipped { get => field ??= []; set; } +} - /// Optional provenance tag copied to the resulting user.message event. Must be `user`, `system`, `command-<command-id>` for command-originated messages, `schedule-<numeric-id>` for scheduled prompts, or `agent-<agent-id>` for prompts sent by another agent. - [RegularExpression("^(user|system|command-.*|schedule-\\d+|agent-.+)$")] - [JsonInclude] - [JsonPropertyName("source")] - internal string? Source { get; set; } +/// Age threshold and optional flags controlling which old sessions are pruned (or simulated when dryRun is true). +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionsPruneOldRequest +{ + /// When true, only report what would be deleted without performing any deletion. + [JsonPropertyName("dryRun")] + public bool? DryRun { get; set; } - /// W3C Trace Context traceparent header for distributed tracing of this agent turn. - [JsonPropertyName("traceparent")] - public string? Traceparent { get; set; } + /// Session IDs that should never be considered for pruning. + [JsonPropertyName("excludeSessionIds")] + public IList? ExcludeSessionIds { get; set; } - /// W3C Trace Context tracestate header for distributed tracing. - [JsonPropertyName("tracestate")] - public string? Tracestate { get; set; } + /// When true, named sessions (set via /rename) are also eligible for pruning. + [JsonPropertyName("includeNamed")] + public bool? IncludeNamed { get; set; } - /// If true, await completion of the agentic loop for this message before returning. Defaults to false (fire-and-forget). When true, the result still contains the same `messageId`; the caller can rely on the agent having processed the message before the call resolves. Transport-dependent tail semantics: on a LOCAL (in-process) session the wait additionally blocks until the completed turn's event tail has been dispatched to this session's in-process subscribers, so a subsequent read of subscriber state already reflects the turn; on a REMOTE session the wait resolves once the loop completes and mirrored delivery follows over the wire. Callers that need the stronger local guarantee on remote sessions should await the event stream explicitly. - [JsonPropertyName("wait")] - public bool? Wait { get; set; } + /// Delete sessions whose modifiedTime is at least this many days old. + [JsonPropertyName("olderThanDays")] + public long OlderThanDays { get; set; } } -/// Result of sending zero or more user messages. +/// Flush a session's pending events to disk. No-op when no writer exists for the session (e.g., already closed). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SendMessagesResult +public sealed class SessionsSaveResult { - /// Unique identifiers assigned to the messages, one per provided message in order. For a batch that starts a run, assistant messages use the final ID as originatingMessageId throughout that run, including tool iterations and stop-hook corrections. Immediate steering does not replace the active run's origin. Empty when no messages were provided; that run has no originatingMessageId. - [JsonPropertyName("messageIds")] - public IList MessageIds { get => field ??= []; set; } } -/// A single user message to append to the session as part of a `session.sendMessages` turn. +/// Session ID whose pending events should be flushed to disk. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SendMessageItem +internal sealed class SessionsSaveRequest { - /// Optional attachments (files, directories, selections, blobs, GitHub references) to include with this message. - [JsonPropertyName("attachments")] - public IList? Attachments { get; set; } - - /// If false, this message will not trigger a Premium Request Unit charge. User messages default to billable. - [JsonInclude] - [JsonPropertyName("billable")] - internal bool? Billable { get; set; } + /// Session ID whose pending events should be flushed to disk. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// If provided, this is shown in the timeline instead of `prompt`. - [JsonPropertyName("displayPrompt")] - public string? DisplayPrompt { get; set; } +/// Release the in-use lock held by this process for the given session. No-op when this process does not currently hold a lock for the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionsReleaseLockResult +{ +} - /// The user message text. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; +/// Session ID whose in-use lock should be released. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionsReleaseLockRequest +{ + /// Session ID whose in-use lock should be released. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// If set, the request will fail if the named tool is not available when this message is among the user messages at the start of the current exchange. - [JsonPropertyName("requiredTool")] - public string? RequiredTool { get; set; } +/// The enriched metadata records, with summary and context fields backfilled where available. Sessions confirmed empty and unnamed are omitted. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionEnrichMetadataResult +{ + /// Enriched records, with summary and context backfilled. Sessions confirmed empty and unnamed may be omitted. + [JsonPropertyName("sessions")] + public IList Sessions { get => field ??= []; set; } +} - /// Optional provenance tag copied to the resulting user.message event. Must be `user`, `system`, `command-<command-id>` for command-originated messages, `schedule-<numeric-id>` for scheduled prompts, or `agent-<agent-id>` for prompts sent by another agent. - [RegularExpression("^(user|system|command-.*|schedule-\\d+|agent-.+)$")] - [JsonInclude] - [JsonPropertyName("source")] - internal string? Source { get; set; } +/// Session metadata records to enrich with summary and context information. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionsEnrichMetadataRequest +{ + /// Session metadata records to enrich. Records that already have summary and context are returned unchanged. + [JsonPropertyName("sessions")] + public IList Sessions { get => field ??= []; set; } } -/// Parameters for sending zero or more user messages to the session in a single turn. Remote-backed (Mission Control) sessions do not support this method and will return an error. +/// The workspace record that was written. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SendMessagesRequest +internal sealed class SessionsCreateWorkspaceResult { - /// The UI mode the agent was in when these messages were sent. Defaults to the session's current mode. - [JsonPropertyName("agentMode")] - public SendAgentMode? AgentMode { get; set; } + /// The created workspace record, as JSON. + [JsonPropertyName("workspaceJson")] + public string WorkspaceJson { get; set; } = string.Empty; +} - /// The user messages to append to the conversation, in order, before running one agent loop. When the batch starts a run, its final message is the primary initiating message; earlier messages provide context, not separate runs or replies. May be empty, in which case a single turn runs over the existing history with no new user message or originatingMessageId. - [JsonPropertyName("messages")] - public IList Messages { get => field ??= []; set; } +/// A working-directory context together with the client that produced it. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionWorkingDirectoryContextWithClient +{ + /// Merge-base commit SHA. + [JsonPropertyName("baseCommit")] + public string? BaseCommit { get; set; } - /// How to deliver the messages. `enqueue` (default) appends to the message queue. `immediate` interjects during an in-progress turn. - [JsonPropertyName("mode")] - public SendMode? Mode { get; set; } + /// Current git branch name. + [JsonPropertyName("branch")] + public string? Branch { get; set; } - /// If true, adds the messages to the front of the queue instead of the end. - [JsonPropertyName("prepend")] - public bool? Prepend { get; set; } + /// Name of the client that created the session. + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } - /// Custom HTTP headers to include in outbound model requests for this turn. Merged with session-level provider headers; per-turn headers augment and overwrite session-level headers with the same key. - [JsonPropertyName("requestHeaders")] - public IDictionary? RequestHeaders { get; set; } + /// Current working directory path. + [JsonPropertyName("cwd")] + public string Cwd { get; set; } = string.Empty; - /// Provider-native output format for the whole turn, including an empty message batch and all tool-call iterations. Not inherited by later turns or subagents. Ordinary steering inherits the active format; specifying responseFormat with mode: immediate is an error, even while idle. Returned assistant content remains text; the runtime does not parse or validate it. Unsupported models or schemas produce provider errors. - [JsonPropertyName("responseFormat")] - public ResponseFormat? ResponseFormat { get; set; } + /// Root directory of the git repository. + [JsonPropertyName("gitRoot")] + public string? GitRoot { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Head commit of the current git branch. + [JsonPropertyName("headCommit")] + public string? HeadCommit { get; set; } - /// W3C Trace Context traceparent header for distributed tracing of this agent turn. - [JsonPropertyName("traceparent")] - public string? Traceparent { get; set; } + /// Hosting platform type of the repository. + [JsonPropertyName("hostType")] + public string? HostType { get; set; } - /// W3C Trace Context tracestate header for distributed tracing. - [JsonPropertyName("tracestate")] - public string? Tracestate { get; set; } + /// Repository identifier derived from the git remote URL. + [JsonPropertyName("repository")] + public string? Repository { get; set; } - /// If true, await completion of the agentic loop for this turn before returning. Defaults to false (fire-and-forget). When true, the result still contains the same `messageIds`; the caller can rely on the agent having processed the messages before the call resolves. Transport-dependent tail semantics: on a LOCAL (in-process) session the wait additionally blocks until the completed turn's event tail has been dispatched to this session's in-process subscribers, so a subsequent read of subscriber state already reflects the turn; on a REMOTE session the wait resolves once the loop completes and mirrored delivery follows over the wire. Callers that need the stronger local guarantee on remote sessions should await the event stream explicitly. - [JsonPropertyName("wait")] - public bool? Wait { get; set; } + /// Raw host string from the git remote URL. + [JsonPropertyName("repositoryHost")] + public string? RepositoryHost { get; set; } } -/// Internal request for sending a system notification. +/// Identity, state location and starting context for a workspace record. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SendSystemNotificationRequest +internal sealed class SessionsCreateWorkspaceRequest { - /// Optional structured notification kind. - [JsonPropertyName("kind")] - public JsonElement? Kind { get; set; } + /// Starting working-directory context. The record keeps `cwd`, `gitRoot`, `repository`, `hostType`, `branch`, and `clientName`. Other fields, including `repositoryHost`, `headCommit`, and `baseCommit`, are ignored. `hostType` must be `github` or `ado`. + [JsonPropertyName("context")] + public SessionWorkingDirectoryContextWithClient? Context { get; set; } - /// Notification text to deliver to the model. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; + /// `windows` (any letter case) selects Windows path rules. Any other value selects POSIX path rules. + [JsonPropertyName("convention")] + public string Convention { get; set; } = string.Empty; - /// Internal delivery options, including passive policy. - [JsonPropertyName("options")] - public JsonElement? Options { get; set; } + /// User-supplied display name for the workspace. + [JsonPropertyName("name")] + public string? Name { get; set; } - /// Target session identifier. + /// Session ID the workspace record belongs to. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Directory the session's state is written under when no session filesystem provider is configured. Ignored when a provider is configured; the provider's session state path is used instead. + [JsonPropertyName("sessionStatePath")] + public string SessionStatePath { get; set; } = string.Empty; } -/// Result of aborting the current turn. +/// The workspace record on disk, omitted when the session has none. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AbortResult +internal sealed class SessionsLoadWorkspaceResult { - /// Error message if the abort failed. - [JsonPropertyName("error")] - public string? Error { get; set; } - - /// Whether the abort completed successfully. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// The workspace record, as JSON. Omitted when the record does not exist. + [JsonPropertyName("workspaceJson")] + public string? WorkspaceJson { get; set; } } -/// Parameters for aborting the current turn. +/// Where the session's state lives, as a root directory and the session ID under it. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AbortRequest +internal sealed class SessionsLoadWorkspaceRequest { - /// Finite reason code describing why the current turn was aborted. - [JsonPropertyName("reason")] - public AbortReason? Reason { get; set; } - - /// Target session identifier. + /// Session ID naming the state directory under the sessions home. Rejected when it is absolute or contains a parent component, so it cannot escape the sessions home. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Root directory every session's state directory sits under. + [JsonPropertyName("sessionsHome")] + public string SessionsHome { get; set; } = string.Empty; } -/// Result of interrupting the main agent turn. +/// The merge completed. The record carries the supplied workspace-schema fields, but a stored `fork_count` stays. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class InterruptMainTurnResult +internal sealed class SessionsUpdateWorkspaceFieldsResult { - /// Whether an in-flight main agent turn was interrupted. False when the main loop was not processing. - [JsonPropertyName("interrupted")] - public bool Interrupted { get; set; } } -/// Parameters for interrupting the main agent turn. +/// Where the session's state lives, plus workspace-schema fields to merge into its workspace record. Stored keys outside the schema are not preserved, and a stored `fork_count` is never replaced. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class InterruptMainTurnRequest +internal sealed class SessionsUpdateWorkspaceFieldsRequest { - /// When true, the user's queued prompts are preserved and run as the next turn once the interrupted turn unwinds; when false (the default), the queue is cleared like a plain abort. - [JsonPropertyName("flushQueued")] - public bool? FlushQueued { get; set; } + /// Workspace-schema fields to merge into the record, as a JSON object. Fields the object omits keep their stored values, except stored keys outside the schema are not preserved and a stored `fork_count` is never replaced. + [JsonPropertyName("fieldsJson")] + public string FieldsJson { get; set; } = string.Empty; - /// Target session identifier. + /// Session ID naming the state directory under the sessions home. Rejected when it is absolute or contains a parent component, so it cannot escape the sessions home. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Root directory every session's state directory sits under. + [JsonPropertyName("sessionsHome")] + public string SessionsHome { get; set; } = string.Empty; } -/// Identifies the target session. +/// Reload all hooks (user, plugin, optionally repo) and apply them to the active session. Call after installing or removing plugins so their hooks take effect immediately. No-op when no active session matches the given sessionId. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionCancelAllBackgroundAgentsRequest +public sealed class SessionsReloadPluginHooksResult { - /// Target session identifier. +} + +/// Active session ID and an optional flag for deferring repo-level hooks until folder trust. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionsReloadPluginHooksRequest +{ + /// When true, skip repo-level hooks. Use before folder trust is confirmed; loadDeferredRepoHooks loads them post-trust. + [JsonPropertyName("deferRepoHooks")] + public bool? DeferRepoHooks { get; set; } + + /// Active session ID to reload hooks for. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Parameters for shutting down the session. +/// Queued repo-level startup prompts and the total hook command count after loading. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ShutdownRequest +public sealed class SessionLoadDeferredRepoHooksResult { - /// Dispatch deferred sessionEnd hooks in the background with their full per-hook timeoutSec instead of awaiting them under the short shared shutdown budget. Set this when the host process keeps running after the session closes (for example the CLI's /clear), so a slow hook neither blocks the close nor is aborted. Hooks still detached when the process later exits are terminated with it. Defaults to false. - [JsonPropertyName("detachSessionEndHooks")] - public bool? DetachSessionEndHooks { get; set; } + /// Total hook command count (user + plugin + repo) loaded for the session by this call. Captured atomically with startupPrompts so callers don't need to read a separate counter. + [JsonPropertyName("hookCount")] + public long HookCount { get; set; } - /// Optional human-readable reason. Typically the message of the error that triggered shutdown when type is 'error'. - [JsonPropertyName("reason")] - public string? Reason { get; set; } + /// Repo-level startup prompts queued from repo hook configs. Empty on resume, when no repo configs were pending, or when disableAllHooks is set. + [JsonPropertyName("startupPrompts")] + public IList StartupPrompts { get => field ??= []; set; } +} - /// Target session identifier. +/// Active session ID whose deferred repo-level hooks should be loaded. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionsLoadDeferredRepoHooksRequest +{ + /// Active session ID whose deferred repo-level hooks should be loaded. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// Why the session is being shut down. Defaults to "routine" when omitted. - [JsonPropertyName("type")] - public ShutdownType? Type { get; set; } } -/// Identifier of the session event that was emitted for the log message. +/// Replace the manager-wide additional plugins. New session creations and subsequent hook reloads see the new set; already-running sessions keep their existing hook installation until the next reload. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class LogResult +public sealed class SessionsSetAdditionalPluginsResult { - /// The unique identifier of the emitted session event. - [JsonPropertyName("eventId")] - public Guid EventId { get; set; } } -/// Message text, optional severity level, persistence flag, optional follow-up URL, and optional tip. +/// Manager-wide additional plugins to register; replaces any previously-configured set. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class LogRequest +internal sealed class SessionsSetAdditionalPluginsRequest { - /// When true, the message is transient and not persisted to the session event log on disk. - [JsonPropertyName("ephemeral")] - public bool? Ephemeral { get; set; } - - /// Log severity level. Determines how the message is displayed in the timeline. Defaults to "info". - [JsonPropertyName("level")] - public SessionLogLevel? Level { get; set; } + /// Manager-wide additional plugins to register. Replaces any previously-configured set. Pass an empty array to clear. + [JsonPropertyName("plugins")] + public IList Plugins { get => field ??= []; set; } +} - /// Human-readable message. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; +/// Dynamic-context board entry count, when available. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionsGetBoardEntryCountResult +{ + /// Board entry count, when available. + [JsonPropertyName("count")] + public long? Count { get; set; } +} - /// Target session identifier. +/// Session ID whose board entry count should be returned. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionsGetBoardEntryCountRequest +{ + /// Session ID whose board entry count should be returned. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; +} - /// Optional actionable tip displayed alongside the message. Only honored on `level: "info"`. - [JsonPropertyName("tip")] - public string? Tip { get; set; } - - /// Domain category for this log entry (e.g., "mcp", "subscription", "policy", "model"). Maps to `infoType`/`warningType`/`errorType` on the emitted event. Defaults to "notification". - [JsonPropertyName("type")] - public string? Type { get; set; } - - /// Optional URL the user can open in their browser for more details. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("url")] - public string? Url { get; set; } -} - -/// Adapter-declared policy that tells clients whether discovery may run automatically. +/// State of the runtime-managed remote-control singleton. +/// Polymorphic base type discriminated by state. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderAutomaticDiscoveryPolicy +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "state", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(RemoteControlStatusOff), "off")] +[JsonDerivedType(typeof(RemoteControlStatusConnecting), "connecting")] +[JsonDerivedType(typeof(RemoteControlStatusActive), "active")] +[JsonDerivedType(typeof(RemoteControlStatusError), "error")] +public partial class RemoteControlStatus { - /// Whether automatic discovery is allowed, limited to configured providers, or explicit-only. - [JsonPropertyName("mode")] - public ModelProviderAutomaticDiscoveryMode Mode { get; set; } - - /// Maximum network scope used by this adapter during discovery. - [JsonPropertyName("networkScope")] - public ModelProviderDiscoveryNetworkScope NetworkScope { get; set; } + /// The type discriminator. + [JsonPropertyName("state")] + public virtual string State { get; set; } = string.Empty; +} - /// True when discovery requires non-null caller input. Omission or null is rejected before adapter execution. When false, omitted or null input selects adapter defaults without schema validation. - [JsonPropertyName("requiresInput")] - public bool RequiresInput { get; set; } - /// True when the adapter must be enabled by a trusted owner, such as a trusted extension, before automatic discovery may run. - [JsonPropertyName("requiresTrust")] - public bool RequiresTrust { get; set; } +/// Remote control is not connected. +/// The off variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class RemoteControlStatusOff : RemoteControlStatus +{ + /// + [JsonIgnore] + public override string State => "off"; } -/// An operation supported by a model-provider adapter. +/// Remote control is in the middle of initial setup. +/// The connecting variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderAdapterOperationDescriptor +public partial class RemoteControlStatusConnecting : RemoteControlStatus { - /// Optional self-contained JSON Schema Draft 7 for non-null discovery input. Only supported on discover. No external references are resolved. Omitted or null input selects defaults when requiresInput is false. Without a schema, the adapter validates supplied input. - [JsonPropertyName("inputSchema")] - public JsonElement? InputSchema { get; set; } + /// + [JsonIgnore] + public override string State => "connecting"; - /// Supported operation name: `discover`, `getStatus`, or `models.list`. Unknown names and duplicate declarations are rejected. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Session id the connection is attaching to. + [JsonPropertyName("attachedSessionId")] + public required string AttachedSessionId { get; set; } } -/// Contributor attribution, independent of routing identity and authorization. +/// Remote control is connected to a local session. +/// The active variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderAttribution +public partial class RemoteControlStatusActive : RemoteControlStatus { - /// Human-readable contributor name, not the adapter display name. - [JsonPropertyName("ownerDisplayName")] - public string? OwnerDisplayName { get; set; } + /// + [JsonIgnore] + public override string State => "active"; - /// Stable contributor identifier. Required and nonblank for extension and custom sources; optional for built-in and configured sources. Does not grant authority. - [JsonPropertyName("ownerId")] - public string? OwnerId { get; set; } + /// Session id remote control is pointed at. + [JsonPropertyName("attachedSessionId")] + public required string AttachedSessionId { get; set; } - /// Kind of component that supplied the adapter. Attribution does not confer authority. - [JsonPropertyName("source")] - public ModelProviderProvenanceSource Source { get; set; } + /// True while a read-only/session-sync export is deferred, awaiting the first `user.message` before its MC session exists. Marked internal: this field is excluded from the public SDK surface and is populated only on the CLI in-process path. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonInclude] + [JsonPropertyName("awaitingFirstMessage")] + internal bool? AwaitingFirstMessage { get; set; } + + /// MC frontend URL for this session, when known. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("frontendUrl")] + public string? FrontendUrl { get; set; } + + /// Whether the MC session may steer this session. + [JsonPropertyName("isSteerable")] + public required bool IsSteerable { get; set; } } -/// A normalized model-provider adapter in the session's effective catalog. +/// The last setup attempt failed. The singleton is otherwise off. +/// The error variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderAdapterDescriptor +public partial class RemoteControlStatusError : RemoteControlStatus { - /// Stable opaque identity for routing to this adapter. Unique in the effective catalog, independent of live registration generations. - [JsonPropertyName("adapterId")] - public string AdapterId { get; set; } = string.Empty; - - /// Adapter-declared policy for passive and automatic discovery. - [JsonPropertyName("automaticDiscovery")] - public ModelProviderAutomaticDiscoveryPolicy AutomaticDiscovery { get => field ??= new(); set; } - - /// Human-readable provider name. - [JsonPropertyName("displayName")] - public string DisplayName { get; set; } = string.Empty; - - /// Operations supported by this provider adapter. - [JsonPropertyName("operations")] - public IList Operations { get => field ??= []; set; } + /// + [JsonIgnore] + public override string State => "error"; - /// Attribution for the adapter itself. - [JsonPropertyName("provenance")] - public ModelProviderAttribution Provenance { get => field ??= new(); set; } + /// Session id the failing setup attempt targeted, when known. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("attachedSessionId")] + public string? AttachedSessionId { get; set; } - /// Descriptive provider family, such as `ollama`. Different adapters may have the same family; use adapterId for routing. - [JsonPropertyName("providerKind")] - public string ProviderKind { get; set; } = string.Empty; + /// Human-readable error message from the last setup attempt. + [JsonPropertyName("error")] + public required string Error { get; set; } } -/// Normalized model-provider adapter definitions available to the session, not discovered instances. +/// Wrapper for the singleton's current status. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderAdapterCatalog +public sealed class RemoteControlStatusResult { - /// Available provider adapters ordered by adapterId. - [JsonPropertyName("providers")] - public IList Providers { get => field ??= []; set; } + /// State of the runtime-managed remote-control singleton. + [JsonPropertyName("status")] + public RemoteControlStatus Status { get => field ??= new(); set; } } -/// Identifies the target session. +/// Reattach to an existing MC session without creating a new one. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionProvidersGetCatalogRequest +public sealed class RemoteControlConfigExistingMcSession { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Existing MC session ID to reattach to. + [JsonPropertyName("mcSessionId")] + public string McSessionId { get; set; } = string.Empty; + + /// Existing MC task ID for the reattached session. + [JsonPropertyName("mcTaskId")] + public string McTaskId { get; set; } = string.Empty; } -/// Attribution for the adapter that produced a provider row. +/// Configuration for the runtime-managed remote-control singleton. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderProvenance +public sealed class RemoteControlConfig { - /// Stable opaque adapter identity from the effective catalog. Treat this as a whole identifier, not a parseable owner or kind. - [JsonPropertyName("adapterId")] - public string AdapterId { get; set; } = string.Empty; + /// Reattach to an existing MC session without creating a new one. + [JsonPropertyName("existingMcSession")] + public RemoteControlConfigExistingMcSession? ExistingMcSession { get; set; } - /// Human-readable contributor name, not the adapter display name. - [JsonPropertyName("ownerDisplayName")] - public string? OwnerDisplayName { get; set; } + /// Whether the user explicitly requested remote (vs. implicit session-sync). Controls warning surfacing for missing-repo cases. + [JsonPropertyName("explicit")] + public bool Explicit { get; set; } - /// Stable contributor identifier when the adapter has an owner outside the runtime. Independent of the contribution mechanism and not a routing key. - [JsonPropertyName("ownerId")] - public string? OwnerId { get; set; } + /// Whether remote export should be enabled. + [JsonPropertyName("remote")] + public bool Remote { get; set; } - /// Descriptive provider family that produced this row; not a routing key. - [JsonPropertyName("providerKind")] - public string ProviderKind { get; set; } = string.Empty; + /// When true, suppresses timeline messages on successful setup. + [JsonPropertyName("silent")] + public bool Silent { get; set; } - /// Kind of component that supplied the adapter. - [JsonPropertyName("source")] - public ModelProviderProvenanceSource Source { get; set; } + /// Whether the MC session may steer the local session (write mode). + [JsonPropertyName("steerable")] + public bool Steerable { get; set; } + + /// Existing Mission Control task ID to attach the exported session to. + [JsonPropertyName("taskId")] + public string? TaskId { get; set; } } -/// Serializable reference to a discovered provider instance. +/// Parameters for attaching the remote-control singleton to a session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderInstanceReference +internal sealed class SessionsStartRemoteControlRequest { - /// Stable opaque identity of the adapter that owns this reference. Must be present in the target session's effective catalog. - [JsonPropertyName("adapterId")] - public string AdapterId { get; set; } = string.Empty; - - /// Stable instance identifier derived by the provider adapter, such as `ollama:{normalizedEndpoint}`. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - - /// Absolute provider management URI. The adapter validates normalization, supported schemes, and permission to access it against its bound configuration; a reference does not grant authority. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("managementEndpoint")] - public string ManagementEndpoint { get; set; } = string.Empty; + /// Configuration for the runtime-managed remote-control singleton. + [JsonPropertyName("config")] + public RemoteControlConfig Config { get => field ??= new(); set; } - /// Descriptive provider family. Must match the selected adapter; not a routing key. - [JsonPropertyName("providerKind")] - public string ProviderKind { get; set; } = string.Empty; + /// Local session id to attach remote control to. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// A normalized model-provider instance discovered by the runtime. +/// Outcome of a transferRemoteControl call. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderInstance +public sealed class RemoteControlTransferResult { - /// Human-readable instance name. - [JsonPropertyName("displayName")] - public string DisplayName { get; set; } = string.Empty; - - /// Inference API endpoint when the provider exposes one separately from its management endpoint. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("inferenceEndpoint")] - public string? InferenceEndpoint { get; set; } - - /// Transport to use for inference against this instance. - [JsonPropertyName("inferenceTransport")] - public ProviderEndpointTransport? InferenceTransport { get; set; } - - /// Provider family to use for inference against this instance. - [JsonPropertyName("inferenceType")] - public ProviderEndpointType? InferenceType { get; set; } - - /// Wire API to use for inference against this instance, when required by the provider family. - [JsonPropertyName("inferenceWireApi")] - public ProviderEndpointWireApi? InferenceWireApi { get; set; } - - /// Attribution for the adapter that produced this instance. - [JsonPropertyName("provenance")] - public ModelProviderProvenance Provenance { get => field ??= new(); set; } + /// State of the runtime-managed remote-control singleton. + [JsonPropertyName("status")] + public RemoteControlStatus Status { get => field ??= new(); set; } - /// Self-contained reference for subsequent provider operations. - [JsonPropertyName("reference")] - public ModelProviderInstanceReference Reference { get => field ??= new(); set; } + /// Whether the rebinding actually happened. + [JsonPropertyName("transferred")] + public bool Transferred { get; set; } } -/// Typed provider-operation outcome. Use the code for control flow and the optional message for display. +/// Parameters for atomically rebinding the remote-control singleton. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderOperationOutcome +internal sealed class SessionsTransferRemoteControlRequest { - /// Machine-readable operation outcome. - [JsonPropertyName("code")] - public ModelProviderOperationOutcomeCode Code { get; set; } + /// When provided, the transfer is rejected unless the singleton currently points at this session id (compare-and-swap semantics to avoid clobbering newer state). + [JsonPropertyName("expectedFromSessionId")] + public string? ExpectedFromSessionId { get; set; } - /// Human-readable detail for non-success outcomes. - [JsonPropertyName("message")] - public string? Message { get; set; } + /// Local session id to point remote control at. + [JsonPropertyName("toSessionId")] + public string ToSessionId { get; set; } = string.Empty; } -/// Provider instances found by a discovery operation. +/// Patch for the singleton's steering state. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderDiscoverResult +internal sealed class SessionsSetRemoteControlSteeringRequest { - /// Discovered provider instances. Empty when passive default discovery finds no reachable provider. - [JsonPropertyName("instances")] - public IList Instances { get => field ??= []; set; } - - /// Typed operation outcome. Passive discovery can return `absent` with an empty instance list. - [JsonPropertyName("outcome")] - public ModelProviderOperationOutcome Outcome { get => field ??= new(); set; } + /// Target steering state. Today only `true` is actionable on the underlying exporter; `false` is reserved for future use. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } } -/// Provider discovery parameters. +/// Outcome of a stopRemoteControl call. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModelProviderDiscoverRequest +public sealed class RemoteControlStopResult { - /// Opaque adapter identity returned by `session.providers.getCatalog`. - [JsonPropertyName("adapterId")] - public string AdapterId { get; set; } = string.Empty; - - /// Provider-specific JSON input. Omission or null selects adapter defaults unless requiresInput is true. Non-null input is validated against the advertised Draft 7 schema when present; otherwise validation belongs to the adapter. - [JsonPropertyName("input")] - public JsonElement? Input { get; set; } + /// State of the runtime-managed remote-control singleton. + [JsonPropertyName("status")] + public RemoteControlStatus Status { get => field ??= new(); set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether the singleton was actually torn down by this call. + [JsonPropertyName("stopped")] + public bool Stopped { get; set; } } -/// Current health information for a provider instance. +/// RPC data type for SessionsStopRemoteControl operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderStatus +internal sealed class SessionsStopRemoteControlRequest { - /// Normalized provider instance. - [JsonPropertyName("instance")] - public ModelProviderInstance Instance { get => field ??= new(); set; } - - /// Typed operation outcome. - [JsonPropertyName("outcome")] - public ModelProviderOperationOutcome Outcome { get => field ??= new(); set; } - - /// Open provider status value, such as `healthy`, `unreachable`, or `notInstalled`. - [JsonPropertyName("status")] - public string Status { get; set; } = string.Empty; + /// When provided, the stop is rejected unless the singleton currently points at this session id (compare-and-swap semantics). + [JsonPropertyName("expectedSessionId")] + public string? ExpectedSessionId { get; set; } - /// Provider-reported version. - [JsonPropertyName("version")] - public string? Version { get; set; } + /// When true, the singleton is unconditionally torn down regardless of `expectedSessionId`. Use during shutdown or explicit `/remote off`. + [JsonPropertyName("force")] + public bool? Force { get; set; } } -/// Provider status request parameters. +/// Params to attach or detach an in-process ExtensionController delegate. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModelProviderGetStatusRequest +internal sealed class ConfigureSessionExtensionsParams { - /// Provider instance reference returned by discovery. - [JsonPropertyName("instance")] - public ModelProviderInstanceReference Instance { get => field ??= new(); set; } - - /// Target session identifier. + /// Session to attach the extension controller delegate to. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Provider-reported model artifact metadata. +/// Outcome of an agentRegistry.spawn call. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelArtifactDetails +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(AgentRegistrySpawnResultSpawned), "spawned")] +[JsonDerivedType(typeof(AgentRegistrySpawnResultSpawnError), "spawn-error")] +[JsonDerivedType(typeof(AgentRegistrySpawnResultRegistryTimeout), "registry-timeout")] +[JsonDerivedType(typeof(AgentRegistrySpawnResultValidationError), "validation-error")] +public partial class AgentRegistrySpawnResult { - /// Provider-reported model architecture. - [JsonPropertyName("architecture")] - public string? Architecture { get; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} - /// Provider-reported model families. - [JsonPropertyName("families")] - public IList? Families { get; set; } - /// Primary model family. - [JsonPropertyName("family")] - public string? Family { get; set; } +/// Full registry entry for the spawned child. Lets the controller call `handleLiveTargetSelected(entry)` directly without re-reading the registry (avoids a TOCTOU window). +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class AgentRegistryLiveTargetEntry +{ + /// Kind of attention required when status === "attention". Meaningful only when status === "attention". + [JsonPropertyName("attentionKind")] + public AgentRegistryLiveTargetEntryAttentionKind? AttentionKind { get; set; } - /// Artifact format, such as `gguf`. - [JsonPropertyName("format")] - public string? Format { get; set; } + /// Git branch of the session (when known). + [JsonPropertyName("branch")] + public string? Branch { get; set; } - /// Provider-reported parameter count label. - [JsonPropertyName("parameterSize")] - public string? ParameterSize { get; set; } + /// Copilot CLI version that wrote the entry. + [JsonPropertyName("copilotVersion")] + public string CopilotVersion { get; set; } = string.Empty; - /// Provider-reported quantization label. - [JsonPropertyName("quantization")] - public string? Quantization { get; set; } + /// Working directory of the session (when known). + [JsonPropertyName("cwd")] + public string? Cwd { get; set; } - /// Provider-reported tokenizer. - [JsonPropertyName("tokenizer")] - public string? Tokenizer { get; set; } -} + /// Bind host for the entry's JSON-RPC server. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; -/// A non-fatal provider observation warning. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderWarning -{ - /// Machine-readable warning code. - [JsonPropertyName("code")] - public string Code { get; set; } = string.Empty; + /// Process kind tag for the registry entry. + [JsonPropertyName("kind")] + public AgentRegistryLiveTargetEntryKind Kind { get; set; } - /// Human-readable warning message. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; -} + /// Wall-clock milliseconds since the watcher last observed this entry (heartbeat freshness). + [JsonPropertyName("lastSeenMs")] + public long LastSeenMs { get; set; } -/// A model offered for agent conversations. Missing capability metadata does not disqualify a candidate. Models known to be incompatible, such as embedding-only models, are excluded by the adapter. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DiscoveredModel -{ - /// Provider-reported model capabilities. Omitted capability fields are unknown; explicit false values are preserved. - [JsonPropertyName("capabilities")] - public ModelCapabilities Capabilities { get => field ??= new(); set; } + /// How the most recent turn ended (clean vs aborted). Lets the renderer distinguish done from done_cancelled. + [JsonPropertyName("lastTerminalEvent")] + public AgentRegistryLiveTargetEntryLastTerminalEvent? LastTerminalEvent { get; set; } - /// Provider-reported model artifact details. - [JsonPropertyName("details")] - public ModelArtifactDetails Details { get => field ??= new(); set; } + /// Model identifier currently selected for the session. + [JsonPropertyName("model")] + public string? Model { get; set; } - /// Provider-reported artifact digest. - [JsonPropertyName("digest")] - public string? Digest { get; set; } + /// Operating-system pid of the process owning this entry. + [JsonPropertyName("pid")] + public long Pid { get; set; } - /// Provider-native model identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// TCP port the entry's JSON-RPC server is listening on. + [JsonPropertyName("port")] + public long Port { get; set; } - /// Provider-reported last-modified timestamp. - [JsonPropertyName("modifiedAt")] - public DateTimeOffset? ModifiedAt { get; set; } + /// Registry entry schema version (1 = ui-server, 2 = managed-server). + [JsonPropertyName("schemaVersion")] + public long SchemaVersion { get; set; } - /// Provider-reported display name. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Session ID of the foreground session for this entry. + [JsonPropertyName("sessionId")] + public string? SessionId { get; set; } - /// Attribution for the adapter that produced this model row. - [JsonPropertyName("provenance")] - public ModelProviderProvenance Provenance { get => field ??= new(); set; } + /// Friendly session name (when set). + [JsonPropertyName("sessionName")] + public string? SessionName { get; set; } - /// Provider-reported artifact size in bytes. - [JsonPropertyName("sizeBytes")] - public long? SizeBytes { get; set; } + /// ISO 8601 timestamp captured at registration. + [JsonPropertyName("startedAt")] + public string StartedAt { get; set; } = string.Empty; - /// Non-fatal warnings encountered while enriching this model. - [JsonPropertyName("warnings")] - public IList Warnings { get => field ??= []; set; } -} + /// Coarse lifecycle status of the foreground session. + [JsonPropertyName("status")] + public AgentRegistryLiveTargetEntryStatus? Status { get; set; } -/// Models offered for agent conversations by one provider instance. Adapters exclude known-incompatible models, but retain candidates with unknown capabilities. Listing does not guarantee compatibility. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DiscoveredModelList -{ - /// Provider-native models in provider order. - [JsonPropertyName("models")] - public IList Models { get => field ??= []; set; } + /// Monotonic per-publisher revision counter incremented on every status update. Lets watchers detect transient flips. + [JsonPropertyName("statusRevision")] + public long? StatusRevision { get; set; } - /// Typed operation outcome. - [JsonPropertyName("outcome")] - public ModelProviderOperationOutcome Outcome { get => field ??= new(); set; } + /// Connection token (null when the target is unauthenticated). + [JsonInclude] + [JsonPropertyName("token")] + internal string? Token { get; set; } } -/// Provider model inventory request parameters. +/// Canonical process-log discovery outcome; populated from spawnLiveTarget. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModelProviderModelsListRequest +public sealed class AgentRegistryLogCapture { - /// Provider instance reference returned by discovery. - [JsonPropertyName("instance")] - public ModelProviderInstanceReference Instance { get => field ??= new(); set; } + /// Whether a canonical process log was discovered for this managed spawn. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Why no canonical process log could be opened for this managed spawn (set only when enabled is false). + [JsonPropertyName("openError")] + public string? OpenError { get; set; } -/// Vision-specific limits. + /// Categorized reason no canonical process log could be opened (set only when enabled is false). + [JsonPropertyName("openErrorReason")] + public AgentRegistryLogCaptureOpenErrorReason? OpenErrorReason { get; set; } + + /// Absolute path to the managed spawn's process-<timestamp>-<pid>.log file (only set when enabled). + [JsonPropertyName("path")] + public string? Path { get; set; } +} + +/// Managed-server child was spawned and registered successfully. +/// The spawned variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelCapabilitiesOverrideLimitsVision +public partial class AgentRegistrySpawnResultSpawned : AgentRegistrySpawnResult { - /// Maximum image size in bytes. - [JsonPropertyName("max_prompt_image_size")] - public long? MaxPromptImageSize { get; set; } + /// + [JsonIgnore] + public override string Kind => "spawned"; - /// Maximum number of images per prompt. - [JsonPropertyName("max_prompt_images")] - public long? MaxPromptImages { get; set; } + /// Full registry entry for the spawned child. Lets the controller call `handleLiveTargetSelected(entry)` directly without re-reading the registry (avoids a TOCTOU window). + [JsonPropertyName("entry")] + public required AgentRegistryLiveTargetEntry Entry { get; set; } - /// MIME types the model accepts. - [JsonPropertyName("supported_media_types")] - public IList? SupportedMediaTypes { get; set; } + /// If the delegate attempted to send the initial prompt and failed, the categorized error message. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("initialPromptError")] + public string? InitialPromptError { get; set; } + + /// Whether the delegate already sent the initial prompt. Always omitted in the current wiring: the controller sends the prompt post-attach via the standard LocalRpcSession.send path. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("initialPromptSent")] + public bool? InitialPromptSent { get; set; } + + /// Per-spawn log-capture outcome; populated from spawnLiveTarget. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("logCapture")] + public AgentRegistryLogCapture? LogCapture { get; set; } } -/// Token limits for prompts, outputs, and context window. +/// `child_process.spawn` itself failed before the child entered the registry. +/// The spawn-error variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelCapabilitiesOverrideLimits +public partial class AgentRegistrySpawnResultSpawnError : AgentRegistrySpawnResult { - /// Maximum total context window size in tokens. - [JsonPropertyName("max_context_window_tokens")] - public long? MaxContextWindowTokens { get; set; } + /// + [JsonIgnore] + public override string Kind => "spawn-error"; - /// Maximum number of output/completion tokens. - [JsonPropertyName("max_output_tokens")] - public long? MaxOutputTokens { get; set; } + /// Underlying errno code (e.g. ENOENT, EACCES) when available. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("code")] + public string? Code { get; set; } - /// Maximum number of prompt/input tokens. - [JsonPropertyName("max_prompt_tokens")] - public long? MaxPromptTokens { get; set; } + /// Human-readable error message. + [JsonPropertyName("message")] + public required string Message { get; set; } +} - /// Vision-specific limits. - [JsonPropertyName("vision")] - public ModelCapabilitiesOverrideLimitsVision? Vision { get; set; } +/// Spawn succeeded but the child did not publish a matching managed-server entry within the timeout. +/// The registry-timeout variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class AgentRegistrySpawnResultRegistryTimeout : AgentRegistrySpawnResult +{ + /// + [JsonIgnore] + public override string Kind => "registry-timeout"; + + /// Process ID of the orphaned child (so the caller can offer 'kill the pid' guidance). + [JsonPropertyName("childPid")] + public required long ChildPid { get; set; } + + /// Per-spawn log-capture outcome; populated from spawnLiveTarget. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("logCapture")] + public AgentRegistryLogCapture? LogCapture { get; set; } } -/// Feature flags indicating what the model supports. +/// Synchronous pre-validation rejected the spawn request. +/// The validation-error variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelCapabilitiesOverrideSupports +public partial class AgentRegistrySpawnResultValidationError : AgentRegistrySpawnResult { - /// Resolved Anthropic adaptive-thinking capability — unsupported / optional / required / adaptive_only. 'required' models reject thinking.type='enabled' with HTTP 400 but still accept 'disabled' (e.g. opus-4.7/4.8/5, sonnet-5); 'adaptive_only' models accept nothing but 'adaptive' (e.g. fable, mythos). - [JsonPropertyName("adaptive_thinking")] - public AdaptiveThinkingSupport? AdaptiveThinking { get; set; } + /// + [JsonIgnore] + public override string Kind => "validation-error"; - /// Whether this model supports reasoning effort configuration. - [JsonPropertyName("reasoningEffort")] - public bool? ReasoningEffort { get; set; } + /// Which parameter field was invalid. Omitted when the rejection is not field-specific. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("field")] + public AgentRegistrySpawnValidationErrorField? Field { get; set; } - /// Whether this model supports canonical tool calling. - [JsonPropertyName("toolCalls")] - public bool? ToolCalls { get; set; } + /// Human-readable explanation; safe to surface in the UI banner. Never logged to unrestricted telemetry. + [JsonPropertyName("message")] + public required string Message { get; set; } - /// Whether this model supports vision/image input. - [JsonPropertyName("vision")] - public bool? Vision { get; set; } + /// Categorized reason for the rejection. Low-cardinality enum so telemetry can aggregate by reason without leaking raw paths or agent/model names. + [JsonPropertyName("reason")] + public required AgentRegistrySpawnValidationErrorReason Reason { get; set; } } -/// Optional capability overrides (vision, tool_calls, reasoning, etc.). +/// Inputs to spawn a managed-server child via the controller's spawn delegate. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelCapabilitiesOverride +internal sealed class AgentRegistrySpawnRequest { - /// Token limits for prompts, outputs, and context window. - [JsonPropertyName("limits")] - public ModelCapabilitiesOverrideLimits? Limits { get; set; } + /// Custom or built-in agent name (e.g. 'explore'). When omitted, the child uses its own default. + [JsonPropertyName("agentName")] + public string? AgentName { get; set; } - /// Feature flags indicating what the model supports. - [JsonPropertyName("supports")] - public ModelCapabilitiesOverrideSupports? Supports { get; set; } + /// Working directory for the spawned child (must be an existing directory). + [JsonPropertyName("cwd")] + public string Cwd { get; set; } = string.Empty; + + /// Optional first user message. Forwarded to the caller (the CLI's spawn wrapper sends it post-attach via the standard LocalRpcSession.send path). + [JsonPropertyName("initialPrompt")] + public string? InitialPrompt { get; set; } + + /// Model identifier to apply to the new session. + [JsonPropertyName("model")] + public string? Model { get; set; } + + /// Friendly session name. Must satisfy validateSessionName: non-empty, no leading/trailing whitespace, <=100 chars, no control chars, no double quotes. + [JsonPropertyName("name")] + public string? Name { get; set; } + + /// Permission posture for the new session. 'yolo' requires the controller-local session to currently be in allow-all mode. + [JsonPropertyName("permissionMode")] + public AgentRegistrySpawnPermissionMode? PermissionMode { get; set; } } -/// RPC data type for ProtocolSystemMessageAppendConfig operations. +/// Feature availability. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProtocolSystemMessageAppendConfig +public sealed class ConnectorDiscoveryCapabilities { - /// Text appended to the standard system prompt. - [JsonPropertyName("content")] - public string? Content { get; set; } + /// API version. + [JsonPropertyName("apiVersion")] + public long ApiVersion { get; set; } - /// Append-mode discriminator. Omission also selects append mode. - [JsonPropertyName("mode")] - public ProtocolAppendMode? Mode { get; set; } + /// Availability. + [JsonPropertyName("availability")] + public ConnectorDiscoveryAvailability Availability { get; set; } + + /// Whether results are cached. + [JsonPropertyName("conditionalCache")] + public bool ConditionalCache { get; set; } + + /// Whether accounts are selected by opaque ID. + [JsonPropertyName("opaqueAccountSelection")] + public bool OpaqueAccountSelection { get; set; } } -/// RPC data type for SystemMessageBlock operations. +/// Account metadata. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SystemMessageBlock +public sealed class ConnectorDiscoveryAuthInfo { - /// Whether providers with explicit prompt caching should place a cache breakpoint after this block. - [JsonPropertyName("cacheBreakpoint")] - public bool? CacheBreakpoint { get; set; } + /// Host. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; - /// Text content for this system-message block. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// Login. + [JsonPropertyName("login")] + public string Login { get; set; } = string.Empty; - /// Whether the block is static and may be cached independently of dynamic prompt content. - [JsonPropertyName("isStatic")] - public bool? IsStatic { get; set; } + /// Authentication type. + [JsonPropertyName("type")] + public AuthInfoType Type { get; set; } } -/// RPC data type for ProtocolSystemMessageReplaceConfig operations. +/// Eligible account. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProtocolSystemMessageReplaceConfig +public sealed class ConnectorDiscoveryAccount { - /// Complete replacement system-message text. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// Opaque account ID. + [JsonPropertyName("accountId")] + public string AccountId { get; set; } = string.Empty; - /// Optional structured blocks corresponding to the replacement content. - [JsonPropertyName("contentBlocks")] - public IList? ContentBlocks { get; set; } + /// Account metadata. + [JsonPropertyName("authInfo")] + public ConnectorDiscoveryAuthInfo AuthInfo { get => field ??= new(); set; } +} - /// Replace-mode discriminator. - [JsonPropertyName("mode")] - public ProtocolReplaceMode Mode { get; set; } +/// Eligible accounts. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorDiscoveryAccountList +{ + /// Eligible accounts. + [JsonPropertyName("accounts")] + public IList Accounts { get => field ??= []; set; } + + /// Availability. + [JsonPropertyName("availability")] + public ConnectorDiscoveryAvailability Availability { get; set; } } -/// RPC data type for ProtocolStaticSectionOverride operations. +/// Entry. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProtocolStaticSectionOverride +public sealed class ConnectorDiscoveryCatalogEntry { - /// Declarative operation applied to the section. - [JsonPropertyName("action")] - public ProtocolStaticSectionAction Action { get; set; } + /// Description. + [JsonPropertyName("description")] + public string? Description { get; set; } - /// Optional content used by replace, append, and prepend operations. - [JsonPropertyName("content")] - public string? Content { get; set; } + /// Display name. + [JsonPropertyName("displayName")] + public string DisplayName { get; set; } = string.Empty; + + /// Logo. + [JsonPropertyName("logo")] + public string? Logo { get; set; } + + /// Name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Release tag. + [JsonPropertyName("releaseTag")] + public string? ReleaseTag { get; set; } + + /// Status. + [JsonPropertyName("status")] + public ConnectorCatalogStatus Status { get; set; } + + /// Tier. + [JsonPropertyName("tier")] + public string? Tier { get; set; } } -/// Polymorphic base type discriminated by action. +/// Entries for the selected account. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorDiscoveryCatalogResult +{ + /// Opaque account ID. + [JsonPropertyName("accountId")] + public string AccountId { get; set; } = string.Empty; + + /// Entries. + [JsonPropertyName("connectors")] + public IList Connectors { get => field ??= []; set; } + + /// Refresh time in Unix epoch milliseconds. + [JsonPropertyName("refreshedAtMs")] + public long RefreshedAtMs { get; set; } + + /// Revision. + [JsonPropertyName("revision")] + public long Revision { get; set; } +} + +/// Selected account. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ConnectorDiscoveryAccountRequest +{ + /// Opaque account ID. + [RegularExpression("^\\S+$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(2048)] + [JsonPropertyName("accountId")] + public string AccountId { get; set; } = string.Empty; +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionSuspendRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Result of sending a user message. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SendResult +{ + /// Unique identifier assigned to the message. + [JsonPropertyName("messageId")] + public string MessageId { get; set; } = string.Empty; +} + +/// Provider-native structured output format. JSON Schema is forwarded without rewriting or validating the schema or the generated output. +/// Polymorphic base type discriminated by type. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( - TypeDiscriminatorPropertyName = "action", + TypeDiscriminatorPropertyName = "type", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(ProtocolMarkerSectionOverrideTransform), "transform")] -[JsonDerivedType(typeof(ProtocolMarkerSectionOverridePreserve), "preserve")] -public partial class ProtocolMarkerSectionOverride +[JsonDerivedType(typeof(ResponseFormatJsonSchema), "json_schema")] +public partial class ResponseFormat { /// The type discriminator. - [JsonPropertyName("action")] - public virtual string Action { get; set; } = string.Empty; + [JsonPropertyName("type")] + public virtual string Type { get; set; } = string.Empty; } -/// The transform variant of . +/// A JSON Schema output contract. OpenAI receives the name, description, schema and strict setting; Anthropic receives the schema in output_config.format and always uses its native strict enforcement. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ProtocolMarkerSectionOverrideTransform : ProtocolMarkerSectionOverride +public sealed class JsonSchemaResponseFormat { - /// - [JsonIgnore] - public override string Action => "transform"; + /// Optional description passed to OpenAI providers. + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Name of the output schema, subject to the provider's naming restrictions. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// JSON Schema passed unchanged to the inference provider. Schemas larger than 32 MiB when JSON-encoded are rejected before admission, using the runtime's existing request-size ceiling. This is not a guarantee that the entire model request fits. Supported keywords and schema restrictions are determined by the provider. + [JsonPropertyName("schema")] + public JsonElement Schema { get; set; } + + /// Optional strict enforcement setting for OpenAI providers. Omitted uses the provider default. Anthropic always enforces its supported schema subset. + [JsonPropertyName("strict")] + public bool? Strict { get; set; } } -/// The preserve variant of . +/// The json_schema variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ProtocolMarkerSectionOverridePreserve : ProtocolMarkerSectionOverride +public partial class ResponseFormatJsonSchema : ResponseFormat { /// [JsonIgnore] - public override string Action => "preserve"; + public override string Type => "json_schema"; + + /// JSON Schema and provider options for the turn's output. + [JsonPropertyName("jsonSchema")] + public required JsonSchemaResponseFormat JsonSchema { get; set; } } -/// JSON union data type for ProtocolSectionOverride. +/// Parameters for sending a user message to the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -public sealed partial class ProtocolSectionOverride +internal sealed class SendRequest { - /// Gets the value when this instance contains . - public ProtocolStaticSectionOverride? ProtocolStaticSectionOverride { get; } + /// The UI mode the agent was in when this message was sent. Defaults to the session's current mode. + [JsonPropertyName("agentMode")] + public SendAgentMode? AgentMode { get; set; } - /// Gets the value when this instance contains . - public ProtocolMarkerSectionOverride? ProtocolMarkerSectionOverride { get; } + /// Optional attachments (files, directories, selections, blobs, GitHub references) to include with the message. + [JsonPropertyName("attachments")] + public IList? Attachments { get; set; } - /// Initializes a new instance of the class from . - public ProtocolSectionOverride(ProtocolStaticSectionOverride value) - { - ArgumentNullException.ThrowIfNull(value); - ProtocolStaticSectionOverride = value; - } + /// If false, this message will not trigger a Premium Request Unit charge. User messages default to billable. + [JsonPropertyName("billable")] + public bool? Billable { get; set; } - /// Converts to . - public static implicit operator ProtocolSectionOverride(ProtocolStaticSectionOverride value) => new(value); + /// If provided, this is shown in the timeline instead of `prompt`. + [JsonPropertyName("displayPrompt")] + public string? DisplayPrompt { get; set; } - /// Initializes a new instance of the class from . - public ProtocolSectionOverride(ProtocolMarkerSectionOverride value) - { - ArgumentNullException.ThrowIfNull(value); - ProtocolMarkerSectionOverride = value; - } + /// How to deliver the message. `enqueue` (default) appends to the message queue. `immediate` interjects during an in-progress turn. + [JsonPropertyName("mode")] + public SendMode? Mode { get; set; } - /// Converts to . - public static implicit operator ProtocolSectionOverride(ProtocolMarkerSectionOverride value) => new(value); + /// If true, adds the message to the front of the queue instead of the end. + [JsonPropertyName("prepend")] + public bool? Prepend { get; set; } - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter - { - /// - public override ProtocolSectionOverride Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - if (reader.TokenType == JsonTokenType.Null) - { - throw new JsonException("Expected JSON object for ProtocolSectionOverride."); - } + /// The user message text. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; - using var document = JsonDocument.ParseValue(ref reader); - var element = document.RootElement; - if (element.ValueKind == JsonValueKind.Object && (element.TryGetProperty("action", out _) && element.GetProperty("action").ValueKind == JsonValueKind.String && (element.GetProperty("action").GetString() == "replace" || element.GetProperty("action").GetString() == "remove" || element.GetProperty("action").GetString() == "append" || element.GetProperty("action").GetString() == "prepend"))) - { - var protocolStaticSectionOverride = JsonSerializer.Deserialize(element, RpcJsonContext.Default.ProtocolStaticSectionOverride); - return protocolStaticSectionOverride is null ? throw new JsonException("Expected ProtocolStaticSectionOverride value.") : new ProtocolSectionOverride(protocolStaticSectionOverride); - } - if ((element.ValueKind == JsonValueKind.Object && (element.TryGetProperty("action", out _) && element.GetProperty("action").ValueKind == JsonValueKind.String && (element.GetProperty("action").GetString() == "transform")) || element.ValueKind == JsonValueKind.Object && (element.TryGetProperty("action", out _) && element.GetProperty("action").ValueKind == JsonValueKind.String && (element.GetProperty("action").GetString() == "preserve")))) - { - var protocolMarkerSectionOverride = JsonSerializer.Deserialize(element, RpcJsonContext.Default.ProtocolMarkerSectionOverride); - return protocolMarkerSectionOverride is null ? throw new JsonException("Expected ProtocolMarkerSectionOverride value.") : new ProtocolSectionOverride(protocolMarkerSectionOverride); - } + /// Custom HTTP headers to include in outbound model requests for this turn. Merged with session-level provider headers; per-turn headers augment and overwrite session-level headers with the same key. + [JsonPropertyName("requestHeaders")] + public IDictionary? RequestHeaders { get; set; } - throw new JsonException("JSON value did not match any ProtocolSectionOverride variant."); - } + /// If set, the request will fail if the named tool is not available when this message is among the user messages at the start of the current exchange. + [JsonPropertyName("requiredTool")] + public string? RequiredTool { get; set; } - /// - public override void Write(Utf8JsonWriter writer, ProtocolSectionOverride value, JsonSerializerOptions options) - { - if (value.ProtocolStaticSectionOverride is { } protocolStaticSectionOverride) - { - JsonSerializer.Serialize(writer, protocolStaticSectionOverride, RpcJsonContext.Default.ProtocolStaticSectionOverride); - return; - } - if (value.ProtocolMarkerSectionOverride is { } protocolMarkerSectionOverride) - { - JsonSerializer.Serialize(writer, protocolMarkerSectionOverride, RpcJsonContext.Default.ProtocolMarkerSectionOverride); - return; - } + /// Provider-native output format for this turn, including all tool-call iterations. Not inherited by later turns or subagents. Ordinary steering inherits the active format; specifying responseFormat with mode: immediate is an error, even while idle. Returned assistant content remains text; the runtime does not parse or validate it. Unsupported models or schemas produce provider errors. + [JsonPropertyName("responseFormat")] + public ResponseFormat? ResponseFormat { get; set; } - throw new JsonException("No ProtocolSectionOverride variant value is set."); - } - } -} + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; -/// RPC data type for ProtocolSystemMessageCustomizeConfig operations. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProtocolSystemMessageCustomizeConfig -{ - /// Text appended after the customized sections. - [JsonPropertyName("content")] - public string? Content { get; set; } + /// Optional provenance tag copied to the resulting user.message event. Must be `user`, `system`, `command-<command-id>` for command-originated messages, `schedule-<numeric-id>` for scheduled prompts, or `agent-<agent-id>` for prompts sent by another agent. + [RegularExpression("^(user|system|command-.*|schedule-\\d+|agent-.+)$")] + [JsonInclude] + [JsonPropertyName("source")] + internal string? Source { get; set; } - /// Customize-mode discriminator. - [JsonPropertyName("mode")] - public ProtocolCustomizeMode Mode { get; set; } + /// W3C Trace Context traceparent header for distributed tracing of this agent turn. + [JsonPropertyName("traceparent")] + public string? Traceparent { get; set; } - /// Named standard-prompt section overrides. - [JsonPropertyName("sections")] - public IDictionary? Sections { get; set; } + /// W3C Trace Context tracestate header for distributed tracing. + [JsonPropertyName("tracestate")] + public string? Tracestate { get; set; } + + /// If true, await completion of the agentic loop for this message before returning. Defaults to false (fire-and-forget). When true, the result still contains the same `messageId`; the caller can rely on the agent having processed the message before the call resolves. Transport-dependent tail semantics: on a LOCAL (in-process) session the wait additionally blocks until the completed turn's event tail has been dispatched to this session's in-process subscribers, so a subsequent read of subscriber state already reflects the turn; on a REMOTE session the wait resolves once the loop completes and mirrored delivery follows over the wire. Callers that need the stronger local guarantee on remote sessions should await the event stream explicitly. + [JsonPropertyName("wait")] + public bool? Wait { get; set; } } -/// JSON union data type for ProtocolSystemMessageConfig. +/// Result of sending zero or more user messages. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -public sealed partial class ProtocolSystemMessageConfig +public sealed class SendMessagesResult { - /// Gets the value when this instance contains . - public ProtocolSystemMessageAppendConfig? ProtocolSystemMessageAppendConfig { get; } + /// Unique identifiers assigned to the messages, one per provided message in order. For a batch that starts a run, assistant messages use the final ID as originatingMessageId throughout that run, including tool iterations and stop-hook corrections. Immediate steering does not replace the active run's origin. Empty when no messages were provided; that run has no originatingMessageId. + [JsonPropertyName("messageIds")] + public IList MessageIds { get => field ??= []; set; } +} - /// Gets the value when this instance contains . - public ProtocolSystemMessageReplaceConfig? ProtocolSystemMessageReplaceConfig { get; } +/// A single user message to append to the session as part of a `session.sendMessages` turn. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SendMessageItem +{ + /// Optional attachments (files, directories, selections, blobs, GitHub references) to include with this message. + [JsonPropertyName("attachments")] + public IList? Attachments { get; set; } - /// Gets the value when this instance contains . - public ProtocolSystemMessageCustomizeConfig? ProtocolSystemMessageCustomizeConfig { get; } - - /// Initializes a new instance of the class from . - public ProtocolSystemMessageConfig(ProtocolSystemMessageAppendConfig value) - { - ArgumentNullException.ThrowIfNull(value); - ProtocolSystemMessageAppendConfig = value; - } - - /// Converts to . - public static implicit operator ProtocolSystemMessageConfig(ProtocolSystemMessageAppendConfig value) => new(value); - - /// Initializes a new instance of the class from . - public ProtocolSystemMessageConfig(ProtocolSystemMessageReplaceConfig value) - { - ArgumentNullException.ThrowIfNull(value); - ProtocolSystemMessageReplaceConfig = value; - } - - /// Converts to . - public static implicit operator ProtocolSystemMessageConfig(ProtocolSystemMessageReplaceConfig value) => new(value); - - /// Initializes a new instance of the class from . - public ProtocolSystemMessageConfig(ProtocolSystemMessageCustomizeConfig value) - { - ArgumentNullException.ThrowIfNull(value); - ProtocolSystemMessageCustomizeConfig = value; - } - - /// Converts to . - public static implicit operator ProtocolSystemMessageConfig(ProtocolSystemMessageCustomizeConfig value) => new(value); - - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter - { - /// - public override ProtocolSystemMessageConfig Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - if (reader.TokenType == JsonTokenType.Null) - { - throw new JsonException("Expected JSON object for ProtocolSystemMessageConfig."); - } + /// If false, this message will not trigger a Premium Request Unit charge. User messages default to billable. + [JsonInclude] + [JsonPropertyName("billable")] + internal bool? Billable { get; set; } - using var document = JsonDocument.ParseValue(ref reader); - var element = document.RootElement; - if (element.ValueKind == JsonValueKind.Object && (!element.TryGetProperty("mode", out _) || (element.TryGetProperty("mode", out _) && element.GetProperty("mode").ValueKind == JsonValueKind.String && (element.GetProperty("mode").GetString() == "append")))) - { - var protocolSystemMessageAppendConfig = JsonSerializer.Deserialize(element, RpcJsonContext.Default.ProtocolSystemMessageAppendConfig); - return protocolSystemMessageAppendConfig is null ? throw new JsonException("Expected ProtocolSystemMessageAppendConfig value.") : new ProtocolSystemMessageConfig(protocolSystemMessageAppendConfig); - } - if (element.ValueKind == JsonValueKind.Object && (element.TryGetProperty("mode", out _) && element.GetProperty("mode").ValueKind == JsonValueKind.String && (element.GetProperty("mode").GetString() == "replace"))) - { - var protocolSystemMessageReplaceConfig = JsonSerializer.Deserialize(element, RpcJsonContext.Default.ProtocolSystemMessageReplaceConfig); - return protocolSystemMessageReplaceConfig is null ? throw new JsonException("Expected ProtocolSystemMessageReplaceConfig value.") : new ProtocolSystemMessageConfig(protocolSystemMessageReplaceConfig); - } - if (element.ValueKind == JsonValueKind.Object && (element.TryGetProperty("mode", out _) && element.GetProperty("mode").ValueKind == JsonValueKind.String && (element.GetProperty("mode").GetString() == "customize"))) - { - var protocolSystemMessageCustomizeConfig = JsonSerializer.Deserialize(element, RpcJsonContext.Default.ProtocolSystemMessageCustomizeConfig); - return protocolSystemMessageCustomizeConfig is null ? throw new JsonException("Expected ProtocolSystemMessageCustomizeConfig value.") : new ProtocolSystemMessageConfig(protocolSystemMessageCustomizeConfig); - } + /// If provided, this is shown in the timeline instead of `prompt`. + [JsonPropertyName("displayPrompt")] + public string? DisplayPrompt { get; set; } - throw new JsonException("JSON value did not match any ProtocolSystemMessageConfig variant."); - } + /// The user message text. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; - /// - public override void Write(Utf8JsonWriter writer, ProtocolSystemMessageConfig value, JsonSerializerOptions options) - { - if (value.ProtocolSystemMessageAppendConfig is { } protocolSystemMessageAppendConfig) - { - JsonSerializer.Serialize(writer, protocolSystemMessageAppendConfig, RpcJsonContext.Default.ProtocolSystemMessageAppendConfig); - return; - } - if (value.ProtocolSystemMessageReplaceConfig is { } protocolSystemMessageReplaceConfig) - { - JsonSerializer.Serialize(writer, protocolSystemMessageReplaceConfig, RpcJsonContext.Default.ProtocolSystemMessageReplaceConfig); - return; - } - if (value.ProtocolSystemMessageCustomizeConfig is { } protocolSystemMessageCustomizeConfig) - { - JsonSerializer.Serialize(writer, protocolSystemMessageCustomizeConfig, RpcJsonContext.Default.ProtocolSystemMessageCustomizeConfig); - return; - } + /// If set, the request will fail if the named tool is not available when this message is among the user messages at the start of the current exchange. + [JsonPropertyName("requiredTool")] + public string? RequiredTool { get; set; } - throw new JsonException("No ProtocolSystemMessageConfig variant value is set."); - } - } + /// Optional provenance tag copied to the resulting user.message event. Must be `user`, `system`, `command-<command-id>` for command-originated messages, `schedule-<numeric-id>` for scheduled prompts, or `agent-<agent-id>` for prompts sent by another agent. + [RegularExpression("^(user|system|command-.*|schedule-\\d+|agent-.+)$")] + [JsonInclude] + [JsonPropertyName("source")] + internal string? Source { get; set; } } -/// A BYOK model definition referencing a named provider. +/// Parameters for sending zero or more user messages to the session in a single turn. Remote-backed (Mission Control) sessions do not support this method and will return an error. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProviderModelConfig +internal sealed class SendMessagesRequest { - /// Optional capability overrides (vision, tool_calls, reasoning, etc.). - [JsonPropertyName("capabilities")] - public ModelCapabilitiesOverride? Capabilities { get; set; } - - /// Provider-local model id, unique within its provider. The session-wide selection id (shown in the model list and passed to switchTo) is the provider-qualified `provider/id`. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - - /// Maximum context window tokens for the model. - [JsonPropertyName("maxContextWindowTokens")] - public double? MaxContextWindowTokens { get; set; } + /// The UI mode the agent was in when these messages were sent. Defaults to the session's current mode. + [JsonPropertyName("agentMode")] + public SendAgentMode? AgentMode { get; set; } - /// Maximum output tokens for the model. - [JsonPropertyName("maxOutputTokens")] - public double? MaxOutputTokens { get; set; } + /// The user messages to append to the conversation, in order, before running one agent loop. When the batch starts a run, its final message is the primary initiating message; earlier messages provide context, not separate runs or replies. May be empty, in which case a single turn runs over the existing history with no new user message or originatingMessageId. + [JsonPropertyName("messages")] + public IList Messages { get => field ??= []; set; } - /// Maximum prompt/input tokens for the model. - [JsonPropertyName("maxPromptTokens")] - public double? MaxPromptTokens { get; set; } + /// How to deliver the messages. `enqueue` (default) appends to the message queue. `immediate` interjects during an in-progress turn. + [JsonPropertyName("mode")] + public SendMode? Mode { get; set; } - /// Provider-published model metadata, preserved verbatim as the public Model.metadata object. - [JsonPropertyName("metadata")] - public IDictionary? Metadata { get; set; } + /// If true, adds the messages to the front of the queue instead of the end. + [JsonPropertyName("prepend")] + public bool? Prepend { get; set; } - /// Well-known base model id used for behavior/capability/config lookup. Defaults to `id`. - [JsonPropertyName("modelId")] - public string? ModelId { get; set; } + /// Custom HTTP headers to include in outbound model requests for this turn. Merged with session-level provider headers; per-turn headers augment and overwrite session-level headers with the same key. + [JsonPropertyName("requestHeaders")] + public IDictionary? RequestHeaders { get; set; } - /// Display name for model pickers. Defaults to the provider-qualified selection id (`provider/id`). - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Provider-native output format for the whole turn, including an empty message batch and all tool-call iterations. Not inherited by later turns or subagents. Ordinary steering inherits the active format; specifying responseFormat with mode: immediate is an error, even while idle. Returned assistant content remains text; the runtime does not parse or validate it. Unsupported models or schemas produce provider errors. + [JsonPropertyName("responseFormat")] + public ResponseFormat? ResponseFormat { get; set; } - /// Name of the configured provider that serves this model. - [JsonPropertyName("provider")] - public string Provider { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// System-message configuration used when the runtime builds the standard prompt for this provider-qualified model, including general-purpose subagents. It uses the same object hierarchy as session-level systemMessage configuration, except transform actions are rejected because the current callback protocol is not model-scoped. When present, it overrides the session-wide configuration on those prompt paths. Selected custom-agent and specialized-subagent prompts remain authoritative. - [JsonPropertyName("systemMessage")] - public ProtocolSystemMessageConfig? SystemMessage { get; set; } + /// W3C Trace Context traceparent header for distributed tracing of this agent turn. + [JsonPropertyName("traceparent")] + public string? Traceparent { get; set; } - /// The model name sent to the provider API for inference. Defaults to `id`. - [JsonPropertyName("wireModel")] - public string? WireModel { get; set; } -} + /// W3C Trace Context tracestate header for distributed tracing. + [JsonPropertyName("tracestate")] + public string? Tracestate { get; set; } -/// Azure-specific provider options. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProviderConfigAzure -{ - /// API version. When set, uses the versioned deployment route. When omitted, uses the GA versionless v1 route. - [JsonPropertyName("apiVersion")] - public string? ApiVersion { get; set; } + /// If true, await completion of the agentic loop for this turn before returning. Defaults to false (fire-and-forget). When true, the result still contains the same `messageIds`; the caller can rely on the agent having processed the messages before the call resolves. Transport-dependent tail semantics: on a LOCAL (in-process) session the wait additionally blocks until the completed turn's event tail has been dispatched to this session's in-process subscribers, so a subsequent read of subscriber state already reflects the turn; on a REMOTE session the wait resolves once the loop completes and mirrored delivery follows over the wire. Callers that need the stronger local guarantee on remote sessions should await the event stream explicitly. + [JsonPropertyName("wait")] + public bool? Wait { get; set; } } -/// External SDK input for a named custom model provider. Ingested by the native protocol boundary before host dispatch. +/// Internal request for sending a system notification. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class NamedProviderConfig +internal sealed class SendSystemNotificationRequest { - /// Static API key used to authenticate provider requests. - [JsonPropertyName("apiKey")] - public string? ApiKey { get; set; } - - /// Azure authentication configuration for the provider. - [JsonPropertyName("azure")] - public ProviderConfigAzure? Azure { get; set; } - - /// Base URL for provider API requests. - [JsonPropertyName("baseUrl")] - public string BaseUrl { get; set; } = string.Empty; - - /// Static bearer token used to authenticate provider requests. - [JsonPropertyName("bearerToken")] - public string? BearerToken { get; set; } - - /// Whether the host supplies bearer tokens dynamically. - [JsonPropertyName("hasBearerTokenProvider")] - public bool? HasBearerTokenProvider { get; set; } - - /// Additional HTTP headers included with provider requests. - [JsonPropertyName("headers")] - public IDictionary? Headers { get; set; } - - /// The product serving the provider's models, reported in telemetry as `model_provider`. Only affects telemetry. - [JsonPropertyName("modelProvider")] - public ProviderConfigModelProvider? ModelProvider { get; set; } - - /// Unique provider name used to qualify model selection IDs. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Optional structured notification kind. + [JsonPropertyName("kind")] + public JsonElement? Kind { get; set; } - /// Transport used to communicate with the provider. - [JsonPropertyName("transport")] - public ProviderConfigTransport? Transport { get; set; } + /// Notification text to deliver to the model. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; - /// Provider protocol family. - [JsonPropertyName("type")] - public ProviderConfigType? Type { get; set; } + /// Internal delivery options, including passive policy. + [JsonPropertyName("options")] + public JsonElement? Options { get; set; } - /// Wire API used to communicate with the provider. - [JsonPropertyName("wireApi")] - public ProviderConfigWireApi? WireApi { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Provider configuration prepared from a discovered model. Preparing a plan changes nothing: it neither registers the model with the session nor writes durable configuration. To apply it, pass `provider` and `model` to `session.provider.add`, omitting whichever the dispositions report as already configured. +/// Result of aborting the current turn. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderConfigurationPlan +public sealed class AbortResult { - /// Model definition prepared from the discovered model. Capability fields the provider did not report stay omitted rather than being asserted false. - [JsonPropertyName("model")] - public ProviderModelConfig Model { get => field ??= new(); set; } - - /// Whether `model` still needs to be registered. When `alreadyConfigured`, `selectionId` is already registered and the caller can select it without adding anything. - [JsonPropertyName("modelDisposition")] - public ModelProviderConfigurationDisposition ModelDisposition { get; set; } - - /// Provider connection prepared from the instance's inference metadata. Carries no credential; supply one if the endpoint requires it. - [JsonPropertyName("provider")] - public NamedProviderConfig Provider { get => field ??= new(); set; } - - /// Whether `provider` still needs to be registered. When `alreadyConfigured`, a provider with the same endpoint is already registered and `provider` restates it under its existing name; adding it again is rejected as a duplicate. - [JsonPropertyName("providerDisposition")] - public ModelProviderConfigurationDisposition ProviderDisposition { get; set; } - - /// Provider-qualified selection id (`provider/id`) to pass to `switchTo` once the plan is applied. - [JsonPropertyName("selectionId")] - public string SelectionId { get; set; } = string.Empty; + /// Error message if the abort failed. + [JsonPropertyName("error")] + public string? Error { get; set; } - /// Non-fatal warnings carried over from the discovered model, such as capabilities the provider did not report. - [JsonPropertyName("warnings")] - public IList Warnings { get => field ??= []; set; } + /// Whether the abort completed successfully. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// A discovered instance and one of its models to translate into provider configuration. Pass back the instance and model as returned by `session.providers.discover` and `session.providers.models.list`. +/// Parameters for aborting the current turn. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModelProviderPrepareConfigurationRequest +internal sealed class AbortRequest { - /// The discovered instance that serves the model. - [JsonPropertyName("instance")] - public ModelProviderInstance Instance { get => field ??= new(); set; } - - /// The discovered model to configure. - [JsonPropertyName("model")] - public DiscoveredModel Model { get => field ??= new(); set; } + /// Finite reason code describing why the current turn was aborted. + [JsonPropertyName("reason")] + public AbortReason? Reason { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Managed sandbox enforcement state for a session. +/// Result of interrupting the main agent turn. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxEnforcementStatus +public sealed class InterruptMainTurnResult { - /// Whether an enforcement failure has permanently blocked the session. - [JsonPropertyName("blocked")] - public bool Blocked { get; set; } + /// Whether an in-flight main agent turn was interrupted. False when the main loop was not processing. + [JsonPropertyName("interrupted")] + public bool Interrupted { get; set; } +} - /// The first sandbox enforcement failure that blocked the session. - [JsonPropertyName("reason")] - public string? Reason { get; set; } +/// Parameters for interrupting the main agent turn. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class InterruptMainTurnRequest +{ + /// When true, the user's queued prompts are preserved and run as the next turn once the interrupted turn unwinds; when false (the default), the queue is cleared like a plain abort. + [JsonPropertyName("flushQueued")] + public bool? FlushQueued { get; set; } - /// Whether the effective managed policy requires an available sandbox backend. - [JsonPropertyName("required")] - public bool Required { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSandboxGetEnforcementStatusRequest +internal sealed class SessionCancelAllBackgroundAgentsRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// A possible secret-bearing environment variable and optional locally suggested HTTPS injection hosts. This is a draft for user review, not an active grant. +/// Parameters for shutting down the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxCredentialSuggestion +internal sealed class ShutdownRequest { - /// Environment variable name. The secret value is never returned. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Dispatch deferred sessionEnd hooks in the background with their full per-hook timeoutSec instead of awaiting them under the short shared shutdown budget. Set this when the host process keeps running after the session closes (for example the CLI's /clear), so a slow hook neither blocks the close nor is aborted. Hooks still detached when the process later exits are terminated with it. Defaults to false. + [JsonPropertyName("detachSessionEndHooks")] + public bool? DetachSessionEndHooks { get; set; } - /// HTTPS hostnames suggested by a local known-provider mapping. An empty list requires the user to supply injection hosts before adding a masking entry. These suggestions do not allow network access. - [JsonPropertyName("suggestedInjectHosts")] - public IList SuggestedInjectHosts { get => field ??= []; set; } + /// Optional human-readable reason. Typically the message of the error that triggered shutdown when type is 'error'. + [JsonPropertyName("reason")] + public string? Reason { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Why the session is being shut down. Defaults to "routine" when omitted. + [JsonPropertyName("type")] + public ShutdownType? Type { get; set; } } -/// Possible unconfigured secrets in the sandbox shell environment, sorted by variable name, with no secret values. +/// Identifier of the session event that was emitted for the log message. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxCredentialSuggestionsResult +public sealed class LogResult { - /// Candidates for user review. Empty when sandboxing is disabled or no unconfigured candidates are present. - [JsonPropertyName("suggestions")] - public IList Suggestions { get => field ??= []; set; } + /// The unique identifier of the emitted session event. + [JsonPropertyName("eventId")] + public Guid EventId { get; set; } } -/// Identifies the target session. +/// Message text, optional severity level, persistence flag, optional follow-up URL, and optional tip. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSandboxGetCredentialSuggestionsRequest +internal sealed class LogRequest { + /// When true, the message is transient and not persisted to the session event log on disk. + [JsonPropertyName("ephemeral")] + public bool? Ephemeral { get; set; } + + /// Log severity level. Determines how the message is displayed in the timeline. Defaults to "info". + [JsonPropertyName("level")] + public SessionLogLevel? Level { get; set; } + + /// Human-readable message. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Optional actionable tip displayed alongside the message. Only honored on `level: "info"`. + [JsonPropertyName("tip")] + public string? Tip { get; set; } + + /// Domain category for this log entry (e.g., "mcp", "subscription", "policy", "model"). Maps to `infoType`/`warningType`/`errorType` on the emitted event. Defaults to "notification". + [JsonPropertyName("type")] + public string? Type { get; set; } + + /// Optional URL the user can open in their browser for more details. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("url")] + public string? Url { get; set; } } -/// Result of attempting to disable sandboxing for the current session. +/// Adapter-declared policy that tells clients whether discovery may run automatically. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxDisableForSessionResult +public sealed class ModelProviderAutomaticDiscoveryPolicy { - /// The authoritative sandbox enabled state after the operation. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// Whether automatic discovery is allowed, limited to configured providers, or explicit-only. + [JsonPropertyName("mode")] + public ModelProviderAutomaticDiscoveryMode Mode { get; set; } - /// Whether this call resolved the pending request and applied the session opt-out. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Maximum network scope used by this adapter during discovery. + [JsonPropertyName("networkScope")] + public ModelProviderDiscoveryNetworkScope NetworkScope { get; set; } + + /// True when discovery requires non-null caller input. Omission or null is rejected before adapter execution. When false, omitted or null input selects adapter defaults without schema validation. + [JsonPropertyName("requiresInput")] + public bool RequiresInput { get; set; } + + /// True when the adapter must be enabled by a trusted owner, such as a trusted extension, before automatic discovery may run. + [JsonPropertyName("requiresTrust")] + public bool RequiresTrust { get; set; } } -/// Optional informational context describing how and where the permission decision was made. This does not affect permission behavior. +/// An operation supported by a model-provider adapter. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionDecisionContext +public sealed class ModelProviderAdapterOperationDescriptor { - /// Disposition of the permission request as observed by the responding client. - [JsonPropertyName("outcome")] - public PermissionDecisionOutcome Outcome { get; set; } + /// Optional self-contained JSON Schema Draft 7 for non-null discovery input. Only supported on discover. No external references are resolved. Omitted or null input selects defaults when requiresInput is false. Without a schema, the adapter validates supplied input. + [JsonPropertyName("inputSchema")] + public JsonElement? InputSchema { get; set; } - /// Whether the responding client could ask a user interactively, was running headlessly, or had no response path. Omit when the client cannot determine this authoritatively. - [JsonPropertyName("responseCapability")] - public PermissionResponseCapability? ResponseCapability { get; set; } + /// Supported operation name: `discover`, `getStatus`, or `models.list`. Unknown names and duplicate declarations are rejected. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; +} - /// Controlled reason or actor responsible for the response. - [JsonPropertyName("source")] - public PermissionDecisionSource Source { get; set; } +/// Contributor attribution, independent of routing identity and authorization. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ModelProviderAttribution +{ + /// Human-readable contributor name, not the adapter display name. + [JsonPropertyName("ownerDisplayName")] + public string? OwnerDisplayName { get; set; } - /// Client surface that submitted the response. - [JsonPropertyName("surface")] - public PermissionDecisionSurface Surface { get; set; } + /// Stable contributor identifier. Required and nonblank for extension and custom sources; optional for built-in and configured sources. Does not grant authority. + [JsonPropertyName("ownerId")] + public string? OwnerId { get; set; } + + /// Kind of component that supplied the adapter. Attribution does not confer authority. + [JsonPropertyName("source")] + public ModelProviderProvenanceSource Source { get; set; } } -/// Request to disable sandboxing for the current session while resolving an active sandbox-bypass permission prompt. +/// A normalized model-provider adapter in the session's effective catalog. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SandboxDisableForSessionRequest +public sealed class ModelProviderAdapterDescriptor { - /// Optional attribution for the permission decision. - [JsonPropertyName("decisionContext")] - public PermissionDecisionContext? DecisionContext { get; set; } + /// Stable opaque identity for routing to this adapter. Unique in the effective catalog, independent of live registration generations. + [JsonPropertyName("adapterId")] + public string AdapterId { get; set; } = string.Empty; - /// Identifier of the exact pending sandbox-bypass permission request that authorized the session opt-out. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// Adapter-declared policy for passive and automatic discovery. + [JsonPropertyName("automaticDiscovery")] + public ModelProviderAutomaticDiscoveryPolicy AutomaticDiscovery { get => field ??= new(); set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Human-readable provider name. + [JsonPropertyName("displayName")] + public string DisplayName { get; set; } = string.Empty; + + /// Operations supported by this provider adapter. + [JsonPropertyName("operations")] + public IList Operations { get => field ??= []; set; } + + /// Attribution for the adapter itself. + [JsonPropertyName("provenance")] + public ModelProviderAttribution Provenance { get => field ??= new(); set; } + + /// Descriptive provider family, such as `ollama`. Different adapters may have the same family; use adapterId for routing. + [JsonPropertyName("providerKind")] + public string ProviderKind { get; set; } = string.Empty; } -/// Result of accepting a sandbox path grant. +/// Normalized model-provider adapter definitions available to the session, not discovered instances. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SandboxGrantPathForRequestResult +public sealed class ModelProviderAdapterCatalog { - /// Whether this call resolved the pending request and added the path to the session's sandbox policy. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Available provider adapters ordered by adapterId. + [JsonPropertyName("providers")] + public IList Providers { get => field ??= []; set; } } -/// Request to accept the sandbox path grant offered on an active sandbox escalation permission prompt. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SandboxGrantPathForRequestRequest +internal sealed class SessionProvidersGetCatalogRequest { - /// Optional attribution for the permission decision. - [JsonPropertyName("decisionContext")] - public PermissionDecisionContext? DecisionContext { get; set; } - - /// Identifier of the exact pending sandbox escalation permission request whose sandboxPathGrant to accept. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Authentication status and account metadata for the session. +/// Attribution for the adapter that produced a provider row. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionAuthStatus +public sealed class ModelProviderProvenance { - /// Authentication type. - [JsonPropertyName("authType")] - public AuthInfoType? AuthType { get; set; } + /// Stable opaque adapter identity from the effective catalog. Treat this as a whole identifier, not a parseable owner or kind. + [JsonPropertyName("adapterId")] + public string AdapterId { get; set; } = string.Empty; - /// Copilot plan tier (e.g., individual_pro, business). - [JsonPropertyName("copilotPlan")] - public string? CopilotPlan { get; set; } + /// Human-readable contributor name, not the adapter display name. + [JsonPropertyName("ownerDisplayName")] + public string? OwnerDisplayName { get; set; } - /// Authentication host URL. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("host")] - public string? Host { get; set; } - - /// Whether the session has resolved authentication. - [JsonPropertyName("isAuthenticated")] - public bool IsAuthenticated { get; set; } + /// Stable contributor identifier when the adapter has an owner outside the runtime. Independent of the contribution mechanism and not a routing key. + [JsonPropertyName("ownerId")] + public string? OwnerId { get; set; } - /// Authenticated login/username, if available. - [JsonPropertyName("login")] - public string? Login { get; set; } + /// Descriptive provider family that produced this row; not a routing key. + [JsonPropertyName("providerKind")] + public string ProviderKind { get; set; } = string.Empty; - /// Human-readable authentication status description. - [JsonPropertyName("statusMessage")] - public string? StatusMessage { get; set; } + /// Kind of component that supplied the adapter. + [JsonPropertyName("source")] + public ModelProviderProvenanceSource Source { get; set; } } -/// Identifies the target session. +/// Serializable reference to a discovered provider instance. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionGitHubAuthGetStatusRequest +public sealed class ModelProviderInstanceReference { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Stable opaque identity of the adapter that owns this reference. Must be present in the target session's effective catalog. + [JsonPropertyName("adapterId")] + public string AdapterId { get; set; } = string.Empty; -/// Indicates whether the credential update succeeded. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionSetCredentialsResult -{ - /// Whether the session ended up with a populated `copilotUser` for the installed credentials. `true` when the supplied credential already carried `copilotUser` or it was successfully re-resolved server-side. `false` when the credential is installed without `copilotUser` — either re-resolution failed, or the variant cannot be re-resolved from the credential alone (only the raw-token variants `token`, `env`, and `gh-cli` can). In both `false` cases the token swap still applied, but plan/quota/billing metadata is degraded. Present whenever a credential was supplied; omitted only when no credential was supplied (no-op call). - [JsonPropertyName("copilotUserResolved")] - public bool? CopilotUserResolved { get; set; } + /// Stable instance identifier derived by the provider adapter, such as `ollama:{normalizedEndpoint}`. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Absolute provider management URI. The adapter validates normalization, supported schemes, and permission to access it against its bound configuration; a reference does not grant authority. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("managementEndpoint")] + public string ManagementEndpoint { get; set; } = string.Empty; + + /// Descriptive provider family. Must match the selected adapter; not a routing key. + [JsonPropertyName("providerKind")] + public string ProviderKind { get; set; } = string.Empty; } -/// Authentication credentials accepted by session.gitHubAuth.setCredentials. Session-owned token-provider identities cannot be installed through this method. -/// Polymorphic base type discriminated by type. +/// A normalized model-provider instance discovered by the runtime. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "type", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(SettableAuthInfoHmac), "hmac")] -[JsonDerivedType(typeof(SettableAuthInfoEnv), "env")] -[JsonDerivedType(typeof(SettableAuthInfoToken), "token")] -[JsonDerivedType(typeof(SettableAuthInfoCopilotApiToken), "copilot-api-token")] -[JsonDerivedType(typeof(SettableAuthInfoUser), "user")] -[JsonDerivedType(typeof(SettableAuthInfoAccount), "account")] -[JsonDerivedType(typeof(SettableAuthInfoGhCli), "gh-cli")] -[JsonDerivedType(typeof(SettableAuthInfoApiKey), "api-key")] -public partial class SettableAuthInfo +public sealed class ModelProviderInstance { - /// The type discriminator. - [JsonPropertyName("type")] - public virtual string Type { get; set; } = string.Empty; -} + /// Human-readable instance name. + [JsonPropertyName("displayName")] + public string DisplayName { get; set; } = string.Empty; + /// Inference API endpoint when the provider exposes one separately from its management endpoint. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("inferenceEndpoint")] + public string? InferenceEndpoint { get; set; } -/// Authentication-info input variant for GitHub-internal HMAC auth, carrying the public GitHub host and HMAC secret. -/// The hmac variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SettableAuthInfoHmac : SettableAuthInfo -{ - /// - [JsonIgnore] - public override string Type => "hmac"; + /// Transport to use for inference against this instance. + [JsonPropertyName("inferenceTransport")] + public ProviderEndpointTransport? InferenceTransport { get; set; } - /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// Provider family to use for inference against this instance. + [JsonPropertyName("inferenceType")] + public ProviderEndpointType? InferenceType { get; set; } - /// HMAC secret used to sign requests. - [JsonPropertyName("hmac")] - public required string Hmac { get; set; } + /// Wire API to use for inference against this instance, when required by the provider family. + [JsonPropertyName("inferenceWireApi")] + public ProviderEndpointWireApi? InferenceWireApi { get; set; } - /// Authentication host. HMAC auth always targets the public GitHub host. - [JsonPropertyName("host")] - public required string Host { get; set; } + /// Attribution for the adapter that produced this instance. + [JsonPropertyName("provenance")] + public ModelProviderProvenance Provenance { get => field ??= new(); set; } + + /// Self-contained reference for subsequent provider operations. + [JsonPropertyName("reference")] + public ModelProviderInstanceReference Reference { get => field ??= new(); set; } } -/// Authentication-info input variant for a token sourced from an environment variable, with host, optional login, token, and env var name. -/// The env variant of . +/// Typed provider-operation outcome. Use the code for control flow and the optional message for display. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SettableAuthInfoEnv : SettableAuthInfo +public sealed class ModelProviderOperationOutcome { - /// - [JsonIgnore] - public override string Type => "env"; + /// Machine-readable operation outcome. + [JsonPropertyName("code")] + public ModelProviderOperationOutcomeCode Code { get; set; } - /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// Human-readable detail for non-success outcomes. + [JsonPropertyName("message")] + public string? Message { get; set; } +} - /// Name of the environment variable the token was sourced from. - [JsonPropertyName("envVar")] - public required string EnvVar { get; set; } +/// Provider instances found by a discovery operation. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ModelProviderDiscoverResult +{ + /// Discovered provider instances. Empty when passive default discovery finds no reachable provider. + [JsonPropertyName("instances")] + public IList Instances { get => field ??= []; set; } - /// Authentication host (e.g. https://github.com or a GHES host). - [JsonPropertyName("host")] - public required string Host { get; set; } + /// Typed operation outcome. Passive discovery can return `absent` with an empty instance list. + [JsonPropertyName("outcome")] + public ModelProviderOperationOutcome Outcome { get => field ??= new(); set; } +} - /// User login associated with the token. Undefined for server-to-server tokens (those starting with `ghs_`). - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("login")] - public string? Login { get; set; } +/// Provider discovery parameters. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ModelProviderDiscoverRequest +{ + /// Opaque adapter identity returned by `session.providers.getCatalog`. + [JsonPropertyName("adapterId")] + public string AdapterId { get; set; } = string.Empty; - /// The token value itself. Treat as a secret. - [JsonPropertyName("token")] - public required string Token { get; set; } + /// Provider-specific JSON input. Omission or null selects adapter defaults unless requiresInput is true. Non-null input is validated against the advertised Draft 7 schema when present; otherwise validation belongs to the adapter. + [JsonPropertyName("input")] + public JsonElement? Input { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Token authentication accepted by session.gitHubAuth.setCredentials. -/// The token variant of . +/// Current health information for a provider instance. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SettableAuthInfoToken : SettableAuthInfo +public sealed class ModelProviderStatus { - /// - [JsonIgnore] - public override string Type => "token"; + /// Normalized provider instance. + [JsonPropertyName("instance")] + public ModelProviderInstance Instance { get => field ??= new(); set; } - /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// Typed operation outcome. + [JsonPropertyName("outcome")] + public ModelProviderOperationOutcome Outcome { get => field ??= new(); set; } - /// Authentication host. - [JsonPropertyName("host")] - public required string Host { get; set; } + /// Open provider status value, such as `healthy`, `unreachable`, or `notInstalled`. + [JsonPropertyName("status")] + public string Status { get; set; } = string.Empty; - /// The token value itself. Treat as a secret. - [JsonPropertyName("token")] - public required string Token { get; set; } + /// Provider-reported version. + [JsonPropertyName("version")] + public string? Version { get; set; } } -/// Authentication-info variant for direct Copilot API token auth sourced from environment variables, with public GitHub host. -/// The copilot-api-token variant of . +/// Provider status request parameters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SettableAuthInfoCopilotApiToken : SettableAuthInfo +internal sealed class ModelProviderGetStatusRequest { - /// - [JsonIgnore] - public override string Type => "copilot-api-token"; - - /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// Provider instance reference returned by discovery. + [JsonPropertyName("instance")] + public ModelProviderInstanceReference Instance { get => field ??= new(); set; } - /// Authentication host (always the public GitHub host). - [JsonPropertyName("host")] - public required string Host { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Authentication-info variant for OAuth user auth, with host and login; the token remains in the runtime secret store. -/// The user variant of . +/// Provider-reported model artifact metadata. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SettableAuthInfoUser : SettableAuthInfo +public sealed class ModelArtifactDetails { - /// - [JsonIgnore] - public override string Type => "user"; + /// Provider-reported model architecture. + [JsonPropertyName("architecture")] + public string? Architecture { get; set; } - /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// Provider-reported model families. + [JsonPropertyName("families")] + public IList? Families { get; set; } - /// Authentication host. - [JsonPropertyName("host")] - public required string Host { get; set; } + /// Primary model family. + [JsonPropertyName("family")] + public string? Family { get; set; } - /// OAuth user login. - [JsonPropertyName("login")] - public required string Login { get; set; } + /// Artifact format, such as `gguf`. + [JsonPropertyName("format")] + public string? Format { get; set; } + + /// Provider-reported parameter count label. + [JsonPropertyName("parameterSize")] + public string? ParameterSize { get; set; } + + /// Provider-reported quantization label. + [JsonPropertyName("quantization")] + public string? Quantization { get; set; } + + /// Provider-reported tokenizer. + [JsonPropertyName("tokenizer")] + public string? Tokenizer { get; set; } } -/// An interactive account whose model provider owns its credentials. It carries no GitHub credential. -/// The account variant of . +/// A non-fatal provider observation warning. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SettableAuthInfoAccount : SettableAuthInfo +public sealed class ModelProviderWarning { - /// - [JsonIgnore] - public override string Type => "account"; - - /// Host coordinate owned by the account's model provider. - [JsonPropertyName("host")] - public required string Host { get; set; } + /// Machine-readable warning code. + [JsonPropertyName("code")] + public string Code { get; set; } = string.Empty; - /// Login identifying the provider-owned account. - [JsonPropertyName("login")] - public required string Login { get; set; } + /// Human-readable warning message. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; } -/// Authentication-info input variant for GitHub CLI credentials, carrying host, login, and the `gh auth token` value. -/// The gh-cli variant of . +/// A model offered for agent conversations. Missing capability metadata does not disqualify a candidate. Models known to be incompatible, such as embedding-only models, are excluded by the adapter. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SettableAuthInfoGhCli : SettableAuthInfo +public sealed class DiscoveredModel { - /// - [JsonIgnore] - public override string Type => "gh-cli"; + /// Provider-reported model capabilities. Omitted capability fields are unknown; explicit false values are preserved. + [JsonPropertyName("capabilities")] + public ModelCapabilities Capabilities { get => field ??= new(); set; } - /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// Provider-reported model artifact details. + [JsonPropertyName("details")] + public ModelArtifactDetails Details { get => field ??= new(); set; } - /// Authentication host. - [JsonPropertyName("host")] - public required string Host { get; set; } + /// Provider-reported artifact digest. + [JsonPropertyName("digest")] + public string? Digest { get; set; } - /// User login as reported by `gh auth status`. - [JsonPropertyName("login")] - public required string Login { get; set; } + /// Provider-native model identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// The token returned by `gh auth token`. Treat as a secret. - [JsonPropertyName("token")] - public required string Token { get; set; } -} + /// Provider-reported last-modified timestamp. + [JsonPropertyName("modifiedAt")] + public DateTimeOffset? ModifiedAt { get; set; } -/// Authentication-info input variant for API-key authentication to a non-GitHub LLM provider, carrying the secret `apiKey` and host. -/// The api-key variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SettableAuthInfoApiKey : SettableAuthInfo -{ - /// - [JsonIgnore] - public override string Type => "api-key"; + /// Provider-reported display name. + [JsonPropertyName("name")] + public string? Name { get; set; } - /// The API key. Treat as a secret. - [JsonPropertyName("apiKey")] - public required string ApiKey { get; set; } + /// Attribution for the adapter that produced this model row. + [JsonPropertyName("provenance")] + public ModelProviderProvenance Provenance { get => field ??= new(); set; } - /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("copilotUser")] - public CopilotUserResponse? CopilotUser { get; set; } + /// Provider-reported artifact size in bytes. + [JsonPropertyName("sizeBytes")] + public long? SizeBytes { get; set; } - /// Authentication host. - [JsonPropertyName("host")] - public required string Host { get; set; } + /// Non-fatal warnings encountered while enriching this model. + [JsonPropertyName("warnings")] + public IList Warnings { get => field ??= []; set; } } -/// New auth credentials to install on the session. Omit to leave credentials unchanged. +/// Models offered for agent conversations by one provider instance. Adapters exclude known-incompatible models, but retain candidates with unknown capabilities. Listing does not guarantee compatibility. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSetCredentialsParams +public sealed class DiscoveredModelList { - /// The new auth credentials to install on the session. When omitted or `undefined`, the call is a no-op and the session's existing credentials are preserved. The runtime installs the supplied value immediately for outbound model/API requests. When the credential carries a raw token (`token`, `env`, or `gh-cli`) but no `copilotUser`, the runtime additionally re-resolves `copilotUser` server-side (best-effort, asynchronously, after the synchronous install) so plan/quota/billing metadata regains fidelity; on resolution failure the verbatim credential remains installed. It does NOT otherwise validate the credential. Several variants carry secret material; treat this method's params as containing secrets at rest and in transit. - [JsonPropertyName("credentials")] - public SettableAuthInfo? Credentials { get; set; } + /// Provider-native models in provider order. + [JsonPropertyName("models")] + public IList Models { get => field ??= []; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Typed operation outcome. + [JsonPropertyName("outcome")] + public ModelProviderOperationOutcome Outcome { get => field ??= new(); set; } } -/// Identifies the target session. +/// Provider model inventory request parameters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionGitHubAuthGetCurrentAuthInfoRequest +internal sealed class ModelProviderModelsListRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Provider instance reference returned by discovery. + [JsonPropertyName("instance")] + public ModelProviderInstanceReference Instance { get => field ??= new(); set; } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionGitHubAuthGetAllAuthAvailableRequest -{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Identifies the target session. +/// Vision-specific limits. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionGitHubAuthRefreshCopilotUserRequest +public sealed class ModelCapabilitiesOverrideLimitsVision { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Maximum image size in bytes. + [JsonPropertyName("max_prompt_image_size")] + public long? MaxPromptImageSize { get; set; } + + /// Maximum number of images per prompt. + [JsonPropertyName("max_prompt_images")] + public long? MaxPromptImages { get; set; } + + /// MIME types the model accepts. + [JsonPropertyName("supported_media_types")] + public IList? SupportedMediaTypes { get; set; } } -/// Internal GitHub login parameters. +/// Token limits for prompts, outputs, and context window. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionAuthLoginRequest +public sealed class ModelCapabilitiesOverrideLimits { - /// GitHub host URL. - [JsonPropertyName("host")] - public string Host { get; set; } = string.Empty; - - /// GitHub login. - [JsonPropertyName("login")] - public string Login { get; set; } = string.Empty; + /// Maximum total context window size in tokens. + [JsonPropertyName("max_context_window_tokens")] + public long? MaxContextWindowTokens { get; set; } - /// Whether to persist the token after login. - [JsonPropertyName("persist")] - public bool? Persist { get; set; } + /// Maximum number of output/completion tokens. + [JsonPropertyName("max_output_tokens")] + public long? MaxOutputTokens { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Maximum number of prompt/input tokens. + [JsonPropertyName("max_prompt_tokens")] + public long? MaxPromptTokens { get; set; } - /// GitHub authentication token. - [JsonPropertyName("token")] - public string Token { get; set; } = string.Empty; + /// Vision-specific limits. + [JsonPropertyName("vision")] + public ModelCapabilitiesOverrideLimitsVision? Vision { get; set; } } -/// Parameters for switching the session's active authentication. +/// Feature flags indicating what the model supports. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionAuthSwitchRequest +public sealed class ModelCapabilitiesOverrideSupports { - /// Authentication information to activate. - [JsonPropertyName("authInfo")] - public AuthInfo AuthInfo { get => field ??= new(); set; } + /// Resolved Anthropic adaptive-thinking capability — unsupported / optional / required / adaptive_only. 'required' models reject thinking.type='enabled' with HTTP 400 but still accept 'disabled' (e.g. opus-4.7/4.8/5, sonnet-5); 'adaptive_only' models accept nothing but 'adaptive' (e.g. fable, mythos). + [JsonPropertyName("adaptive_thinking")] + public AdaptiveThinkingSupport? AdaptiveThinking { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether this model supports reasoning effort configuration. + [JsonPropertyName("reasoningEffort")] + public bool? ReasoningEffort { get; set; } - /// Optional token paired with the authentication information. - [JsonPropertyName("token")] - public string? Token { get; set; } + /// Whether this model supports canonical tool calling. + [JsonPropertyName("toolCalls")] + public bool? ToolCalls { get; set; } + + /// Whether this model supports vision/image input. + [JsonPropertyName("vision")] + public bool? Vision { get; set; } } -/// Identifies the target session. +/// Optional capability overrides (vision, tool_calls, reasoning, etc.). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionGitHubAuthLogoutRequest +public sealed class ModelCapabilitiesOverride { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Token limits for prompts, outputs, and context window. + [JsonPropertyName("limits")] + public ModelCapabilitiesOverrideLimits? Limits { get; set; } + + /// Feature flags indicating what the model supports. + [JsonPropertyName("supports")] + public ModelCapabilitiesOverrideSupports? Supports { get; set; } } -/// Parameters identifying a GitHub authentication to log out. +/// RPC data type for ProtocolSystemMessageAppendConfig operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionAuthLogoutUserRequest +public sealed class ProtocolSystemMessageAppendConfig { - /// Authentication information to log out. - [JsonPropertyName("authInfo")] - public AuthInfo AuthInfo { get => field ??= new(); set; } + /// Text appended to the standard system prompt. + [JsonPropertyName("content")] + public string? Content { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Append-mode discriminator. Omission also selects append mode. + [JsonPropertyName("mode")] + public ProtocolAppendMode? Mode { get; set; } } -/// Validation error from an authentication attempt. +/// RPC data type for SystemMessageBlock operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AuthValidationError +public sealed class SystemMessageBlock { - /// Optional message returned by GitHub. - [JsonPropertyName("githubMessage")] - public string? GitHubMessage { get; set; } + /// Whether providers with explicit prompt caching should place a cache breakpoint after this block. + [JsonPropertyName("cacheBreakpoint")] + public bool? CacheBreakpoint { get; set; } - /// Authentication validation error message. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; + /// Text content for this system-message block. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; + + /// Whether the block is static and may be cached independently of dynamic prompt content. + [JsonPropertyName("isStatic")] + public bool? IsStatic { get; set; } } -/// Identifies the target session. +/// RPC data type for ProtocolSystemMessageReplaceConfig operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionGitHubAuthLastAuthErrorsRequest +public sealed class ProtocolSystemMessageReplaceConfig { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Complete replacement system-message text. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; + + /// Optional structured blocks corresponding to the replacement content. + [JsonPropertyName("contentBlocks")] + public IList? ContentBlocks { get; set; } + + /// Replace-mode discriminator. + [JsonPropertyName("mode")] + public ProtocolReplaceMode Mode { get; set; } } -/// The enumerated collection, keyed by the same selector as the query. -/// Polymorphic base type discriminated by kind. +/// RPC data type for ProtocolStaticSectionOverride operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ProtocolStaticSectionOverride +{ + /// Declarative operation applied to the section. + [JsonPropertyName("action")] + public ProtocolStaticSectionAction Action { get; set; } + + /// Optional content used by replace, append, and prepend operations. + [JsonPropertyName("content")] + public string? Content { get; set; } +} + +/// Polymorphic base type discriminated by action. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", + TypeDiscriminatorPropertyName = "action", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(AuthEnumerateValueAccounts), "accounts")] -[JsonDerivedType(typeof(AuthEnumerateValueProviders), "providers")] -public partial class AuthEnumerateValue +[JsonDerivedType(typeof(ProtocolMarkerSectionOverrideTransform), "transform")] +[JsonDerivedType(typeof(ProtocolMarkerSectionOverridePreserve), "preserve")] +public partial class ProtocolMarkerSectionOverride { /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; + [JsonPropertyName("action")] + public virtual string Action { get; set; } = string.Empty; } -/// One signed-in account in the roster forest. +/// The transform variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AccountStatus +public partial class ProtocolMarkerSectionOverrideTransform : ProtocolMarkerSectionOverride { - /// Whether this is the active account. - [JsonPropertyName("active")] - public bool Active { get; set; } - - /// Human-readable credential source used to authenticate this account, such as `gh` or `GITHUB_TOKEN`. - [JsonPropertyName("authSource")] - public string? AuthSource { get; set; } - - /// Opaque id of the account this one was derived from (e.g. an EMU account's base Entra identity); absent for a root account. Matches the base identity account's selectionId, forming the derivation edge. - [JsonPropertyName("derivedFrom")] - public string? DerivedFrom { get; set; } - - /// Authentication host URL. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("host")] - public string Host { get; set; } = string.Empty; - - /// The provider kind of this account. - [JsonPropertyName("kind")] - public AccountKind Kind { get; set; } - - /// Authenticated login/username. - [JsonPropertyName("login")] - public string Login { get; set; } = string.Empty; - - /// Opaque selection id used to switch to, or log out, this account. - [JsonPropertyName("selectionId")] - public string SelectionId { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Action => "transform"; } -/// The accounts variant of . +/// The preserve variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthEnumerateValueAccounts : AuthEnumerateValue +public partial class ProtocolMarkerSectionOverridePreserve : ProtocolMarkerSectionOverride { /// [JsonIgnore] - public override string Kind => "accounts"; - - /// The signed-in account forest; empty when not logged in. - [JsonPropertyName("items")] - public required IList Items { get; set; } + public override string Action => "preserve"; } -/// A provider offered for interactive login. +/// JSON union data type for ProtocolSectionOverride. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProviderDescriptor +[JsonConverter(typeof(Converter))] +public sealed partial class ProtocolSectionOverride { - /// Whether this provider is currently available to sign in with. - [JsonPropertyName("available")] - public bool Available { get; set; } + /// Gets the value when this instance contains . + public ProtocolStaticSectionOverride? ProtocolStaticSectionOverride { get; } - /// The neutral provider kind. - [JsonPropertyName("kind")] - public LoginProviderKind Kind { get; set; } + /// Gets the value when this instance contains . + public ProtocolMarkerSectionOverride? ProtocolMarkerSectionOverride { get; } - /// Human-readable menu label, owned by the runtime so every consumer renders identical text. - [JsonPropertyName("label")] - public string Label { get; set; } = string.Empty; -} + /// Initializes a new instance of the class from . + public ProtocolSectionOverride(ProtocolStaticSectionOverride value) + { + ArgumentNullException.ThrowIfNull(value); + ProtocolStaticSectionOverride = value; + } -/// The providers variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthEnumerateValueProviders : AuthEnumerateValue -{ - /// - [JsonIgnore] - public override string Kind => "providers"; + /// Converts to . + public static implicit operator ProtocolSectionOverride(ProtocolStaticSectionOverride value) => new(value); - /// The providers offered for interactive login. - [JsonPropertyName("items")] - public required IList Items { get; set; } -} + /// Initializes a new instance of the class from . + public ProtocolSectionOverride(ProtocolMarkerSectionOverride value) + { + ArgumentNullException.ThrowIfNull(value); + ProtocolMarkerSectionOverride = value; + } -/// Selects which accounts collection to enumerate. A no-arg selector is the empty-payload variant. -/// Polymorphic base type discriminated by kind. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(AuthEnumerateQueryAccounts), "accounts")] -[JsonDerivedType(typeof(AuthEnumerateQueryProviders), "providers")] -public partial class AuthEnumerateQuery -{ - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Converts to . + public static implicit operator ProtocolSectionOverride(ProtocolMarkerSectionOverride value) => new(value); + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ProtocolSectionOverride Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + throw new JsonException("Expected JSON object for ProtocolSectionOverride."); + } -/// The accounts variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthEnumerateQueryAccounts : AuthEnumerateQuery -{ - /// - [JsonIgnore] - public override string Kind => "accounts"; -} + using var document = JsonDocument.ParseValue(ref reader); + var element = document.RootElement; + if (element.ValueKind == JsonValueKind.Object && (element.TryGetProperty("action", out _) && element.GetProperty("action").ValueKind == JsonValueKind.String && (element.GetProperty("action").GetString() == "replace" || element.GetProperty("action").GetString() == "remove" || element.GetProperty("action").GetString() == "append" || element.GetProperty("action").GetString() == "prepend"))) + { + var protocolStaticSectionOverride = JsonSerializer.Deserialize(element, RpcJsonContext.Default.ProtocolStaticSectionOverride); + return protocolStaticSectionOverride is null ? throw new JsonException("Expected ProtocolStaticSectionOverride value.") : new ProtocolSectionOverride(protocolStaticSectionOverride); + } + if ((element.ValueKind == JsonValueKind.Object && (element.TryGetProperty("action", out _) && element.GetProperty("action").ValueKind == JsonValueKind.String && (element.GetProperty("action").GetString() == "transform")) || element.ValueKind == JsonValueKind.Object && (element.TryGetProperty("action", out _) && element.GetProperty("action").ValueKind == JsonValueKind.String && (element.GetProperty("action").GetString() == "preserve")))) + { + var protocolMarkerSectionOverride = JsonSerializer.Deserialize(element, RpcJsonContext.Default.ProtocolMarkerSectionOverride); + return protocolMarkerSectionOverride is null ? throw new JsonException("Expected ProtocolMarkerSectionOverride value.") : new ProtocolSectionOverride(protocolMarkerSectionOverride); + } -/// The providers variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthEnumerateQueryProviders : AuthEnumerateQuery -{ - /// - [JsonIgnore] - public override string Kind => "providers"; + throw new JsonException("JSON value did not match any ProtocolSectionOverride variant."); + } - /// Whether an interactive Entra broker is available on the host; gates Entra availability in the returned list. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("brokerAvailable")] - public bool? BrokerAvailable { get; set; } + /// + public override void Write(Utf8JsonWriter writer, ProtocolSectionOverride value, JsonSerializerOptions options) + { + if (value.ProtocolStaticSectionOverride is { } protocolStaticSectionOverride) + { + JsonSerializer.Serialize(writer, protocolStaticSectionOverride, RpcJsonContext.Default.ProtocolStaticSectionOverride); + return; + } + if (value.ProtocolMarkerSectionOverride is { } protocolMarkerSectionOverride) + { + JsonSerializer.Serialize(writer, protocolMarkerSectionOverride, RpcJsonContext.Default.ProtocolMarkerSectionOverride); + return; + } + + throw new JsonException("No ProtocolSectionOverride variant value is set."); + } + } } -/// Enumerate request carrying the typed collection query. +/// RPC data type for ProtocolSystemMessageCustomizeConfig operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AccountsEnumerateRequest +public sealed class ProtocolSystemMessageCustomizeConfig { - /// Which typed accounts collection to enumerate. - [JsonPropertyName("query")] - public AuthEnumerateQuery Query { get => field ??= new(); set; } + /// Text appended after the customized sections. + [JsonPropertyName("content")] + public string? Content { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Customize-mode discriminator. + [JsonPropertyName("mode")] + public ProtocolCustomizeMode Mode { get; set; } + + /// Named standard-prompt section overrides. + [JsonPropertyName("sections")] + public IDictionary? Sections { get; set; } } -/// The read result, keyed by the same selector as the query. -/// Polymorphic base type discriminated by kind. +/// JSON union data type for ProtocolSystemMessageConfig. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(AuthReadValueActiveAccount), "activeAccount")] -[JsonDerivedType(typeof(AuthReadValueStatus), "status")] -[JsonDerivedType(typeof(AuthReadValueLastErrors), "lastErrors")] -public partial class AuthReadValue +[JsonConverter(typeof(Converter))] +public sealed partial class ProtocolSystemMessageConfig { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Gets the value when this instance contains . + public ProtocolSystemMessageAppendConfig? ProtocolSystemMessageAppendConfig { get; } + /// Gets the value when this instance contains . + public ProtocolSystemMessageReplaceConfig? ProtocolSystemMessageReplaceConfig { get; } -/// The activeAccount variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthReadValueActiveAccount : AuthReadValue -{ - /// - [JsonIgnore] - public override string Kind => "activeAccount"; + /// Gets the value when this instance contains . + public ProtocolSystemMessageCustomizeConfig? ProtocolSystemMessageCustomizeConfig { get; } - /// The active account, or absent when not logged in. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("account")] - public AccountStatus? Account { get; set; } + /// Initializes a new instance of the class from . + public ProtocolSystemMessageConfig(ProtocolSystemMessageAppendConfig value) + { + ArgumentNullException.ThrowIfNull(value); + ProtocolSystemMessageAppendConfig = value; + } - /// Credential-free identity metadata for the active account, including resolved Copilot user information when available. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("authInfo")] - public AuthIdentity? AuthInfo { get; set; } -} + /// Converts to . + public static implicit operator ProtocolSystemMessageConfig(ProtocolSystemMessageAppendConfig value) => new(value); -/// Neutral authentication status summary. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AuthStatusDto -{ - /// Number of signed-in accounts in the roster. - [JsonPropertyName("accountCount")] - public long AccountCount { get; set; } + /// Initializes a new instance of the class from . + public ProtocolSystemMessageConfig(ProtocolSystemMessageReplaceConfig value) + { + ArgumentNullException.ThrowIfNull(value); + ProtocolSystemMessageReplaceConfig = value; + } - /// Active account host, if authenticated. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("activeHost")] - public string? ActiveHost { get; set; } + /// Converts to . + public static implicit operator ProtocolSystemMessageConfig(ProtocolSystemMessageReplaceConfig value) => new(value); - /// Active account login, if authenticated. - [JsonPropertyName("activeLogin")] - public string? ActiveLogin { get; set; } + /// Initializes a new instance of the class from . + public ProtocolSystemMessageConfig(ProtocolSystemMessageCustomizeConfig value) + { + ArgumentNullException.ThrowIfNull(value); + ProtocolSystemMessageCustomizeConfig = value; + } - /// Copilot plan tier of the active account, if known. - [JsonPropertyName("copilotPlan")] - public string? CopilotPlan { get; set; } + /// Converts to . + public static implicit operator ProtocolSystemMessageConfig(ProtocolSystemMessageCustomizeConfig value) => new(value); - /// Whether the session has resolved authentication. - [JsonPropertyName("isAuthenticated")] - public bool IsAuthenticated { get; set; } -} + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ProtocolSystemMessageConfig Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + throw new JsonException("Expected JSON object for ProtocolSystemMessageConfig."); + } -/// The status variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthReadValueStatus : AuthReadValue -{ - /// - [JsonIgnore] - public override string Kind => "status"; + using var document = JsonDocument.ParseValue(ref reader); + var element = document.RootElement; + if (element.ValueKind == JsonValueKind.Object && (!element.TryGetProperty("mode", out _) || (element.TryGetProperty("mode", out _) && element.GetProperty("mode").ValueKind == JsonValueKind.String && (element.GetProperty("mode").GetString() == "append")))) + { + var protocolSystemMessageAppendConfig = JsonSerializer.Deserialize(element, RpcJsonContext.Default.ProtocolSystemMessageAppendConfig); + return protocolSystemMessageAppendConfig is null ? throw new JsonException("Expected ProtocolSystemMessageAppendConfig value.") : new ProtocolSystemMessageConfig(protocolSystemMessageAppendConfig); + } + if (element.ValueKind == JsonValueKind.Object && (element.TryGetProperty("mode", out _) && element.GetProperty("mode").ValueKind == JsonValueKind.String && (element.GetProperty("mode").GetString() == "replace"))) + { + var protocolSystemMessageReplaceConfig = JsonSerializer.Deserialize(element, RpcJsonContext.Default.ProtocolSystemMessageReplaceConfig); + return protocolSystemMessageReplaceConfig is null ? throw new JsonException("Expected ProtocolSystemMessageReplaceConfig value.") : new ProtocolSystemMessageConfig(protocolSystemMessageReplaceConfig); + } + if (element.ValueKind == JsonValueKind.Object && (element.TryGetProperty("mode", out _) && element.GetProperty("mode").ValueKind == JsonValueKind.String && (element.GetProperty("mode").GetString() == "customize"))) + { + var protocolSystemMessageCustomizeConfig = JsonSerializer.Deserialize(element, RpcJsonContext.Default.ProtocolSystemMessageCustomizeConfig); + return protocolSystemMessageCustomizeConfig is null ? throw new JsonException("Expected ProtocolSystemMessageCustomizeConfig value.") : new ProtocolSystemMessageConfig(protocolSystemMessageCustomizeConfig); + } - /// The neutral authentication status summary. - [JsonPropertyName("status")] - public required AuthStatusDto Status { get; set; } -} + throw new JsonException("JSON value did not match any ProtocolSystemMessageConfig variant."); + } -/// The lastErrors variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthReadValueLastErrors : AuthReadValue -{ - /// - [JsonIgnore] - public override string Kind => "lastErrors"; + /// + public override void Write(Utf8JsonWriter writer, ProtocolSystemMessageConfig value, JsonSerializerOptions options) + { + if (value.ProtocolSystemMessageAppendConfig is { } protocolSystemMessageAppendConfig) + { + JsonSerializer.Serialize(writer, protocolSystemMessageAppendConfig, RpcJsonContext.Default.ProtocolSystemMessageAppendConfig); + return; + } + if (value.ProtocolSystemMessageReplaceConfig is { } protocolSystemMessageReplaceConfig) + { + JsonSerializer.Serialize(writer, protocolSystemMessageReplaceConfig, RpcJsonContext.Default.ProtocolSystemMessageReplaceConfig); + return; + } + if (value.ProtocolSystemMessageCustomizeConfig is { } protocolSystemMessageCustomizeConfig) + { + JsonSerializer.Serialize(writer, protocolSystemMessageCustomizeConfig, RpcJsonContext.Default.ProtocolSystemMessageCustomizeConfig); + return; + } - /// Validation errors from the most recent authentication attempt. - [JsonPropertyName("errors")] - public required IList Errors { get; set; } + throw new JsonException("No ProtocolSystemMessageConfig variant value is set."); + } + } } -/// Selects which typed accounts datum to read. -/// Polymorphic base type discriminated by kind. +/// A BYOK model definition referencing a named provider. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(AuthReadQueryActiveAccount), "activeAccount")] -[JsonDerivedType(typeof(AuthReadQueryStatus), "status")] -[JsonDerivedType(typeof(AuthReadQueryLastErrors), "lastErrors")] -public partial class AuthReadQuery +public sealed class ProviderModelConfig { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Optional capability overrides (vision, tool_calls, reasoning, etc.). + [JsonPropertyName("capabilities")] + public ModelCapabilitiesOverride? Capabilities { get; set; } + /// Provider-local model id, unique within its provider. The session-wide selection id (shown in the model list and passed to switchTo) is the provider-qualified `provider/id`. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; -/// The activeAccount variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthReadQueryActiveAccount : AuthReadQuery -{ - /// - [JsonIgnore] - public override string Kind => "activeAccount"; -} + /// Maximum context window tokens for the model. + [JsonPropertyName("maxContextWindowTokens")] + public double? MaxContextWindowTokens { get; set; } -/// The status variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthReadQueryStatus : AuthReadQuery -{ - /// - [JsonIgnore] - public override string Kind => "status"; -} + /// Maximum output tokens for the model. + [JsonPropertyName("maxOutputTokens")] + public double? MaxOutputTokens { get; set; } -/// The lastErrors variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthReadQueryLastErrors : AuthReadQuery -{ - /// - [JsonIgnore] - public override string Kind => "lastErrors"; -} + /// Maximum prompt/input tokens for the model. + [JsonPropertyName("maxPromptTokens")] + public double? MaxPromptTokens { get; set; } -/// Read request carrying the typed datum query. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AccountsGetRequest -{ - /// Which typed accounts datum to read. - [JsonPropertyName("query")] - public AuthReadQuery Query { get => field ??= new(); set; } + /// Provider-published model metadata, preserved verbatim as the public Model.metadata object. + [JsonPropertyName("metadata")] + public IDictionary? Metadata { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Well-known base model id used for behavior/capability/config lookup. Defaults to `id`. + [JsonPropertyName("modelId")] + public string? ModelId { get; set; } -/// Result of a non-interactive accounts mutation. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AuthWriteResult -{ - /// For a logout, whether other signed-in accounts remain. - [JsonPropertyName("moreUsers")] - public bool? MoreUsers { get; set; } + /// Display name for model pickers. Defaults to the provider-qualified selection id (`provider/id`). + [JsonPropertyName("name")] + public string? Name { get; set; } - /// Whether the mutation was applied. - [JsonPropertyName("ok")] - public bool Ok { get; set; } + /// Name of the configured provider that serves this model. + [JsonPropertyName("provider")] + public string Provider { get; set; } = string.Empty; + + /// System-message configuration used when the runtime builds the standard prompt for this provider-qualified model, including general-purpose subagents. It uses the same object hierarchy as session-level systemMessage configuration, except transform actions are rejected because the current callback protocol is not model-scoped. When present, it overrides the session-wide configuration on those prompt paths. Selected custom-agent and specialized-subagent prompts remain authoritative. + [JsonPropertyName("systemMessage")] + public ProtocolSystemMessageConfig? SystemMessage { get; set; } + + /// The model name sent to the provider API for inference. Defaults to `id`. + [JsonPropertyName("wireModel")] + public string? WireModel { get; set; } } -/// One non-interactive accounts mutation command (the selector is fused with its typed args). -/// Polymorphic base type discriminated by kind. +/// Azure-specific provider options. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(AuthWriteSwitchActive), "switchActive")] -[JsonDerivedType(typeof(AuthWriteLogout), "logout")] -[JsonDerivedType(typeof(AuthWriteSetCredentials), "setCredentials")] -public partial class AuthWrite +public sealed class ProviderConfigAzure { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; + /// API version. When set, uses the versioned deployment route. When omitted, uses the GA versionless v1 route. + [JsonPropertyName("apiVersion")] + public string? ApiVersion { get; set; } } - -/// The switchActive variant of . +/// External SDK input for a named custom model provider. Ingested by the native protocol boundary before host dispatch. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthWriteSwitchActive : AuthWrite +public sealed class NamedProviderConfig { - /// - [JsonIgnore] - public override string Kind => "switchActive"; + /// Static API key used to authenticate provider requests. + [JsonPropertyName("apiKey")] + public string? ApiKey { get; set; } - /// Opaque selection id of the account to make active. - [JsonPropertyName("selectionId")] - public required string SelectionId { get; set; } -} + /// Azure authentication configuration for the provider. + [JsonPropertyName("azure")] + public ProviderConfigAzure? Azure { get; set; } -/// The logout variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthWriteLogout : AuthWrite -{ - /// - [JsonIgnore] - public override string Kind => "logout"; + /// Base URL for provider API requests. + [JsonPropertyName("baseUrl")] + public string BaseUrl { get; set; } = string.Empty; - /// Opaque selection id of the account to log out; absent logs out the active account. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("selectionId")] - public string? SelectionId { get; set; } + /// Static bearer token used to authenticate provider requests. + [JsonPropertyName("bearerToken")] + public string? BearerToken { get; set; } + + /// Whether the host supplies bearer tokens dynamically. + [JsonPropertyName("hasBearerTokenProvider")] + public bool? HasBearerTokenProvider { get; set; } + + /// Additional HTTP headers included with provider requests. + [JsonPropertyName("headers")] + public IDictionary? Headers { get; set; } + + /// The product serving the provider's models, reported in telemetry as `model_provider`. Only affects telemetry. + [JsonPropertyName("modelProvider")] + public ProviderConfigModelProvider? ModelProvider { get; set; } + + /// Unique provider name used to qualify model selection IDs. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Transport used to communicate with the provider. + [JsonPropertyName("transport")] + public ProviderConfigTransport? Transport { get; set; } + + /// Provider protocol family. + [JsonPropertyName("type")] + public ProviderConfigType? Type { get; set; } + + /// Wire API used to communicate with the provider. + [JsonPropertyName("wireApi")] + public ProviderConfigWireApi? WireApi { get; set; } } -/// The setCredentials variant of . +/// Provider configuration prepared from a discovered model. Preparing a plan changes nothing: it neither registers the model with the session nor writes durable configuration. To apply it, pass `provider` and `model` to `session.provider.add`, omitting whichever the dispositions report as already configured. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthWriteSetCredentials : AuthWrite +public sealed class ModelProviderConfigurationPlan { - /// - [JsonIgnore] - public override string Kind => "setCredentials"; + /// Model definition prepared from the discovered model. Capability fields the provider did not report stay omitted rather than being asserted false. + [JsonPropertyName("model")] + public ProviderModelConfig Model { get => field ??= new(); set; } - /// Authentication host URL. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("host")] - public required string Host { get; set; } + /// Whether `model` still needs to be registered. When `alreadyConfigured`, `selectionId` is already registered and the caller can select it without adding anything. + [JsonPropertyName("modelDisposition")] + public ModelProviderConfigurationDisposition ModelDisposition { get; set; } - /// Login/username for the credential. - [JsonPropertyName("login")] - public required string Login { get; set; } + /// Provider connection prepared from the instance's inference metadata. Carries no credential; supply one if the endpoint requires it. + [JsonPropertyName("provider")] + public NamedProviderConfig Provider { get => field ??= new(); set; } - /// GitHub authentication token to install. - [JsonPropertyName("token")] - public required string Token { get; set; } + /// Whether `provider` still needs to be registered. When `alreadyConfigured`, a provider with the same endpoint is already registered and `provider` restates it under its existing name; adding it again is rejected as a duplicate. + [JsonPropertyName("providerDisposition")] + public ModelProviderConfigurationDisposition ProviderDisposition { get; set; } + + /// Provider-qualified selection id (`provider/id`) to pass to `switchTo` once the plan is applied. + [JsonPropertyName("selectionId")] + public string SelectionId { get; set; } = string.Empty; + + /// Non-fatal warnings carried over from the discovered model, such as capabilities the provider did not report. + [JsonPropertyName("warnings")] + public IList Warnings { get => field ??= []; set; } } -/// Mutation request carrying the typed write command. +/// A discovered instance and one of its models to translate into provider configuration. Pass back the instance and model as returned by `session.providers.discover` and `session.providers.models.list`. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AccountsSetRequest +internal sealed class ModelProviderPrepareConfigurationRequest { - /// The non-interactive mutation command to apply. - [JsonPropertyName("command")] - public AuthWrite Command { get => field ??= new(); set; } + /// The discovered instance that serves the model. + [JsonPropertyName("instance")] + public ModelProviderInstance Instance { get => field ??= new(); set; } + + /// The discovered model to configure. + [JsonPropertyName("model")] + public DiscoveredModel Model { get => field ??= new(); set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// One step in an interactive login flow. The consumer acts on the step and calls advance to proceed. Browser-open is encoded as two distinct steps by design: `open-url` is CONSUMER-driven (the provider surfaces the authorize URL and the consumer opens it — github.com/GHEC web), while `needs-interaction` is PROVIDER-driven (the provider opens the browser or broker UI itself and does not surface a URL — Entra). -/// Polymorphic base type discriminated by kind. +/// Managed sandbox enforcement state for a session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(AuthLoginStepOpenUrl), "open-url")] -[JsonDerivedType(typeof(AuthLoginStepInputRequired), "input-required")] -[JsonDerivedType(typeof(AuthLoginStepAwaiting), "awaiting")] -[JsonDerivedType(typeof(AuthLoginStepNeedsInteraction), "needs-interaction")] -[JsonDerivedType(typeof(AuthLoginStepCompleted), "completed")] -[JsonDerivedType(typeof(AuthLoginStepError), "error")] -public partial class AuthLoginStep +public sealed class SandboxEnforcementStatus { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Whether an enforcement failure has permanently blocked the session. + [JsonPropertyName("blocked")] + public bool Blocked { get; set; } + /// The first sandbox enforcement failure that blocked the session. + [JsonPropertyName("reason")] + public string? Reason { get; set; } -/// The open-url variant of . + /// Whether the effective managed policy requires an available sandbox backend. + [JsonPropertyName("required")] + public bool Required { get; set; } +} + +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthLoginStepOpenUrl : AuthLoginStep +internal sealed class SessionSandboxGetEnforcementStatusRequest { - /// - [JsonIgnore] - public override string Kind => "open-url"; - - /// Authorize URL the consumer should open in a browser (consumer-driven browser-open). - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// The input-required variant of . +/// A possible secret-bearing environment variable and optional locally suggested HTTPS injection hosts. This is a draft for user review, not an active grant. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthLoginStepInputRequired : AuthLoginStep +public sealed class SandboxCredentialSuggestion { - /// - [JsonIgnore] - public override string Kind => "input-required"; + /// Environment variable name. The secret value is never returned. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Prompt for the value the provider needs; the consumer supplies it as advance input (e.g. a GitHub Enterprise Cloud host, *.ghe.com). - [JsonPropertyName("prompt")] - public required string Prompt { get; set; } + /// HTTPS hostnames suggested by a local known-provider mapping. An empty list requires the user to supply injection hosts before adding a masking entry. These suggestions do not allow network access. + [JsonPropertyName("suggestedInjectHosts")] + public IList SuggestedInjectHosts { get => field ??= []; set; } } -/// The awaiting variant of . +/// Possible unconfigured secrets in the sandbox shell environment, sorted by variable name, with no secret values. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthLoginStepAwaiting : AuthLoginStep +public sealed class SandboxCredentialSuggestionsResult { - /// - [JsonIgnore] - public override string Kind => "awaiting"; + /// Candidates for user review. Empty when sandboxing is disabled or no unconfigured candidates are present. + [JsonPropertyName("suggestions")] + public IList Suggestions { get => field ??= []; set; } } -/// The needs-interaction variant of . +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthLoginStepNeedsInteraction : AuthLoginStep +internal sealed class SessionSandboxGetCredentialSuggestionsRequest { - /// - [JsonIgnore] - public override string Kind => "needs-interaction"; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// A credential-free account choice after sign-in. +/// Result of attempting to disable sandboxing for the current session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AuthLoginAccount +public sealed class SandboxDisableForSessionResult { - /// Host coordinate owned by the selected account's provider. - [JsonPropertyName("host")] - public string Host { get; set; } = string.Empty; - - /// Provider kind that owns this account choice. - [JsonPropertyName("kind")] - public AccountKind Kind { get; set; } - - /// Human-readable login for the account choice. - [JsonPropertyName("login")] - public string Login { get; set; } = string.Empty; + /// The authoritative sandbox enabled state after the operation. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } - /// Opaque identifier supplied to the next login step to select this account. - [JsonPropertyName("selectionId")] - public string SelectionId { get; set; } = string.Empty; + /// Whether this call resolved the pending request and applied the session opt-out. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Result of an interactive login flow. Pending consent or account selection is not terminal. +/// Optional informational context describing how and where the permission decision was made. This does not affect permission behavior. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AuthLoginResultDto +public sealed class PermissionDecisionContext { - /// Available accounts when sign-in is awaiting account selection, ordered with Microsoft 365 first. - [JsonPropertyName("accounts")] - public IList? Accounts { get; set; } + /// Disposition of the permission request as observed by the responding client. + [JsonPropertyName("outcome")] + public PermissionDecisionOutcome Outcome { get; set; } - /// Host that was signed in, when completed. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("host")] - public string? Host { get; set; } + /// Whether the responding client could ask a user interactively, was running headlessly, or had no response path. Omit when the client cannot determine this authoritatively. + [JsonPropertyName("responseCapability")] + public PermissionResponseCapability? ResponseCapability { get; set; } - /// Login that was signed in, when completed. - [JsonPropertyName("login")] - public string? Login { get; set; } + /// Controlled reason or actor responsible for the response. + [JsonPropertyName("source")] + public PermissionDecisionSource Source { get; set; } - /// Current disposition of the login, including pending user decisions. - [JsonPropertyName("status")] - public AuthLoginResultStatus Status { get; set; } + /// Client surface that submitted the response. + [JsonPropertyName("surface")] + public PermissionDecisionSurface Surface { get; set; } } -/// The completed variant of . +/// Request to disable sandboxing for the current session while resolving an active sandbox-bypass permission prompt. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthLoginStepCompleted : AuthLoginStep +internal sealed class SandboxDisableForSessionRequest { - /// - [JsonIgnore] - public override string Kind => "completed"; - - /// Login result. When status is needs-plaintext-consent or needs-account-selection, advance with the user's decision to continue. - [JsonPropertyName("result")] - public required AuthLoginResultDto Result { get; set; } -} + /// Optional attribution for the permission decision. + [JsonPropertyName("decisionContext")] + public PermissionDecisionContext? DecisionContext { get; set; } -/// The error variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class AuthLoginStepError : AuthLoginStep -{ - /// - [JsonIgnore] - public override string Kind => "error"; + /// Identifier of the exact pending sandbox-bypass permission request that authorized the session opt-out. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; - /// Human-readable failure message. - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// A started login flow: its opaque id and first step. +/// Result of accepting a sandbox path grant. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AuthLoginBegun +public sealed class SandboxGrantPathForRequestResult { - /// Opaque flow id used to advance or cancel this login. - [JsonPropertyName("flowId")] - public string FlowId { get; set; } = string.Empty; - - /// The first step of the flow. - [JsonPropertyName("step")] - public AuthLoginStep Step { get => field ??= new(); set; } + /// Whether this call resolved the pending request and added the path to the session's sandbox policy. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Begin an interactive login flow for a provider kind. Dispatch is kind-only. +/// Request to accept the sandbox path grant offered on an active sandbox escalation permission prompt. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AuthLoginBeginRequest +internal sealed class SandboxGrantPathForRequestRequest { - /// The provider kind to sign in with. - [JsonPropertyName("kind")] - public LoginProviderKind Kind { get; set; } + /// Optional attribution for the permission decision. + [JsonPropertyName("decisionContext")] + public PermissionDecisionContext? DecisionContext { get; set; } + + /// Identifier of the exact pending sandbox escalation permission request whose sandboxPathGrant to accept. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Advance an in-flight login flow, optionally fulfilling an input-required step. +/// Authentication status and account metadata for the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AuthLoginAdvanceRequest +public sealed class SessionAuthStatus { - /// Opaque flow id from begin. - [JsonPropertyName("flowId")] - public string FlowId { get; set; } = string.Empty; + /// Authentication type. + [JsonPropertyName("authType")] + public AuthInfoType? AuthType { get; set; } - /// Neutral input fulfilling a preceding input-required step (e.g. a GHEC host); ignored otherwise. - [JsonPropertyName("input")] - public string? Input { get; set; } + /// Copilot plan tier (e.g., individual_pro, business). + [JsonPropertyName("copilotPlan")] + public string? CopilotPlan { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Authentication host URL. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("host")] + public string? Host { get; set; } + + /// Whether the session has resolved authentication. + [JsonPropertyName("isAuthenticated")] + public bool IsAuthenticated { get; set; } + + /// Authenticated login/username, if available. + [JsonPropertyName("login")] + public string? Login { get; set; } + + /// Human-readable authentication status description. + [JsonPropertyName("statusMessage")] + public string? StatusMessage { get; set; } } -/// Cancel an in-flight login flow. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AuthLoginCancelRequest +internal sealed class SessionGitHubAuthGetStatusRequest { - /// Opaque flow id from begin. - [JsonPropertyName("flowId")] - public string FlowId { get; set; } = string.Empty; - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// A file included in the session debug bundle. +/// Indicates whether the credential update succeeded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DebugCollectLogsCollectedEntry +public sealed class SessionSetCredentialsResult { - /// Relative path of the file in the staged bundle/archive. - [JsonPropertyName("bundlePath")] - public string BundlePath { get; set; } = string.Empty; - - /// Redacted output size in bytes. - [JsonPropertyName("sizeBytes")] - public long SizeBytes { get; set; } + /// Whether the session ended up with a populated `copilotUser` for the installed credentials. `true` when the supplied credential already carried `copilotUser` or it was successfully re-resolved server-side. `false` when the credential is installed without `copilotUser` — either re-resolution failed, or the variant cannot be re-resolved from the credential alone (only the raw-token variants `token`, `env`, and `gh-cli` can). In both `false` cases the token swap still applied, but plan/quota/billing metadata is degraded. Present whenever a credential was supplied; omitted only when no credential was supplied (no-op call). + [JsonPropertyName("copilotUserResolved")] + public bool? CopilotUserResolved { get; set; } - /// Source category for this entry. - [JsonPropertyName("source")] - public DebugCollectLogsSource Source { get; set; } + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// An optional debug bundle entry that could not be included. +/// Authentication credentials accepted by session.gitHubAuth.setCredentials. Session-owned token-provider identities cannot be installed through this method. +/// Polymorphic base type discriminated by type. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DebugCollectLogsSkippedEntry +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "type", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(SettableAuthInfoHmac), "hmac")] +[JsonDerivedType(typeof(SettableAuthInfoEnv), "env")] +[JsonDerivedType(typeof(SettableAuthInfoToken), "token")] +[JsonDerivedType(typeof(SettableAuthInfoCopilotApiToken), "copilot-api-token")] +[JsonDerivedType(typeof(SettableAuthInfoUser), "user")] +[JsonDerivedType(typeof(SettableAuthInfoAccount), "account")] +[JsonDerivedType(typeof(SettableAuthInfoGhCli), "gh-cli")] +[JsonDerivedType(typeof(SettableAuthInfoApiKey), "api-key")] +public partial class SettableAuthInfo { - /// Relative path requested for this bundle entry. - [JsonPropertyName("bundlePath")] - public string BundlePath { get; set; } = string.Empty; - - /// Server-local source path that could not be read. - [JsonPropertyName("path")] - public string? Path { get; set; } - - /// Reason the entry was skipped. - [JsonPropertyName("reason")] - public string Reason { get; set; } = string.Empty; + /// The type discriminator. + [JsonPropertyName("type")] + public virtual string Type { get; set; } = string.Empty; } -/// Result of collecting a session debug bundle. + +/// Authentication-info input variant for GitHub-internal HMAC auth, carrying the public GitHub host and HMAC secret. +/// The hmac variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DebugCollectLogsResult +public partial class SettableAuthInfoHmac : SettableAuthInfo { - /// Files included in the bundle. - [JsonPropertyName("entries")] - public IList Entries { get => field ??= []; set; } + /// + [JsonIgnore] + public override string Type => "hmac"; - /// Destination kind that was written. - [JsonPropertyName("kind")] - public DebugCollectLogsResultKind Kind { get; set; } + /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } - /// Actual archive path or staging directory path written. This may differ from the requested path when no-overwrite suffixing or fallback-to-temp-directory was needed. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// HMAC secret used to sign requests. + [JsonPropertyName("hmac")] + public required string Hmac { get; set; } - /// Optional files or directories that could not be included. - [JsonPropertyName("skippedEntries")] - public IList? SkippedEntries { get; set; } + /// Authentication host. HMAC auth always targets the public GitHub host. + [JsonPropertyName("host")] + public required string Host { get; set; } } -/// A caller-provided server-local file or directory to include in the debug bundle. +/// Authentication-info input variant for a token sourced from an environment variable, with host, optional login, token, and env var name. +/// The env variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DebugCollectLogsEntry +public partial class SettableAuthInfoEnv : SettableAuthInfo { - /// Relative path to use inside the staged bundle/archive. - [JsonPropertyName("bundlePath")] - public string BundlePath { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Type => "env"; - /// Kind of source path to include. - [JsonPropertyName("kind")] - public DebugCollectLogsEntryKind Kind { get; set; } + /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } - /// Server-local source path to read. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Name of the environment variable the token was sourced from. + [JsonPropertyName("envVar")] + public required string EnvVar { get; set; } - /// How text content from this entry should be redacted. Defaults to plain-text. With none, no redaction is applied; the caller must ensure any necessary redaction is performed before this call. - [JsonPropertyName("redaction")] - public DebugCollectLogsRedaction? Redaction { get; set; } + /// Authentication host (e.g. https://github.com or a GHES host). + [JsonPropertyName("host")] + public required string Host { get; set; } - /// When true, collection fails if this entry cannot be read. Defaults to false, which records the entry in `skippedEntries`. - [JsonPropertyName("required")] - public bool? Required { get; set; } -} + /// User login associated with the token. Undefined for server-to-server tokens (those starting with `ghs_`). + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("login")] + public string? Login { get; set; } -/// Destination for the session debug bundle. -/// Polymorphic base type discriminated by kind. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(DebugCollectLogsDestinationArchive), "archive")] -[JsonDerivedType(typeof(DebugCollectLogsDestinationDirectory), "directory")] -public partial class DebugCollectLogsDestination -{ - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; + /// The token value itself. Treat as a secret. + [JsonPropertyName("token")] + public required string Token { get; set; } } - -/// The archive variant of . +/// Token authentication accepted by session.gitHubAuth.setCredentials. +/// The token variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class DebugCollectLogsDestinationArchive : DebugCollectLogsDestination +public partial class SettableAuthInfoToken : SettableAuthInfo { /// [JsonIgnore] - public override string Kind => "archive"; + public override string Type => "token"; - /// When true, create the archive atomically without overwriting an existing file by appending ` (N)` before the extension as needed. Defaults to false. + /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("noOverwrite")] - public bool? NoOverwrite { get; set; } + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } - /// Absolute or server-relative path for the .tgz archive to create. - [JsonPropertyName("outputPath")] - public required string OutputPath { get; set; } + /// Authentication host. + [JsonPropertyName("host")] + public required string Host { get; set; } + + /// The token value itself. Treat as a secret. + [JsonPropertyName("token")] + public required string Token { get; set; } } -/// The directory variant of . +/// Authentication-info variant for direct Copilot API token auth sourced from environment variables, with public GitHub host. +/// The copilot-api-token variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class DebugCollectLogsDestinationDirectory : DebugCollectLogsDestination +public partial class SettableAuthInfoCopilotApiToken : SettableAuthInfo { /// [JsonIgnore] - public override string Kind => "directory"; + public override string Type => "copilot-api-token"; - /// Directory where files should be staged. The directory is created if needed. - [JsonPropertyName("outputDirectory")] - public required string OutputDirectory { get; set; } -} + /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } -/// Built-in session diagnostics to include in the bundle. Omitted fields default to true. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DebugCollectLogsInclude -{ - /// Server-local path to the current process log. When set, it is included as `process.log` and its directory is searched for prior logs from the same session. - [JsonPropertyName("currentProcessLogPath")] - public string? CurrentProcessLogPath { get; set; } - - /// Include the session event log (`events.jsonl`). Defaults to true. - [JsonPropertyName("events")] - public bool? Events { get; set; } - - /// Server-local path to the session's events.jsonl file. Internal callers normally omit this and let the runtime derive it from the session. - [JsonPropertyName("eventsPath")] - public string? EventsPath { get; set; } - - /// Maximum number of previous process logs to include. Defaults to 5. - [JsonPropertyName("previousProcessLogLimit")] - public long? PreviousProcessLogLimit { get; set; } - - /// Server-local process log directory to search when `currentProcessLogPath` is unavailable, useful for collecting logs for inactive sessions. - [JsonPropertyName("processLogDirectory")] - public string? ProcessLogDirectory { get; set; } - - /// Include process logs for the session. Defaults to true. - [JsonPropertyName("processLogs")] - public bool? ProcessLogs { get; set; } - - /// Include interactive shell logs written under the session's `shell-logs` directory. Defaults to true. - [JsonPropertyName("shellLogs")] - public bool? ShellLogs { get; set; } + /// Authentication host (always the public GitHub host). + [JsonPropertyName("host")] + public required string Host { get; set; } } -/// Options for collecting a session debug bundle with configurable redaction. +/// Authentication-info variant for OAuth user auth, with host and login; the token remains in the runtime secret store. +/// The user variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class DebugCollectLogsRequest +public partial class SettableAuthInfoUser : SettableAuthInfo { - /// Caller-provided server-local files or directories to include in addition to the runtime's built-in session diagnostics. This lets host applications add their own diagnostics without changing the API shape. - [JsonPropertyName("additionalEntries")] - public IList? AdditionalEntries { get; set; } + /// + [JsonIgnore] + public override string Type => "user"; - /// Where the bundle should be written. Use `archive` to produce a .tgz, or `directory` to stage files for caller-managed upload/post-processing. - [JsonPropertyName("destination")] - public DebugCollectLogsDestination Destination { get => field ??= new(); set; } + /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } - /// Which built-in session diagnostics to include. Omitted fields default to true. - [JsonPropertyName("include")] - public DebugCollectLogsInclude? Include { get; set; } + /// Authentication host. + [JsonPropertyName("host")] + public required string Host { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// OAuth user login. + [JsonPropertyName("login")] + public required string Login { get; set; } } -/// Canvas action that the agent or host can invoke. To discover the input schema for a particular action, call the list_canvas_capabilities tool. +/// An interactive account whose model provider owns its credentials. It carries no GitHub credential. +/// The account variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CanvasAction +public partial class SettableAuthInfoAccount : SettableAuthInfo { - /// Description of the action. - [JsonPropertyName("description")] - public string? Description { get; set; } + /// + [JsonIgnore] + public override string Type => "account"; - /// JSON Schema for the action input. - [JsonPropertyName("inputSchema")] - public JsonElement? InputSchema { get; set; } + /// Host coordinate owned by the account's model provider. + [JsonPropertyName("host")] + public required string Host { get; set; } - /// Action name exposed by the canvas provider. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Login identifying the provider-owned account. + [JsonPropertyName("login")] + public required string Login { get; set; } } -/// Canvas available in the current session. +/// Authentication-info input variant for GitHub CLI credentials, carrying host, login, and the `gh auth token` value. +/// The gh-cli variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DiscoveredCanvas +public partial class SettableAuthInfoGhCli : SettableAuthInfo { - /// Actions the agent or host may invoke on an open instance. - [JsonPropertyName("actions")] - public IList? Actions { get; set; } - - /// Provider-local canvas identifier. - [JsonPropertyName("canvasId")] - public string CanvasId { get; set; } = string.Empty; - - /// Short, single-sentence description shown to the agent in canvas catalogs. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; - - /// Human-readable canvas name. - [JsonPropertyName("displayName")] - public string DisplayName { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Type => "gh-cli"; - /// Owning provider identifier. - [JsonPropertyName("extensionId")] - public string ExtensionId { get; set; } = string.Empty; + /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } - /// Owning extension display name, when available. - [JsonPropertyName("extensionName")] - public string? ExtensionName { get; set; } + /// Authentication host. + [JsonPropertyName("host")] + public required string Host { get; set; } - /// Host-local PNG path for the canvas icon, when supplied. - [JsonPropertyName("icon")] - public string? Icon { get; set; } + /// User login as reported by `gh auth status`. + [JsonPropertyName("login")] + public required string Login { get; set; } - /// JSON Schema for canvas open input. - [JsonPropertyName("inputSchema")] - public JsonElement? InputSchema { get; set; } + /// The token returned by `gh auth token`. Treat as a secret. + [JsonPropertyName("token")] + public required string Token { get; set; } } -/// Declared canvases available in this session. +/// Authentication-info input variant for API-key authentication to a non-GitHub LLM provider, carrying the secret `apiKey` and host. +/// The api-key variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CanvasList +public partial class SettableAuthInfoApiKey : SettableAuthInfo { - /// Declared canvases available in this session. - [JsonPropertyName("canvases")] - public IList Canvases { get => field ??= []; set; } + /// + [JsonIgnore] + public override string Type => "api-key"; + + /// The API key. Treat as a secret. + [JsonPropertyName("apiKey")] + public required string ApiKey { get; set; } + + /// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this verbatim and does not re-fetch when set. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("copilotUser")] + public CopilotUserResponse? CopilotUser { get; set; } + + /// Authentication host. + [JsonPropertyName("host")] + public required string Host { get; set; } } -/// Identifies the target session. +/// New auth credentials to install on the session. Omit to leave credentials unchanged. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionCanvasListRequest +internal sealed class SessionSetCredentialsParams { + /// The new auth credentials to install on the session. When omitted or `undefined`, the call is a no-op and the session's existing credentials are preserved. The runtime installs the supplied value immediately for outbound model/API requests. When the credential carries a raw token (`token`, `env`, or `gh-cli`) but no `copilotUser`, the runtime additionally re-resolves `copilotUser` server-side (best-effort, asynchronously, after the synchronous install) so plan/quota/billing metadata regains fidelity; on resolution failure the verbatim credential remains installed. It does NOT otherwise validate the credential. Several variants carry secret material; treat this method's params as containing secrets at rest and in transit. + [JsonPropertyName("credentials")] + public SettableAuthInfo? Credentials { get; set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Open canvas instance snapshot. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class OpenCanvasInstance +internal sealed class SessionGitHubAuthGetCurrentAuthInfoRequest { - /// Provider-local canvas identifier. - [JsonPropertyName("canvasId")] - public string CanvasId { get; set; } = string.Empty; - - /// Owning provider identifier. - [JsonPropertyName("extensionId")] - public string ExtensionId { get; set; } = string.Empty; - - /// Owning extension display name, when available. - [JsonPropertyName("extensionName")] - public string? ExtensionName { get; set; } - - /// Host-local PNG path for the canvas icon, when supplied. - [JsonPropertyName("icon")] - public string? Icon { get; set; } - - /// Input supplied when the instance was opened. - [JsonPropertyName("input")] - public JsonElement? Input { get; set; } - - /// Stable caller-supplied canvas instance identifier. - [JsonPropertyName("instanceId")] - public string InstanceId { get; set; } = string.Empty; - - /// Provider-supplied status text. - [JsonPropertyName("status")] - public string? Status { get; set; } - - /// Rendered title. - [JsonPropertyName("title")] - public string? Title { get; set; } - - /// URL for web-rendered canvases. - [JsonPropertyName("url")] - public string? Url { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Live open-canvas snapshot. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CanvasListOpenResult +internal sealed class SessionGitHubAuthGetAllAuthAvailableRequest { - /// Currently open canvas instances. - [JsonPropertyName("openCanvases")] - public IList OpenCanvases { get => field ??= []; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionCanvasListOpenRequest +internal sealed class SessionGitHubAuthRefreshCopilotUserRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Canvas open parameters. +/// Internal GitHub login parameters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CanvasOpenRequest +internal sealed class SessionAuthLoginRequest { - /// Provider-local canvas identifier. - [JsonPropertyName("canvasId")] - public string CanvasId { get; set; } = string.Empty; - - /// Owning provider identifier. Optional when the canvasId is unique across providers; required to disambiguate when multiple providers register the same canvasId. - [JsonPropertyName("extensionId")] - public string? ExtensionId { get; set; } + /// GitHub host URL. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; - /// Canvas open input. - [JsonPropertyName("input")] - public JsonElement? Input { get; set; } + /// GitHub login. + [JsonPropertyName("login")] + public string Login { get; set; } = string.Empty; - /// Caller-supplied stable instance identifier. - [JsonPropertyName("instanceId")] - public string InstanceId { get; set; } = string.Empty; + /// Whether to persist the token after login. + [JsonPropertyName("persist")] + public bool? Persist { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// GitHub authentication token. + [JsonPropertyName("token")] + public string Token { get; set; } = string.Empty; } -/// Canvas close parameters. +/// Parameters for switching the session's active authentication. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CanvasCloseRequest +internal sealed class SessionAuthSwitchRequest { - /// Open canvas instance identifier. - [JsonPropertyName("instanceId")] - public string InstanceId { get; set; } = string.Empty; + /// Authentication information to activate. + [JsonPropertyName("authInfo")] + public AuthInfo AuthInfo { get => field ??= new(); set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; -} -/// Canvas action invocation result. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CanvasActionInvokeResult -{ - /// Provider-supplied action result. - [JsonPropertyName("result")] - public JsonElement? Result { get; set; } + /// Optional token paired with the authentication information. + [JsonPropertyName("token")] + public string? Token { get; set; } } -/// Canvas action invocation parameters. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CanvasActionInvokeRequest +internal sealed class SessionGitHubAuthLogoutRequest { - /// Action name to invoke. - [JsonPropertyName("actionName")] - public string ActionName { get; set; } = string.Empty; - - /// Action input. - [JsonPropertyName("input")] - public JsonElement? Input { get; set; } - - /// Open canvas instance identifier. - [JsonPropertyName("instanceId")] - public string InstanceId { get; set; } = string.Empty; - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Internal canvas provider registration parameters. +/// Parameters identifying a GitHub authentication to log out. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CanvasProviderRegisterRequest +internal sealed class SessionAuthLogoutUserRequest { - /// Canvas contributions supplied by the provider. - [JsonPropertyName("canvases")] - public IList Canvases { get => field ??= []; set; } - - /// Connection identifier for callback routing. - [JsonPropertyName("connectionId")] - public string ConnectionId { get; set; } = string.Empty; - - /// Provider metadata supplied by the host. - [JsonPropertyName("info")] - public JsonElement Info { get; set; } + /// Authentication information to log out. + [JsonPropertyName("authInfo")] + public AuthInfo AuthInfo { get => field ??= new(); set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Internal canvas provider unregistration parameters. +/// Validation error from an authentication attempt. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CanvasProviderUnregisterRequest +public sealed class AuthValidationError { - /// Connection identifier to unregister. - [JsonPropertyName("connectionId")] - public string ConnectionId { get; set; } = string.Empty; + /// Optional message returned by GitHub. + [JsonPropertyName("githubMessage")] + public string? GitHubMessage { get; set; } + + /// Authentication validation error message. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; +} +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionGitHubAuthLastAuthErrorsRequest +{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Machine-readable workflow run failure. -/// Polymorphic base type discriminated by type. +/// The enumerated collection, keyed by the same selector as the query. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( - TypeDiscriminatorPropertyName = "type", + TypeDiscriminatorPropertyName = "kind", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(WorkflowRunFailureWorkflowLimitReached), "workflow_limit_reached")] -[JsonDerivedType(typeof(WorkflowRunFailureWorkflowResumeDeclined), "workflow_resume_declined")] -[JsonDerivedType(typeof(WorkflowRunFailureWorkflowDurableFailure), "workflow_durable_failure")] -[JsonDerivedType(typeof(WorkflowRunFailureWorkflowAccountingIncomplete), "workflow_accounting_incomplete")] -[JsonDerivedType(typeof(WorkflowRunFailureWorkflowProviderDisconnected), "workflow_provider_disconnected")] -public partial class WorkflowRunFailure +[JsonDerivedType(typeof(AuthEnumerateValueAccounts), "accounts")] +[JsonDerivedType(typeof(AuthEnumerateValueProviders), "providers")] +public partial class AuthEnumerateValue { /// The type discriminator. - [JsonPropertyName("type")] - public virtual string Type { get; set; } = string.Empty; + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// The workflow_limit_reached variant of . +/// One signed-in account in the roster forest. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class WorkflowRunFailureWorkflowLimitReached : WorkflowRunFailure +public sealed class AccountStatus { - /// - [JsonIgnore] - public override string Type => "workflow_limit_reached"; - - /// Resource ceiling that stopped the run. - [JsonPropertyName("kind")] - public required WorkflowRunFailureKind Kind { get; set; } + /// Whether this is the active account. + [JsonPropertyName("active")] + public bool Active { get; set; } - /// Workflow run identifier. - [JsonPropertyName("runId")] - public required string RunId { get; set; } + /// Human-readable credential source used to authenticate this account, such as `gh` or `GITHUB_TOKEN`. + [JsonPropertyName("authSource")] + public string? AuthSource { get; set; } - /// Suggested larger ceiling when the runtime can derive one safely. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("suggestedValue")] - public double? SuggestedValue { get; set; } + /// Opaque id of the account this one was derived from (e.g. an EMU account's base Entra identity); absent for a root account. Matches the base identity account's selectionId, forming the derivation edge. + [JsonPropertyName("derivedFrom")] + public string? DerivedFrom { get; set; } - /// Approved effective ceiling that was reached. - [JsonPropertyName("value")] - public required double Value { get; set; } -} + /// Authentication host URL. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; -/// The workflow_resume_declined variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class WorkflowRunFailureWorkflowResumeDeclined : WorkflowRunFailure -{ - /// - [JsonIgnore] - public override string Type => "workflow_resume_declined"; + /// The provider kind of this account. + [JsonPropertyName("kind")] + public AccountKind Kind { get; set; } - /// Human-readable reason the resume did not proceed. - [JsonPropertyName("reason")] - public required string Reason { get; set; } + /// Authenticated login/username. + [JsonPropertyName("login")] + public string Login { get; set; } = string.Empty; - /// Workflow run identifier whose changed limits were declined. - [JsonPropertyName("runId")] - public required string RunId { get; set; } + /// Opaque selection id used to switch to, or log out, this account. + [JsonPropertyName("selectionId")] + public string SelectionId { get; set; } = string.Empty; } -/// The workflow_durable_failure variant of . +/// The accounts variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class WorkflowRunFailureWorkflowDurableFailure : WorkflowRunFailure +public partial class AuthEnumerateValueAccounts : AuthEnumerateValue { /// [JsonIgnore] - public override string Type => "workflow_durable_failure"; - - /// Stable failure code. - [JsonPropertyName("code")] - public required string Code { get; set; } - - /// Execution-critical durable operation that failed. - [JsonPropertyName("operation")] - public required WorkflowDurableOperation Operation { get; set; } + public override string Kind => "accounts"; - /// Workflow run identifier. - [JsonPropertyName("runId")] - public required string RunId { get; set; } + /// The signed-in account forest; empty when not logged in. + [JsonPropertyName("items")] + public required IList Items { get; set; } } -/// The run stopped because its usage accounting could not be completed. -/// The workflow_accounting_incomplete variant of . +/// A provider offered for interactive login. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class WorkflowRunFailureWorkflowAccountingIncomplete : WorkflowRunFailure +public sealed class ProviderDescriptor { - /// - [JsonIgnore] - public override string Type => "workflow_accounting_incomplete"; + /// Whether this provider is currently available to sign in with. + [JsonPropertyName("available")] + public bool Available { get; set; } - /// Confirmed usage in nano-AIU, representing the floor of what the run spent. - [JsonPropertyName("drainedNanoAiu")] - public required long DrainedNanoAiu { get; set; } + /// The neutral provider kind. + [JsonPropertyName("kind")] + public LoginProviderKind Kind { get; set; } - /// Workflow run identifier. - [JsonPropertyName("runId")] - public required string RunId { get; set; } + /// Human-readable menu label, owned by the runtime so every consumer renders identical text. + [JsonPropertyName("label")] + public string Label { get; set; } = string.Empty; } -/// The extension that owns the workflow disconnected while the run was executing, so the host halted it. The run's journaled subagent results are preserved so a resume can reuse them. -/// The workflow_provider_disconnected variant of . +/// The providers variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class WorkflowRunFailureWorkflowProviderDisconnected : WorkflowRunFailure +public partial class AuthEnumerateValueProviders : AuthEnumerateValue { /// [JsonIgnore] - public override string Type => "workflow_provider_disconnected"; + public override string Kind => "providers"; - /// Workflow run identifier. - [JsonPropertyName("runId")] - public required string RunId { get; set; } + /// The providers offered for interactive login. + [JsonPropertyName("items")] + public required IList Items { get; set; } } -/// Durable metadata describing who initiated a workflow pause. -/// Polymorphic base type discriminated by type. +/// Selects which accounts collection to enumerate. A no-arg selector is the empty-payload variant. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( - TypeDiscriminatorPropertyName = "type", + TypeDiscriminatorPropertyName = "kind", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(WorkflowPauseInfoUser), "user")] -[JsonDerivedType(typeof(WorkflowPauseInfoCheckpoint), "checkpoint")] -public partial class WorkflowPauseInfo +[JsonDerivedType(typeof(AuthEnumerateQueryAccounts), "accounts")] +[JsonDerivedType(typeof(AuthEnumerateQueryProviders), "providers")] +public partial class AuthEnumerateQuery { /// The type discriminator. - [JsonPropertyName("type")] - public virtual string Type { get; set; } = string.Empty; + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// The user variant of . +/// The accounts variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class WorkflowPauseInfoUser : WorkflowPauseInfo +public partial class AuthEnumerateQueryAccounts : AuthEnumerateQuery { /// [JsonIgnore] - public override string Type => "user"; + public override string Kind => "accounts"; } -/// The checkpoint variant of . +/// The providers variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class WorkflowPauseInfoCheckpoint : WorkflowPauseInfo +public partial class AuthEnumerateQueryProviders : AuthEnumerateQuery { /// [JsonIgnore] - public override string Type => "checkpoint"; + public override string Kind => "providers"; - /// Stable author-defined checkpoint key that initiated the pause. - [JsonPropertyName("key")] - public required string Key { get; set; } + /// Whether an interactive Entra broker is available on the host; gates Entra availability in the returned list. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("brokerAvailable")] + public bool? BrokerAvailable { get; set; } } -/// Complete current or terminal workflow run envelope. +/// Enumerate request carrying the typed collection query. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowRunResult +internal sealed class AccountsEnumerateRequest { - /// One-based execution attempt represented by this envelope. Absent before the first attempt starts or when returned by an older runtime. - [JsonPropertyName("attempt")] - public long? Attempt { get; set; } + /// Which typed accounts collection to enumerate. + [JsonPropertyName("query")] + public AuthEnumerateQuery Query { get => field ??= new(); set; } - /// Error message for an errored run. - [JsonPropertyName("error")] - public string? Error { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Machine-readable failure details for a halted or errored run. - [JsonPropertyName("failure")] - public WorkflowRunFailure? Failure { get; set; } - - /// Structured pause initiator metadata for a paused attempt. - [JsonPropertyName("pauseInfo")] - public WorkflowPauseInfo? PauseInfo { get; set; } - - /// Reason for a halted or cancelled run. - [JsonPropertyName("reason")] - public string? Reason { get; set; } +/// The read result, keyed by the same selector as the query. +/// Polymorphic base type discriminated by kind. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(AuthReadValueActiveAccount), "activeAccount")] +[JsonDerivedType(typeof(AuthReadValueStatus), "status")] +[JsonDerivedType(typeof(AuthReadValueLastErrors), "lastErrors")] +public partial class AuthReadValue +{ + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} - /// Completed workflow result. - [JsonPropertyName("result")] - public JsonElement? Result { get; set; } - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; +/// The activeAccount variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class AuthReadValueActiveAccount : AuthReadValue +{ + /// + [JsonIgnore] + public override string Kind => "activeAccount"; - /// Partial journal and progress snapshot for a halted, cancelled, or errored run. - [JsonPropertyName("snapshot")] - public JsonElement? Snapshot { get; set; } + /// The active account, or absent when not logged in. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("account")] + public AccountStatus? Account { get; set; } - /// Current or terminal workflow run status. - [JsonPropertyName("status")] - public WorkflowRunStatus Status { get; set; } + /// Credential-free identity metadata for the active account, including resolved Copilot user information when available. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("authInfo")] + public AuthIdentity? AuthInfo { get; set; } } -/// Wire-only per-invocation workflow resource ceiling overrides. +/// Neutral authentication status summary. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowRunLimits +public sealed class AuthStatusDto { - /// Maximum AI credits consumed by workflow subagents and their descendants. The post-paid ceiling is soft: parallel turns can settle beyond it before the run stops. - [JsonPropertyName("maxAiCredits")] - public double? MaxAiCredits { get; set; } + /// Number of signed-in accounts in the roster. + [JsonPropertyName("accountCount")] + public long AccountCount { get; set; } - /// Maximum number of workflow subagents that may run concurrently. - [JsonPropertyName("maxConcurrentSubagents")] - public long? MaxConcurrentSubagents { get; set; } + /// Active account host, if authenticated. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("activeHost")] + public string? ActiveHost { get; set; } - /// Maximum total number of workflow subagents that may be admitted. - [JsonPropertyName("maxTotalSubagents")] - public long? MaxTotalSubagents { get; set; } + /// Active account login, if authenticated. + [JsonPropertyName("activeLogin")] + public string? ActiveLogin { get; set; } - /// Maximum accumulated active-execution time in seconds. Active execution includes the entire extension body, subprocess waits, queued-agent waits, and sleeps; time between resumed attempts is not counted. - [JsonPropertyName("timeoutSeconds")] - public double? TimeoutSeconds { get; set; } + /// Copilot plan tier of the active account, if known. + [JsonPropertyName("copilotPlan")] + public string? CopilotPlan { get; set; } + + /// Whether the session has resolved authentication. + [JsonPropertyName("isAuthenticated")] + public bool IsAuthenticated { get; set; } } -/// Options controlling workflow invocation. +/// The status variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowRunOptions +public partial class AuthReadValueStatus : AuthReadValue { - /// Per-invocation resource ceiling overrides. - [JsonPropertyName("limits")] - public WorkflowRunLimits? Limits { get; set; } + /// + [JsonIgnore] + public override string Kind => "status"; - /// Whether to emit workflow phase names to the session transcript. - [JsonPropertyName("logPhaseNames")] - public bool? LogPhaseNames { get; set; } + /// The neutral authentication status summary. + [JsonPropertyName("status")] + public required AuthStatusDto Status { get; set; } +} - /// Whether to notify the originating session when the workflow completes. - [JsonPropertyName("notifyOnComplete")] - public bool? NotifyOnComplete { get; set; } +/// The lastErrors variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class AuthReadValueLastErrors : AuthReadValue +{ + /// + [JsonIgnore] + public override string Kind => "lastErrors"; - /// Run identifier whose journal and progress should seed this resumed run. - [JsonPropertyName("resumeFromRunId")] - public string? ResumeFromRunId { get; set; } + /// Validation errors from the most recent authentication attempt. + [JsonPropertyName("errors")] + public required IList Errors { get; set; } } -/// Parameters for invoking a registered workflow. +/// Selects which typed accounts datum to read. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowRunRequest +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(AuthReadQueryActiveAccount), "activeAccount")] +[JsonDerivedType(typeof(AuthReadQueryStatus), "status")] +[JsonDerivedType(typeof(AuthReadQueryLastErrors), "lastErrors")] +public partial class AuthReadQuery { - /// Workflow input value. - [JsonPropertyName("args")] - public JsonElement Args { get; set; } - - /// Registered workflow name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} - /// Workflow invocation options. - [JsonPropertyName("options")] - public WorkflowRunOptions? Options { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; +/// The activeAccount variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class AuthReadQueryActiveAccount : AuthReadQuery +{ + /// + [JsonIgnore] + public override string Kind => "activeAccount"; } -/// Resolved persisted workflow identity and resumed run envelope. +/// The status variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowResumeResult +public partial class AuthReadQueryStatus : AuthReadQuery { - /// Terminal resumed run envelope. - [JsonPropertyName("run")] - public WorkflowRunResult Run { get => field ??= new(); set; } - - /// Persisted workflow name resolved for the resumed run. - [JsonPropertyName("workflowName")] - public string WorkflowName { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "status"; } -/// Parameters for resuming a workflow run from its persisted identity. +/// The lastErrors variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowResumeRequest +public partial class AuthReadQueryLastErrors : AuthReadQuery { - /// Optional per-invocation resource ceiling overrides. - [JsonPropertyName("limits")] - public WorkflowRunLimits? Limits { get; set; } - - /// Whether to emit workflow phase names to the session transcript. - [JsonPropertyName("logPhaseNames")] - public bool? LogPhaseNames { get; set; } - - /// Whether to notify the originating session when the workflow completes. - [JsonPropertyName("notifyOnComplete")] - public bool? NotifyOnComplete { get; set; } + /// + [JsonIgnore] + public override string Kind => "lastErrors"; +} - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; +/// Read request carrying the typed datum query. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AccountsGetRequest +{ + /// Which typed accounts datum to read. + [JsonPropertyName("query")] + public AuthReadQuery Query { get => field ??= new(); set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Options for an internal tool-originated workflow invocation. +/// Result of a non-interactive accounts mutation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowToolRunOptions +public sealed class AuthWriteResult { - /// Per-invocation resource ceiling overrides. - [JsonPropertyName("limits")] - public WorkflowRunLimits? Limits { get; set; } + /// For a logout, whether other signed-in accounts remain. + [JsonPropertyName("moreUsers")] + public bool? MoreUsers { get; set; } - /// Run identifier whose journal and progress should seed this resumed run. - [JsonPropertyName("resumeFromRunId")] - public string? ResumeFromRunId { get; set; } + /// Whether the mutation was applied. + [JsonPropertyName("ok")] + public bool Ok { get; set; } } -/// Internal parameters for invoking a registered workflow from a tool. +/// One non-interactive accounts mutation command (the selector is fused with its typed args). +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowToolRunRequest +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(AuthWriteSwitchActive), "switchActive")] +[JsonDerivedType(typeof(AuthWriteLogout), "logout")] +[JsonDerivedType(typeof(AuthWriteSetCredentials), "setCredentials")] +public partial class AuthWrite { - /// Workflow input value. - [JsonPropertyName("args")] - public JsonElement Args { get; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} - /// Registered workflow name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - /// Tool-originated workflow invocation options. - [JsonPropertyName("options")] - public WorkflowToolRunOptions? Options { get; set; } +/// The switchActive variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class AuthWriteSwitchActive : AuthWrite +{ + /// + [JsonIgnore] + public override string Kind => "switchActive"; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Opaque selection id of the account to make active. + [JsonPropertyName("selectionId")] + public required string SelectionId { get; set; } +} - /// Opaque identifier of the originating tool call. - [JsonPropertyName("toolCallId")] - public string? ToolCallId { get; set; } +/// The logout variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class AuthWriteLogout : AuthWrite +{ + /// + [JsonIgnore] + public override string Kind => "logout"; + + /// Opaque selection id of the account to log out; absent logs out the active account. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("selectionId")] + public string? SelectionId { get; set; } } -/// Internal parameters for resuming a workflow run from a tool. +/// The setCredentials variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowToolResumeRequest +public partial class AuthWriteSetCredentials : AuthWrite { - /// Optional per-invocation resource ceiling overrides. - [JsonPropertyName("limits")] - public WorkflowRunLimits? Limits { get; set; } + /// + [JsonIgnore] + public override string Kind => "setCredentials"; - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// Authentication host URL. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("host")] + public required string Host { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Login/username for the credential. + [JsonPropertyName("login")] + public required string Login { get; set; } - /// Opaque identifier of the originating tool call. - [JsonPropertyName("toolCallId")] - public string? ToolCallId { get; set; } + /// GitHub authentication token to install. + [JsonPropertyName("token")] + public required string Token { get; set; } } -/// Parameters for retrieving a workflow run. +/// Mutation request carrying the typed write command. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowGetRunRequest +internal sealed class AccountsSetRequest { - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// The non-interactive mutation command to apply. + [JsonPropertyName("command")] + public AuthWrite Command { get => field ??= new(); set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Declared or approved workflow resource ceilings. +/// One step in an interactive login flow. The consumer acts on the step and calls advance to proceed. Browser-open is encoded as two distinct steps by design: `open-url` is CONSUMER-driven (the provider surfaces the authorize URL and the consumer opens it — github.com/GHEC web), while `needs-interaction` is PROVIDER-driven (the provider opens the browser or broker UI itself and does not surface a URL — Entra). +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowDeclaredLimits +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(AuthLoginStepOpenUrl), "open-url")] +[JsonDerivedType(typeof(AuthLoginStepInputRequired), "input-required")] +[JsonDerivedType(typeof(AuthLoginStepAwaiting), "awaiting")] +[JsonDerivedType(typeof(AuthLoginStepNeedsInteraction), "needs-interaction")] +[JsonDerivedType(typeof(AuthLoginStepCompleted), "completed")] +[JsonDerivedType(typeof(AuthLoginStepError), "error")] +public partial class AuthLoginStep { - /// Maximum AI credits consumed by subagents and descendants. - [JsonPropertyName("maxAiCredits")] - public double? MaxAiCredits { get; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} - /// Maximum concurrently active subagents. - [JsonPropertyName("maxConcurrentSubagents")] - public long? MaxConcurrentSubagents { get; set; } - /// Maximum total subagents spawned by the run. - [JsonPropertyName("maxTotalSubagents")] - public long? MaxTotalSubagents { get; set; } +/// The open-url variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class AuthLoginStepOpenUrl : AuthLoginStep +{ + /// + [JsonIgnore] + public override string Kind => "open-url"; - /// Maximum accumulated active execution time in seconds. - [JsonPropertyName("timeoutSeconds")] - public double? TimeoutSeconds { get; set; } + /// Authorize URL the consumer should open in a browser (consumer-driven browser-open). + [JsonPropertyName("url")] + public required string Url { get; set; } } -/// Durable workflow resource consumption. +/// The input-required variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowRunConsumed +public partial class AuthLoginStepInputRequired : AuthLoginStep { - /// Accumulated active execution time in milliseconds. - [JsonPropertyName("activeMs")] - public long ActiveMs { get; set; } - - /// AI usage consumed by the run in nano-AIU. - [JsonPropertyName("nanoAiu")] - public long NanoAiu { get; set; } + /// + [JsonIgnore] + public override string Kind => "input-required"; - /// Total subagents spawned by the run. - [JsonPropertyName("subagents")] - public long Subagents { get; set; } + /// Prompt for the value the provider needs; the consumer supplies it as advance input (e.g. a GitHub Enterprise Cloud host, *.ghe.com). + [JsonPropertyName("prompt")] + public required string Prompt { get; set; } } -/// Current workflow phase identity. +/// The awaiting variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowCurrentPhase +public partial class AuthLoginStepAwaiting : AuthLoginStep { - /// Current phase identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - - /// Zero-based declared phase ordinal, or null for an undeclared phase. - [JsonPropertyName("ordinal")] - public long? Ordinal { get; set; } + /// + [JsonIgnore] + public override string Kind => "awaiting"; } -/// Prompt-safe terminal workflow outcome. +/// The needs-interaction variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowRunTerminal +public partial class AuthLoginStepNeedsInteraction : AuthLoginStep { - /// Human-readable terminal error. - [JsonPropertyName("error")] - public string? Error { get; set; } + /// + [JsonIgnore] + public override string Kind => "needs-interaction"; +} - /// Machine-readable terminal failure. - [JsonPropertyName("failure")] - public WorkflowRunFailure? Failure { get; set; } +/// A credential-free account choice after sign-in. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class AuthLoginAccount +{ + /// Host coordinate owned by the selected account's provider. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; - /// Pause initiator metadata, or null when the run did not pause. - [JsonPropertyName("pauseInfo")] - public WorkflowPauseInfo? PauseInfo { get; set; } + /// Provider kind that owns this account choice. + [JsonPropertyName("kind")] + public AccountKind Kind { get; set; } - /// Human-readable terminal reason. - [JsonPropertyName("reason")] - public string? Reason { get; set; } + /// Human-readable login for the account choice. + [JsonPropertyName("login")] + public string Login { get; set; } = string.Empty; - /// Prompt-safe preview of the completed result. - [JsonPropertyName("resultPreview")] - public string? ResultPreview { get; set; } + /// Opaque identifier supplied to the next login step to select this account. + [JsonPropertyName("selectionId")] + public string SelectionId { get; set; } = string.Empty; } -/// Durable workflow run summary with read-time live overlays. +/// Result of an interactive login flow. Pending consent or account selection is not terminal. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowRunSummary +public sealed class AuthLoginResultDto { - /// Epoch milliseconds when the current active segment started, or null while inactive. - [JsonPropertyName("activeSegmentStartedAt")] - public long? ActiveSegmentStartedAt { get; set; } + /// Available accounts when sign-in is awaiting account selection, ordered with Microsoft 365 first. + [JsonPropertyName("accounts")] + public IList? Accounts { get; set; } - /// Approved effective resource ceilings, or null until approved. - [JsonPropertyName("approved")] - public WorkflowDeclaredLimits? Approved { get; set; } + /// Host that was signed in, when completed. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("host")] + public string? Host { get; set; } - /// Whether the durable run state currently passes runtime resume eligibility checks. - [JsonPropertyName("canResume")] - public bool CanResume { get; set; } + /// Login that was signed in, when completed. + [JsonPropertyName("login")] + public string? Login { get; set; } - /// Epoch milliseconds when the run completed, or null while nonterminal. - [JsonPropertyName("completedAt")] - public long? CompletedAt { get; set; } + /// Current disposition of the login, including pending user decisions. + [JsonPropertyName("status")] + public AuthLoginResultStatus Status { get; set; } +} - /// Durable resource consumption. - [JsonPropertyName("consumed")] - public WorkflowRunConsumed Consumed { get => field ??= new(); set; } +/// The completed variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class AuthLoginStepCompleted : AuthLoginStep +{ + /// + [JsonIgnore] + public override string Kind => "completed"; - /// Epoch milliseconds when the run was created. - [JsonPropertyName("createdAt")] - public long CreatedAt { get; set; } + /// Login result. When status is needs-plaintext-consent or needs-account-selection, advance with the user's decision to continue. + [JsonPropertyName("result")] + public required AuthLoginResultDto Result { get; set; } +} - /// Current phase identity, or null before any phase is entered. - [JsonPropertyName("currentPhase")] - public WorkflowCurrentPhase? CurrentPhase { get; set; } +/// The error variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class AuthLoginStepError : AuthLoginStep +{ + /// + [JsonIgnore] + public override string Kind => "error"; - /// Resource ceilings declared by the workflow. - [JsonPropertyName("declaredLimits")] - public WorkflowDeclaredLimits DeclaredLimits { get => field ??= new(); set; } + /// Human-readable failure message. + [JsonPropertyName("message")] + public required string Message { get; set; } +} - /// Number of phases declared by the workflow. - [JsonPropertyName("declaredPhaseCount")] - public long DeclaredPhaseCount { get; set; } +/// A started login flow: its opaque id and first step. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class AuthLoginBegun +{ + /// Opaque flow id used to advance or cancel this login. + [JsonPropertyName("flowId")] + public string FlowId { get; set; } = string.Empty; - /// Human-readable workflow description. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; + /// The first step of the flow. + [JsonPropertyName("step")] + public AuthLoginStep Step { get => field ??= new(); set; } +} - /// Number of direct workflow agents currently live. - [JsonPropertyName("liveAgentCount")] - public long LiveAgentCount { get; set; } +/// Begin an interactive login flow for a provider kind. Dispatch is kind-only. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class AuthLoginBeginRequest +{ + /// The provider kind to sign in with. + [JsonPropertyName("kind")] + public LoginProviderKind Kind { get; set; } - /// Epoch milliseconds when this live-overlay snapshot was observed. - [JsonPropertyName("observedAt")] - public long ObservedAt { get; set; } - - /// Monotonic durable run revision. - [JsonPropertyName("revision")] - public long Revision { get; set; } - - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; - - /// Epoch milliseconds when execution first started, or null before start. - [JsonPropertyName("startedAt")] - public long? StartedAt { get; set; } - - /// Current workflow run status. - [JsonPropertyName("status")] - public WorkflowRunStatus Status { get; set; } - - /// Terminal run outcome, or null while nonterminal. - [JsonPropertyName("terminal")] - public WorkflowRunTerminal? Terminal { get; set; } - - /// Total direct workflow agents spawned across all attempts. - [JsonPropertyName("totalSpawnedAgentCount")] - public long TotalSpawnedAgentCount { get; set; } - - /// Epoch milliseconds when the durable run was last updated. - [JsonPropertyName("updatedAt")] - public long UpdatedAt { get; set; } - - /// Registered workflow name. - [JsonPropertyName("workflowName")] - public string WorkflowName { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// A page of workflow runs in durable creation order. +/// Advance an in-flight login flow, optionally fulfilling an input-required step. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowListRunsResult +internal sealed class AuthLoginAdvanceRequest { - /// Whether terminal runs newer than this page exist. - [JsonPropertyName("hasMoreNewer")] - public bool? HasMoreNewer { get; set; } - - /// Newest terminal-run cursor in this page, or null when the terminal window is empty. - [JsonPropertyName("newestSeq")] - public long? NewestSeq { get; set; } - - /// Oldest terminal-run cursor in this page, or null when the terminal window is empty. - [JsonPropertyName("oldestSeq")] - public long? OldestSeq { get; set; } + /// Opaque flow id from begin. + [JsonPropertyName("flowId")] + public string FlowId { get; set; } = string.Empty; - /// Number of terminal runs older than this page. - [JsonPropertyName("omittedOlder")] - public long? OmittedOlder { get; set; } + /// Neutral input fulfilling a preceding input-required step (e.g. a GHEC host); ignored otherwise. + [JsonPropertyName("input")] + public string? Input { get; set; } - /// Workflow run summaries in durable creation order. - [JsonPropertyName("runs")] - public IList Runs { get => field ??= []; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Parameters for paging workflow runs. +/// Cancel an in-flight login flow. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowListRunsRequest +internal sealed class AuthLoginCancelRequest { - /// Exclusive forward cursor. - [JsonPropertyName("afterSeq")] - public long? AfterSeq { get; set; } - - /// Exclusive backward cursor. - [JsonPropertyName("beforeSeq")] - public long? BeforeSeq { get; set; } - - /// Maximum terminal runs to return. Defaults to 200 and is capped at 500. - [JsonPropertyName("limit")] - public int? Limit { get; set; } + /// Opaque flow id from begin. + [JsonPropertyName("flowId")] + public string FlowId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Prompt-safe durable identity and live status for a direct workflow agent. +/// A file included in the session debug bundle. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowAgentSummary +public sealed class DebugCollectLogsCollectedEntry { - /// Accumulated active agent time in milliseconds. - [JsonPropertyName("activeMs")] - public long ActiveMs { get; set; } - - /// Prompt-safe live activity text. - [JsonPropertyName("activity")] - public string? Activity { get; set; } - - /// Stable direct-agent identifier. - [JsonPropertyName("agentId")] - public string AgentId { get; set; } = string.Empty; - - /// Registered agent type. - [JsonPropertyName("agentType")] - public string AgentType { get; set; } = string.Empty; - - /// Epoch milliseconds when the agent completed. - [JsonPropertyName("completedAt")] - public long? CompletedAt { get; set; } - - /// Friendly, non-unique name intended for display. - [JsonPropertyName("displayName")] - public string? DisplayName { get; set; } - - /// Friendly, non-unique name intended for display. - [JsonPropertyName("label")] - public string Label { get; set; } = string.Empty; - - /// Phase identifier active when the agent was launched, or null. - [JsonPropertyName("phaseId")] - public string? PhaseId { get; set; } - - /// Model requested when the agent was launched. - [JsonPropertyName("requestedModel")] - public string? RequestedModel { get; set; } - - /// Concrete model resolved for the agent. - [JsonPropertyName("resolvedModel")] - public string? ResolvedModel { get; set; } - - /// Owning workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; - - /// Epoch milliseconds when the agent started. - [JsonPropertyName("startedAt")] - public long? StartedAt { get; set; } + /// Relative path of the file in the staged bundle/archive. + [JsonPropertyName("bundlePath")] + public string BundlePath { get; set; } = string.Empty; - /// Current durable or live agent status. - [JsonPropertyName("status")] - public string Status { get; set; } = string.Empty; + /// Redacted output size in bytes. + [JsonPropertyName("sizeBytes")] + public long SizeBytes { get; set; } - /// Tool-call identifier that launched the agent. - [JsonPropertyName("toolCallId")] - public string ToolCallId { get; set; } = string.Empty; + /// Source category for this entry. + [JsonPropertyName("source")] + public DebugCollectLogsSource Source { get; set; } } -/// Durable lifecycle and timing for one workflow phase. +/// An optional debug bundle entry that could not be included. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowPhaseObservation +public sealed class DebugCollectLogsSkippedEntry { - /// Completed active time accumulated by this phase in milliseconds. - [JsonPropertyName("accumulatedActiveMs")] - public long AccumulatedActiveMs { get; set; } - - /// Epoch milliseconds when this phase completed; for a skipped phase, the synthetic skip timestamp (equal to `startedAt`). - [JsonPropertyName("completedAt")] - public long? CompletedAt { get; set; } + /// Relative path requested for this bundle entry. + [JsonPropertyName("bundlePath")] + public string BundlePath { get; set; } = string.Empty; - /// Current live active time for this phase in milliseconds. - [JsonPropertyName("currentActiveMs")] - public long CurrentActiveMs { get; set; } + /// Server-local source path that could not be read. + [JsonPropertyName("path")] + public string? Path { get; set; } - /// Optional human-readable phase detail. - [JsonPropertyName("detail")] - public string? Detail { get; set; } + /// Reason the entry was skipped. + [JsonPropertyName("reason")] + public string Reason { get; set; } = string.Empty; +} - /// Number of times execution entered this phase. - [JsonPropertyName("entryCount")] - public long EntryCount { get; set; } +/// Result of collecting a session debug bundle. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class DebugCollectLogsResult +{ + /// Files included in the bundle. + [JsonPropertyName("entries")] + public IList Entries { get => field ??= []; set; } - /// Phase identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Destination kind that was written. + [JsonPropertyName("kind")] + public DebugCollectLogsResultKind Kind { get; set; } - /// Most recent run attempt that entered this phase, or `0` if the phase has never been entered. - [JsonPropertyName("lastEnteredRunAttempt")] - public long LastEnteredRunAttempt { get; set; } + /// Actual archive path or staging directory path written. This may differ from the requested path when no-overwrite suffixing or fallback-to-temp-directory was needed. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Direct agents in this phase that are currently live. - [JsonPropertyName("liveAgentCount")] - public long LiveAgentCount { get; set; } + /// Optional files or directories that could not be included. + [JsonPropertyName("skippedEntries")] + public IList? SkippedEntries { get; set; } +} - /// Zero-based declared phase ordinal, or null for an undeclared phase. - [JsonPropertyName("ordinal")] - public long? Ordinal { get; set; } +/// A caller-provided server-local file or directory to include in the debug bundle. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class DebugCollectLogsEntry +{ + /// Relative path to use inside the staged bundle/archive. + [JsonPropertyName("bundlePath")] + public string BundlePath { get; set; } = string.Empty; - /// Epoch milliseconds when this phase first started; for a skipped phase, the synthetic skip timestamp (equal to `completedAt`). - [JsonPropertyName("startedAt")] - public long? StartedAt { get; set; } + /// Kind of source path to include. + [JsonPropertyName("kind")] + public DebugCollectLogsEntryKind Kind { get; set; } - /// Derived lifecycle state of the phase. - [JsonPropertyName("status")] - public WorkflowPhaseStatus Status { get; set; } + /// Server-local source path to read. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Human-readable phase title. - [JsonPropertyName("title")] - public string Title { get; set; } = string.Empty; + /// How text content from this entry should be redacted. Defaults to plain-text. With none, no redaction is applied; the caller must ensure any necessary redaction is performed before this call. + [JsonPropertyName("redaction")] + public DebugCollectLogsRedaction? Redaction { get; set; } - /// Total direct agents associated with this phase. - [JsonPropertyName("totalAgentCount")] - public long TotalAgentCount { get; set; } + /// When true, collection fails if this entry cannot be read. Defaults to false, which records the entry in `skippedEntries`. + [JsonPropertyName("required")] + public bool? Required { get; set; } } -/// One durable workflow progress record. +/// Destination for the session debug bundle. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowProgressLine +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(DebugCollectLogsDestinationArchive), "archive")] +[JsonDerivedType(typeof(DebugCollectLogsDestinationDirectory), "directory")] +public partial class DebugCollectLogsDestination { - /// Resume attempt that emitted this record. - [JsonPropertyName("attempt")] - public long Attempt { get; set; } - - /// Progress record kind. + /// The type discriminator. [JsonPropertyName("kind")] - public WorkflowLogLineKind Kind { get; set; } + public virtual string Kind { get; set; } = string.Empty; +} - /// Phase active when the record was emitted, or null before any phase. - [JsonPropertyName("phaseId")] - public string? PhaseId { get; set; } - /// Epoch milliseconds when the record was persisted. - [JsonPropertyName("recordedAt")] - public long RecordedAt { get; set; } +/// The archive variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class DebugCollectLogsDestinationArchive : DebugCollectLogsDestination +{ + /// + [JsonIgnore] + public override string Kind => "archive"; - /// Global monotonic sequence number within the run. - [JsonPropertyName("seq")] - public long Seq { get; set; } + /// When true, create the archive atomically without overwriting an existing file by appending ` (N)` before the extension as needed. Defaults to false. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("noOverwrite")] + public bool? NoOverwrite { get; set; } - /// Prompt-safe progress text. - [JsonPropertyName("text")] - public string Text { get; set; } = string.Empty; + /// Absolute or server-relative path for the .tgz archive to create. + [JsonPropertyName("outputPath")] + public required string OutputPath { get; set; } } -/// A bidirectional page of workflow progress. +/// The directory variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowProgressPage +public partial class DebugCollectLogsDestinationDirectory : DebugCollectLogsDestination { - /// Whether progress records newer than this page exist. - [JsonPropertyName("hasMoreNewer")] - public bool HasMoreNewer { get; set; } - - /// Whether progress records older than this page exist. - [JsonPropertyName("hasMoreOlder")] - public bool HasMoreOlder { get; set; } - - /// Newest sequence number in this page, or null when empty. - [JsonPropertyName("newestSeq")] - public long? NewestSeq { get; set; } - - /// Oldest sequence number in this page, or null when empty. - [JsonPropertyName("oldestSeq")] - public long? OldestSeq { get; set; } - - /// Progress records in sequence order. - [JsonPropertyName("records")] - public IList Records { get => field ??= []; set; } + /// + [JsonIgnore] + public override string Kind => "directory"; - /// Run revision reflected by this page. - [JsonPropertyName("revision")] - public long Revision { get; set; } + /// Directory where files should be staged. The directory is created if needed. + [JsonPropertyName("outputDirectory")] + public required string OutputDirectory { get; set; } } -/// Full workflow run observability detail. +/// Built-in session diagnostics to include in the bundle. Omitted fields default to true. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowRunDetail +public sealed class DebugCollectLogsInclude { - /// Epoch milliseconds when the current active segment started, or null while inactive. - [JsonPropertyName("activeSegmentStartedAt")] - public long? ActiveSegmentStartedAt { get; set; } - - /// Durable identities and live statuses for direct workflow agents. - [JsonPropertyName("agents")] - public IList Agents { get => field ??= []; set; } + /// Server-local path to the current process log. When set, it is included as `process.log` and its directory is searched for prior logs from the same session. + [JsonPropertyName("currentProcessLogPath")] + public string? CurrentProcessLogPath { get; set; } - /// Approved effective resource ceilings, or null until approved. - [JsonPropertyName("approved")] - public WorkflowDeclaredLimits? Approved { get; set; } + /// Include the session event log (`events.jsonl`). Defaults to true. + [JsonPropertyName("events")] + public bool? Events { get; set; } - /// Whether the durable run state currently passes runtime resume eligibility checks. - [JsonPropertyName("canResume")] - public bool CanResume { get; set; } + /// Server-local path to the session's events.jsonl file. Internal callers normally omit this and let the runtime derive it from the session. + [JsonPropertyName("eventsPath")] + public string? EventsPath { get; set; } - /// Epoch milliseconds when the run completed, or null while nonterminal. - [JsonPropertyName("completedAt")] - public long? CompletedAt { get; set; } + /// Maximum number of previous process logs to include. Defaults to 5. + [JsonPropertyName("previousProcessLogLimit")] + public long? PreviousProcessLogLimit { get; set; } - /// Durable resource consumption. - [JsonPropertyName("consumed")] - public WorkflowRunConsumed Consumed { get => field ??= new(); set; } + /// Server-local process log directory to search when `currentProcessLogPath` is unavailable, useful for collecting logs for inactive sessions. + [JsonPropertyName("processLogDirectory")] + public string? ProcessLogDirectory { get; set; } - /// Epoch milliseconds when the run was created. - [JsonPropertyName("createdAt")] - public long CreatedAt { get; set; } + /// Include process logs for the session. Defaults to true. + [JsonPropertyName("processLogs")] + public bool? ProcessLogs { get; set; } - /// Current phase identity, or null before any phase is entered. - [JsonPropertyName("currentPhase")] - public WorkflowCurrentPhase? CurrentPhase { get; set; } + /// Include interactive shell logs written under the session's `shell-logs` directory. Defaults to true. + [JsonPropertyName("shellLogs")] + public bool? ShellLogs { get; set; } +} - /// Resource ceilings declared by the workflow. - [JsonPropertyName("declaredLimits")] - public WorkflowDeclaredLimits DeclaredLimits { get => field ??= new(); set; } +/// Options for collecting a session debug bundle with configurable redaction. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class DebugCollectLogsRequest +{ + /// Caller-provided server-local files or directories to include in addition to the runtime's built-in session diagnostics. This lets host applications add their own diagnostics without changing the API shape. + [JsonPropertyName("additionalEntries")] + public IList? AdditionalEntries { get; set; } - /// Number of phases declared by the workflow. - [JsonPropertyName("declaredPhaseCount")] - public long DeclaredPhaseCount { get; set; } + /// Where the bundle should be written. Use `archive` to produce a .tgz, or `directory` to stage files for caller-managed upload/post-processing. + [JsonPropertyName("destination")] + public DebugCollectLogsDestination Destination { get => field ??= new(); set; } - /// Human-readable workflow description. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; + /// Which built-in session diagnostics to include. Omitted fields default to true. + [JsonPropertyName("include")] + public DebugCollectLogsInclude? Include { get; set; } - /// Number of direct workflow agents currently live. - [JsonPropertyName("liveAgentCount")] - public long LiveAgentCount { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Epoch milliseconds when this live-overlay snapshot was observed. - [JsonPropertyName("observedAt")] - public long ObservedAt { get; set; } +/// Canvas action that the agent or host can invoke. To discover the input schema for a particular action, call the list_canvas_capabilities tool. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class CanvasAction +{ + /// Description of the action. + [JsonPropertyName("description")] + public string? Description { get; set; } - /// Lifecycle and timing observations for each workflow phase. - [JsonPropertyName("phases")] - public IList Phases { get => field ??= []; set; } + /// JSON Schema for the action input. + [JsonPropertyName("inputSchema")] + public JsonElement? InputSchema { get; set; } - /// Bidirectional page of durable workflow progress. - [JsonPropertyName("progress")] - public WorkflowProgressPage Progress { get => field ??= new(); set; } + /// Action name exposed by the canvas provider. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; +} - /// Monotonic durable run revision. - [JsonPropertyName("revision")] - public long Revision { get; set; } +/// Canvas available in the current session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class DiscoveredCanvas +{ + /// Actions the agent or host may invoke on an open instance. + [JsonPropertyName("actions")] + public IList? Actions { get; set; } - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// Provider-local canvas identifier. + [JsonPropertyName("canvasId")] + public string CanvasId { get; set; } = string.Empty; - /// Epoch milliseconds when execution first started, or null before start. - [JsonPropertyName("startedAt")] - public long? StartedAt { get; set; } + /// Short, single-sentence description shown to the agent in canvas catalogs. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// Current workflow run status. - [JsonPropertyName("status")] - public WorkflowRunStatus Status { get; set; } + /// Human-readable canvas name. + [JsonPropertyName("displayName")] + public string DisplayName { get; set; } = string.Empty; - /// Terminal run outcome, or null while nonterminal. - [JsonPropertyName("terminal")] - public WorkflowRunTerminal? Terminal { get; set; } + /// Owning provider identifier. + [JsonPropertyName("extensionId")] + public string ExtensionId { get; set; } = string.Empty; - /// Total direct workflow agents spawned across all attempts. - [JsonPropertyName("totalSpawnedAgentCount")] - public long TotalSpawnedAgentCount { get; set; } + /// Owning extension display name, when available. + [JsonPropertyName("extensionName")] + public string? ExtensionName { get; set; } - /// Epoch milliseconds when the durable run was last updated. - [JsonPropertyName("updatedAt")] - public long UpdatedAt { get; set; } + /// Host-local PNG path for the canvas icon, when supplied. + [JsonPropertyName("icon")] + public string? Icon { get; set; } - /// Registered workflow name. - [JsonPropertyName("workflowName")] - public string WorkflowName { get; set; } = string.Empty; + /// JSON Schema for canvas open input. + [JsonPropertyName("inputSchema")] + public JsonElement? InputSchema { get; set; } } -/// Parameters for paging workflow progress. +/// Declared canvases available in this session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowGetRunProgressRequest +public sealed class CanvasList { - /// Exclusive forward cursor. - [JsonPropertyName("afterSeq")] - public long? AfterSeq { get; set; } - - /// Exclusive backward cursor. - [JsonPropertyName("beforeSeq")] - public long? BeforeSeq { get; set; } - - /// Maximum records to return. Defaults to 200 and is capped at 500. - [JsonPropertyName("limit")] - public int? Limit { get; set; } - - /// Optional phase identifier used to scope records and cursors. - [JsonPropertyName("phaseId")] - public string? PhaseId { get; set; } - - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// Declared canvases available in this session. + [JsonPropertyName("canvases")] + public IList Canvases { get => field ??= []; set; } +} +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionCanvasListRequest +{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Parameters for cancelling a workflow run. +/// Open canvas instance snapshot. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowCancelRequest +public sealed class OpenCanvasInstance { - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// Provider-local canvas identifier. + [JsonPropertyName("canvasId")] + public string CanvasId { get; set; } = string.Empty; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Owning provider identifier. + [JsonPropertyName("extensionId")] + public string ExtensionId { get; set; } = string.Empty; -/// Parameters for pausing a running workflow. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowPauseRequest -{ - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// Owning extension display name, when available. + [JsonPropertyName("extensionName")] + public string? ExtensionName { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Host-local PNG path for the canvas icon, when supplied. + [JsonPropertyName("icon")] + public string? Icon { get; set; } + + /// Input supplied when the instance was opened. + [JsonPropertyName("input")] + public JsonElement? Input { get; set; } + + /// Stable caller-supplied canvas instance identifier. + [JsonPropertyName("instanceId")] + public string InstanceId { get; set; } = string.Empty; + + /// Provider-supplied status text. + [JsonPropertyName("status")] + public string? Status { get; set; } + + /// Rendered title. + [JsonPropertyName("title")] + public string? Title { get; set; } + + /// URL for web-rendered canvases. + [JsonPropertyName("url")] + public string? Url { get; set; } } -/// RPC data type for SessionWorkflowPauseAtCheckpoint operations. +/// Live open-canvas snapshot. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionWorkflowPauseAtCheckpointResult +public sealed class CanvasListOpenResult { - /// Whether this execution attempt must pause or may continue. - [JsonPropertyName("action")] - public WorkflowPauseCheckpointAction Action { get; set; } + /// Currently open canvas instances. + [JsonPropertyName("openCanvases")] + public IList OpenCanvases { get => field ??= []; set; } } -/// Parameters for an owned durable pause checkpoint. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowPauseCheckpointRequest +internal sealed class SessionCanvasListOpenRequest { - /// Opaque token identifying the execution attempt that reached the checkpoint. - [JsonPropertyName("executionToken")] - public string ExecutionToken { get; set; } = string.Empty; - - /// Stable author-defined checkpoint key. - [JsonPropertyName("key")] - public string Key { get; set; } = string.Empty; - - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Acknowledgement that a workflow request was accepted. +/// Canvas open parameters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowAckResult +internal sealed class CanvasOpenRequest { -} + /// Provider-local canvas identifier. + [JsonPropertyName("canvasId")] + public string CanvasId { get; set; } = string.Empty; -/// One ordered workflow progress line. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowLogLine -{ - /// Progress line kind. - [JsonPropertyName("kind")] - public WorkflowLogLineKind Kind { get; set; } + /// Owning provider identifier. Optional when the canvasId is unique across providers; required to disambiguate when multiple providers register the same canvasId. + [JsonPropertyName("extensionId")] + public string? ExtensionId { get; set; } - /// Monotonic sequence number within the workflow run. - [JsonPropertyName("seq")] - public long Seq { get; set; } + /// Canvas open input. + [JsonPropertyName("input")] + public JsonElement? Input { get; set; } - /// Progress text. - [JsonPropertyName("text")] - public string Text { get; set; } = string.Empty; + /// Caller-supplied stable instance identifier. + [JsonPropertyName("instanceId")] + public string InstanceId { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Parameters for recording workflow progress. +/// Canvas close parameters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowLogRequest +internal sealed class CanvasCloseRequest { - /// Opaque token identifying the current workflow execution attempt. - [JsonPropertyName("executionToken")] - public string ExecutionToken { get; set; } = string.Empty; - - /// Ordered progress lines to append. - [JsonPropertyName("lines")] - public IList Lines { get => field ??= []; set; } - - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// Open canvas instance identifier. + [JsonPropertyName("instanceId")] + public string InstanceId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Result of one workflow-scoped subagent call. +/// Canvas action invocation result. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowAgentResult +public sealed class CanvasActionInvokeResult { - /// Agent result, omitted when the agent produced no result. + /// Provider-supplied action result. [JsonPropertyName("result")] public JsonElement? Result { get; set; } } -/// Options for one workflow-scoped subagent call. +/// Canvas action invocation parameters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowAgentOptions +internal sealed class CanvasActionInvokeRequest { - /// Optional built-in or custom agent name whose definition configures the subagent. - [JsonPropertyName("agent")] - public string? Agent { get; set; } - - /// Optional context tier override for the subagent. - [JsonPropertyName("contextTier")] - public ContextTier? ContextTier { get; set; } - - /// Optional label distinguishing otherwise identical memoized agent calls. - [JsonPropertyName("label")] - public string? Label { get; set; } + /// Action name to invoke. + [JsonPropertyName("actionName")] + public string ActionName { get; set; } = string.Empty; - /// Optional model identifier for the subagent. - [JsonPropertyName("model")] - public string? Model { get; set; } + /// Action input. + [JsonPropertyName("input")] + public JsonElement? Input { get; set; } - /// Optional reasoning effort override for the subagent. - [JsonPropertyName("reasoningEffort")] - public string? ReasoningEffort { get; set; } + /// Open canvas instance identifier. + [JsonPropertyName("instanceId")] + public string InstanceId { get; set; } = string.Empty; - /// Optional JSON Schema for structured agent output. - [JsonPropertyName("schema")] - public JsonElement? Schema { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Parameters for one workflow-scoped subagent call. +/// Internal canvas provider registration parameters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowAgentRequest +internal sealed class CanvasProviderRegisterRequest { - /// Opaque token identifying the current workflow execution attempt. - [JsonPropertyName("executionToken")] - public string ExecutionToken { get; set; } = string.Empty; + /// Canvas contributions supplied by the provider. + [JsonPropertyName("canvases")] + public IList Canvases { get => field ??= []; set; } - /// Subagent execution options. - [JsonPropertyName("opts")] - public WorkflowAgentOptions Opts { get => field ??= new(); set; } + /// Connection identifier for callback routing. + [JsonPropertyName("connectionId")] + public string ConnectionId { get; set; } = string.Empty; - /// Prompt to send to the subagent. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; + /// Provider metadata supplied by the host. + [JsonPropertyName("info")] + public JsonElement Info { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// Workflow run identifier that owns the subagent. - [JsonPropertyName("workflowRunId")] - public string WorkflowRunId { get; set; } = string.Empty; } -/// Result of reading a workflow journal entry. +/// Internal canvas provider unregistration parameters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowJournalGetResult +internal sealed class CanvasProviderUnregisterRequest { - /// Whether the journal contained the requested key. - [JsonPropertyName("hit")] - public bool Hit { get; set; } + /// Connection identifier to unregister. + [JsonPropertyName("connectionId")] + public string ConnectionId { get; set; } = string.Empty; - /// Cached JSON result. The hit field distinguishes a cached JSON null from a miss. - [JsonPropertyName("resultJson")] - public JsonElement? ResultJson { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Parameters for reading a workflow journal entry. +/// Machine-readable workflow run failure. +/// Polymorphic base type discriminated by type. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowJournalGetRequest +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "type", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(WorkflowRunFailureWorkflowLimitReached), "workflow_limit_reached")] +[JsonDerivedType(typeof(WorkflowRunFailureWorkflowResumeDeclined), "workflow_resume_declined")] +[JsonDerivedType(typeof(WorkflowRunFailureWorkflowDurableFailure), "workflow_durable_failure")] +[JsonDerivedType(typeof(WorkflowRunFailureWorkflowAccountingIncomplete), "workflow_accounting_incomplete")] +[JsonDerivedType(typeof(WorkflowRunFailureWorkflowProviderDisconnected), "workflow_provider_disconnected")] +public partial class WorkflowRunFailure { - /// Opaque token identifying the current workflow execution attempt. - [JsonPropertyName("executionToken")] - public string ExecutionToken { get; set; } = string.Empty; + /// The type discriminator. + [JsonPropertyName("type")] + public virtual string Type { get; set; } = string.Empty; +} - /// Namespaced journal key. - [JsonPropertyName("key")] - public string Key { get; set; } = string.Empty; + +/// The workflow_limit_reached variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class WorkflowRunFailureWorkflowLimitReached : WorkflowRunFailure +{ + /// + [JsonIgnore] + public override string Type => "workflow_limit_reached"; + + /// Resource ceiling that stopped the run. + [JsonPropertyName("kind")] + public required WorkflowRunFailureKind Kind { get; set; } /// Workflow run identifier. [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + public required string RunId { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Suggested larger ceiling when the runtime can derive one safely. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("suggestedValue")] + public double? SuggestedValue { get; set; } + + /// Approved effective ceiling that was reached. + [JsonPropertyName("value")] + public required double Value { get; set; } } -/// Parameters for storing a workflow journal entry. +/// The workflow_resume_declined variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkflowJournalPutRequest +public partial class WorkflowRunFailureWorkflowResumeDeclined : WorkflowRunFailure { - /// Opaque token identifying the current workflow execution attempt. - [JsonPropertyName("executionToken")] - public string ExecutionToken { get; set; } = string.Empty; - - /// Namespaced journal key. - [JsonPropertyName("key")] - public string Key { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Type => "workflow_resume_declined"; - /// JSON result to memoize. - [JsonPropertyName("resultJson")] - public JsonElement ResultJson { get; set; } + /// Human-readable reason the resume did not proceed. + [JsonPropertyName("reason")] + public required string Reason { get; set; } - /// Workflow run identifier. + /// Workflow run identifier whose changed limits were declined. [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + public required string RunId { get; set; } } -/// The session's authoritative model snapshot. Auto preference fields are configuration for the virtual `auto` model and do not change the selected model identifier. The context tier reflects `Session.getContextTier()`, restored from the session journal on resume. +/// The workflow_durable_failure variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CurrentModel +public partial class WorkflowRunFailureWorkflowDurableFailure : WorkflowRunFailure { - /// Auto preference currently claimed by an in-progress activation. Null means the activation is returning to provider-default routing. - [JsonPropertyName("activatingAutoTier")] - public AutoTier? ActivatingAutoTier { get; set; } + /// + [JsonIgnore] + public override string Type => "workflow_durable_failure"; - /// Auto preference currently committed for the session. This can remain available while another model is selected so a later switch to `auto` can reuse it. - [JsonPropertyName("autoTier")] - public AutoTier? AutoTier { get; set; } + /// Stable failure code. + [JsonPropertyName("code")] + public required string Code { get; set; } - /// Context tier for models that support multiple context-window sizes. - [JsonPropertyName("contextTier")] - public ContextTier? ContextTier { get; set; } + /// Execution-critical durable operation that failed. + [JsonPropertyName("operation")] + public required WorkflowDurableOperation Operation { get; set; } - /// Currently active model identifier. - [JsonPropertyName("modelId")] - public string? ModelId { get; set; } + /// Workflow run identifier. + [JsonPropertyName("runId")] + public required string RunId { get; set; } +} - /// Latest unclaimed Auto preference waiting for a future user turn. Null means the pending request is returning to provider-default routing. - [JsonPropertyName("pendingAutoTier")] - public AutoTier? PendingAutoTier { get; set; } +/// The run stopped because its usage accounting could not be completed. +/// The workflow_accounting_incomplete variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class WorkflowRunFailureWorkflowAccountingIncomplete : WorkflowRunFailure +{ + /// + [JsonIgnore] + public override string Type => "workflow_accounting_incomplete"; - /// Captured base model to restore when leaving plan mode. Omitted outside plan mode or when no plan override has captured a base model. Persistent agent model requirements apply to this model rather than the temporary plan model. - [JsonPropertyName("planBaseModelId")] - public string? PlanBaseModelId { get; set; } + /// Confirmed usage in nano-AIU, representing the floor of what the run spent. + [JsonPropertyName("drainedNanoAiu")] + public required long DrainedNanoAiu { get; set; } - /// Provider of planBaseModelId, when that saved selection is provider-qualified. - [JsonPropertyName("planBaseProviderId")] - public string? PlanBaseProviderId { get; set; } + /// Workflow run identifier. + [JsonPropertyName("runId")] + public required string RunId { get; set; } +} - /// Provider selected for this model. Together with modelId, identifies a catalog entry even when providers serve the same model. Omitted for unattributed legacy selections. - [JsonPropertyName("providerId")] - public string? ProviderId { get; set; } +/// The extension that owns the workflow disconnected while the run was executing, so the host halted it. The run's journaled subagent results are preserved so a resume can reuse them. +/// The workflow_provider_disconnected variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class WorkflowRunFailureWorkflowProviderDisconnected : WorkflowRunFailure +{ + /// + [JsonIgnore] + public override string Type => "workflow_provider_disconnected"; - /// Reasoning effort level currently applied to the active model, when one is set. Reads `Session.getReasoningEffort()` synchronously after `getSelectedModel()` resolves so the two values are reported as a snapshot. - [JsonPropertyName("reasoningEffort")] - public string? ReasoningEffort { get; set; } + /// Workflow run identifier. + [JsonPropertyName("runId")] + public required string RunId { get; set; } } -/// Identifies the target session. +/// Durable metadata describing who initiated a workflow pause. +/// Polymorphic base type discriminated by type. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionModelGetCurrentRequest +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "type", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(WorkflowPauseInfoUser), "user")] +[JsonDerivedType(typeof(WorkflowPauseInfoCheckpoint), "checkpoint")] +public partial class WorkflowPauseInfo { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// The type discriminator. + [JsonPropertyName("type")] + public virtual string Type { get; set; } = string.Empty; } -/// RPC data type for ModelSwitchConfirmation operations. + +/// The user variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelSwitchConfirmation +public partial class WorkflowPauseInfoUser : WorkflowPauseInfo { - /// Current conversation token count before switching models. - [JsonPropertyName("currentTokens")] - public double CurrentTokens { get; set; } + /// + [JsonIgnore] + public override string Type => "user"; +} - /// Target model token limit used by the compaction preflight. - [JsonPropertyName("targetLimit")] - public double TargetLimit { get; set; } +/// The checkpoint variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class WorkflowPauseInfoCheckpoint : WorkflowPauseInfo +{ + /// + [JsonIgnore] + public override string Type => "checkpoint"; - /// Display name of the model that requires compaction confirmation. - [JsonPropertyName("targetModelDisplayName")] - public string TargetModelDisplayName { get; set; } = string.Empty; + /// Stable author-defined checkpoint key that initiated the pause. + [JsonPropertyName("key")] + public required string Key { get; set; } } -/// The model identifier active on the session after the switch. +/// Complete current or terminal workflow run envelope. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelSwitchToResult +public sealed class WorkflowRunResult { - /// Compaction confirmation projection when status is confirmation_required. - [JsonPropertyName("confirmation")] - public ModelSwitchConfirmation? Confirmation { get; set; } + /// One-based execution attempt represented by this envelope. Absent before the first attempt starts or when returned by an older runtime. + [JsonPropertyName("attempt")] + public long? Attempt { get; set; } - /// True when the switch was deferred (enqueued as a cancellable `/model` command) because a turn was active or another model change was already queued, rather than applied immediately. When true, the session's live model is unchanged until the queued change drains. - [JsonPropertyName("deferred")] - public bool? Deferred { get; set; } + /// Error message for an errored run. + [JsonPropertyName("error")] + public string? Error { get; set; } - /// Deprecation warnings associated with the selected model or options. - [JsonPropertyName("deprecationWarnings")] - public IList? DeprecationWarnings { get; set; } + /// Machine-readable failure details for a halted or errored run. + [JsonPropertyName("failure")] + public WorkflowRunFailure? Failure { get; set; } - /// User-facing outcome message for the model switch. - [JsonPropertyName("message")] - public string? Message { get; set; } + /// Structured pause initiator metadata for a paused attempt. + [JsonPropertyName("pauseInfo")] + public WorkflowPauseInfo? PauseInfo { get; set; } - /// Currently active model identifier after the switch. - [JsonPropertyName("modelId")] - public string? ModelId { get; set; } + /// Reason for a halted or cancelled run. + [JsonPropertyName("reason")] + public string? Reason { get; set; } - /// Authoritative model and Auto preference state after an immediate switch. For deferred switches this remains the current state until the queued change drains. - [JsonPropertyName("modelState")] - public CurrentModel? ModelState { get; set; } + /// Completed workflow result. + [JsonPropertyName("result")] + public JsonElement? Result { get; set; } - /// Persistence failure encountered after applying the model switch. - [JsonPropertyName("persistenceError")] - public string? PersistenceError { get; set; } + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; - /// Stable queue item identifier when this request was enqueued. Remains present if the item drains before the response is returned. - [JsonPropertyName("queueId")] - public string? QueueId { get; set; } + /// Partial journal and progress snapshot for a halted, cancelled, or errored run. + [JsonPropertyName("snapshot")] + public JsonElement? Snapshot { get; set; } - /// Lifecycle result for the requested switch. + /// Current or terminal workflow run status. [JsonPropertyName("status")] - public string? Status { get; set; } - - /// User-facing warning produced while applying the model switch. - [JsonPropertyName("warning")] - public string? Warning { get; set; } -} - -/// Environment variables consulted while resolving model-picker settings. -public sealed class ModelPickerSettingsContextEnvironment -{ + public WorkflowRunStatus Status { get; set; } } -/// Filesystem and environment context used to resolve model-picker settings. +/// Wire-only per-invocation workflow resource ceiling overrides. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelPickerSettingsContext +public sealed class WorkflowRunLimits { - /// Optional Copilot configuration directory containing persisted settings. - [JsonPropertyName("configDir")] - public string? ConfigDir { get; set; } + /// Maximum AI credits consumed by workflow subagents and their descendants. The post-paid ceiling is soft: parallel turns can settle beyond it before the run stops. + [JsonPropertyName("maxAiCredits")] + public double? MaxAiCredits { get; set; } - /// Environment variables consulted while resolving model-picker settings. - [JsonPropertyName("environment")] - public ModelPickerSettingsContextEnvironment Environment { get => field ??= new(); set; } + /// Maximum number of workflow subagents that may run concurrently. + [JsonPropertyName("maxConcurrentSubagents")] + public long? MaxConcurrentSubagents { get; set; } - /// User home directory used when resolving persisted settings. - [JsonPropertyName("homeDirectory")] - public string HomeDirectory { get; set; } = string.Empty; + /// Maximum total number of workflow subagents that may be admitted. + [JsonPropertyName("maxTotalSubagents")] + public long? MaxTotalSubagents { get; set; } + + /// Maximum accumulated active-execution time in seconds. Active execution includes the entire extension body, subprocess waits, queued-agent waits, and sleeps; time between resumed attempts is not counted. + [JsonPropertyName("timeoutSeconds")] + public double? TimeoutSeconds { get; set; } } -/// RPC data type for ModelPickerPersistence operations. +/// Options controlling workflow invocation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelPickerPersistenceRequest +public sealed class WorkflowRunOptions { - /// Whether context tier was explicitly selected and should be persisted. - [JsonPropertyName("contextTierExplicit")] - public bool? ContextTierExplicit { get; set; } + /// Per-invocation resource ceiling overrides. + [JsonPropertyName("limits")] + public WorkflowRunLimits? Limits { get; set; } - /// Whether reasoning effort was explicitly selected and should be persisted. - [JsonPropertyName("reasoningEffortExplicit")] - public bool? ReasoningEffortExplicit { get; set; } + /// Whether to emit workflow phase names to the session transcript. + [JsonPropertyName("logPhaseNames")] + public bool? LogPhaseNames { get; set; } - /// Filesystem and environment context used to resolve settings persistence. - [JsonPropertyName("settingsContext")] - public ModelPickerSettingsContext SettingsContext { get => field ??= new(); set; } -} + /// Whether to notify the originating session when the workflow completes. + [JsonPropertyName("notifyOnComplete")] + public bool? NotifyOnComplete { get; set; } -/// Target model identifier and optional reasoning effort, summary, capability overrides, and context tier. + /// Run identifier whose journal and progress should seed this resumed run. + [JsonPropertyName("resumeFromRunId")] + public string? ResumeFromRunId { get; set; } +} + +/// Parameters for invoking a registered workflow. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelSwitchToRequest +internal sealed class WorkflowRunRequest { - /// Optional Auto routing preference to stage atomically with selecting `auto`. Pass null to return to provider-default Auto routing. This field is rejected when `modelId` is not `auto`. - [JsonPropertyName("autoTier")] - public AutoTier? AutoTier { get; set; } - - /// Explicit response to a model-switch compaction preflight. Omit to request a confirmation projection when compaction is necessary. - [JsonPropertyName("compactionDecision")] - public string? CompactionDecision { get; set; } - - /// Explicit context tier for the selected model. `"default"` / `"long_context"` apply the requested tier; omit this field to use normal model behavior with no explicit tier. - [JsonPropertyName("contextTier")] - public ContextTier? ContextTier { get; set; } - - /// When true, defer this switch (enqueue it) if another model change is already queued, even when no turn is active — so it drains last (FIFO) and wins over the already-queued change. Intended for genuine user-initiated model selections; internal restore/reapply switches omit it and apply immediately when no turn is active. When no other model change is queued this has no effect (a switch still applies immediately unless a turn is active). - [JsonPropertyName("deferIfModelChangeQueued")] - public bool? DeferIfModelChangeQueued { get; set; } - - /// Override individual model capabilities resolved by the runtime. - [JsonPropertyName("modelCapabilities")] - public ModelCapabilitiesOverride? ModelCapabilities { get; set; } - - /// Settings scope used when persisting the selected model. - [JsonPropertyName("modelChangeScope")] - public string? ModelChangeScope { get; set; } - - /// Model id to switch to, as returned by `list`. Include providerId to select an exact catalog entry when providers share the id. Without providerId, a bare id retains incumbent selection behavior; a registry-qualified id (`provider/id`, e.g. `acme/claude-sonnet`) targets a BYOK model. - [JsonPropertyName("modelId")] - public required string ModelId { get; set; } - - /// Optional settings context and explicit-override flags used to persist a picker selection. - [JsonPropertyName("pickerPersistence")] - public ModelPickerPersistenceRequest? PickerPersistence { get; set; } - - /// Provider id from the selected list entry's provider reference. Selects this exact provider/model pair; an unavailable pair fails rather than using another provider. Omit for deterministic legacy bare-model selection. - [JsonPropertyName("providerId")] - public string? ProviderId { get; set; } - - /// Reasoning effort level to use for the model. CAPI values are model-defined and validated against the selected model; BYOK providers may define additional values. "none" disables reasoning. Pass null to clear any session effort override and fall back to the model's default. When omitted, the session's current effort is kept. - [JsonPropertyName("reasoningEffort")] - public string? ReasoningEffort { get; set; } - - /// Reasoning summary mode to request for supported model clients. - [JsonPropertyName("reasoningSummary")] - public ReasoningSummary? ReasoningSummary { get; set; } - - /// Optional repository settings scope to persist after the switch commits. - [JsonPropertyName("repoScope")] - public string? RepoScope { get; set; } - - /// Require the target to be currently available and enabled before applying the switch. - [JsonPropertyName("requireAvailable")] - public bool? RequireAvailable { get; set; } + /// Workflow input value. + [JsonPropertyName("args")] + public JsonElement Args { get; set; } - /// When true, evaluate context-window compaction policy before applying the switch. - [JsonPropertyName("runCompactionPreflight")] - public bool? RunCompactionPreflight { get; set; } + /// Registered workflow name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Origin to record on the effective `session.model_change` event for trusted in-process calls. Transport SDK calls are always recorded as `sdk`, regardless of this value. - [JsonPropertyName("source")] - public ModelChangeSource? Source { get; set; } + /// Workflow invocation options. + [JsonPropertyName("options")] + public WorkflowRunOptions? Options { get; set; } - /// Output verbosity level to request for supported models. - [JsonPropertyName("verbosity")] - public Verbosity? Verbosity { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Target model identifier and optional reasoning effort, summary, capability overrides, and context tier. +/// Resolved persisted workflow identity and resumed run envelope. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModelSwitchToRequestWithSession +public sealed class WorkflowResumeResult { - /// Optional Auto routing preference to stage atomically with selecting `auto`. Pass null to return to provider-default Auto routing. This field is rejected when `modelId` is not `auto`. - [JsonPropertyName("autoTier")] - public AutoTier? AutoTier { get; set; } - - /// Explicit response to a model-switch compaction preflight. Omit to request a confirmation projection when compaction is necessary. - [JsonPropertyName("compactionDecision")] - public string? CompactionDecision { get; set; } - - /// Explicit context tier for the selected model. `"default"` / `"long_context"` apply the requested tier; omit this field to use normal model behavior with no explicit tier. - [JsonPropertyName("contextTier")] - public ContextTier? ContextTier { get; set; } - - /// When true, defer this switch (enqueue it) if another model change is already queued, even when no turn is active — so it drains last (FIFO) and wins over the already-queued change. Intended for genuine user-initiated model selections; internal restore/reapply switches omit it and apply immediately when no turn is active. When no other model change is queued this has no effect (a switch still applies immediately unless a turn is active). - [JsonPropertyName("deferIfModelChangeQueued")] - public bool? DeferIfModelChangeQueued { get; set; } - - /// Override individual model capabilities resolved by the runtime. - [JsonPropertyName("modelCapabilities")] - public ModelCapabilitiesOverride? ModelCapabilities { get; set; } - - /// Settings scope used when persisting the selected model. - [JsonPropertyName("modelChangeScope")] - public string? ModelChangeScope { get; set; } - - /// Model id to switch to, as returned by `list`. Include providerId to select an exact catalog entry when providers share the id. Without providerId, a bare id retains incumbent selection behavior; a registry-qualified id (`provider/id`, e.g. `acme/claude-sonnet`) targets a BYOK model. - [JsonPropertyName("modelId")] - public string ModelId { get; set; } = string.Empty; - - /// Optional settings context and explicit-override flags used to persist a picker selection. - [JsonPropertyName("pickerPersistence")] - public ModelPickerPersistenceRequest? PickerPersistence { get; set; } - - /// Provider id from the selected list entry's provider reference. Selects this exact provider/model pair; an unavailable pair fails rather than using another provider. Omit for deterministic legacy bare-model selection. - [JsonPropertyName("providerId")] - public string? ProviderId { get; set; } + /// Terminal resumed run envelope. + [JsonPropertyName("run")] + public WorkflowRunResult Run { get => field ??= new(); set; } - /// Reasoning effort level to use for the model. CAPI values are model-defined and validated against the selected model; BYOK providers may define additional values. "none" disables reasoning. Pass null to clear any session effort override and fall back to the model's default. When omitted, the session's current effort is kept. - [JsonPropertyName("reasoningEffort")] - public string? ReasoningEffort { get; set; } + /// Persisted workflow name resolved for the resumed run. + [JsonPropertyName("workflowName")] + public string WorkflowName { get; set; } = string.Empty; +} - /// Reasoning summary mode to request for supported model clients. - [JsonPropertyName("reasoningSummary")] - public ReasoningSummary? ReasoningSummary { get; set; } +/// Parameters for resuming a workflow run from its persisted identity. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class WorkflowResumeRequest +{ + /// Optional per-invocation resource ceiling overrides. + [JsonPropertyName("limits")] + public WorkflowRunLimits? Limits { get; set; } - /// Optional repository settings scope to persist after the switch commits. - [JsonPropertyName("repoScope")] - public string? RepoScope { get; set; } + /// Whether to emit workflow phase names to the session transcript. + [JsonPropertyName("logPhaseNames")] + public bool? LogPhaseNames { get; set; } - /// Require the target to be currently available and enabled before applying the switch. - [JsonPropertyName("requireAvailable")] - public bool? RequireAvailable { get; set; } + /// Whether to notify the originating session when the workflow completes. + [JsonPropertyName("notifyOnComplete")] + public bool? NotifyOnComplete { get; set; } - /// When true, evaluate context-window compaction policy before applying the switch. - [JsonPropertyName("runCompactionPreflight")] - public bool? RunCompactionPreflight { get; set; } + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// Origin to record on the effective `session.model_change` event for trusted in-process calls. Transport SDK calls are always recorded as `sdk`, regardless of this value. - [JsonPropertyName("source")] - public ModelChangeSource? Source { get; set; } - - /// Output verbosity level to request for supported models. - [JsonPropertyName("verbosity")] - public Verbosity? Verbosity { get; set; } } -/// Immediate acknowledgement and Auto preference snapshot after a switch request. This result never implies that a pending preference committed. +/// Options for an internal tool-originated workflow invocation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelSwitchAutoTierResult +internal sealed class WorkflowToolRunOptions { - /// Auto preference currently claimed by an in-progress activation. Null means the activation is returning to provider-default routing. - [JsonPropertyName("activatingAutoTier")] - public AutoTier? ActivatingAutoTier { get; set; } - - /// Auto preference currently committed for the session. - [JsonPropertyName("effectiveAutoTier")] - public AutoTier? EffectiveAutoTier { get; set; } - - /// Latest unclaimed Auto preference waiting for a future user turn. - [JsonPropertyName("pendingAutoTier")] - public AutoTier? PendingAutoTier { get; set; } - - /// Immediate request status. `pending` means accepted but not committed. - [JsonPropertyName("status")] - public ModelSwitchAutoTierStatus Status { get; set; } + /// Per-invocation resource ceiling overrides. + [JsonPropertyName("limits")] + public WorkflowRunLimits? Limits { get; set; } - /// Earlier unclaimed preference replaced by this request. This can be present with either status, including when selecting the effective preference cancels pending work. - [JsonPropertyName("supersededAutoTier")] - public AutoTier? SupersededAutoTier { get; set; } + /// Run identifier whose journal and progress should seed this resumed run. + [JsonPropertyName("resumeFromRunId")] + public string? ResumeFromRunId { get; set; } } -/// An Auto preference request for the session. This updates Auto configuration only; it does not change the selected model to `auto`. +/// Internal parameters for invoking a registered workflow from a tool. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModelSwitchAutoTierRequest +internal sealed class WorkflowToolRunRequest { - /// Auto preference to activate when a future user turn using the `auto` model safely mints a replacement model and token pair. Pass null to return to provider-default Auto routing. - [JsonPropertyName("autoTier")] - [JsonIgnore(Condition = JsonIgnoreCondition.Never)] - public AutoTier? AutoTier { get; set; } + /// Workflow input value. + [JsonPropertyName("args")] + public JsonElement Args { get; set; } + + /// Registered workflow name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Tool-originated workflow invocation options. + [JsonPropertyName("options")] + public WorkflowToolRunOptions? Options { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - /// Origin to record on the effective `session.model_change` event. Defaults to `sdk` when omitted. - [JsonPropertyName("source")] - public ModelChangeSource? Source { get; set; } + /// Opaque identifier of the originating tool call. + [JsonPropertyName("toolCallId")] + public string? ToolCallId { get; set; } } -/// Managed, repository, and CLI model overrides to overlay onto the session at startup. +/// Internal parameters for resuming a workflow run from a tool. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModelApplyStartupOverlayRequest +internal sealed class WorkflowToolResumeRequest { - /// Effective default Auto routing preference from user and managed settings. Applies only to fresh sessions and never replaces a per-session selection. - [JsonPropertyName("autoTier")] - public AutoTier? AutoTier { get; set; } - - /// Model explicitly selected by the CLI, when provided. - [JsonPropertyName("cliModel")] - public string? CliModel { get; set; } - - /// Whether the overlay is being applied while resuming a deferred session. - [JsonPropertyName("deferredResume")] - public bool? DeferredResume { get; set; } - - /// Model required by device-managed policy, when configured. - [JsonPropertyName("deviceManagedModel")] - public string? DeviceManagedModel { get; set; } - - /// Context tier paired with the effective organization-managed model. Applies only when that concrete managed model is selected; it is ignored for Auto and for CLI, resume, or user overrides. - [JsonPropertyName("managedContextTier")] - public string? ManagedContextTier { get; set; } - - /// Reasoning effort paired with the effective organization-managed model. Applies only when that concrete managed model is selected; it is ignored for Auto and for CLI, resume, or user overrides. - [JsonPropertyName("managedReasoningEffort")] - public string? ManagedReasoningEffort { get; set; } - - /// Startup default model from the enterprise policy helper, when configured. Weakest of the managed sources: it applies only when neither device nor server policy names a model, and an explicit user selection still wins. - [JsonPropertyName("policyHelperModel")] - public string? PolicyHelperModel { get; set; } - - /// Auto routing preference selected by repository settings, when configured. Applied only when the overlay selects the Auto model; beside a concrete model it stays dormant. - [JsonPropertyName("repoAutoTier")] - public string? RepoAutoTier { get; set; } - - /// Context tier selected by repository settings, when configured. - [JsonPropertyName("repoContextTier")] - public string? RepoContextTier { get; set; } - - /// Model selected by repository settings, when configured. - [JsonPropertyName("repoModel")] - public string? RepoModel { get; set; } - - /// Provider owning the repository-selected model. Omitted repository provider identity retains legacy bare-model behavior. - [JsonPropertyName("repoModelProviderId")] - public string? RepoModelProviderId { get; set; } - - /// Reasoning effort selected by repository settings, when configured. - [JsonPropertyName("repoReasoningEffort")] - public string? RepoReasoningEffort { get; set; } + /// Optional per-invocation resource ceiling overrides. + [JsonPropertyName("limits")] + public WorkflowRunLimits? Limits { get; set; } - /// Model required by server-managed policy, when configured. - [JsonPropertyName("serverManagedModel")] - public string? ServerManagedModel { get; set; } + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; -} -/// RPC data type for SessionModelClearStartupSeed operations. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionModelClearStartupSeedResult -{ - /// Gets or sets the cleared value. - [JsonPropertyName("cleared")] - public bool Cleared { get; set; } + /// Opaque identifier of the originating tool call. + [JsonPropertyName("toolCallId")] + public string? ToolCallId { get; set; } } -/// RPC data type for SessionModelClearStartupSeed operations. +/// Parameters for retrieving a workflow run. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionModelClearStartupSeedRequest +internal sealed class WorkflowGetRunRequest { - /// Gets or sets the expectedModel value. - [JsonPropertyName("expectedModel")] - public string ExpectedModel { get; set; } = string.Empty; - - /// Provider captured with the startup seed; omission matches only an unqualified seed. - [JsonPropertyName("expectedProviderId")] - public string? ExpectedProviderId { get; set; } + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// The applied host allowlist and effective session model policy after intersection. +/// Declared or approved workflow resource ceilings. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelSetAllowedModelsResult +public sealed class WorkflowDeclaredLimits { - /// Normalized host allowlist. Omitted when the host restriction was cleared, or when a relay client does not return the host policy. - [JsonPropertyName("allowedModels")] - public IList? AllowedModels { get; set; } + /// Maximum AI credits consumed by subagents and descendants. + [JsonPropertyName("maxAiCredits")] + public double? MaxAiCredits { get; set; } - /// Effective exact IDs or repository policy patterns after applying the host restriction. Omitted by relay clients that do not return the host policy. - [JsonPropertyName("effectiveAllowedModels")] - public IList? EffectiveAllowedModels { get; set; } + /// Maximum concurrently active subagents. + [JsonPropertyName("maxConcurrentSubagents")] + public long? MaxConcurrentSubagents { get; set; } - /// Effective deterministic fallback model, when the policy defines one. - [JsonPropertyName("fallbackModel")] - public string? FallbackModel { get; set; } + /// Maximum total subagents spawned by the run. + [JsonPropertyName("maxTotalSubagents")] + public long? MaxTotalSubagents { get; set; } - /// Selected session model after reconciling a now-disallowed concrete selection. - [JsonPropertyName("modelId")] - public string? ModelId { get; set; } + /// Maximum accumulated active execution time in seconds. + [JsonPropertyName("timeoutSeconds")] + public double? TimeoutSeconds { get; set; } } -/// Host-supplied exact model selection IDs to allow for this running session. CAPI IDs are intersected with repository `.github/allowed_models.txt` policy; provider-qualified IDs remain exempt from repository-only policy but are restricted by this host list. Omit or pass null to clear the host restriction; an explicit empty or disjoint list is rejected. Validation and pre-selection fallback failures preserve the previous restriction. Failures after a fallback selection commits retain the new restriction and selected model; callers should inspect current session state after such an error. +/// Durable workflow resource consumption. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModelSetAllowedModelsRequest +public sealed class WorkflowRunConsumed { - /// Exact model IDs to permit, or null to clear the host restriction. - [JsonPropertyName("allowedModels")] - public IList? AllowedModels { get; set; } + /// Accumulated active execution time in milliseconds. + [JsonPropertyName("activeMs")] + public long ActiveMs { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// AI usage consumed by the run in nano-AIU. + [JsonPropertyName("nanoAiu")] + public long NanoAiu { get; set; } -/// Update the session's reasoning effort without changing the selected model. Use `switchTo` instead when you also need to change the model. The runtime stores the effort on the session and applies it to subsequent turns. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelSetReasoningEffortResult -{ - /// Reasoning effort level recorded on the session after the update. - [JsonPropertyName("reasoningEffort")] - public string ReasoningEffort { get; set; } = string.Empty; + /// Total subagents spawned by the run. + [JsonPropertyName("subagents")] + public long Subagents { get; set; } } -/// Reasoning effort level to apply to the currently selected model. +/// Current workflow phase identity. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModelSetReasoningEffortRequest +public sealed class WorkflowCurrentPhase { - /// Reasoning effort level to apply to the currently selected model. The host is responsible for validating the value against the model's supported levels before calling. - [JsonPropertyName("reasoningEffort")] - public string ReasoningEffort { get; set; } = string.Empty; + /// Current phase identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Zero-based declared phase ordinal, or null for an undeclared phase. + [JsonPropertyName("ordinal")] + public long? Ordinal { get; set; } } -/// Reasoning-summaries presentation policy for the session's current model. +/// Prompt-safe terminal workflow outcome. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelGetReasoningSummariesResult +public sealed class WorkflowRunTerminal { - /// Whether the supplied `persistedShowReasoning` setting only restates the model default. This reports a redundancy, not a standing instruction to delete the setting: it stays true for as long as the setting and the model default agree, including for a user who later chose that value deliberately. It exists for a one-time migration of a legacy setting written before the model default made it redundant, so a host that acts on it owns the cleanup and must gate it behind its own persisted `done` marker, delete only a setting whose value still matches the one it read, and never repeat the deletion on a later launch. Under an off-by-default reasoning-summaries experiment an explicit `showReasoning: true` opt-in also reads as redundant on a summary-producing model, so an ungated host would keep deleting that opt-in and hide summaries again on every launch. - [JsonPropertyName("clearRedundantSetting")] - public bool ClearRedundantSetting { get; set; } - - /// Whether the session's reasoning-summaries experiment assignment has settled. False means this read does not wait for a pending assignment and reports the experiment-derived fields conservatively: `showHiddenHint` is false and `visibility` falls back to `persistedShowReasoning`, or is omitted when none was supplied. A host that wants the assigned answer re-reads until this is true. - [JsonPropertyName("experimentSettled")] - public bool ExperimentSettled { get; set; } - - /// Whether the selected model shows reasoning summaries by default. - [JsonPropertyName("modelDefaultShowsSummaries")] - public bool ModelDefaultShowsSummaries { get; set; } - - /// False until the session has a model catalog and a selected model. This read never resolves the catalog itself, and the runtime emits no readiness notification, so repeating this call alone leaves `ready` false indefinitely on a session that has neither listed models nor run a turn. `session.model.list` is the prerequisite and the signal: it resolves and caches the catalog for the session, so a successful return means the next read is ready. The exception is a session that resolves models without a Copilot catalog, that is a BYOK registry or an alternate provider: `session.model.list` returns an empty list without caching a catalog, so `ready` stays false and this policy is unavailable there. While false, every model-policy field is false and `visibility` is omitted; `experimentSettled` is independent of readiness and still reports the assignment state. - [JsonPropertyName("ready")] - public bool Ready { get; set; } + /// Human-readable terminal error. + [JsonPropertyName("error")] + public string? Error { get; set; } - /// Whether turns on this session produce reasoning summaries, honouring an explicit session reasoning-summary override. - [JsonPropertyName("sessionShowsSummaries")] - public bool SessionShowsSummaries { get; set; } + /// Machine-readable terminal failure. + [JsonPropertyName("failure")] + public WorkflowRunFailure? Failure { get; set; } - /// Whether to show the hint that reasoning summaries are hidden. Always false while `experimentSettled` is false. - [JsonPropertyName("showHiddenHint")] - public bool ShowHiddenHint { get; set; } + /// Pause initiator metadata, or null when the run did not pause. + [JsonPropertyName("pauseInfo")] + public WorkflowPauseInfo? PauseInfo { get; set; } - /// Whether the selected model emits reasoning headers. - [JsonPropertyName("showReasoningHeaders")] - public bool ShowReasoningHeaders { get; set; } + /// Human-readable terminal reason. + [JsonPropertyName("reason")] + public string? Reason { get; set; } - /// Default reasoning visibility, and only meaningful once `ready` is true: false when the session produces no summaries, else the persisted setting, else the experiment's default. While `ready` is true it is omitted only when all three are unavailable, that is when the session produces summaries, no `persistedShowReasoning` was supplied, and `experimentSettled` is false. While `ready` is false there is no model policy to report and this field is always omitted, so an absent value alone does not imply a pending experiment. - [JsonPropertyName("visibility")] - public bool? Visibility { get; set; } + /// Prompt-safe preview of the completed result. + [JsonPropertyName("resultPreview")] + public string? ResultPreview { get; set; } } -/// Host presentation state the reasoning-summaries policy depends on. +/// Durable workflow run summary with read-time live overlays. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModelGetReasoningSummariesRequest +public sealed class WorkflowRunSummary { - /// The host's persisted `showReasoning` user setting, omitted when unset. - [JsonPropertyName("persistedShowReasoning")] - public bool? PersistedShowReasoning { get; set; } + /// Epoch milliseconds when the current active segment started, or null while inactive. + [JsonPropertyName("activeSegmentStartedAt")] + public long? ActiveSegmentStartedAt { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Approved effective resource ceilings, or null until approved. + [JsonPropertyName("approved")] + public WorkflowDeclaredLimits? Approved { get; set; } - /// Whether the host is currently showing reasoning summaries. Defaults to false. - [JsonPropertyName("summariesVisible")] - public bool? SummariesVisible { get; set; } -} + /// Whether the durable run state currently passes runtime resume eligibility checks. + [JsonPropertyName("canResume")] + public bool CanResume { get; set; } -/// Availability of a server-advertised routing preference. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AutoTierStatus -{ - /// Whether the provider permits selecting this preference. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// Epoch milliseconds when the run completed, or null while nonterminal. + [JsonPropertyName("completedAt")] + public long? CompletedAt { get; set; } - /// Human-readable explanation of availability. - [JsonPropertyName("message")] - public string? Message { get; set; } + /// Durable resource consumption. + [JsonPropertyName("consumed")] + public WorkflowRunConsumed Consumed { get => field ??= new(); set; } - /// Extensible machine-readable unavailability reason. - [JsonPropertyName("reason")] - public string? Reason { get; set; } -} + /// Epoch milliseconds when the run was created. + [JsonPropertyName("createdAt")] + public long CreatedAt { get; set; } -/// A server-advertised routing preference. Identifiers and execution types are extensible. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AutoTierDescriptor -{ - /// Description displayed beside the preference. + /// Current phase identity, or null before any phase is entered. + [JsonPropertyName("currentPhase")] + public WorkflowCurrentPhase? CurrentPhase { get; set; } + + /// Resource ceilings declared by the workflow. + [JsonPropertyName("declaredLimits")] + public WorkflowDeclaredLimits DeclaredLimits { get => field ??= new(); set; } + + /// Number of phases declared by the workflow. + [JsonPropertyName("declaredPhaseCount")] + public long DeclaredPhaseCount { get; set; } + + /// Human-readable workflow description. [JsonPropertyName("description")] public string Description { get; set; } = string.Empty; - /// Human-readable label, not a routing identifier. - [JsonPropertyName("displayName")] - public string DisplayName { get; set; } = string.Empty; + /// Number of direct workflow agents currently live. + [JsonPropertyName("liveAgentCount")] + public long LiveAgentCount { get; set; } - /// Opaque routing identifier transmitted unchanged to the provider. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Epoch milliseconds when this live-overlay snapshot was observed. + [JsonPropertyName("observedAt")] + public long ObservedAt { get; set; } - /// Current account-specific availability. - [JsonPropertyName("status")] - public AutoTierStatus Status { get => field ??= new(); set; } + /// Monotonic durable run revision. + [JsonPropertyName("revision")] + public long Revision { get; set; } - /// Execution kind; this client supports `auto` preferences on the Auto model. - [JsonPropertyName("type")] - public string Type { get; set; } = string.Empty; -} + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; -/// Account-bound discovery metadata for the virtual `auto` model. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AutoTierMetadata -{ - /// Provider-default preference, used only when no explicit preference exists. - [JsonPropertyName("defaultTier")] - public string DefaultTier { get; set; } = string.Empty; + /// Epoch milliseconds when execution first started, or null before start. + [JsonPropertyName("startedAt")] + public long? StartedAt { get; set; } - /// Provider that supplied this metadata, when the catalog is provider-attributed. - [JsonPropertyName("providerId")] - public string? ProviderId { get; set; } + /// Current workflow run status. + [JsonPropertyName("status")] + public WorkflowRunStatus Status { get; set; } - /// Routing preferences in the server's presentation order. - [JsonPropertyName("tiers")] - public IList Tiers { get => field ??= []; set; } + /// Terminal run outcome, or null while nonterminal. + [JsonPropertyName("terminal")] + public WorkflowRunTerminal? Terminal { get; set; } + + /// Total direct workflow agents spawned across all attempts. + [JsonPropertyName("totalSpawnedAgentCount")] + public long TotalSpawnedAgentCount { get; set; } + + /// Epoch milliseconds when the durable run was last updated. + [JsonPropertyName("updatedAt")] + public long UpdatedAt { get; set; } + + /// Registered workflow name. + [JsonPropertyName("workflowName")] + public string WorkflowName { get; set; } = string.Empty; } -/// Cost-category metadata for a CAPI model. +/// A page of workflow runs in durable creation order. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionModelPriceCategory +public sealed class WorkflowListRunsResult { - /// CAPI model identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Whether terminal runs newer than this page exist. + [JsonPropertyName("hasMoreNewer")] + public bool? HasMoreNewer { get; set; } - /// Cost category assigned to the model. - [JsonPropertyName("priceCategory")] - public ModelPickerPriceCategory PriceCategory { get; set; } + /// Newest terminal-run cursor in this page, or null when the terminal window is empty. + [JsonPropertyName("newestSeq")] + public long? NewestSeq { get; set; } + + /// Oldest terminal-run cursor in this page, or null when the terminal window is empty. + [JsonPropertyName("oldestSeq")] + public long? OldestSeq { get; set; } + + /// Number of terminal runs older than this page. + [JsonPropertyName("omittedOlder")] + public long? OmittedOlder { get; set; } + + /// Workflow run summaries in durable creation order. + [JsonPropertyName("runs")] + public IList Runs { get => field ??= []; set; } } -/// One model provider available to the session — the model analog of the account `ProviderDescriptor`. Opaque id/label/kind plus a stable ordering; central code never branches on kind. +/// Parameters for paging workflow runs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModelProviderDescriptor +internal sealed class WorkflowListRunsRequest { - /// Opaque, stable provider id, stamped onto every model this provider returns. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Exclusive forward cursor. + [JsonPropertyName("afterSeq")] + public long? AfterSeq { get; set; } - /// The neutral provider kind. - [JsonPropertyName("kind")] - public ModelProviderKind Kind { get; set; } + /// Exclusive backward cursor. + [JsonPropertyName("beforeSeq")] + public long? BeforeSeq { get; set; } - /// Human-readable menu label, owned by the runtime so every consumer renders identical text. - [JsonPropertyName("label")] - public string Label { get; set; } = string.Empty; + /// Maximum terminal runs to return. Defaults to 200 and is capped at 500. + [JsonPropertyName("limit")] + public int? Limit { get; set; } - /// Stable ordering key for presenting providers in a deterministic sequence. - [JsonPropertyName("ordering")] - public long Ordering { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// The list of models available to this session. +/// Prompt-safe durable identity and live status for a direct workflow agent. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionModelList +public sealed class WorkflowAgentSummary { - /// Ordered Auto routing preferences discovered for this session's account. - [JsonPropertyName("auto")] - public AutoTierMetadata? Auto { get; set; } + /// Accumulated active agent time in milliseconds. + [JsonPropertyName("activeMs")] + public long ActiveMs { get; set; } - /// Available models, ordered with the most preferred default first. Includes both Copilot (CAPI) models and any registry BYOK models; a BYOK model appears under its provider-qualified selection id (`provider/id`). - [JsonPropertyName("list")] - public IList List { get => field ??= []; set; } + /// Prompt-safe live activity text. + [JsonPropertyName("activity")] + public string? Activity { get; set; } - /// Cost categories for the full CAPI catalog, including picker-disabled models that Auto may select. Metadata only; entries absent from `list` are not manually selectable. - [JsonPropertyName("modelPriceCategories")] - public IList? ModelPriceCategories { get; set; } + /// Stable direct-agent identifier. + [JsonPropertyName("agentId")] + public string AgentId { get; set; } = string.Empty; - /// The model providers available to this session, in ordering order, resolved from the account roster; empty when no provider is entitled (logged out / seatless). Each model in `list` carries its own provider reference; this roster gives the deterministic provider sequence and lets a consumer group by provider without deriving ordering from the model list. Central code never branches on a provider kind. - [JsonPropertyName("providers")] - public IList? Providers { get; set; } + /// Registered agent type. + [JsonPropertyName("agentType")] + public string AgentType { get; set; } = string.Empty; - /// Per-quota snapshots returned alongside the model list, keyed by quota type. - [JsonPropertyName("quotaSnapshots")] - public IDictionary? QuotaSnapshots { get; set; } + /// Epoch milliseconds when the agent completed. + [JsonPropertyName("completedAt")] + public long? CompletedAt { get; set; } + + /// Friendly, non-unique name intended for display. + [JsonPropertyName("displayName")] + public string? DisplayName { get; set; } + + /// Friendly, non-unique name intended for display. + [JsonPropertyName("label")] + public string Label { get; set; } = string.Empty; + + /// Phase identifier active when the agent was launched, or null. + [JsonPropertyName("phaseId")] + public string? PhaseId { get; set; } + + /// Model requested when the agent was launched. + [JsonPropertyName("requestedModel")] + public string? RequestedModel { get; set; } + + /// Concrete model resolved for the agent. + [JsonPropertyName("resolvedModel")] + public string? ResolvedModel { get; set; } + + /// Owning workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; + + /// Epoch milliseconds when the agent started. + [JsonPropertyName("startedAt")] + public long? StartedAt { get; set; } + + /// Current durable or live agent status. + [JsonPropertyName("status")] + public string Status { get; set; } = string.Empty; + + /// Tool-call identifier that launched the agent. + [JsonPropertyName("toolCallId")] + public string ToolCallId { get; set; } = string.Empty; } -/// RPC data type for SessionModelList operations. +/// Durable lifecycle and timing for one workflow phase. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionModelListRequest +public sealed class WorkflowPhaseObservation { - /// If true, bypasses the per-session model list cache and re-fetches from CAPI. - [JsonPropertyName("skipCache")] - public bool? SkipCache { get; set; } + /// Completed active time accumulated by this phase in milliseconds. + [JsonPropertyName("accumulatedActiveMs")] + public long AccumulatedActiveMs { get; set; } + + /// Epoch milliseconds when this phase completed; for a skipped phase, the synthetic skip timestamp (equal to `startedAt`). + [JsonPropertyName("completedAt")] + public long? CompletedAt { get; set; } + + /// Current live active time for this phase in milliseconds. + [JsonPropertyName("currentActiveMs")] + public long CurrentActiveMs { get; set; } + + /// Optional human-readable phase detail. + [JsonPropertyName("detail")] + public string? Detail { get; set; } + + /// Number of times execution entered this phase. + [JsonPropertyName("entryCount")] + public long EntryCount { get; set; } + + /// Phase identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + /// Most recent run attempt that entered this phase, or `0` if the phase has never been entered. + [JsonPropertyName("lastEnteredRunAttempt")] + public long LastEnteredRunAttempt { get; set; } + + /// Direct agents in this phase that are currently live. + [JsonPropertyName("liveAgentCount")] + public long LiveAgentCount { get; set; } + + /// Zero-based declared phase ordinal, or null for an undeclared phase. + [JsonPropertyName("ordinal")] + public long? Ordinal { get; set; } + + /// Epoch milliseconds when this phase first started; for a skipped phase, the synthetic skip timestamp (equal to `completedAt`). + [JsonPropertyName("startedAt")] + public long? StartedAt { get; set; } + + /// Derived lifecycle state of the phase. + [JsonPropertyName("status")] + public WorkflowPhaseStatus Status { get; set; } + + /// Human-readable phase title. + [JsonPropertyName("title")] + public string Title { get; set; } = string.Empty; + + /// Total direct agents associated with this phase. + [JsonPropertyName("totalAgentCount")] + public long TotalAgentCount { get; set; } } -/// RPC data type for SessionModelListRequestWithSession operations. +/// One durable workflow progress record. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionModelListRequestWithSession +public sealed class WorkflowProgressLine { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Resume attempt that emitted this record. + [JsonPropertyName("attempt")] + public long Attempt { get; set; } - /// If true, bypasses the per-session model list cache and re-fetches from CAPI. - [JsonPropertyName("skipCache")] - public bool? SkipCache { get; set; } + /// Progress record kind. + [JsonPropertyName("kind")] + public WorkflowLogLineKind Kind { get; set; } + + /// Phase active when the record was emitted, or null before any phase. + [JsonPropertyName("phaseId")] + public string? PhaseId { get; set; } + + /// Epoch milliseconds when the record was persisted. + [JsonPropertyName("recordedAt")] + public long RecordedAt { get; set; } + + /// Global monotonic sequence number within the run. + [JsonPropertyName("seq")] + public long Seq { get; set; } + + /// Prompt-safe progress text. + [JsonPropertyName("text")] + public string Text { get; set; } = string.Empty; } -/// Identifies the target session. +/// A bidirectional page of workflow progress. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionModeGetRequest +public sealed class WorkflowProgressPage { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether progress records newer than this page exist. + [JsonPropertyName("hasMoreNewer")] + public bool HasMoreNewer { get; set; } + + /// Whether progress records older than this page exist. + [JsonPropertyName("hasMoreOlder")] + public bool HasMoreOlder { get; set; } + + /// Newest sequence number in this page, or null when empty. + [JsonPropertyName("newestSeq")] + public long? NewestSeq { get; set; } + + /// Oldest sequence number in this page, or null when empty. + [JsonPropertyName("oldestSeq")] + public long? OldestSeq { get; set; } + + /// Progress records in sequence order. + [JsonPropertyName("records")] + public IList Records { get => field ??= []; set; } + + /// Run revision reflected by this page. + [JsonPropertyName("revision")] + public long Revision { get; set; } } -/// Outcome of a session mode change, including any model switch it triggered and follow-up the host must perform. +/// Full workflow run observability detail. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ModeSetResult +public sealed class WorkflowRunDetail { - /// Whether the host should arm an interactive continuation after the mode change. - [JsonPropertyName("armInteractiveContinuation")] - public bool? ArmInteractiveContinuation { get; set; } + /// Epoch milliseconds when the current active segment started, or null while inactive. + [JsonPropertyName("activeSegmentStartedAt")] + public long? ActiveSegmentStartedAt { get; set; } - /// Compaction confirmation required before the mode change can complete. - [JsonPropertyName("confirmation")] - public ModelSwitchConfirmation? Confirmation { get; set; } + /// Durable identities and live statuses for direct workflow agents. + [JsonPropertyName("agents")] + public IList Agents { get => field ??= []; set; } - /// Whether the host must defer implementing the requested mode change. - [JsonPropertyName("deferImplementation")] - public bool? DeferImplementation { get; set; } + /// Approved effective resource ceilings, or null until approved. + [JsonPropertyName("approved")] + public WorkflowDeclaredLimits? Approved { get; set; } - /// Deprecation warnings associated with the model selected by the mode change. - [JsonPropertyName("deprecationWarnings")] - public IList? DeprecationWarnings { get; set; } + /// Whether the durable run state currently passes runtime resume eligibility checks. + [JsonPropertyName("canResume")] + public bool CanResume { get; set; } - /// User-facing outcome message for the model switch triggered by the mode change. - [JsonPropertyName("message")] - public string? Message { get; set; } + /// Epoch milliseconds when the run completed, or null while nonterminal. + [JsonPropertyName("completedAt")] + public long? CompletedAt { get; set; } - /// Whether the requested mode was applied to the session. False only when an 'expectedMode' precondition did not hold, in which case any model change reported alongside it was still applied. - [JsonPropertyName("modeApplied")] - public bool? ModeApplied { get; set; } + /// Durable resource consumption. + [JsonPropertyName("consumed")] + public WorkflowRunConsumed Consumed { get => field ??= new(); set; } - /// Whether applying the mode changed the active model. - [JsonPropertyName("modelChanged")] - public bool ModelChanged { get; set; } + /// Epoch milliseconds when the run was created. + [JsonPropertyName("createdAt")] + public long CreatedAt { get; set; } - /// Lifecycle status of the requested mode change. - [JsonPropertyName("status")] - public string Status { get; set; } = string.Empty; + /// Current phase identity, or null before any phase is entered. + [JsonPropertyName("currentPhase")] + public WorkflowCurrentPhase? CurrentPhase { get; set; } - /// User-facing warning produced while applying the mode change. - [JsonPropertyName("warning")] - public string? Warning { get; set; } -} + /// Resource ceilings declared by the workflow. + [JsonPropertyName("declaredLimits")] + public WorkflowDeclaredLimits DeclaredLimits { get => field ??= new(); set; } -/// Agent interaction mode to apply to the session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ModeSetRequest -{ - /// Explicit response to a model-switch compaction preflight. - [JsonPropertyName("compactionDecision")] - public string? CompactionDecision { get; set; } + /// Number of phases declared by the workflow. + [JsonPropertyName("declaredPhaseCount")] + public long DeclaredPhaseCount { get; set; } - /// Mode the session must currently be in for the change to apply. When set and the session is in a different mode the request is a no-op and reports status 'unchanged'. - [JsonPropertyName("expectedMode")] - public SessionMode? ExpectedMode { get; set; } + /// Human-readable workflow description. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// Session whose plan-mode base state should be inherited. - [JsonPropertyName("inheritPlanBaseFromSessionId")] - public string? InheritPlanBaseFromSessionId { get; set; } + /// Number of direct workflow agents currently live. + [JsonPropertyName("liveAgentCount")] + public long LiveAgentCount { get; set; } - /// The session mode the agent is operating in. - [JsonPropertyName("mode")] - public SessionMode Mode { get; set; } + /// Epoch milliseconds when this live-overlay snapshot was observed. + [JsonPropertyName("observedAt")] + public long ObservedAt { get; set; } - /// Whether the selected plan model should be persisted. - [JsonPropertyName("persistPlanSelection")] - public bool? PersistPlanSelection { get; set; } + /// Lifecycle and timing observations for each workflow phase. + [JsonPropertyName("phases")] + public IList Phases { get => field ??= []; set; } - /// Settings context used when persisting the selected plan model. - [JsonPropertyName("pickerSettingsContext")] - public ModelPickerSettingsContext? PickerSettingsContext { get; set; } + /// Bidirectional page of durable workflow progress. + [JsonPropertyName("progress")] + public WorkflowProgressPage Progress { get => field ??= new(); set; } - /// Context tier to use with the dedicated plan model. - [JsonPropertyName("planContextTier")] - public string? PlanContextTier { get; set; } + /// Monotonic durable run revision. + [JsonPropertyName("revision")] + public long Revision { get; set; } - /// Action to perform when leaving plan mode. - [JsonPropertyName("planExitAction")] - public string? PlanExitAction { get; set; } + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; - /// Dedicated model to use in plan mode, when configured. - [JsonPropertyName("planModel")] - public string? PlanModel { get; set; } + /// Epoch milliseconds when execution first started, or null before start. + [JsonPropertyName("startedAt")] + public long? StartedAt { get; set; } - /// Whether a dedicated plan model is configured. - [JsonPropertyName("planModelConfigured")] - public bool? PlanModelConfigured { get; set; } + /// Current workflow run status. + [JsonPropertyName("status")] + public WorkflowRunStatus Status { get; set; } - /// Provider owning planModel. Omit for legacy bare-model selection. - [JsonPropertyName("planModelProviderId")] - public string? PlanModelProviderId { get; set; } + /// Terminal run outcome, or null while nonterminal. + [JsonPropertyName("terminal")] + public WorkflowRunTerminal? Terminal { get; set; } - /// Reasoning effort to use with the dedicated plan model. - [JsonPropertyName("planReasoningEffort")] - public string? PlanReasoningEffort { get; set; } + /// Total direct workflow agents spawned across all attempts. + [JsonPropertyName("totalSpawnedAgentCount")] + public long TotalSpawnedAgentCount { get; set; } - /// Whether leaving plan mode should restore the session's previous model. - [JsonPropertyName("restorePlanModel")] - public bool? RestorePlanModel { get; set; } + /// Epoch milliseconds when the durable run was last updated. + [JsonPropertyName("updatedAt")] + public long UpdatedAt { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Registered workflow name. + [JsonPropertyName("workflowName")] + public string WorkflowName { get; set; } = string.Empty; } -/// The session's friendly name, or null when not yet set. +/// Parameters for paging workflow progress. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class NameGetResult +internal sealed class WorkflowGetRunProgressRequest { - /// The session name (user-set or auto-generated), or null if not yet set. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Exclusive forward cursor. + [JsonPropertyName("afterSeq")] + public long? AfterSeq { get; set; } + + /// Exclusive backward cursor. + [JsonPropertyName("beforeSeq")] + public long? BeforeSeq { get; set; } + + /// Maximum records to return. Defaults to 200 and is capped at 500. + [JsonPropertyName("limit")] + public int? Limit { get; set; } + + /// Optional phase identifier used to scope records and cursors. + [JsonPropertyName("phaseId")] + public string? PhaseId { get; set; } + + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Identifies the target session. +/// Parameters for cancelling a workflow run. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionNameGetRequest +internal sealed class WorkflowCancelRequest { + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// New friendly name to apply to the session. +/// Parameters for pausing a running workflow. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class NameSetRequest +internal sealed class WorkflowPauseRequest { - /// New session name (1–100 characters, trimmed of leading/trailing whitespace). - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [MaxLength(100)] - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the auto-generated summary was applied as the session's name. +/// RPC data type for SessionWorkflowPauseAtCheckpoint operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class NameSetAutoResult +internal sealed class SessionWorkflowPauseAtCheckpointResult { - /// Whether the auto-generated summary was persisted. False if the session already has a user-set name, the summary normalized to empty, or the session does not have a workspace. - [JsonPropertyName("applied")] - public bool Applied { get; set; } + /// Whether this execution attempt must pause or may continue. + [JsonPropertyName("action")] + public WorkflowPauseCheckpointAction Action { get; set; } } -/// Auto-generated session summary to apply as the session's name when no user-set name exists. +/// Parameters for an owned durable pause checkpoint. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class NameSetAutoRequest +internal sealed class WorkflowPauseCheckpointRequest { + /// Opaque token identifying the execution attempt that reached the checkpoint. + [JsonPropertyName("executionToken")] + public string ExecutionToken { get; set; } = string.Empty; + + /// Stable author-defined checkpoint key. + [JsonPropertyName("key")] + public string Key { get; set; } = string.Empty; + + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// Auto-generated session summary. Empty/whitespace-only values are ignored; values are trimmed before persisting. - [JsonPropertyName("summary")] - public string Summary { get; set; } = string.Empty; } -/// Existence, contents, and resolved path of the session plan file. +/// Acknowledgement that a workflow request was accepted. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PlanReadResult +public sealed class WorkflowAckResult { - /// The content of the plan file, or null if it does not exist. - [JsonPropertyName("content")] - public string? Content { get; set; } - - /// Whether the plan file exists in the workspace. - [JsonPropertyName("exists")] - public bool Exists { get; set; } - - /// Absolute file path of the plan file, or null if workspace is not enabled. - [JsonPropertyName("path")] - public string? Path { get; set; } } -/// Identifies the target session. +/// One ordered workflow progress line. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPlanReadRequest +public sealed class WorkflowLogLine { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Progress line kind. + [JsonPropertyName("kind")] + public WorkflowLogLineKind Kind { get; set; } + + /// Monotonic sequence number within the workflow run. + [JsonPropertyName("seq")] + public long Seq { get; set; } + + /// Progress text. + [JsonPropertyName("text")] + public string Text { get; set; } = string.Empty; } -/// Replacement contents to write to the session plan file. +/// Parameters for recording workflow progress. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PlanUpdateRequest +internal sealed class WorkflowLogRequest { - /// The new content for the plan file. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// Opaque token identifying the current workflow execution attempt. + [JsonPropertyName("executionToken")] + public string ExecutionToken { get; set; } = string.Empty; + + /// Ordered progress lines to append. + [JsonPropertyName("lines")] + public IList Lines { get => field ??= []; set; } + + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Identifies the target session. +/// Result of one workflow-scoped subagent call. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPlanDeleteRequest +public sealed class WorkflowAgentResult { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Agent result, omitted when the agent produced no result. + [JsonPropertyName("result")] + public JsonElement? Result { get; set; } } -/// A single todo row read from the session SQL `todos` table. All fields are optional because the SQL schema is best-effort and the agent may not have populated every column. +/// Options for one workflow-scoped subagent call. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PlanSqlTodosRow +public sealed class WorkflowAgentOptions { - /// Todo creation time, as stored by the session SQL schema's `datetime('now')` default: `YYYY-MM-DD HH:MM:SS` in UTC. Lets clients attribute todos to the work item that created them (e.g. scoping a goal's progress to the todos it produced) rather than to the whole session. - [JsonPropertyName("createdAt")] - public string? CreatedAt { get; set; } + /// Optional built-in or custom agent name whose definition configures the subagent. + [JsonPropertyName("agent")] + public string? Agent { get; set; } - /// Todo description. - [JsonPropertyName("description")] - public string? Description { get; set; } + /// Optional context tier override for the subagent. + [JsonPropertyName("contextTier")] + public ContextTier? ContextTier { get; set; } - /// Todo identifier. - [JsonPropertyName("id")] - public string? Id { get; set; } + /// Optional label distinguishing otherwise identical memoized agent calls. + [JsonPropertyName("label")] + public string? Label { get; set; } - /// Todo status. - [JsonPropertyName("status")] - public string? Status { get; set; } + /// Optional model identifier for the subagent. + [JsonPropertyName("model")] + public string? Model { get; set; } - /// Todo title. - [JsonPropertyName("title")] - public string? Title { get; set; } -} + /// Optional reasoning effort override for the subagent. + [JsonPropertyName("reasoningEffort")] + public string? ReasoningEffort { get; set; } -/// Todo rows read from the session SQL database. Empty when no session database is available. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PlanReadSqlTodosResult -{ - /// Rows from the session SQL todos table, ordered by creation time with insertion order used to break ties when available and id used for WITHOUT ROWID tables. - [JsonPropertyName("rows")] - public IList Rows { get => field ??= []; set; } + /// Optional JSON Schema for structured agent output. + [JsonPropertyName("schema")] + public JsonElement? Schema { get; set; } } -/// Identifies the target session. +/// Parameters for one workflow-scoped subagent call. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPlanReadSqlTodosRequest +internal sealed class WorkflowAgentRequest { + /// Opaque token identifying the current workflow execution attempt. + [JsonPropertyName("executionToken")] + public string ExecutionToken { get; set; } = string.Empty; + + /// Subagent execution options. + [JsonPropertyName("opts")] + public WorkflowAgentOptions Opts { get => field ??= new(); set; } + + /// Prompt to send to the subagent. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Workflow run identifier that owns the subagent. + [JsonPropertyName("workflowRunId")] + public string WorkflowRunId { get; set; } = string.Empty; } -/// A single dependency edge read from the session SQL `todo_deps` table, indicating that one todo must complete before another. +/// Result of reading a workflow journal entry. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PlanSqlTodoDependency +public sealed class WorkflowJournalGetResult { - /// ID of the todo it depends on. - [JsonPropertyName("dependsOn")] - public string DependsOn { get; set; } = string.Empty; + /// Whether the journal contained the requested key. + [JsonPropertyName("hit")] + public bool Hit { get; set; } - /// ID of the todo that has the dependency. - [JsonPropertyName("todoId")] - public string TodoId { get; set; } = string.Empty; + /// Cached JSON result. The hit field distinguishes a cached JSON null from a miss. + [JsonPropertyName("resultJson")] + public JsonElement? ResultJson { get; set; } } -/// Todo rows + dependency edges read from the session SQL database. +/// Parameters for reading a workflow journal entry. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PlanReadSqlTodosWithDependenciesResult +internal sealed class WorkflowJournalGetRequest { - /// Edges from the session SQL todo_deps table. Empty when no database, no todo_deps table, or the SELECT failed. Read independently from `rows`, so a broken todo_deps table does not affect the rows result and vice versa. - [JsonPropertyName("dependencies")] - public IList Dependencies { get => field ??= []; set; } + /// Opaque token identifying the current workflow execution attempt. + [JsonPropertyName("executionToken")] + public string ExecutionToken { get; set; } = string.Empty; - /// Rows from the session SQL todos table, ordered by creation time with insertion order used to break ties when available and id used for WITHOUT ROWID tables. Empty when no database, no todos table, or the SELECT failed. - [JsonPropertyName("rows")] - public IList Rows { get => field ??= []; set; } -} + /// Namespaced journal key. + [JsonPropertyName("key")] + public string Key { get; set; } = string.Empty; + + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPlanReadSqlTodosWithDependenciesRequest -{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// RPC data type for WorkspacesGetWorkspaceResultWorkspace operations. -public sealed class WorkspacesGetWorkspaceResultWorkspace +/// Parameters for storing a workflow journal entry. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class WorkflowJournalPutRequest { - /// Current Git branch. - [JsonPropertyName("branch")] - public string? Branch { get; set; } - - /// Whether the per-session Chronicle upgrade prompt was dismissed for the workspace. - [JsonPropertyName("chronicle_sync_dismissed")] - public bool? ChronicleSyncDismissed { get; set; } - - /// Name of the client that created the workspace. - [JsonPropertyName("client_name")] - public string? ClientName { get; set; } - - /// Timestamp when the workspace was created. - [JsonPropertyName("created_at")] - public DateTimeOffset? CreatedAt { get; set; } - - /// Current working directory associated with the workspace. - [JsonPropertyName("cwd")] - public string? Cwd { get; set; } - - /// Git repository root associated with the workspace. - [JsonPropertyName("git_root")] - public string? GitRoot { get; set; } - - /// Allowed values for the `WorkspacesWorkspaceDetailsHostType` enumeration. - [JsonPropertyName("host_type")] - public WorkspacesWorkspaceDetailsHostType? HostType { get; set; } - - /// Stable workspace identifier. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - - /// Most recent Mission Control event identifier observed for the workspace. - [JsonPropertyName("mc_last_event_id")] - public string? McLastEventId { get; set; } - - /// Mission Control session identifier associated with the workspace. - [JsonPropertyName("mc_session_id")] - public string? McSessionId { get; set; } - - /// Mission Control task identifier associated with the workspace. - [JsonPropertyName("mc_task_id")] - public string? McTaskId { get; set; } - - /// Workspace display name. - [JsonPropertyName("name")] - public string? Name { get; set; } - - /// Whether the workspace session can be steered remotely. - [JsonPropertyName("remote_steerable")] - public bool? RemoteSteerable { get; set; } - - /// Repository identifier associated with the workspace. - [JsonPropertyName("repository")] - public string? Repository { get; set; } - - /// Number of persisted summaries in the workspace. - [JsonPropertyName("summary_count")] - public long? SummaryCount { get; set; } - - /// Timestamp when the workspace was last updated. - [JsonPropertyName("updated_at")] - public DateTimeOffset? UpdatedAt { get; set; } + /// Opaque token identifying the current workflow execution attempt. + [JsonPropertyName("executionToken")] + public string ExecutionToken { get; set; } = string.Empty; - /// Whether the workspace name was explicitly chosen by the user. - [JsonPropertyName("user_named")] - public bool? UserNamed { get; set; } -} + /// Namespaced journal key. + [JsonPropertyName("key")] + public string Key { get; set; } = string.Empty; -/// Current workspace metadata for the session, including its absolute filesystem path when available. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesGetWorkspaceResult -{ - /// Absolute filesystem path to the workspace directory. Omitted when the session has no workspace (e.g. remote sessions). - [JsonPropertyName("path")] - public string? Path { get; set; } + /// JSON result to memoize. + [JsonPropertyName("resultJson")] + public JsonElement ResultJson { get; set; } - /// Current workspace metadata, or null if not available. - [JsonPropertyName("workspace")] - public WorkspacesGetWorkspaceResultWorkspace? Workspace { get; set; } -} + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionWorkspacesGetWorkspaceRequest -{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Workspace metadata fields to update. +/// The session's authoritative model snapshot. Auto preference fields are configuration for the virtual `auto` model and do not change the selected model identifier. The context tier reflects `Session.getContextTier()`, restored from the session journal on resume. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesUpdateMetadataRequest +public sealed class CurrentModel { - /// Opaque workspace context supplied by the session host. - [JsonPropertyName("context")] - public JsonElement? Context { get; set; } + /// Auto preference currently claimed by an in-progress activation. Null means the activation is returning to provider-default routing. + [JsonPropertyName("activatingAutoTier")] + public AutoTier? ActivatingAutoTier { get; set; } - /// Optional workspace display name override. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Auto preference currently committed for the session. This can remain available while another model is selected so a later switch to `auto` can reuse it. + [JsonPropertyName("autoTier")] + public AutoTier? AutoTier { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Context tier for models that support multiple context-window sizes. + [JsonPropertyName("contextTier")] + public ContextTier? ContextTier { get; set; } -/// Optional session context used when creating a local workspace. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesEnsureRequest -{ - /// Opaque workspace context supplied by the session host. - [JsonPropertyName("context")] - public JsonElement? Context { get; set; } + /// Currently active model identifier. + [JsonPropertyName("modelId")] + public string? ModelId { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Latest unclaimed Auto preference waiting for a future user turn. Null means the pending request is returning to provider-default routing. + [JsonPropertyName("pendingAutoTier")] + public AutoTier? PendingAutoTier { get; set; } -/// Relative paths of files stored in the session workspace files directory. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesListFilesResult -{ - /// Slash-separated relative file paths in the workspace files directory. - [JsonPropertyName("files")] - public IList Files { get => field ??= []; set; } + /// Captured base model to restore when leaving plan mode. Omitted outside plan mode or when no plan override has captured a base model. Persistent agent model requirements apply to this model rather than the temporary plan model. + [JsonPropertyName("planBaseModelId")] + public string? PlanBaseModelId { get; set; } + + /// Provider of planBaseModelId, when that saved selection is provider-qualified. + [JsonPropertyName("planBaseProviderId")] + public string? PlanBaseProviderId { get; set; } + + /// Provider selected for this model. Together with modelId, identifies a catalog entry even when providers serve the same model. Omitted for unattributed legacy selections. + [JsonPropertyName("providerId")] + public string? ProviderId { get; set; } + + /// Reasoning effort level currently applied to the active model, when one is set. Reads `Session.getReasoningEffort()` synchronously after `getSelectedModel()` resolves so the two values are reported as a snapshot. + [JsonPropertyName("reasoningEffort")] + public string? ReasoningEffort { get; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionWorkspacesListFilesRequest +internal sealed class SessionModelGetCurrentRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Contents of the requested workspace file as a UTF-8 string. +/// RPC data type for ModelSwitchConfirmation operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesReadFileResult +public sealed class ModelSwitchConfirmation { - /// File content as a UTF-8 string. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; -} + /// Current conversation token count before switching models. + [JsonPropertyName("currentTokens")] + public double CurrentTokens { get; set; } -/// Relative path of the workspace file to read. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesReadFileRequest -{ - /// Slash-separated relative path within the workspace files directory. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Target model token limit used by the compaction preflight. + [JsonPropertyName("targetLimit")] + public double TargetLimit { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Display name of the model that requires compaction confirmation. + [JsonPropertyName("targetModelDisplayName")] + public string TargetModelDisplayName { get; set; } = string.Empty; } -/// Relative path and UTF-8 content for the workspace file to create or overwrite. +/// The model identifier active on the session after the switch. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesCreateFileRequest +public sealed class ModelSwitchToResult { - /// File content to write as a UTF-8 string. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// Compaction confirmation projection when status is confirmation_required. + [JsonPropertyName("confirmation")] + public ModelSwitchConfirmation? Confirmation { get; set; } - /// Slash-separated relative path within the workspace files directory. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// True when the switch was deferred (enqueued as a cancellable `/model` command) because a turn was active or another model change was already queued, rather than applied immediately. When true, the session's live model is unchanged until the queued change drains. + [JsonPropertyName("deferred")] + public bool? Deferred { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Deprecation warnings associated with the selected model or options. + [JsonPropertyName("deprecationWarnings")] + public IList? DeprecationWarnings { get; set; } -/// Filesystem metadata for a path in the session workspace files directory. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesStatFileResult -{ - /// Creation time in Unix epoch milliseconds. - [JsonPropertyName("birthtimeMs")] - public double BirthtimeMs { get; set; } + /// User-facing outcome message for the model switch. + [JsonPropertyName("message")] + public string? Message { get; set; } - /// Whether the path identifies a directory. - [JsonPropertyName("isDirectory")] - public bool IsDirectory { get; set; } + /// Currently active model identifier after the switch. + [JsonPropertyName("modelId")] + public string? ModelId { get; set; } - /// Whether the path identifies a regular file. - [JsonPropertyName("isFile")] - public bool IsFile { get; set; } + /// Authoritative model and Auto preference state after an immediate switch. For deferred switches this remains the current state until the queued change drains. + [JsonPropertyName("modelState")] + public CurrentModel? ModelState { get; set; } - /// Last modification time in Unix epoch milliseconds. - [JsonPropertyName("mtimeMs")] - public double MtimeMs { get; set; } + /// Persistence failure encountered after applying the model switch. + [JsonPropertyName("persistenceError")] + public string? PersistenceError { get; set; } - /// Size in bytes. - [JsonPropertyName("size")] - public double Size { get; set; } -} + /// Stable queue item identifier when this request was enqueued. Remains present if the item drains before the response is returned. + [JsonPropertyName("queueId")] + public string? QueueId { get; set; } -/// Relative path of the workspace file or directory to inspect. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesStatFileRequest -{ - /// Slash-separated relative path within the workspace files directory. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Lifecycle result for the requested switch. + [JsonPropertyName("status")] + public string? Status { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// User-facing warning produced while applying the model switch. + [JsonPropertyName("warning")] + public string? Warning { get; set; } } -/// Directory to create within the session workspace files directory. +/// Filesystem and environment context used to resolve model-picker settings. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesCreateDirectoryRequest +public sealed class ModelPickerSettingsContext { - /// Slash-separated relative path within the workspace files directory. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Optional Copilot configuration directory containing persisted settings. + [JsonPropertyName("configDir")] + public string? ConfigDir { get; set; } - /// Whether to create missing parent directories. Defaults to false. - [JsonPropertyName("recursive")] - public bool? Recursive { get; set; } + /// Environment variables consulted while resolving model-picker settings. + [JsonPropertyName("environment")] + public IDictionary Environment { get => field ??= new Dictionary(); set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// User home directory used when resolving persisted settings. + [JsonPropertyName("homeDirectory")] + public string HomeDirectory { get; set; } = string.Empty; } -/// File or directory to remove from the session workspace files directory. +/// RPC data type for ModelPickerPersistence operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesRemovePathRequest +public sealed class ModelPickerPersistenceRequest { - /// Whether a missing path should be treated as success. Defaults to false. - [JsonPropertyName("force")] - public bool? Force { get; set; } - - /// Slash-separated relative path within the workspace files directory. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Whether context tier was explicitly selected and should be persisted. + [JsonPropertyName("contextTierExplicit")] + public bool? ContextTierExplicit { get; set; } - /// Whether to remove directory contents recursively. Defaults to false. - [JsonPropertyName("recursive")] - public bool? Recursive { get; set; } + /// Whether reasoning effort was explicitly selected and should be persisted. + [JsonPropertyName("reasoningEffortExplicit")] + public bool? ReasoningEffortExplicit { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Filesystem and environment context used to resolve settings persistence. + [JsonPropertyName("settingsContext")] + public ModelPickerSettingsContext SettingsContext { get => field ??= new(); set; } } -/// Source and destination paths for a rename within the session workspace files directory. +/// Target model identifier and optional reasoning effort, summary, capability overrides, and context tier. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesRenamePathRequest +public sealed class ModelSwitchToRequest { - /// Slash-separated destination path relative to the workspace files directory. - [JsonPropertyName("destination")] - public string Destination { get; set; } = string.Empty; + /// Optional Auto routing preference to stage atomically with selecting `auto`. Pass null to return to provider-default Auto routing. This field is rejected when `modelId` is not `auto`. + [JsonPropertyName("autoTier")] + public AutoTier? AutoTier { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Explicit response to a model-switch compaction preflight. Omit to request a confirmation projection when compaction is necessary. + [JsonPropertyName("compactionDecision")] + public string? CompactionDecision { get; set; } - /// Slash-separated source path relative to the workspace files directory. - [JsonPropertyName("source")] - public string Source { get; set; } = string.Empty; -} + /// Explicit context tier for the selected model. `"default"` / `"long_context"` apply the requested tier; omit this field to use normal model behavior with no explicit tier. + [JsonPropertyName("contextTier")] + public ContextTier? ContextTier { get; set; } -/// Workspace checkpoint metadata with assigned number, human-readable title, and checkpoint filename. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesCheckpoints -{ - /// Filename of the checkpoint within the workspace checkpoints directory. - [JsonPropertyName("filename")] - public string Filename { get; set; } = string.Empty; + /// When true, defer this switch (enqueue it) if another model change is already queued, even when no turn is active — so it drains last (FIFO) and wins over the already-queued change. Intended for genuine user-initiated model selections; internal restore/reapply switches omit it and apply immediately when no turn is active. When no other model change is queued this has no effect (a switch still applies immediately unless a turn is active). + [JsonPropertyName("deferIfModelChangeQueued")] + public bool? DeferIfModelChangeQueued { get; set; } - /// Checkpoint number assigned by the workspace manager. - [JsonPropertyName("number")] - public long Number { get; set; } + /// Override individual model capabilities resolved by the runtime. + [JsonPropertyName("modelCapabilities")] + public ModelCapabilitiesOverride? ModelCapabilities { get; set; } - /// Human-readable checkpoint title. - [JsonPropertyName("title")] - public string Title { get; set; } = string.Empty; -} + /// Settings scope used when persisting the selected model. + [JsonPropertyName("modelChangeScope")] + public string? ModelChangeScope { get; set; } -/// Workspace checkpoints in chronological order; empty when the workspace is not enabled. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesListCheckpointsResult -{ - /// Workspace checkpoints in chronological order. Empty when workspace is not enabled. - [JsonPropertyName("checkpoints")] - public IList Checkpoints { get => field ??= []; set; } -} + /// Model id to switch to, as returned by `list`. Include providerId to select an exact catalog entry when providers share the id. Without providerId, a bare id retains incumbent selection behavior; a registry-qualified id (`provider/id`, e.g. `acme/claude-sonnet`) targets a BYOK model. + [JsonPropertyName("modelId")] + public required string ModelId { get; set; } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionWorkspacesListCheckpointsRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Optional settings context and explicit-override flags used to persist a picker selection. + [JsonPropertyName("pickerPersistence")] + public ModelPickerPersistenceRequest? PickerPersistence { get; set; } -/// Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesReadCheckpointResult -{ - /// Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing. - [JsonPropertyName("content")] - public string? Content { get; set; } + /// Provider id from the selected list entry's provider reference. Selects this exact provider/model pair; an unavailable pair fails rather than using another provider. Omit for deterministic legacy bare-model selection. + [JsonPropertyName("providerId")] + public string? ProviderId { get; set; } + + /// Reasoning effort level to use for the model. CAPI values are model-defined and validated against the selected model; BYOK providers may define additional values. "none" disables reasoning. Pass null to clear any session effort override and fall back to the model's default. When omitted, the session's current effort is kept. + [JsonPropertyName("reasoningEffort")] + public string? ReasoningEffort { get; set; } + + /// Reasoning summary mode to request for supported model clients. + [JsonPropertyName("reasoningSummary")] + public ReasoningSummary? ReasoningSummary { get; set; } + + /// Optional repository settings scope to persist after the switch commits. + [JsonPropertyName("repoScope")] + public string? RepoScope { get; set; } + + /// Require the target to be currently available and enabled before applying the switch. + [JsonPropertyName("requireAvailable")] + public bool? RequireAvailable { get; set; } + + /// When true, evaluate context-window compaction policy before applying the switch. + [JsonPropertyName("runCompactionPreflight")] + public bool? RunCompactionPreflight { get; set; } + + /// Origin to record on the effective `session.model_change` event for trusted in-process calls. Transport SDK calls are always recorded as `sdk`, regardless of this value. + [JsonPropertyName("source")] + public ModelChangeSource? Source { get; set; } + + /// Output verbosity level to request for supported models. + [JsonPropertyName("verbosity")] + public Verbosity? Verbosity { get; set; } } -/// Checkpoint number to read. +/// Target model identifier and optional reasoning effort, summary, capability overrides, and context tier. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesReadCheckpointRequest +internal sealed class ModelSwitchToRequestWithSession { - /// Checkpoint number to read. - [JsonPropertyName("number")] - public long Number { get; set; } + /// Optional Auto routing preference to stage atomically with selecting `auto`. Pass null to return to provider-default Auto routing. This field is rejected when `modelId` is not `auto`. + [JsonPropertyName("autoTier")] + public AutoTier? AutoTier { get; set; } + + /// Explicit response to a model-switch compaction preflight. Omit to request a confirmation projection when compaction is necessary. + [JsonPropertyName("compactionDecision")] + public string? CompactionDecision { get; set; } + + /// Explicit context tier for the selected model. `"default"` / `"long_context"` apply the requested tier; omit this field to use normal model behavior with no explicit tier. + [JsonPropertyName("contextTier")] + public ContextTier? ContextTier { get; set; } + + /// When true, defer this switch (enqueue it) if another model change is already queued, even when no turn is active — so it drains last (FIFO) and wins over the already-queued change. Intended for genuine user-initiated model selections; internal restore/reapply switches omit it and apply immediately when no turn is active. When no other model change is queued this has no effect (a switch still applies immediately unless a turn is active). + [JsonPropertyName("deferIfModelChangeQueued")] + public bool? DeferIfModelChangeQueued { get; set; } + + /// Override individual model capabilities resolved by the runtime. + [JsonPropertyName("modelCapabilities")] + public ModelCapabilitiesOverride? ModelCapabilities { get; set; } + + /// Settings scope used when persisting the selected model. + [JsonPropertyName("modelChangeScope")] + public string? ModelChangeScope { get; set; } + + /// Model id to switch to, as returned by `list`. Include providerId to select an exact catalog entry when providers share the id. Without providerId, a bare id retains incumbent selection behavior; a registry-qualified id (`provider/id`, e.g. `acme/claude-sonnet`) targets a BYOK model. + [JsonPropertyName("modelId")] + public string ModelId { get; set; } = string.Empty; + + /// Optional settings context and explicit-override flags used to persist a picker selection. + [JsonPropertyName("pickerPersistence")] + public ModelPickerPersistenceRequest? PickerPersistence { get; set; } + + /// Provider id from the selected list entry's provider reference. Selects this exact provider/model pair; an unavailable pair fails rather than using another provider. Omit for deterministic legacy bare-model selection. + [JsonPropertyName("providerId")] + public string? ProviderId { get; set; } + + /// Reasoning effort level to use for the model. CAPI values are model-defined and validated against the selected model; BYOK providers may define additional values. "none" disables reasoning. Pass null to clear any session effort override and fall back to the model's default. When omitted, the session's current effort is kept. + [JsonPropertyName("reasoningEffort")] + public string? ReasoningEffort { get; set; } + + /// Reasoning summary mode to request for supported model clients. + [JsonPropertyName("reasoningSummary")] + public ReasoningSummary? ReasoningSummary { get; set; } + + /// Optional repository settings scope to persist after the switch commits. + [JsonPropertyName("repoScope")] + public string? RepoScope { get; set; } + + /// Require the target to be currently available and enabled before applying the switch. + [JsonPropertyName("requireAvailable")] + public bool? RequireAvailable { get; set; } + + /// When true, evaluate context-window compaction policy before applying the switch. + [JsonPropertyName("runCompactionPreflight")] + public bool? RunCompactionPreflight { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; -} -/// Metadata for the persisted summary. -public sealed class WorkspacesAddSummaryResultSummary -{ -} + /// Origin to record on the effective `session.model_change` event for trusted in-process calls. Transport SDK calls are always recorded as `sdk`, regardless of this value. + [JsonPropertyName("source")] + public ModelChangeSource? Source { get; set; } -/// Refreshed metadata for the containing workspace. -public sealed class WorkspacesAddSummaryResultWorkspace -{ + /// Output verbosity level to request for supported models. + [JsonPropertyName("verbosity")] + public Verbosity? Verbosity { get; set; } } -/// Persisted summary metadata and refreshed workspace metadata. +/// Immediate acknowledgement and Auto preference snapshot after a switch request. This result never implies that a pending preference committed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesAddSummaryResult +public sealed class ModelSwitchAutoTierResult { - /// Metadata for the persisted summary. - [JsonPropertyName("summary")] - public WorkspacesAddSummaryResultSummary? Summary { get; set; } + /// Auto preference currently claimed by an in-progress activation. Null means the activation is returning to provider-default routing. + [JsonPropertyName("activatingAutoTier")] + public AutoTier? ActivatingAutoTier { get; set; } - /// Refreshed metadata for the containing workspace. - [JsonPropertyName("workspace")] - public WorkspacesAddSummaryResultWorkspace? Workspace { get; set; } + /// Auto preference currently committed for the session. + [JsonPropertyName("effectiveAutoTier")] + public AutoTier? EffectiveAutoTier { get; set; } + + /// Latest unclaimed Auto preference waiting for a future user turn. + [JsonPropertyName("pendingAutoTier")] + public AutoTier? PendingAutoTier { get; set; } + + /// Immediate request status. `pending` means accepted but not committed. + [JsonPropertyName("status")] + public ModelSwitchAutoTierStatus Status { get; set; } + + /// Earlier unclaimed preference replaced by this request. This can be present with either status, including when selecting the effective preference cancels pending work. + [JsonPropertyName("supersededAutoTier")] + public AutoTier? SupersededAutoTier { get; set; } } -/// Compaction summary checkpoint to persist. +/// An Auto preference request for the session. This updates Auto configuration only; it does not change the selected model to `auto`. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesAddSummaryRequest +internal sealed class ModelSwitchAutoTierRequest { - /// Markdown summary content to persist. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// Auto preference to activate when a future user turn using the `auto` model safely mints a replacement model and token pair. Pass null to return to provider-default Auto routing. + [JsonPropertyName("autoTier")] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public AutoTier? AutoTier { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - /// Summary title shown in checkpoint listings. - [JsonPropertyName("title")] - public string Title { get; set; } = string.Empty; + /// Origin to record on the effective `session.model_change` event. Defaults to `sdk` when omitted. + [JsonPropertyName("source")] + public ModelChangeSource? Source { get; set; } } -/// Rollback point for local workspace summaries. +/// Managed, repository, and CLI model overrides to overlay onto the session at startup. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesTruncateSummariesRequest +internal sealed class ModelApplyStartupOverlayRequest { - /// Number of newest summaries to keep. - [JsonPropertyName("keepCount")] - public long KeepCount { get; set; } + /// Effective default Auto routing preference from user and managed settings. Applies only to fresh sessions and never replaces a per-session selection. + [JsonPropertyName("autoTier")] + public AutoTier? AutoTier { get; set; } + + /// Model explicitly selected by the CLI, when provided. + [JsonPropertyName("cliModel")] + public string? CliModel { get; set; } + + /// Whether the overlay is being applied while resuming a deferred session. + [JsonPropertyName("deferredResume")] + public bool? DeferredResume { get; set; } + + /// Model required by device-managed policy, when configured. + [JsonPropertyName("deviceManagedModel")] + public string? DeviceManagedModel { get; set; } + + /// Context tier paired with the effective organization-managed model. Applies only when that concrete managed model is selected; it is ignored for Auto and for CLI, resume, or user overrides. + [JsonPropertyName("managedContextTier")] + public string? ManagedContextTier { get; set; } + + /// Reasoning effort paired with the effective organization-managed model. Applies only when that concrete managed model is selected; it is ignored for Auto and for CLI, resume, or user overrides. + [JsonPropertyName("managedReasoningEffort")] + public string? ManagedReasoningEffort { get; set; } + + /// Startup default model from the enterprise policy helper, when configured. Weakest of the managed sources: it applies only when neither device nor server policy names a model, and an explicit user selection still wins. + [JsonPropertyName("policyHelperModel")] + public string? PolicyHelperModel { get; set; } + + /// Auto routing preference selected by repository settings, when configured. Applied only when the overlay selects the Auto model; beside a concrete model it stays dormant. + [JsonPropertyName("repoAutoTier")] + public string? RepoAutoTier { get; set; } + + /// Context tier selected by repository settings, when configured. + [JsonPropertyName("repoContextTier")] + public string? RepoContextTier { get; set; } + + /// Model selected by repository settings, when configured. + [JsonPropertyName("repoModel")] + public string? RepoModel { get; set; } + + /// Provider owning the repository-selected model. Omitted repository provider identity retains legacy bare-model behavior. + [JsonPropertyName("repoModelProviderId")] + public string? RepoModelProviderId { get; set; } + + /// Reasoning effort selected by repository settings, when configured. + [JsonPropertyName("repoReasoningEffort")] + public string? RepoReasoningEffort { get; set; } + + /// Model required by server-managed policy, when configured. + [JsonPropertyName("serverManagedModel")] + public string? ServerManagedModel { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Autopilot objective file content, or null when missing. +/// RPC data type for SessionModelClearStartupSeed operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesReadAutopilotObjectiveResult +internal sealed class SessionModelClearStartupSeedResult { - /// Autopilot objective file content, or null when missing. - [JsonPropertyName("content")] - public string? Content { get; set; } + /// Gets or sets the cleared value. + [JsonPropertyName("cleared")] + public bool Cleared { get; set; } } -/// Identifies the target session. +/// RPC data type for SessionModelClearStartupSeed operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionWorkspacesReadAutopilotObjectiveRequest +internal sealed class SessionModelClearStartupSeedRequest { + /// Gets or sets the expectedModel value. + [JsonPropertyName("expectedModel")] + public string ExpectedModel { get; set; } = string.Empty; + + /// Provider captured with the startup seed; omission matches only an unqualified seed. + [JsonPropertyName("expectedProviderId")] + public string? ExpectedProviderId { get; set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Result of writing the autopilot objective file. +/// The applied host allowlist and effective session model policy after intersection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesWriteAutopilotObjectiveResult +public sealed class ModelSetAllowedModelsResult { - /// Filesystem operation performed. - [JsonPropertyName("operation")] - public string Operation { get; set; } = string.Empty; + /// Normalized host allowlist. Omitted when the host restriction was cleared, or when a relay client does not return the host policy. + [JsonPropertyName("allowedModels")] + public IList? AllowedModels { get; set; } + + /// Effective exact IDs or repository policy patterns after applying the host restriction. Omitted by relay clients that do not return the host policy. + [JsonPropertyName("effectiveAllowedModels")] + public IList? EffectiveAllowedModels { get; set; } + + /// Effective deterministic fallback model, when the policy defines one. + [JsonPropertyName("fallbackModel")] + public string? FallbackModel { get; set; } + + /// Selected session model after reconciling a now-disallowed concrete selection. + [JsonPropertyName("modelId")] + public string? ModelId { get; set; } } -/// Autopilot objective file content to persist. +/// Host-supplied exact model selection IDs to allow for this running session. CAPI IDs are intersected with repository `.github/allowed_models.txt` policy; provider-qualified IDs remain exempt from repository-only policy but are restricted by this host list. Omit or pass null to clear the host restriction; an explicit empty or disjoint list is rejected. Validation and pre-selection fallback failures preserve the previous restriction. Failures after a fallback selection commits retain the new restriction and selected model; callers should inspect current session state after such an error. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesWriteAutopilotObjectiveRequest +internal sealed class ModelSetAllowedModelsRequest { - /// Autopilot objective file content. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// Exact model IDs to permit, or null to clear the host restriction. + [JsonPropertyName("allowedModels")] + public IList? AllowedModels { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Result of deleting the autopilot objective file. +/// Update the session's reasoning effort without changing the selected model. Use `switchTo` instead when you also need to change the model. The runtime stores the effort on the session and applies it to subsequent turns. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesDeleteAutopilotObjectiveResult +public sealed class ModelSetReasoningEffortResult { - /// True when a file was deleted. - [JsonPropertyName("deleted")] - public bool Deleted { get; set; } + /// Reasoning effort level recorded on the session after the update. + [JsonPropertyName("reasoningEffort")] + public string ReasoningEffort { get; set; } = string.Empty; } -/// Identifies the target session. +/// Reasoning effort level to apply to the currently selected model. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionWorkspacesDeleteAutopilotObjectiveRequest +internal sealed class ModelSetReasoningEffortRequest { + /// Reasoning effort level to apply to the currently selected model. The host is responsible for validating the value against the model's supported levels before calling. + [JsonPropertyName("reasoningEffort")] + public string ReasoningEffort { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Whether the autopilot objective file exists. +/// Reasoning-summaries presentation policy for the session's current model. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesAutopilotObjectiveExistsResult +public sealed class ModelGetReasoningSummariesResult { - /// True when the objective file exists. - [JsonPropertyName("exists")] - public bool Exists { get; set; } -} + /// Whether the supplied `persistedShowReasoning` setting only restates the model default. This reports a redundancy, not a standing instruction to delete the setting: it stays true for as long as the setting and the model default agree, including for a user who later chose that value deliberately. It exists for a one-time migration of a legacy setting written before the model default made it redundant, so a host that acts on it owns the cleanup and must gate it behind its own persisted `done` marker, delete only a setting whose value still matches the one it read, and never repeat the deletion on a later launch. Under an off-by-default reasoning-summaries experiment an explicit `showReasoning: true` opt-in also reads as redundant on a summary-producing model, so an ungated host would keep deleting that opt-in and hide summaries again on every launch. + [JsonPropertyName("clearRedundantSetting")] + public bool ClearRedundantSetting { get; set; } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionWorkspacesAutopilotObjectiveExistsRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Whether the session's reasoning-summaries experiment assignment has settled. False means this read does not wait for a pending assignment and reports the experiment-derived fields conservatively: `showHiddenHint` is false and `visibility` falls back to `persistedShowReasoning`, or is omitted when none was supplied. A host that wants the assigned answer re-reads until this is true. + [JsonPropertyName("experimentSettled")] + public bool ExperimentSettled { get; set; } -/// RPC data type for WorkspacesSaveLargePasteResultSaved operations. -public sealed class WorkspacesSaveLargePasteResultSaved -{ - /// Filename within the workspace files directory. - [JsonPropertyName("filename")] - public string Filename { get; set; } = string.Empty; + /// Whether the selected model shows reasoning summaries by default. + [JsonPropertyName("modelDefaultShowsSummaries")] + public bool ModelDefaultShowsSummaries { get; set; } - /// Absolute filesystem path to the saved paste file. - [JsonPropertyName("filePath")] - public string FilePath { get; set; } = string.Empty; + /// False until the session has a model catalog and a selected model. This read never resolves the catalog itself, and the runtime emits no readiness notification, so repeating this call alone leaves `ready` false indefinitely on a session that has neither listed models nor run a turn. `session.model.list` is the prerequisite and the signal: it resolves and caches the catalog for the session, so a successful return means the next read is ready. The exception is a session that resolves models without a Copilot catalog, that is a BYOK registry or an alternate provider: `session.model.list` returns an empty list without caching a catalog, so `ready` stays false and this policy is unavailable there. While false, every model-policy field is false and `visibility` is omitted; `experimentSettled` is independent of readiness and still reports the assignment state. + [JsonPropertyName("ready")] + public bool Ready { get; set; } - /// Size of the saved file in bytes. - [JsonPropertyName("sizeBytes")] - public long SizeBytes { get; set; } -} + /// Whether turns on this session produce reasoning summaries, honouring an explicit session reasoning-summary override. + [JsonPropertyName("sessionShowsSummaries")] + public bool SessionShowsSummaries { get; set; } -/// Descriptor for the saved paste file, or null when the workspace is unavailable. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesSaveLargePasteResult -{ - /// Saved-paste descriptor, or null when the workspace is unavailable (e.g. CCA runtime, non-infinite sessions, remote sessions). - [JsonPropertyName("saved")] - public WorkspacesSaveLargePasteResultSaved? Saved { get; set; } + /// Whether to show the hint that reasoning summaries are hidden. Always false while `experimentSettled` is false. + [JsonPropertyName("showHiddenHint")] + public bool ShowHiddenHint { get; set; } + + /// Whether the selected model emits reasoning headers. + [JsonPropertyName("showReasoningHeaders")] + public bool ShowReasoningHeaders { get; set; } + + /// Default reasoning visibility, and only meaningful once `ready` is true: false when the session produces no summaries, else the persisted setting, else the experiment's default. While `ready` is true it is omitted only when all three are unavailable, that is when the session produces summaries, no `persistedShowReasoning` was supplied, and `experimentSettled` is false. While `ready` is false there is no model policy to report and this field is always omitted, so an absent value alone does not imply a pending experiment. + [JsonPropertyName("visibility")] + public bool? Visibility { get; set; } } -/// Pasted content to save as a UTF-8 file in the session workspace. +/// Host presentation state the reasoning-summaries policy depends on. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesSaveLargePasteRequest +internal sealed class ModelGetReasoningSummariesRequest { - /// Pasted content to save as a UTF-8 file. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// The host's persisted `showReasoning` user setting, omitted when unset. + [JsonPropertyName("persistedShowReasoning")] + public bool? PersistedShowReasoning { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Whether the host is currently showing reasoning summaries. Defaults to false. + [JsonPropertyName("summariesVisible")] + public bool? SummariesVisible { get; set; } } -/// Complete text used to generate one session diff. These are display contents, with the same text decoding as the patch, not a file-restore contract. +/// Availability of a server-advertised routing preference. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspaceDiffContents +public sealed class AutoTierStatus { - /// Complete current text read when computing the diff. Omitted for a deleted file; an empty string represents an existing empty file. - [JsonPropertyName("after")] - public string? After { get; set; } + /// Whether the provider permits selecting this preference. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } - /// Complete text before the session first changed the file. Omitted when the file did not exist; an empty string represents an existing empty file. - [JsonPropertyName("before")] - public string? Before { get; set; } + /// Human-readable explanation of availability. + [JsonPropertyName("message")] + public string? Message { get; set; } + + /// Extensible machine-readable unavailability reason. + [JsonPropertyName("reason")] + public string? Reason { get; set; } } -/// A single changed file and its unified diff. +/// A server-advertised routing preference. Identifiers and execution types are extensible. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspaceDiffFileChange +public sealed class AutoTierDescriptor { - /// Type of change represented by this file diff. - [JsonPropertyName("changeType")] - public WorkspaceDiffFileChangeType ChangeType { get; set; } - - /// Full text used for this patch, only when includeContents was requested for session mode. Omitted for binary, oversized or unavailable contents, and for fallback results. Read isFallback and isTruncated before treating an absent value as a missing file. - [JsonPropertyName("contents")] - public WorkspaceDiffContents? Contents { get; set; } + /// Description displayed beside the preference. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// Unified diff content for the file. Empty when the diff was truncated. - [JsonPropertyName("diff")] - public string Diff { get; set; } = string.Empty; + /// Human-readable label, not a routing identifier. + [JsonPropertyName("displayName")] + public string DisplayName { get; set; } = string.Empty; - /// Whether the diff content was omitted because it exceeded the per-file size limit. - [JsonPropertyName("isTruncated")] - public bool? IsTruncated { get; set; } + /// Opaque routing identifier transmitted unchanged to the provider. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Original file path for renamed files. - [JsonPropertyName("oldPath")] - public string? OldPath { get; set; } + /// Current account-specific availability. + [JsonPropertyName("status")] + public AutoTierStatus Status { get => field ??= new(); set; } - /// Path to the changed file, relative to the workspace root when the file lives under it. A file changed outside the workspace root keeps a `../`-relative path, or an absolute path when no relative path exists (for example a different Windows drive). - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Execution kind; this client supports `auto` preferences on the Auto model. + [JsonPropertyName("type")] + public string Type { get; set; } = string.Empty; } -/// Workspace diff result for the requested mode. +/// Account-bound discovery metadata for the virtual `auto` model. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspaceDiffResult +public sealed class AutoTierMetadata { - /// Default branch used for a branch diff, when branch mode was requested. - [JsonPropertyName("baseBranch")] - public string? BaseBranch { get; set; } - - /// Changed files and their unified diffs. - [JsonPropertyName("changes")] - public IList Changes { get => field ??= []; set; } - - /// Whether the requested diff fell back to unstaged changes, either because branch diff failed or session diff was unavailable. - [JsonPropertyName("isFallback")] - public bool IsFallback { get; set; } - - /// Effective mode used for the returned changes. - [JsonPropertyName("mode")] - public WorkspaceDiffMode Mode { get; set; } + /// Provider-default preference, used only when no explicit preference exists. + [JsonPropertyName("defaultTier")] + public string DefaultTier { get; set; } = string.Empty; - /// Diff mode requested by the client. - [JsonPropertyName("requestedMode")] - public WorkspaceDiffMode RequestedMode { get; set; } + /// Provider that supplied this metadata, when the catalog is provider-attributed. + [JsonPropertyName("providerId")] + public string? ProviderId { get; set; } - /// Why the session diff could not be produced, when applicable. Set only when `session` mode was requested and `isFallback` is true, so a client can tell the permanent `file-change-tracking-disabled` apart from the transient `session-busy`, which the same request answers once the session settles. Never set for `unstaged` or `branch` mode, and never `unsupported-remote-session`: a remote session's captures live on its own host, so a `session`-mode diff is rejected for one rather than answered with a controller-side fallback. - [JsonPropertyName("unavailableReason")] - public HistoryRewindUnavailableReason? UnavailableReason { get; set; } + /// Routing preferences in the server's presentation order. + [JsonPropertyName("tiers")] + public IList Tiers { get => field ??= []; set; } } -/// Parameters for computing a workspace diff. +/// Cost-category metadata for a CAPI model. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkspacesDiffRequest +public sealed class SessionModelPriceCategory { - /// When true, ignore whitespace-only changes (git `--ignore-all-space`). Defaults to false. - [JsonPropertyName("ignoreWhitespace")] - public bool? IgnoreWhitespace { get; set; } - - /// Include the full before/after text used to compute each session diff. Defaults to false; true is accepted only for session mode. Existing capture/read limits still apply, and binary or unavailable contents are not returned. This can substantially increase response size. - [JsonPropertyName("includeContents")] - public bool? IncludeContents { get; set; } + /// CAPI model identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Diff mode requested by the client. - [JsonPropertyName("mode")] - public required WorkspaceDiffMode Mode { get; set; } + /// Cost category assigned to the model. + [JsonPropertyName("priceCategory")] + public ModelPickerPriceCategory PriceCategory { get; set; } } -/// Parameters for computing a workspace diff. +/// One model provider available to the session — the model analog of the account `ProviderDescriptor`. Opaque id/label/kind plus a stable ordering; central code never branches on kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class WorkspacesDiffRequestWithSession +public sealed class ModelProviderDescriptor { - /// When true, ignore whitespace-only changes (git `--ignore-all-space`). Defaults to false. - [JsonPropertyName("ignoreWhitespace")] - public bool? IgnoreWhitespace { get; set; } + /// Opaque, stable provider id, stamped onto every model this provider returns. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Include the full before/after text used to compute each session diff. Defaults to false; true is accepted only for session mode. Existing capture/read limits still apply, and binary or unavailable contents are not returned. This can substantially increase response size. - [JsonPropertyName("includeContents")] - public bool? IncludeContents { get; set; } - - /// Diff mode requested by the client. - [JsonPropertyName("mode")] - public WorkspaceDiffMode Mode { get; set; } - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} - -/// Current per-window credit limit and consumption for an autopilot objective. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AutopilotObjectiveCreditLimit -{ - /// Configured AI-credit cap, when one is set. - [JsonPropertyName("credits")] - public double? Credits { get; set; } + /// The neutral provider kind. + [JsonPropertyName("kind")] + public ModelProviderKind Kind { get; set; } - /// Window consumption in fractional AI credits, for display. - [JsonPropertyName("creditsUsed")] - public double CreditsUsed { get; set; } + /// Human-readable menu label, owned by the runtime so every consumer renders identical text. + [JsonPropertyName("label")] + public string Label { get; set; } = string.Empty; - /// Exact window consumption in non-negative integer nano-AIU, encoded as a decimal string. - [RegularExpression("^[0-9]+$")] - [JsonPropertyName("creditsUsedNanoAiu")] - public string CreditsUsedNanoAiu { get; set; } = string.Empty; + /// Stable ordering key for presenting providers in a deterministic sequence. + [JsonPropertyName("ordering")] + public long Ordering { get; set; } } -/// Public, persistence-independent projection of an autopilot objective. +/// The list of models available to this session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AutopilotObjectiveState +public sealed class SessionModelList { - /// Optional summary recorded when the objective completed. - [JsonPropertyName("completionSummary")] - public string? CompletionSummary { get; set; } - - /// Exact lifetime AI-credit consumption in non-negative integer nano-AIU, encoded as a decimal string. - [RegularExpression("^[0-9]+$")] - [JsonPropertyName("creditCountNanoAiu")] - public string CreditCountNanoAiu { get; set; } = string.Empty; - - /// Current per-window consumption and optional cap, when a credit-tracking window is present. - [JsonPropertyName("creditLimit")] - public AutopilotObjectiveCreditLimit? CreditLimit { get; set; } - - /// Session-local objective identifier. - [JsonPropertyName("id")] - public long Id { get; set; } + /// Ordered Auto routing preferences discovered for this session's account. + [JsonPropertyName("auto")] + public AutoTierMetadata? Auto { get; set; } - /// User-provided objective text. - [JsonPropertyName("objective")] - public string Objective { get; set; } = string.Empty; + /// Available models, ordered with the most preferred default first. Includes both Copilot (CAPI) models and any registry BYOK models; a BYOK model appears under its provider-qualified selection id (`provider/id`). + [JsonPropertyName("list")] + public IList List { get => field ??= []; set; } - /// Optional reason the objective is paused. - [JsonPropertyName("pauseReason")] - public string? PauseReason { get; set; } + /// Cost categories for the full CAPI catalog, including picker-disabled models that Auto may select. Metadata only; entries absent from `list` are not manually selectable. + [JsonPropertyName("modelPriceCategories")] + public IList? ModelPriceCategories { get; set; } - /// Current normalized lifecycle status. - [JsonPropertyName("status")] - public AutopilotObjectiveStatus Status { get; set; } + /// The model providers available to this session, in ordering order, resolved from the account roster; empty when no provider is entitled (logged out / seatless). Each model in `list` carries its own provider reference; this roster gives the deterministic provider sequence and lets a consumer group by provider without deriving ordering from the model list. Central code never branches on a provider kind. + [JsonPropertyName("providers")] + public IList? Providers { get; set; } - /// Number of objective turns started. - [JsonPropertyName("turnCount")] - public long TurnCount { get; set; } + /// Per-quota snapshots returned alongside the model list, keyed by quota type. + [JsonPropertyName("quotaSnapshots")] + public IDictionary? QuotaSnapshots { get; set; } } -/// Canonical runtime state for the session's current autopilot objective. +/// RPC data type for SessionModelList operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AutopilotObjectiveGetStateResult +public sealed class SessionModelListRequest { - /// Current objective state, or `null` when the session has no objective. - [JsonPropertyName("state")] - public AutopilotObjectiveState? State { get; set; } + /// If true, bypasses the per-session model list cache and re-fetches from CAPI. + [JsonPropertyName("skipCache")] + public bool? SkipCache { get; set; } } -/// Identifies the target session. +/// RPC data type for SessionModelListRequestWithSession operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionAutopilotObjectiveGetStateRequest +internal sealed class SessionModelListRequestWithSession { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; -} -/// Characters that, when typed in the composer, should trigger a `completions.request`. Empty when the session has no host-driven completions (e.g. local sessions, or a relay host that does not advertise `completionTriggerCharacters`). -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CompletionsGetTriggerCharactersResult -{ - /// Trigger characters advertised by the host (e.g. `["@", "#"]`). Empty disables host-driven completions for the session. - [JsonPropertyName("triggerCharacters")] - public IList TriggerCharacters { get => field ??= []; set; } + /// If true, bypasses the per-session model list cache and re-fetches from CAPI. + [JsonPropertyName("skipCache")] + public bool? SkipCache { get; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionCompletionsGetTriggerCharactersRequest +internal sealed class SessionModeGetRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// A single host-driven completion. Accepting an item replaces `[rangeStart, rangeEnd)` (UTF-16 code units) in the composer with `insertText`; when the range is absent, the active token around the cursor is replaced. +/// Outcome of a session mode change, including any model switch it triggered and follow-up the host must perform. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionCompletionItem +public sealed class ModeSetResult { - /// Text spliced into the composer when the item is accepted. - [JsonPropertyName("insertText")] - public string InsertText { get; set; } = string.Empty; + /// Whether the host should arm an interactive continuation after the mode change. + [JsonPropertyName("armInteractiveContinuation")] + public bool? ArmInteractiveContinuation { get; set; } - /// Render-kind hint for the picker row (e.g. `"document"`, `"directory"`), derived from the host's display kind. - [JsonPropertyName("kind")] - public string? Kind { get; set; } + /// Compaction confirmation required before the mode change can complete. + [JsonPropertyName("confirmation")] + public ModelSwitchConfirmation? Confirmation { get; set; } - /// Primary display label for the picker row. Falls back to `insertText` when absent. - [JsonPropertyName("label")] - public string? Label { get; set; } + /// Whether the host must defer implementing the requested mode change. + [JsonPropertyName("deferImplementation")] + public bool? DeferImplementation { get; set; } - /// End (exclusive) of the replacement range in `text`, in UTF-16 code units. - [JsonPropertyName("rangeEnd")] - public long? RangeEnd { get; set; } + /// Deprecation warnings associated with the model selected by the mode change. + [JsonPropertyName("deprecationWarnings")] + public IList? DeprecationWarnings { get; set; } - /// Start of the replacement range in `text`, in UTF-16 code units. - [JsonPropertyName("rangeStart")] - public long? RangeStart { get; set; } -} + /// User-facing outcome message for the model switch triggered by the mode change. + [JsonPropertyName("message")] + public string? Message { get; set; } -/// Host-driven completion items for the current composer input. Empty when the host returns no items or does not support completions. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CompletionsRequestResult -{ - /// Completion items in host-ranked order. - [JsonPropertyName("items")] - public IList Items { get => field ??= []; set; } + /// Whether the requested mode was applied to the session. False only when an 'expectedMode' precondition did not hold, in which case any model change reported alongside it was still applied. + [JsonPropertyName("modeApplied")] + public bool? ModeApplied { get; set; } + + /// Whether applying the mode changed the active model. + [JsonPropertyName("modelChanged")] + public bool ModelChanged { get; set; } + + /// Lifecycle status of the requested mode change. + [JsonPropertyName("status")] + public string Status { get; set; } = string.Empty; + + /// User-facing warning produced while applying the mode change. + [JsonPropertyName("warning")] + public string? Warning { get; set; } } -/// Request host-driven completions for the current composer input. +/// Agent interaction mode to apply to the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CompletionsRequestRequest +internal sealed class ModeSetRequest { - /// Cursor offset within `text`, in UTF-16 code units. - [JsonPropertyName("offset")] - public long Offset { get; set; } + /// Explicit response to a model-switch compaction preflight. + [JsonPropertyName("compactionDecision")] + public string? CompactionDecision { get; set; } + + /// Mode the session must currently be in for the change to apply. When set and the session is in a different mode the request is a no-op and reports status 'unchanged'. + [JsonPropertyName("expectedMode")] + public SessionMode? ExpectedMode { get; set; } + + /// Session whose plan-mode base state should be inherited. + [JsonPropertyName("inheritPlanBaseFromSessionId")] + public string? InheritPlanBaseFromSessionId { get; set; } + + /// The session mode the agent is operating in. + [JsonPropertyName("mode")] + public SessionMode Mode { get; set; } + + /// Whether the selected plan model should be persisted. + [JsonPropertyName("persistPlanSelection")] + public bool? PersistPlanSelection { get; set; } + + /// Settings context used when persisting the selected plan model. + [JsonPropertyName("pickerSettingsContext")] + public ModelPickerSettingsContext? PickerSettingsContext { get; set; } + + /// Context tier to use with the dedicated plan model. + [JsonPropertyName("planContextTier")] + public string? PlanContextTier { get; set; } + + /// Action to perform when leaving plan mode. + [JsonPropertyName("planExitAction")] + public string? PlanExitAction { get; set; } + + /// Dedicated model to use in plan mode, when configured. + [JsonPropertyName("planModel")] + public string? PlanModel { get; set; } + + /// Whether a dedicated plan model is configured. + [JsonPropertyName("planModelConfigured")] + public bool? PlanModelConfigured { get; set; } + + /// Provider owning planModel. Omit for legacy bare-model selection. + [JsonPropertyName("planModelProviderId")] + public string? PlanModelProviderId { get; set; } + + /// Reasoning effort to use with the dedicated plan model. + [JsonPropertyName("planReasoningEffort")] + public string? PlanReasoningEffort { get; set; } + + /// Whether leaving plan mode should restore the session's previous model. + [JsonPropertyName("restorePlanModel")] + public bool? RestorePlanModel { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// The full composed composer input. - [JsonPropertyName("text")] - public string Text { get; set; } = string.Empty; } -/// Instruction sources loaded for the session, in merge order. +/// The session's friendly name, or null when not yet set. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class InstructionsGetSourcesResult +public sealed class NameGetResult { - /// Instruction sources for the session. - [JsonPropertyName("sources")] - public IList Sources { get => field ??= []; set; } + /// The session name (user-set or auto-generated), or null if not yet set. + [JsonPropertyName("name")] + public string? Name { get; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionInstructionsGetSourcesRequest +internal sealed class SessionNameGetRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Identifies the target session. +/// New friendly name to apply to the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionInstructionsReloadRequest +internal sealed class NameSetRequest { + /// New session name (1–100 characters, trimmed of leading/trailing whitespace). + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(100)] + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Result of one customization reload component. +/// Indicates whether the auto-generated summary was applied as the session's name. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CustomizationReloadOutcome +public sealed class NameSetAutoResult { - /// Reason for a skipped component or description of a failure, when available. - [JsonPropertyName("detail")] - public string? Detail { get; set; } + /// Whether the auto-generated summary was persisted. False if the session already has a user-set name, the summary normalized to empty, or the session does not have a workspace. + [JsonPropertyName("applied")] + public bool Applied { get; set; } +} - /// Whether the component reloaded, was skipped, or failed. - [JsonPropertyName("status")] - public CustomizationReloadStatus Status { get; set; } +/// Auto-generated session summary to apply as the session's name when no user-set name exists. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class NameSetAutoRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// Component whose reload was attempted or skipped. - [JsonPropertyName("subsystem")] - public CustomizationReloadSubsystem Subsystem { get; set; } + /// Auto-generated session summary. Empty/whitespace-only values are ignored; values are trimmed before persisting. + [JsonPropertyName("summary")] + public string Summary { get; set; } = string.Empty; } -/// Results of reloading discovered session customizations. Inspect outcomes for reloaded, skipped, or failed subsystems; a rejection may follow partial mutation. Changes to the model-facing prompt and tools apply on the next turn. +/// Existence, contents, and resolved path of the session plan file. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CustomizationsReloadResult +public sealed class PlanReadResult { - /// Errors from any component that could not be refreshed. - [JsonPropertyName("errors")] - public IList Errors { get => field ??= []; set; } + /// The content of the plan file, or null if it does not exist. + [JsonPropertyName("content")] + public string? Content { get; set; } - /// Outcome of each component in reload order; a skipped component was not configured or loaded. - [JsonPropertyName("outcomes")] - public IList Outcomes { get => field ??= []; set; } + /// Whether the plan file exists in the workspace. + [JsonPropertyName("exists")] + public bool Exists { get; set; } - /// Warnings from skill discovery. - [JsonPropertyName("warnings")] - public IList Warnings { get => field ??= []; set; } + /// Absolute file path of the plan file, or null if workspace is not enabled. + [JsonPropertyName("path")] + public string? Path { get; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionCustomizationsReloadRequest +internal sealed class SessionPlanReadRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether fleet mode was successfully activated. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class FleetStartResult -{ - /// Whether fleet mode was successfully activated. - [JsonPropertyName("started")] - public bool Started { get; set; } -} - -/// Parameters for starting fleet orchestration: an optional user prompt combined with the fleet instructions, plus the send options forwarded to the resulting turn. +/// Replacement contents to write to the session plan file. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class FleetStartRequest +internal sealed class PlanUpdateRequest { - /// Optional attachments (files, directories, selections, blobs, GitHub references) to include with the fleet request. - [JsonPropertyName("attachments")] - public IList? Attachments { get; set; } - - /// If false, this request will not trigger a Premium Request Unit charge. User requests default to billable. - [JsonInclude] - [JsonPropertyName("billable")] - internal bool? Billable { get; set; } - - /// Optional user prompt to combine with fleet instructions. - [JsonPropertyName("prompt")] - public string? Prompt { get; set; } + /// The new content for the plan file. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// If true, await completion of the agentic loop for this fleet request before returning. Defaults to false. - [JsonPropertyName("wait")] - public bool? Wait { get; set; } -} - -/// Agents available to the session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AgentList -{ - /// Available agents. - [JsonPropertyName("agents")] - public IList Agents { get => field ??= []; set; } -} - -/// RPC data type for SessionAgentList operations. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionAgentListRequest -{ - /// When true, request the session's configured built-in agents alongside custom agents. Listing applies feature, context, inclusion, exclusion, and user-disabled-agent policy, but does not evaluate transient invocation requirements such as model availability. Built-in metadata may be omitted when the session cannot project it, such as a relay session. - [JsonPropertyName("includeBuiltInAgents")] - public bool? IncludeBuiltInAgents { get; set; } - - /// When true, request authored base prompt text on each AgentInfo. Prompt text may be omitted when unavailable, such as for agents projected through a relay session. - [JsonPropertyName("includePrompt")] - public bool? IncludePrompt { get; set; } } -/// RPC data type for SessionAgentListRequestWithSession operations. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionAgentListRequestWithSession +internal sealed class SessionPlanDeleteRequest { - /// When true, request the session's configured built-in agents alongside custom agents. Listing applies feature, context, inclusion, exclusion, and user-disabled-agent policy, but does not evaluate transient invocation requirements such as model availability. Built-in metadata may be omitted when the session cannot project it, such as a relay session. - [JsonPropertyName("includeBuiltInAgents")] - public bool? IncludeBuiltInAgents { get; set; } - - /// When true, request authored base prompt text on each AgentInfo. Prompt text may be omitted when unavailable, such as for agents projected through a relay session. - [JsonPropertyName("includePrompt")] - public bool? IncludePrompt { get; set; } - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// An in-memory authored prompt override for an available agent. +/// A single todo row read from the session SQL `todos` table. All fields are optional because the SQL schema is best-effort and the agent may not have populated every column. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AgentSetPromptRequest +public sealed class PlanSqlTodosRow { - /// Stable effective agent id. Plugin namespace separators are normalized. + /// Todo creation time, as stored by the session SQL schema's `datetime('now')` default: `YYYY-MM-DD HH:MM:SS` in UTC. Lets clients attribute todos to the work item that created them (e.g. scoping a goal's progress to the todos it produced) rather than to the whole session. + [JsonPropertyName("createdAt")] + public string? CreatedAt { get; set; } + + /// Todo description. + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Todo identifier. [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + public string? Id { get; set; } - /// Replacement authored prompt. Empty text is valid. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; + /// Todo status. + [JsonPropertyName("status")] + public string? Status { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Todo title. + [JsonPropertyName("title")] + public string? Title { get; set; } } -/// The currently selected custom agent, or null when using the default agent. +/// Todo rows read from the session SQL database. Empty when no session database is available. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AgentGetCurrentResult +public sealed class PlanReadSqlTodosResult { - /// Currently selected custom agent, or null if using the default agent. - [JsonPropertyName("agent")] - public AgentInfo? Agent { get; set; } + /// Rows from the session SQL todos table, ordered by creation time with insertion order used to break ties when available and id used for WITHOUT ROWID tables. + [JsonPropertyName("rows")] + public IList Rows { get => field ??= []; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionAgentGetCurrentRequest +internal sealed class SessionPlanReadSqlTodosRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// The newly selected custom agent. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AgentSelectResult -{ - /// The newly selected custom agent. - [JsonPropertyName("agent")] - public AgentInfo Agent { get => field ??= new(); set; } -} - -/// Name of the custom agent to select for subsequent turns. +/// A single dependency edge read from the session SQL `todo_deps` table, indicating that one todo must complete before another. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class AgentSelectRequest +public sealed class PlanSqlTodoDependency { - /// Name of the custom agent to select. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// ID of the todo it depends on. + [JsonPropertyName("dependsOn")] + public string DependsOn { get; set; } = string.Empty; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// ID of the todo that has the dependency. + [JsonPropertyName("todoId")] + public string TodoId { get; set; } = string.Empty; } -/// Identifies the target session. +/// Todo rows + dependency edges read from the session SQL database. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionAgentDeselectRequest +public sealed class PlanReadSqlTodosWithDependenciesResult { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Edges from the session SQL todo_deps table. Empty when no database, no todo_deps table, or the SELECT failed. Read independently from `rows`, so a broken todo_deps table does not affect the rows result and vice versa. + [JsonPropertyName("dependencies")] + public IList Dependencies { get => field ??= []; set; } -/// Custom agents available to the session after reloading definitions from disk. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AgentReloadResult -{ - /// Reloaded custom agents. - [JsonPropertyName("agents")] - public IList Agents { get => field ??= []; set; } + /// Rows from the session SQL todos table, ordered by creation time with insertion order used to break ties when available and id used for WITHOUT ROWID tables. Empty when no database, no todos table, or the SELECT failed. + [JsonPropertyName("rows")] + public IList Rows { get => field ??= []; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionAgentReloadRequest +internal sealed class SessionPlanReadSqlTodosWithDependenciesRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Identifier assigned to the newly started background agent task. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksStartAgentResult +/// RPC data type for WorkspacesGetWorkspaceResultWorkspace operations. +public sealed class WorkspacesGetWorkspaceResultWorkspace { - /// Generated agent ID for the background task. - [JsonPropertyName("agentId")] - public string AgentId { get; set; } = string.Empty; -} + /// Current Git branch. + [JsonPropertyName("branch")] + public string? Branch { get; set; } -/// Agent type, prompt, name, and optional description and model override for the new task. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class TasksStartAgentRequest -{ - /// Type of agent to start (e.g., 'explore', 'task', 'general-purpose'). - [JsonPropertyName("agentType")] - public string AgentType { get; set; } = string.Empty; + /// Whether the per-session Chronicle upgrade prompt was dismissed for the workspace. + [JsonPropertyName("chronicle_sync_dismissed")] + public bool? ChronicleSyncDismissed { get; set; } - /// Short description of the task. - [JsonPropertyName("description")] - public string? Description { get; set; } + /// Name of the client that created the workspace. + [JsonPropertyName("client_name")] + public string? ClientName { get; set; } - /// Optional model override. - [JsonPropertyName("model")] - public string? Model { get; set; } + /// Timestamp when the workspace was created. + [JsonPropertyName("created_at")] + public DateTimeOffset? CreatedAt { get; set; } - /// Friendly, non-unique name used when displaying the agent. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Current working directory associated with the workspace. + [JsonPropertyName("cwd")] + public string? Cwd { get; set; } - /// Task prompt for the agent. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; + /// Git repository root associated with the workspace. + [JsonPropertyName("git_root")] + public string? GitRoot { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Allowed values for the `WorkspacesWorkspaceDetailsHostType` enumeration. + [JsonPropertyName("host_type")] + public WorkspacesWorkspaceDetailsHostType? HostType { get; set; } -/// Tracked task union returned by task APIs, containing an agent, client, or shell task. -/// Polymorphic base type discriminated by type. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "type", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(TaskInfoAgent), "agent")] -[JsonDerivedType(typeof(TaskInfoClient), "client")] -[JsonDerivedType(typeof(TaskInfoShell), "shell")] -public partial class TaskInfo -{ - /// The type discriminator. - [JsonPropertyName("type")] - public virtual string Type { get; set; } = string.Empty; -} - - -/// Tracked background agent task metadata, including IDs, status, timing, agent type, prompt, model, result, and latest response. -/// The agent variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class TaskInfoAgent : TaskInfo -{ - /// - [JsonIgnore] - public override string Type => "agent"; - - /// ISO 8601 timestamp when the current active period began. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("activeStartedAt")] - public DateTimeOffset? ActiveStartedAt { get; set; } - - /// Accumulated active execution time in milliseconds. - [JsonConverter(typeof(MillisecondsTimeSpanConverter))] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("activeTimeMs")] - public TimeSpan? ActiveTime { get; set; } - - /// Type of agent running this task. - [JsonPropertyName("agentType")] - public required string AgentType { get; set; } - - /// Whether the task is currently in the original sync wait and can be moved to background mode. False once it is already backgrounded, idle, finished, or no longer has a promotable sync waiter. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("canPromoteToBackground")] - public bool? CanPromoteToBackground { get; set; } - - /// ISO 8601 timestamp when the task finished. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("completedAt")] - public DateTimeOffset? CompletedAt { get; set; } - - /// Short description of the task. - [JsonPropertyName("description")] - public required string Description { get; set; } - - /// Friendly, non-unique name intended for display. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("displayName")] - public string? DisplayName { get; set; } - - /// Error message when the task failed. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("error")] - public string? Error { get; set; } - - /// Whether task execution is synchronously awaited or managed in the background. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("executionMode")] - public TaskExecutionMode? ExecutionMode { get; set; } - - /// Unique task identifier. + /// Stable workspace identifier. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] [JsonPropertyName("id")] - public required string Id { get; set; } + public string Id { get; set; } = string.Empty; - /// ISO 8601 timestamp when the agent entered idle state. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("idleSince")] - public DateTimeOffset? IdleSince { get; set; } + /// Most recent Mission Control event identifier observed for the workspace. + [JsonPropertyName("mc_last_event_id")] + public string? McLastEventId { get; set; } - /// Most recent response text from the agent. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("latestResponse")] - public string? LatestResponse { get; set; } + /// Mission Control session identifier associated with the workspace. + [JsonPropertyName("mc_session_id")] + public string? McSessionId { get; set; } - /// Requested model override for the task when specified. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("model")] - public string? Model { get; set; } + /// Mission Control task identifier associated with the workspace. + [JsonPropertyName("mc_task_id")] + public string? McTaskId { get; set; } - /// Most recent prompt delivered to the agent. Updated whenever the agent receives a follow-up message. - [JsonPropertyName("prompt")] - public required string Prompt { get; set; } + /// Workspace display name. + [JsonPropertyName("name")] + public string? Name { get; set; } - /// Runtime model resolved for the task when available. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("resolvedModel")] - public string? ResolvedModel { get; set; } + /// Whether the workspace session can be steered remotely. + [JsonPropertyName("remote_steerable")] + public bool? RemoteSteerable { get; set; } - /// Result text from the task when available. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("result")] - public string? Result { get; set; } + /// Repository identifier associated with the workspace. + [JsonPropertyName("repository")] + public string? Repository { get; set; } - /// ISO 8601 timestamp when the task was started. - [JsonPropertyName("startedAt")] - public required DateTimeOffset StartedAt { get; set; } + /// Number of persisted summaries in the workspace. + [JsonPropertyName("summary_count")] + public long? SummaryCount { get; set; } - /// Current lifecycle status of the task. - [JsonPropertyName("status")] - public required TaskStatus Status { get; set; } + /// Timestamp when the workspace was last updated. + [JsonPropertyName("updated_at")] + public DateTimeOffset? UpdatedAt { get; set; } - /// Tool call ID associated with this agent task. - [JsonPropertyName("toolCallId")] - public required string ToolCallId { get; set; } + /// Whether the workspace name was explicitly chosen by the user. + [JsonPropertyName("user_named")] + public bool? UserNamed { get; set; } } -/// Public owner attribution for a client-owned task. Identifiers are opaque and never authorize requests. +/// Current workspace metadata for the session, including its absolute filesystem path when available. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TaskClientOwner +public sealed class WorkspacesGetWorkspaceResult { - /// ISO 8601 timestamp when the bound join disconnected. - [JsonPropertyName("disconnectedAt")] - public DateTimeOffset? DisconnectedAt { get; set; } - - /// Display-only owner name. - [JsonPropertyName("displayName")] - public string? DisplayName { get; set; } + /// Absolute filesystem path to the workspace directory. Omitted when the session has no workspace (e.g. remote sessions). + [JsonPropertyName("path")] + public string? Path { get; set; } - /// Opaque identity of the currently or most recently bound session join. - [JsonPropertyName("joinId")] - public string JoinId { get; set; } = string.Empty; + /// Current workspace metadata, or null if not available. + [JsonPropertyName("workspace")] + public WorkspacesGetWorkspaceResultWorkspace? Workspace { get; set; } +} - /// Class of the task owner. - [JsonPropertyName("kind")] - public TaskClientOwnerKind Kind { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionWorkspacesGetWorkspaceRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Opaque session-scoped participant identity. - [JsonPropertyName("participantId")] - public string ParticipantId { get; set; } = string.Empty; +/// Workspace metadata fields to update. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class WorkspacesUpdateMetadataRequest +{ + /// Opaque workspace context supplied by the session host. + [JsonPropertyName("context")] + public JsonElement? Context { get; set; } - /// Whether this task's bound join is currently connected. - [JsonPropertyName("presence")] - public TaskClientOwnerPresence Presence { get; set; } + /// Optional workspace display name override. + [JsonPropertyName("name")] + public string? Name { get; set; } - /// Display-only owner source. - [JsonPropertyName("source")] - public string? Source { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Tracked client-owned task metadata. -/// The client variant of . +/// Optional session context used when creating a local workspace. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class TaskInfoClient : TaskInfo +internal sealed class WorkspacesEnsureRequest { - /// - [JsonIgnore] - public override string Type => "client"; - - /// ISO 8601 timestamp when the current active segment started. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("activeStartedAt")] - public DateTimeOffset? ActiveStartedAt { get; set; } - - /// Accumulated active execution time in milliseconds. - [JsonPropertyName("activeTimeMs")] - public required long ActiveTimeMs { get; set; } + /// Opaque workspace context supplied by the session host. + [JsonPropertyName("context")] + public JsonElement? Context { get; set; } - /// Whether the currently bound owner can receive a cancellation request. - [JsonPropertyName("canCancel")] - public required bool CanCancel { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Human-readable reason for terminal cancellation. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("cancellationReason")] - public string? CancellationReason { get; set; } +/// Relative paths of files stored in the session workspace files directory. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class WorkspacesListFilesResult +{ + /// Slash-separated relative file paths in the workspace files directory. + [JsonPropertyName("files")] + public IList Files { get => field ??= []; set; } +} - /// Owner-scoped registration and reclaim key. - [JsonPropertyName("clientTaskId")] - public required string ClientTaskId { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionWorkspacesListFilesRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// ISO 8601 timestamp when the task reached a terminal status. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("completedAt")] - public DateTimeOffset? CompletedAt { get; set; } +/// Contents of the requested workspace file as a UTF-8 string. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class WorkspacesReadFileResult +{ + /// File content as a UTF-8 string. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; +} - /// Task description. - [JsonPropertyName("description")] - public required string Description { get; set; } +/// Relative path of the workspace file to read. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class WorkspacesReadFileRequest +{ + /// Slash-separated relative path within the workspace files directory. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Optional task display name. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("displayName")] - public string? DisplayName { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Human-readable terminal failure message. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("error")] - public string? Error { get; set; } +/// Relative path and UTF-8 content for the workspace file to create or overwrite. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class WorkspacesCreateFileRequest +{ + /// File content to write as a UTF-8 string. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; - /// Optional owner-supplied terminal failure code. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("errorCode")] - public string? ErrorCode { get; set; } + /// Slash-separated relative path within the workspace files directory. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Execution mode, which is always background for client-owned tasks. - [JsonPropertyName("executionMode")] - public required TaskClientExecutionMode ExecutionMode { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Canonical runtime-generated task identifier. - [JsonPropertyName("id")] - public required string Id { get; set; } +/// Filesystem metadata for a path in the session workspace files directory. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class WorkspacesStatFileResult +{ + /// Creation time in Unix epoch milliseconds. + [JsonPropertyName("birthtimeMs")] + public double BirthtimeMs { get; set; } - /// ISO 8601 timestamp when the connected owner entered idle status. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("idleSince")] - public DateTimeOffset? IdleSince { get; set; } + /// Whether the path identifies a directory. + [JsonPropertyName("isDirectory")] + public bool IsDirectory { get; set; } - /// ISO 8601 timestamp of the most recent orphan transition. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("orphanedAt")] - public DateTimeOffset? OrphanedAt { get; set; } + /// Whether the path identifies a regular file. + [JsonPropertyName("isFile")] + public bool IsFile { get; set; } - /// Public attribution and presence for the task owner. - [JsonPropertyName("owner")] - public required TaskClientOwner Owner { get; set; } + /// Last modification time in Unix epoch milliseconds. + [JsonPropertyName("mtimeMs")] + public double MtimeMs { get; set; } - /// ISO 8601 timestamp of the most recent successful reclaim. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("reclaimedAt")] - public DateTimeOffset? ReclaimedAt { get; set; } + /// Size in bytes. + [JsonPropertyName("size")] + public double Size { get; set; } +} - /// Opaque successful terminal result supplied by the task owner. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("result")] - public JsonElement? Result { get; set; } +/// Relative path of the workspace file or directory to inspect. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class WorkspacesStatFileRequest +{ + /// Slash-separated relative path within the workspace files directory. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Sequence number of the latest accepted owner update. - [JsonPropertyName("sequence")] - public required long Sequence { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// ISO 8601 timestamp when the task started. - [JsonPropertyName("startedAt")] - public required DateTimeOffset StartedAt { get; set; } +/// Directory to create within the session workspace files directory. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class WorkspacesCreateDirectoryRequest +{ + /// Slash-separated relative path within the workspace files directory. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Client task lifecycle status. - [JsonPropertyName("status")] - public required TaskClientStatus Status { get; set; } + /// Whether to create missing parent directories. Defaults to false. + [JsonPropertyName("recursive")] + public bool? Recursive { get; set; } - /// ISO 8601 timestamp of the latest accepted lifecycle change. - [JsonPropertyName("updatedAt")] - public required DateTimeOffset UpdatedAt { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Tracked shell task metadata, including ID, command, status, timing, attachment/execution mode, log path, and PID. -/// The shell variant of . +/// File or directory to remove from the session workspace files directory. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class TaskInfoShell : TaskInfo +internal sealed class WorkspacesRemovePathRequest { - /// - [JsonIgnore] - public override string Type => "shell"; - - /// Whether the shell runs inside a managed PTY session or as an independent background process. - [JsonPropertyName("attachmentMode")] - public required TaskShellInfoAttachmentMode AttachmentMode { get; set; } - - /// Whether this shell task can be promoted to background mode. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("canPromoteToBackground")] - public bool? CanPromoteToBackground { get; set; } + /// Whether a missing path should be treated as success. Defaults to false. + [JsonPropertyName("force")] + public bool? Force { get; set; } - /// Command being executed. - [JsonPropertyName("command")] - public required string Command { get; set; } + /// Slash-separated relative path within the workspace files directory. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// ISO 8601 timestamp when the task finished. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("completedAt")] - public DateTimeOffset? CompletedAt { get; set; } + /// Whether to remove directory contents recursively. Defaults to false. + [JsonPropertyName("recursive")] + public bool? Recursive { get; set; } - /// Short description of the task. - [JsonPropertyName("description")] - public required string Description { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Whether task execution is synchronously awaited or managed in the background. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("executionMode")] - public TaskExecutionMode? ExecutionMode { get; set; } +/// Source and destination paths for a rename within the session workspace files directory. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class WorkspacesRenamePathRequest +{ + /// Slash-separated destination path relative to the workspace files directory. + [JsonPropertyName("destination")] + public string Destination { get; set; } = string.Empty; - /// Unique task identifier. - [JsonPropertyName("id")] - public required string Id { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// Path to the detached shell log, when available. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("logPath")] - public string? LogPath { get; set; } + /// Slash-separated source path relative to the workspace files directory. + [JsonPropertyName("source")] + public string Source { get; set; } = string.Empty; +} - /// Process ID when available. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("pid")] - public long? Pid { get; set; } +/// Workspace checkpoint metadata with assigned number, human-readable title, and checkpoint filename. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class WorkspacesCheckpoints +{ + /// Filename of the checkpoint within the workspace checkpoints directory. + [JsonPropertyName("filename")] + public string Filename { get; set; } = string.Empty; - /// ISO 8601 timestamp when the task was started. - [JsonPropertyName("startedAt")] - public required DateTimeOffset StartedAt { get; set; } + /// Checkpoint number assigned by the workspace manager. + [JsonPropertyName("number")] + public long Number { get; set; } - /// Current lifecycle status of the task. - [JsonPropertyName("status")] - public required TaskStatus Status { get; set; } + /// Human-readable checkpoint title. + [JsonPropertyName("title")] + public string Title { get; set; } = string.Empty; } -/// Background tasks currently tracked by the session. +/// Workspace checkpoints in chronological order; empty when the workspace is not enabled. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TaskList +public sealed class WorkspacesListCheckpointsResult { - /// Currently tracked tasks. - [JsonPropertyName("tasks")] - public IList Tasks { get => field ??= []; set; } + /// Workspace checkpoints in chronological order. Empty when workspace is not enabled. + [JsonPropertyName("checkpoints")] + public IList Checkpoints { get => field ??= []; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionTasksListRequest +internal sealed class SessionWorkspacesListCheckpointsRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Tracked client-owned task metadata. +/// Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TaskClientInfo +public sealed class WorkspacesReadCheckpointResult { - /// ISO 8601 timestamp when the current active segment started. - [JsonPropertyName("activeStartedAt")] - public DateTimeOffset? ActiveStartedAt { get; set; } + /// Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing. + [JsonPropertyName("content")] + public string? Content { get; set; } +} - /// Accumulated active execution time in milliseconds. - [JsonPropertyName("activeTimeMs")] - public long ActiveTimeMs { get; set; } +/// Checkpoint number to read. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class WorkspacesReadCheckpointRequest +{ + /// Checkpoint number to read. + [JsonPropertyName("number")] + public long Number { get; set; } - /// Whether the currently bound owner can receive a cancellation request. - [JsonPropertyName("canCancel")] - public bool CanCancel { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Human-readable reason for terminal cancellation. - [JsonPropertyName("cancellationReason")] - public string? CancellationReason { get; set; } +/// Persisted summary metadata and refreshed workspace metadata. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class WorkspacesAddSummaryResult +{ + /// Metadata for the persisted summary. + [JsonPropertyName("summary")] + public IDictionary? Summary { get; set; } - /// Owner-scoped registration and reclaim key. - [JsonPropertyName("clientTaskId")] - public string ClientTaskId { get; set; } = string.Empty; + /// Refreshed metadata for the containing workspace. + [JsonPropertyName("workspace")] + public IDictionary? Workspace { get; set; } +} - /// ISO 8601 timestamp when the task reached a terminal status. - [JsonPropertyName("completedAt")] - public DateTimeOffset? CompletedAt { get; set; } +/// Compaction summary checkpoint to persist. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class WorkspacesAddSummaryRequest +{ + /// Markdown summary content to persist. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; - /// Task description. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// Optional task display name. - [JsonPropertyName("displayName")] - public string? DisplayName { get; set; } + /// Summary title shown in checkpoint listings. + [JsonPropertyName("title")] + public string Title { get; set; } = string.Empty; +} - /// Human-readable terminal failure message. - [JsonPropertyName("error")] - public string? Error { get; set; } +/// Rollback point for local workspace summaries. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class WorkspacesTruncateSummariesRequest +{ + /// Number of newest summaries to keep. + [JsonPropertyName("keepCount")] + public long KeepCount { get; set; } - /// Optional owner-supplied terminal failure code. - [JsonPropertyName("errorCode")] - public string? ErrorCode { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Execution mode, which is always background for client-owned tasks. - [JsonPropertyName("executionMode")] - public TaskClientExecutionMode ExecutionMode { get; set; } +/// Autopilot objective file content, or null when missing. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class WorkspacesReadAutopilotObjectiveResult +{ + /// Autopilot objective file content, or null when missing. + [JsonPropertyName("content")] + public string? Content { get; set; } +} - /// Canonical runtime-generated task identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionWorkspacesReadAutopilotObjectiveRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// ISO 8601 timestamp when the connected owner entered idle status. - [JsonPropertyName("idleSince")] - public DateTimeOffset? IdleSince { get; set; } +/// Result of writing the autopilot objective file. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class WorkspacesWriteAutopilotObjectiveResult +{ + /// Filesystem operation performed. + [JsonPropertyName("operation")] + public string Operation { get; set; } = string.Empty; +} - /// ISO 8601 timestamp of the most recent orphan transition. - [JsonPropertyName("orphanedAt")] - public DateTimeOffset? OrphanedAt { get; set; } +/// Autopilot objective file content to persist. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class WorkspacesWriteAutopilotObjectiveRequest +{ + /// Autopilot objective file content. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; - /// Public attribution and presence for the task owner. - [JsonPropertyName("owner")] - public TaskClientOwner Owner { get => field ??= new(); set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// ISO 8601 timestamp of the most recent successful reclaim. - [JsonPropertyName("reclaimedAt")] - public DateTimeOffset? ReclaimedAt { get; set; } +/// Result of deleting the autopilot objective file. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class WorkspacesDeleteAutopilotObjectiveResult +{ + /// True when a file was deleted. + [JsonPropertyName("deleted")] + public bool Deleted { get; set; } +} - /// Opaque successful terminal result supplied by the task owner. - [JsonPropertyName("result")] - public JsonElement? Result { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionWorkspacesDeleteAutopilotObjectiveRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Sequence number of the latest accepted owner update. - [JsonPropertyName("sequence")] - public long Sequence { get; set; } +/// Whether the autopilot objective file exists. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class WorkspacesAutopilotObjectiveExistsResult +{ + /// True when the objective file exists. + [JsonPropertyName("exists")] + public bool Exists { get; set; } +} - /// ISO 8601 timestamp when the task started. - [JsonPropertyName("startedAt")] - public DateTimeOffset StartedAt { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionWorkspacesAutopilotObjectiveExistsRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Client task lifecycle status. - [JsonPropertyName("status")] - public TaskClientStatus Status { get; set; } +/// RPC data type for WorkspacesSaveLargePasteResultSaved operations. +public sealed class WorkspacesSaveLargePasteResultSaved +{ + /// Filename within the workspace files directory. + [JsonPropertyName("filename")] + public string Filename { get; set; } = string.Empty; - /// Task kind. - [JsonPropertyName("type")] - public TaskClientType Type { get; set; } + /// Absolute filesystem path to the saved paste file. + [JsonPropertyName("filePath")] + public string FilePath { get; set; } = string.Empty; - /// ISO 8601 timestamp of the latest accepted lifecycle change. - [JsonPropertyName("updatedAt")] - public DateTimeOffset UpdatedAt { get; set; } + /// Size of the saved file in bytes. + [JsonPropertyName("sizeBytes")] + public long SizeBytes { get; set; } } -/// Result of registering or reclaiming a client-owned task. +/// Descriptor for the saved paste file, or null when the workspace is unavailable. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksRegisterResult +public sealed class WorkspacesSaveLargePasteResult { - /// True only when this invocation created a new task. - [JsonPropertyName("created")] - public bool Created { get; set; } - - /// True only when this invocation reclaimed an orphaned task. - [JsonPropertyName("reclaimed")] - public bool Reclaimed { get; set; } - - /// Authoritative registered or reclaimed task. - [JsonPropertyName("task")] - public TaskClientInfo Task { get => field ??= new(); set; } + /// Saved-paste descriptor, or null when the workspace is unavailable (e.g. CCA runtime, non-infinite sessions, remote sessions). + [JsonPropertyName("saved")] + public WorkspacesSaveLargePasteResultSaved? Saved { get; set; } } -/// Registers or reclaims a client-owned task. +/// Pasted content to save as a UTF-8 file in the session workspace. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class TasksRegisterRequest +internal sealed class WorkspacesSaveLargePasteRequest { - /// Whether the owner supports runtime cancellation requests. - [JsonPropertyName("cancellable")] - public bool Cancellable { get; set; } - - /// Owner-scoped idempotency key used for registration and reclaim. - [JsonPropertyName("clientTaskId")] - public string ClientTaskId { get; set; } = string.Empty; - - /// Human-readable description of the external work. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; - - /// Optional short display name for the external work. - [JsonPropertyName("displayName")] - public string? DisplayName { get; set; } - - /// Expected current sequence for idempotent registration or orphan reclaim. - [JsonPropertyName("expectedSequence")] - public long? ExpectedSequence { get; set; } + /// Pasted content to save as a UTF-8 file. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// Task kind. - [JsonPropertyName("type")] - public TaskClientType Type { get; set; } } -/// Result of publishing a client-owned task update. +/// Complete text used to generate one session diff. These are display contents, with the same text decoding as the patch, not a file-restore contract. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksUpdateResult +public sealed class WorkspaceDiffContents { - /// Whether this invocation changed task state. - [JsonPropertyName("applied")] - public bool Applied { get; set; } - - /// Whether this invocation repeated the latest accepted update. - [JsonPropertyName("duplicate")] - public bool Duplicate { get; set; } + /// Complete current text read when computing the diff. Omitted for a deleted file; an empty string represents an existing empty file. + [JsonPropertyName("after")] + public string? After { get; set; } - /// Authoritative task after processing the update. - [JsonPropertyName("task")] - public TaskClientInfo Task { get => field ??= new(); set; } + /// Complete text before the session first changed the file. Omitted when the file did not exist; an empty string represents an existing empty file. + [JsonPropertyName("before")] + public string? Before { get; set; } } -/// Progress or terminal update for a client-owned task. -/// Polymorphic base type discriminated by kind. +/// A single changed file and its unified diff. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(TaskClientUpdateProgress), "progress")] -[JsonDerivedType(typeof(TaskClientUpdateCompleted), "completed")] -[JsonDerivedType(typeof(TaskClientUpdateFailed), "failed")] -[JsonDerivedType(typeof(TaskClientUpdateCancelled), "cancelled")] -public partial class TaskClientUpdate +public sealed class WorkspaceDiffFileChange { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Type of change represented by this file diff. + [JsonPropertyName("changeType")] + public WorkspaceDiffFileChangeType ChangeType { get; set; } + /// Full text used for this patch, only when includeContents was requested for session mode. Omitted for binary, oversized or unavailable contents, and for fallback results. Read isFallback and isTruncated before treating an absent value as a missing file. + [JsonPropertyName("contents")] + public WorkspaceDiffContents? Contents { get; set; } -/// Publishes nonterminal progress for a running or idle client task. -/// The progress variant of . + /// Unified diff content for the file. Empty when the diff was truncated. + [JsonPropertyName("diff")] + public string Diff { get; set; } = string.Empty; + + /// Whether the diff content was omitted because it exceeded the per-file size limit. + [JsonPropertyName("isTruncated")] + public bool? IsTruncated { get; set; } + + /// Original file path for renamed files. + [JsonPropertyName("oldPath")] + public string? OldPath { get; set; } + + /// Path to the changed file, relative to the workspace root when the file lives under it. A file changed outside the workspace root keeps a `../`-relative path, or an absolute path when no relative path exists (for example a different Windows drive). + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; +} + +/// Workspace diff result for the requested mode. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class TaskClientUpdateProgress : TaskClientUpdate +public sealed class WorkspaceDiffResult { - /// - [JsonIgnore] - public override string Kind => "progress"; + /// Default branch used for a branch diff, when branch mode was requested. + [JsonPropertyName("baseBranch")] + public string? BaseBranch { get; set; } - /// Optional progress message appended to recent activity when nonempty. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("message")] - public string? Message { get; set; } + /// Changed files and their unified diffs. + [JsonPropertyName("changes")] + public IList Changes { get => field ??= []; set; } - /// Optional completion percentage; null clears the current percentage. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("percentage")] - public double? Percentage { get; set; } + /// Whether the requested diff fell back to unstaged changes, either because branch diff failed or session diff was unavailable. + [JsonPropertyName("isFallback")] + public bool IsFallback { get; set; } - /// Optional progress phase; null clears the current phase. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("phase")] - public string? Phase { get; set; } + /// Effective mode used for the returned changes. + [JsonPropertyName("mode")] + public WorkspaceDiffMode Mode { get; set; } - /// Optional active status transition. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("status")] - public TaskClientActiveStatus? Status { get; set; } + /// Diff mode requested by the client. + [JsonPropertyName("requestedMode")] + public WorkspaceDiffMode RequestedMode { get; set; } + + /// Why the session diff could not be produced, when applicable. Set only when `session` mode was requested and `isFallback` is true, so a client can tell the permanent `file-change-tracking-disabled` apart from the transient `session-busy`, which the same request answers once the session settles. Never set for `unstaged` or `branch` mode, and never `unsupported-remote-session`: a remote session's captures live on its own host, so a `session`-mode diff is rejected for one rather than answered with a controller-side fallback. + [JsonPropertyName("unavailableReason")] + public HistoryRewindUnavailableReason? UnavailableReason { get; set; } } -/// Reports successful terminal completion. -/// The completed variant of . +/// Parameters for computing a workspace diff. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class TaskClientUpdateCompleted : TaskClientUpdate +public sealed class WorkspacesDiffRequest { - /// - [JsonIgnore] - public override string Kind => "completed"; + /// When true, ignore whitespace-only changes (git `--ignore-all-space`). Defaults to false. + [JsonPropertyName("ignoreWhitespace")] + public bool? IgnoreWhitespace { get; set; } - /// Optional final progress message. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("message")] - public string? Message { get; set; } + /// Include the full before/after text used to compute each session diff. Defaults to false; true is accepted only for session mode. Existing capture/read limits still apply, and binary or unavailable contents are not returned. This can substantially increase response size. + [JsonPropertyName("includeContents")] + public bool? IncludeContents { get; set; } - /// Optional opaque successful terminal result. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("result")] - public JsonElement? Result { get; set; } + /// Diff mode requested by the client. + [JsonPropertyName("mode")] + public required WorkspaceDiffMode Mode { get; set; } } -/// Reports terminal failure. -/// The failed variant of . +/// Parameters for computing a workspace diff. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class TaskClientUpdateFailed : TaskClientUpdate +internal sealed class WorkspacesDiffRequestWithSession { - /// - [JsonIgnore] - public override string Kind => "failed"; + /// When true, ignore whitespace-only changes (git `--ignore-all-space`). Defaults to false. + [JsonPropertyName("ignoreWhitespace")] + public bool? IgnoreWhitespace { get; set; } - /// Optional owner-supplied terminal failure code. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("code")] - public string? Code { get; set; } + /// Include the full before/after text used to compute each session diff. Defaults to false; true is accepted only for session mode. Existing capture/read limits still apply, and binary or unavailable contents are not returned. This can substantially increase response size. + [JsonPropertyName("includeContents")] + public bool? IncludeContents { get; set; } - /// Human-readable terminal failure message. - [JsonPropertyName("error")] - public required string Error { get; set; } + /// Diff mode requested by the client. + [JsonPropertyName("mode")] + public WorkspaceDiffMode Mode { get; set; } - /// Optional final progress message. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("message")] - public string? Message { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Reports terminal cancellation after external work stopped. -/// The cancelled variant of . +/// Current per-window credit limit and consumption for an autopilot objective. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class TaskClientUpdateCancelled : TaskClientUpdate +public sealed class AutopilotObjectiveCreditLimit { - /// - [JsonIgnore] - public override string Kind => "cancelled"; + /// Configured AI-credit cap, when one is set. + [JsonPropertyName("credits")] + public double? Credits { get; set; } - /// Optional final progress message. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("message")] - public string? Message { get; set; } + /// Window consumption in fractional AI credits, for display. + [JsonPropertyName("creditsUsed")] + public double CreditsUsed { get; set; } - /// Optional human-readable cancellation reason. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("reason")] - public string? Reason { get; set; } + /// Exact window consumption in non-negative integer nano-AIU, encoded as a decimal string. + [RegularExpression("^[0-9]+$")] + [JsonPropertyName("creditsUsedNanoAiu")] + public string CreditsUsedNanoAiu { get; set; } = string.Empty; } -/// Updates a client-owned task. +/// Public, persistence-independent projection of an autopilot objective. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class TasksUpdateRequest +public sealed class AutopilotObjectiveState { - /// Canonical runtime-generated task identifier. + /// Optional summary recorded when the objective completed. + [JsonPropertyName("completionSummary")] + public string? CompletionSummary { get; set; } + + /// Exact lifetime AI-credit consumption in non-negative integer nano-AIU, encoded as a decimal string. + [RegularExpression("^[0-9]+$")] + [JsonPropertyName("creditCountNanoAiu")] + public string CreditCountNanoAiu { get; set; } = string.Empty; + + /// Current per-window consumption and optional cap, when a credit-tracking window is present. + [JsonPropertyName("creditLimit")] + public AutopilotObjectiveCreditLimit? CreditLimit { get; set; } + + /// Session-local objective identifier. [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + public long Id { get; set; } - /// Owner update sequence to apply. - [JsonPropertyName("sequence")] - public long Sequence { get; set; } + /// User-provided objective text. + [JsonPropertyName("objective")] + public string Objective { get; set; } = string.Empty; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Optional reason the objective is paused. + [JsonPropertyName("pauseReason")] + public string? PauseReason { get; set; } - /// Progress or terminal update payload. - [JsonPropertyName("update")] - public TaskClientUpdate Update { get => field ??= new(); set; } + /// Current normalized lifecycle status. + [JsonPropertyName("status")] + public AutopilotObjectiveStatus Status { get; set; } + + /// Number of objective turns started. + [JsonPropertyName("turnCount")] + public long TurnCount { get; set; } } -/// Refresh metadata for any detached background shells the runtime knows about. Use after a long pause to pick up exit/output state for shells running outside the agent loop. +/// Canonical runtime state for the session's current autopilot objective. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksRefreshResult +public sealed class AutopilotObjectiveGetStateResult { + /// Current objective state, or `null` when the session has no objective. + [JsonPropertyName("state")] + public AutopilotObjectiveState? State { get; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionTasksRefreshRequest +internal sealed class SessionAutopilotObjectiveGetStateRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Wait until all in-flight background tasks (agents + shells) and any follow-up turns scheduled by their completions have settled. Returns when the runtime is fully drained or after an internal timeout (default 10 minutes; configurable via COPILOT_TASK_WAIT_TIMEOUT_SECONDS). +/// Characters that, when typed in the composer, should trigger a `completions.request`. Empty when the session has no host-driven completions (e.g. local sessions, or a relay host that does not advertise `completionTriggerCharacters`). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksWaitForPendingResult +public sealed class CompletionsGetTriggerCharactersResult { + /// Trigger characters advertised by the host (e.g. `["@", "#"]`). Empty disables host-driven completions for the session. + [JsonPropertyName("triggerCharacters")] + public IList TriggerCharacters { get => field ??= []; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionTasksWaitForPendingRequest +internal sealed class SessionCompletionsGetTriggerCharactersRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Progress information for the task, discriminated by type. Returns null when no task with this ID is currently tracked. -/// Polymorphic base type discriminated by type. +/// A single host-driven completion. Accepting an item replaces `[rangeStart, rangeEnd)` (UTF-16 code units) in the composer with `insertText`; when the range is absent, the active token around the cursor is replaced. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "type", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(TaskProgressAgent), "agent")] -[JsonDerivedType(typeof(TaskProgressClient), "client")] -[JsonDerivedType(typeof(TaskProgressShell), "shell")] -public partial class TaskProgress +public sealed class SessionCompletionItem { - /// The type discriminator. - [JsonPropertyName("type")] - public virtual string Type { get; set; } = string.Empty; -} + /// Text spliced into the composer when the item is accepted. + [JsonPropertyName("insertText")] + public string InsertText { get; set; } = string.Empty; + /// Render-kind hint for the picker row (e.g. `"document"`, `"directory"`), derived from the host's display kind. + [JsonPropertyName("kind")] + public string? Kind { get; set; } -/// Timestamped display line for task progress output or recent agent activity. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TaskProgressLine -{ - /// Display message, e.g., "▸ bash", "✓ edit src/foo.ts". - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; + /// Primary display label for the picker row. Falls back to `insertText` when absent. + [JsonPropertyName("label")] + public string? Label { get; set; } - /// ISO 8601 timestamp when this event occurred. - [JsonPropertyName("timestamp")] - public DateTimeOffset Timestamp { get; set; } + /// End (exclusive) of the replacement range in `text`, in UTF-16 code units. + [JsonPropertyName("rangeEnd")] + public long? RangeEnd { get; set; } + + /// Start of the replacement range in `text`, in UTF-16 code units. + [JsonPropertyName("rangeStart")] + public long? RangeStart { get; set; } } -/// Progress snapshot for an agent task, with recent activity lines and optional latest intent. -/// The agent variant of . +/// Host-driven completion items for the current composer input. Empty when the host returns no items or does not support completions. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class TaskProgressAgent : TaskProgress +public sealed class CompletionsRequestResult { - /// - [JsonIgnore] - public override string Type => "agent"; - - /// The most recent intent reported by the agent. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("latestIntent")] - public string? LatestIntent { get; set; } - - /// Recent tool execution events converted to display lines. - [JsonPropertyName("recentActivity")] - public required IList RecentActivity { get; set; } + /// Completion items in host-ranked order. + [JsonPropertyName("items")] + public IList Items { get => field ??= []; set; } } -/// Generic progress for a client-owned task. -/// The client variant of . +/// Request host-driven completions for the current composer input. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class TaskProgressClient : TaskProgress -{ - /// - [JsonIgnore] - public override string Type => "client"; - - /// Most recent nonempty progress message. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("lastMessage")] - public string? LastMessage { get; set; } - - /// Current completion percentage from zero through one hundred. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("percentage")] - public double? Percentage { get; set; } - - /// Current owner-defined progress phase. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("phase")] - public string? Phase { get; set; } - - /// Recent server-timestamped progress messages. - [JsonPropertyName("recentActivity")] - public required IList RecentActivity { get; set; } - - /// Sequence number of the latest accepted owner update. - [JsonPropertyName("sequence")] - public required long Sequence { get; set; } - - /// Current client task lifecycle status. - [JsonPropertyName("status")] - public required TaskClientStatus Status { get; set; } - - /// ISO 8601 timestamp of the latest accepted lifecycle change. - [JsonPropertyName("updatedAt")] - public required DateTimeOffset UpdatedAt { get; set; } -} - -/// Progress snapshot for a shell task, with recent stdout/stderr output and optional process ID. -/// The shell variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class TaskProgressShell : TaskProgress +internal sealed class CompletionsRequestRequest { - /// - [JsonIgnore] - public override string Type => "shell"; + /// Cursor offset within `text`, in UTF-16 code units. + [JsonPropertyName("offset")] + public long Offset { get; set; } - /// Process ID when available. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("pid")] - public long? Pid { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// Recent stdout/stderr lines from the running shell command. - [JsonPropertyName("recentOutput")] - public required string RecentOutput { get; set; } + /// The full composed composer input. + [JsonPropertyName("text")] + public string Text { get; set; } = string.Empty; } -/// Progress information for the task, or null when no task with that ID is tracked. +/// Instruction sources loaded for the session, in merge order. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksGetProgressResult +public sealed class InstructionsGetSourcesResult { - /// Progress information for the task, discriminated by type. Returns null when no task with this ID is currently tracked. - [JsonPropertyName("progress")] - public TaskProgress? Progress { get; set; } + /// Instruction sources for the session. + [JsonPropertyName("sources")] + public IList Sources { get => field ??= []; set; } } -/// Identifier of the background task to fetch progress for. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class TasksGetProgressRequest +internal sealed class SessionInstructionsGetSourcesRequest { - /// Task identifier (agent ID or shell ID). - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// The first sync-waiting task that can currently be promoted to background mode. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksGetCurrentPromotableResult -{ - /// The first sync-waiting task (agent first, then shell) that can currently be promoted to background mode. Omitted if no such task exists. The returned task is guaranteed to have executionMode='sync' and canPromoteToBackground=true at the time of the call. - [JsonPropertyName("task")] - public TaskInfo? Task { get; set; } -} - /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionTasksGetCurrentPromotableRequest +internal sealed class SessionInstructionsReloadRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the task was successfully promoted to background mode. +/// Result of one customization reload component. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksPromoteToBackgroundResult +public sealed class CustomizationReloadOutcome { - /// Whether the task was successfully promoted to background mode. - [JsonPropertyName("promoted")] - public bool Promoted { get; set; } -} + /// Reason for a skipped component or description of a failure, when available. + [JsonPropertyName("detail")] + public string? Detail { get; set; } -/// Identifier of the task to promote to background mode. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class TasksPromoteToBackgroundRequest -{ - /// Task identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Whether the component reloaded, was skipped, or failed. + [JsonPropertyName("status")] + public CustomizationReloadStatus Status { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Component whose reload was attempted or skipped. + [JsonPropertyName("subsystem")] + public CustomizationReloadSubsystem Subsystem { get; set; } } -/// The promoted task as it now exists in background mode, omitted if no promotable task was waiting. +/// Results of reloading discovered session customizations. Inspect outcomes for reloaded, skipped, or failed subsystems; a rejection may follow partial mutation. Changes to the model-facing prompt and tools apply on the next turn. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksPromoteCurrentToBackgroundResult +public sealed class CustomizationsReloadResult { - /// The promoted task as it now exists in background mode, omitted if no promotable task was waiting. Atomic operation: avoids the race window of getCurrentPromotable + promoteToBackground. - [JsonPropertyName("task")] - public TaskInfo? Task { get; set; } + /// Errors from any component that could not be refreshed. + [JsonPropertyName("errors")] + public IList Errors { get => field ??= []; set; } + + /// Outcome of each component in reload order; a skipped component was not configured or loaded. + [JsonPropertyName("outcomes")] + public IList Outcomes { get => field ??= []; set; } + + /// Warnings from skill discovery. + [JsonPropertyName("warnings")] + public IList Warnings { get => field ??= []; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionTasksPromoteCurrentToBackgroundRequest +internal sealed class SessionCustomizationsReloadRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the background task was successfully cancelled. +/// Indicates whether fleet mode was successfully activated. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksCancelResult +public sealed class FleetStartResult { - /// Whether the task was successfully cancelled. - [JsonPropertyName("cancelled")] - public bool Cancelled { get; set; } + /// Whether fleet mode was successfully activated. + [JsonPropertyName("started")] + public bool Started { get; set; } } -/// Identifier of the background task to cancel. +/// Parameters for starting fleet orchestration: an optional user prompt combined with the fleet instructions, plus the send options forwarded to the resulting turn. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class TasksCancelRequest +internal sealed class FleetStartRequest { - /// Task identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Optional attachments (files, directories, selections, blobs, GitHub references) to include with the fleet request. + [JsonPropertyName("attachments")] + public IList? Attachments { get; set; } + + /// If false, this request will not trigger a Premium Request Unit charge. User requests default to billable. + [JsonInclude] + [JsonPropertyName("billable")] + internal bool? Billable { get; set; } + + /// Optional user prompt to combine with fleet instructions. + [JsonPropertyName("prompt")] + public string? Prompt { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; -} -/// Indicates whether the task was removed. False when the task does not exist or is still running/idle. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksRemoveResult -{ - /// Whether the task was removed. Returns false if the task does not exist or is still running/idle (cancel it first). - [JsonPropertyName("removed")] - public bool Removed { get; set; } + /// If true, await completion of the agentic loop for this fleet request before returning. Defaults to false. + [JsonPropertyName("wait")] + public bool? Wait { get; set; } } -/// Identifier of the completed or cancelled task to remove from tracking. +/// Agents available to the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class TasksRemoveRequest +public sealed class AgentList { - /// Task identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Available agents. + [JsonPropertyName("agents")] + public IList Agents { get => field ??= []; set; } } -/// Indicates whether the message was delivered, with an error message when delivery failed. +/// RPC data type for SessionAgentList operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TasksSendMessageResult +public sealed class SessionAgentListRequest { - /// Error message if delivery failed. - [JsonPropertyName("error")] - public string? Error { get; set; } + /// When true, request the session's configured built-in agents alongside custom agents. Listing applies feature, context, inclusion, exclusion, and user-disabled-agent policy, but does not evaluate transient invocation requirements such as model availability. Built-in metadata may be omitted when the session cannot project it, such as a relay session. + [JsonPropertyName("includeBuiltInAgents")] + public bool? IncludeBuiltInAgents { get; set; } - /// Whether the message was successfully delivered or steered. - [JsonPropertyName("sent")] - public bool Sent { get; set; } + /// When true, request authored base prompt text on each AgentInfo. Prompt text may be omitted when unavailable, such as for agents projected through a relay session. + [JsonPropertyName("includePrompt")] + public bool? IncludePrompt { get; set; } } -/// Identifier of the target agent task, message content, and optional sender agent ID. +/// RPC data type for SessionAgentListRequestWithSession operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class TasksSendMessageRequest +internal sealed class SessionAgentListRequestWithSession { - /// Agent ID of the sender, if sent on behalf of another agent. - [JsonPropertyName("fromAgentId")] - public string? FromAgentId { get; set; } - - /// Agent task identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// When true, request the session's configured built-in agents alongside custom agents. Listing applies feature, context, inclusion, exclusion, and user-disabled-agent policy, but does not evaluate transient invocation requirements such as model availability. Built-in metadata may be omitted when the session cannot project it, such as a relay session. + [JsonPropertyName("includeBuiltInAgents")] + public bool? IncludeBuiltInAgents { get; set; } - /// Message content to send to the agent. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; + /// When true, request authored base prompt text on each AgentInfo. Prompt text may be omitted when unavailable, such as for agents projected through a relay session. + [JsonPropertyName("includePrompt")] + public bool? IncludePrompt { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Skill metadata available to a session, with name, description, source, enabled/invocable state, path, plugin, and argument hint. +/// An in-memory authored prompt override for an available agent. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class Skill +internal sealed class AgentSetPromptRequest { - /// Optional freeform hint describing the skill's expected arguments, from the `argument-hint` frontmatter field. - [JsonPropertyName("argumentHint")] - public string? ArgumentHint { get; set; } - - /// Canonical slash command name used to invoke the skill, without the leading '/'. - [JsonPropertyName("commandName")] - public string? CommandName { get; set; } - - /// Description of what the skill does. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; - - /// Whether the skill is currently enabled. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } - - /// Unique identifier for the skill. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - - /// Absolute path to the skill file. - [JsonPropertyName("path")] - public string? Path { get; set; } - - /// Name of the plugin that provides the skill, when source is 'plugin'. - [JsonPropertyName("pluginName")] - public string? PluginName { get; set; } + /// Stable effective agent id. Plugin namespace separators are normalized. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Source location type (e.g., project, personal-copilot, plugin, builtin). - [JsonPropertyName("source")] - public SkillSource Source { get; set; } + /// Replacement authored prompt. Empty text is valid. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; - /// Whether the skill can be invoked by the user as a slash command. - [JsonPropertyName("userInvocable")] - public bool UserInvocable { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Skills available to the session, with their enabled state. +/// The currently selected custom agent, or null when using the default agent. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillList +public sealed class AgentGetCurrentResult { - /// Available skills. - [JsonPropertyName("skills")] - public IList Skills { get => field ??= []; set; } + /// Currently selected custom agent, or null if using the default agent. + [JsonPropertyName("agent")] + public AgentInfo? Agent { get; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSkillsListRequest +internal sealed class SessionAgentGetCurrentRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Skill invocation record with name, path, content, allowed tools, and turn number. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillsInvokedSkill -{ - /// Tools that should be auto-approved when this skill is active, captured at invocation time. - [JsonPropertyName("allowedTools")] - public IList? AllowedTools { get; set; } - - /// Full content of the skill file. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; - - /// Whether model invocation was disabled when this skill was invoked. - [JsonPropertyName("disableModelInvocation")] - public bool? DisableModelInvocation { get; set; } - - /// Turn number when the skill was invoked. - [JsonPropertyName("invokedAtTurn")] - public long InvokedAtTurn { get; set; } - - /// Unique identifier for the skill. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - - /// Path to the SKILL.md file, or an empty string for an SDK-provided skill without a filesystem identity. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; -} - -/// Skills invoked during this session, ordered by invocation time (most recent last). -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillsGetInvokedResult -{ - /// Skills invoked during this session, ordered by invocation time (most recent last). - [JsonPropertyName("skills")] - public IList Skills { get => field ??= []; set; } -} - -/// Identifies the target session. +/// The newly selected custom agent. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSkillsGetInvokedRequest +public sealed class AgentSelectResult { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// The newly selected custom agent. + [JsonPropertyName("agent")] + public AgentInfo Agent { get => field ??= new(); set; } } -/// Name of the skill to enable for the session. +/// Name of the custom agent to select for subsequent turns. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillsEnableRequest +internal sealed class AgentSelectRequest { - /// Name of the skill to enable. + /// Name of the custom agent to select. [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; @@ -17374,1423 +17565,1425 @@ internal sealed class SkillsEnableRequest public string SessionId { get; set; } = string.Empty; } -/// Name of the skill to disable for the session. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SkillsDisableRequest +internal sealed class SessionAgentDeselectRequest { - /// Name of the skill to disable. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Diagnostics from reloading skill definitions, with warnings and errors as separate lists. +/// Custom agents available to the session after reloading definitions from disk. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SkillsLoadDiagnostics +public sealed class AgentReloadResult { - /// Errors emitted while loading skills (e.g. skills that failed to load entirely). - [JsonPropertyName("errors")] - public IList Errors { get => field ??= []; set; } - - /// Warnings emitted while loading skills (e.g. skills that loaded but had issues). - [JsonPropertyName("warnings")] - public IList Warnings { get => field ??= []; set; } + /// Reloaded custom agents. + [JsonPropertyName("agents")] + public IList Agents { get => field ??= []; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSkillsReloadRequest +internal sealed class SessionAgentReloadRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Identifies the target session. +/// Identifier assigned to the newly started background agent task. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSkillsEnsureLoadedRequest +public sealed class TasksStartAgentResult { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Generated agent ID for the background task. + [JsonPropertyName("agentId")] + public string AgentId { get; set; } = string.Empty; } -/// The IDE a host is connected to, as reported to the session. +/// Agent type, prompt, name, and optional description and model override for the new task. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionConnectedIdeInfo +internal sealed class TasksStartAgentRequest { - /// Display name of the connected IDE, for example `VS Code`. - [JsonPropertyName("ideName")] - public string IdeName { get; set; } = string.Empty; + /// Type of agent to start (e.g., 'explore', 'task', 'general-purpose'). + [JsonPropertyName("agentType")] + public string AgentType { get; set; } = string.Empty; - /// Absolute path of the workspace folder the IDE has open. - [JsonPropertyName("workspaceFolder")] - public string WorkspaceFolder { get; set; } = string.Empty; -} + /// Short description of the task. + [JsonPropertyName("description")] + public string? Description { get; set; } -/// Records which IDE the host is connected to, or clears it. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMcpSetConnectedIdeInfoParams -{ - /// The connected IDE. Null or omitted clears the recorded IDE, which is how a host reports that it is disconnected. - [JsonPropertyName("ide")] - public SessionConnectedIdeInfo? Ide { get; set; } + /// Optional model override. + [JsonPropertyName("model")] + public string? Model { get; set; } + + /// Friendly, non-unique name used when displaying the agent. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Task prompt for the agent. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Recorded MCP server connection failure. +/// Tracked task union returned by task APIs, containing an agent, client, or shell task. +/// Polymorphic base type discriminated by type. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpServerFailureInfo +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "type", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(TaskInfoAgent), "agent")] +[JsonDerivedType(typeof(TaskInfoClient), "client")] +[JsonDerivedType(typeof(TaskInfoShell), "shell")] +public partial class TaskInfo { - /// Failure message produced when the MCP server connection failed. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; - - /// epoch-ms timestamp at which the failure was recorded. - [JsonPropertyName("timestamp")] - public long Timestamp { get; set; } + /// The type discriminator. + [JsonPropertyName("type")] + public virtual string Type { get; set; } = string.Empty; } -/// Recorded MCP server pending-auth state. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpServerNeedsAuthInfo -{ - /// epoch-ms timestamp at which the server signalled it needs authentication. - [JsonPropertyName("timestamp")] - public long Timestamp { get; set; } -} -/// Host-level state, omitted when no MCP host is initialized. +/// Tracked background agent task metadata, including IDs, status, timing, agent type, prompt, model, result, and latest response. +/// The agent variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpHostState +public partial class TaskInfoAgent : TaskInfo { - /// Names of currently-connected MCP clients. - [JsonPropertyName("clients")] - public IList Clients { get => field ??= []; set; } - - /// Configured servers that are explicitly disabled. - [JsonPropertyName("disabledServers")] - public IList DisabledServers { get => field ??= []; set; } + /// + [JsonIgnore] + public override string Type => "agent"; - /// Map of server name to recorded connection failure. - [JsonPropertyName("failedServers")] - public IDictionary FailedServers { get => field ??= new Dictionary(); set; } + /// ISO 8601 timestamp when the current active period began. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("activeStartedAt")] + public DateTimeOffset? ActiveStartedAt { get; set; } - /// Configured servers filtered out by MCP server policy. - [JsonPropertyName("filteredServers")] - public IList FilteredServers { get => field ??= []; set; } + /// Accumulated active execution time in milliseconds. + [JsonConverter(typeof(MillisecondsTimeSpanConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("activeTimeMs")] + public TimeSpan? ActiveTime { get; set; } - /// Whether third-party MCP servers are policy-enabled for this session. - [JsonPropertyName("mcp3pEnabled")] - public bool Mcp3pEnabled { get; set; } + /// Type of agent running this task. + [JsonPropertyName("agentType")] + public required string AgentType { get; set; } - /// Map of server name to recorded pending-auth state. - [JsonPropertyName("needsAuthServers")] - public IDictionary NeedsAuthServers { get => field ??= new Dictionary(); set; } + /// Whether the task is currently in the original sync wait and can be moved to background mode. False once it is already backgrounded, idle, finished, or no longer has a promotable sync waiter. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("canPromoteToBackground")] + public bool? CanPromoteToBackground { get; set; } - /// Names of servers with in-flight connection attempts. - [JsonPropertyName("pendingConnections")] - public IList PendingConnections { get => field ??= []; set; } -} + /// ISO 8601 timestamp when the task finished. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("completedAt")] + public DateTimeOffset? CompletedAt { get; set; } -/// Owned installation that a listed MCP server's live configuration came from. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpServerOwnership -{ - /// Stable installation identifier from the owned installation receipt. - [JsonPropertyName("installationId")] - public string InstallationId { get; set; } = string.Empty; -} + /// Short description of the task. + [JsonPropertyName("description")] + public required string Description { get; set; } -/// MCP server status entry, including config source/plugin source and any connection error. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpServer -{ - /// Human-readable display name supplied by a managed server catalog. + /// Friendly, non-unique name intended for display. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("displayName")] public string? DisplayName { get; set; } - /// Error message if the server failed to connect. + /// Error message when the task failed. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("error")] public string? Error { get; set; } - /// Server name (config key). - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Whether task execution is synchronously awaited or managed in the background. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("executionMode")] + public TaskExecutionMode? ExecutionMode { get; set; } - /// Owned installation this entry's live configuration came from. Absent for manual, workspace, plugin, builtin and same-name servers, and on runtimes without owned installations. - [JsonPropertyName("owned")] - public McpServerOwnership? Owned { get; set; } + /// Unique task identifier. + [JsonPropertyName("id")] + public required string Id { get; set; } - /// Server-advertised metadata for a connected server. Omitted when no live connection metadata is available, including while pending or when failed, disabled, stopped, or not configured. - [JsonPropertyName("serverMetadata")] - public McpServerMetadata? ServerMetadata { get; set; } + /// ISO 8601 timestamp when the agent entered idle state. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("idleSince")] + public DateTimeOffset? IdleSince { get; set; } - /// Configuration source: user, workspace, plugin, builtin, or managed. - [JsonPropertyName("source")] - public McpServerSource? Source { get; set; } + /// Most recent response text from the agent. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("latestResponse")] + public string? LatestResponse { get; set; } - /// Plugin name that provided this server, when source is plugin. - [JsonPropertyName("sourcePlugin")] - public string? SourcePlugin { get; set; } + /// Requested model override for the task when specified. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("model")] + public string? Model { get; set; } - /// Plugin version that provided this server, when source is plugin. - [JsonPropertyName("sourcePluginVersion")] - public string? SourcePluginVersion { get; set; } + /// Most recent prompt delivered to the agent. Updated whenever the agent receives a follow-up message. + [JsonPropertyName("prompt")] + public required string Prompt { get; set; } - /// Connection status: connected, failed, needs-auth, pending, disabled, stopped, or not_configured. - [JsonPropertyName("status")] - public McpServerStatus Status { get; set; } + /// Runtime model resolved for the task when available. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("resolvedModel")] + public string? ResolvedModel { get; set; } - /// Configured URL for an HTTP/SSE server, regardless of configuration source. Omitted for local and in-memory servers. - [JsonPropertyName("url")] - public string? Url { get; set; } -} + /// Result text from the task when available. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("result")] + public string? Result { get; set; } -/// MCP servers configured for the session, with their connection status and host-level state. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpServerList -{ - /// Host-level state, omitted when no MCP host is initialized. - [JsonPropertyName("host")] - public McpHostState? Host { get; set; } + /// ISO 8601 timestamp when the task was started. + [JsonPropertyName("startedAt")] + public required DateTimeOffset StartedAt { get; set; } - /// Configured MCP servers. - [JsonPropertyName("servers")] - public IList Servers { get => field ??= []; set; } -} + /// Current lifecycle status of the task. + [JsonPropertyName("status")] + public required TaskStatus Status { get; set; } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMcpListRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Tool call ID associated with this agent task. + [JsonPropertyName("toolCallId")] + public required string ToolCallId { get; set; } } -/// Observational state for a matching already materialized MCP server. +/// Public owner attribution for a client-owned task. Identifiers are opaque and never authorize requests. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpConfiguredServerState +public sealed class TaskClientOwner { - /// Observed connection error, when the materialized server failed. - [JsonPropertyName("error")] - public string? Error { get; set; } - - /// Observed connection status. This is not a configuration or readiness guarantee. - [JsonPropertyName("status")] - public McpServerStatus Status { get; set; } -} + /// ISO 8601 timestamp when the bound join disconnected. + [JsonPropertyName("disconnectedAt")] + public DateTimeOffset? DisconnectedAt { get; set; } -/// Effective MCP configuration entry. Configuration enablement is distinct from the optional live observation. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpConfiguredServer -{ - /// Human-readable display name supplied by configuration. + /// Display-only owner name. [JsonPropertyName("displayName")] public string? DisplayName { get; set; } - /// Whether this configured server is enabled after session configuration and policy filtering. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } - - /// Observed state from an already materialized matching server. Omitted when no live graph has this configured server; it never determines configuration enablement. - [JsonPropertyName("live")] - public McpConfiguredServerState Live { get => field ??= new(); set; } + /// Opaque identity of the currently or most recently bound session join. + [JsonPropertyName("joinId")] + public string JoinId { get; set; } = string.Empty; - /// Server name (config key). - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Class of the task owner. + [JsonPropertyName("kind")] + public TaskClientOwnerKind Kind { get; set; } - /// Configuration provenance: user, workspace, plugin, builtin, or managed. - [JsonPropertyName("source")] - public McpServerSource? Source { get; set; } + /// Opaque session-scoped participant identity. + [JsonPropertyName("participantId")] + public string ParticipantId { get; set; } = string.Empty; - /// Plugin name that provided this server, when source is plugin. - [JsonPropertyName("sourcePlugin")] - public string? SourcePlugin { get; set; } + /// Whether this task's bound join is currently connected. + [JsonPropertyName("presence")] + public TaskClientOwnerPresence Presence { get; set; } - /// Plugin version that provided this server, when source is plugin. - [JsonPropertyName("sourcePluginVersion")] - public string? SourcePluginVersion { get; set; } + /// Display-only owner source. + [JsonPropertyName("source")] + public string? Source { get; set; } } -/// Effective MCP configuration with optional live observations from matching already materialized servers. +/// Tracked client-owned task metadata. +/// The client variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpConfiguredServerList +public partial class TaskInfoClient : TaskInfo { - /// Effective configured MCP servers. - [JsonPropertyName("servers")] - public IList Servers { get => field ??= []; set; } -} + /// + [JsonIgnore] + public override string Type => "client"; -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMcpListConfiguredRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// ISO 8601 timestamp when the current active segment started. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("activeStartedAt")] + public DateTimeOffset? ActiveStartedAt { get; set; } -/// Normalized MCP Apps discovery metadata from a tool's `_meta.ui` block. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpToolUi -{ - /// URI of the tool's MCP App resource, typically a `ui://` resource identifier. Use `session.mcp.resources.read` to fetch its HTML and resource metadata. - [JsonPropertyName("resourceUri")] - public string? ResourceUri { get; set; } + /// Accumulated active execution time in milliseconds. + [JsonPropertyName("activeTimeMs")] + public required long ActiveTimeMs { get; set; } - /// Tool visibility advertised by the server. When absent, MCP Apps defaults apply. - [JsonPropertyName("visibility")] - public IList? Visibility { get; set; } -} + /// Whether the currently bound owner can receive a cancellation request. + [JsonPropertyName("canCancel")] + public required bool CanCancel { get; set; } -/// MCP tool metadata with tool name, optional description, and normalized MCP Apps discovery metadata. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpTools -{ - /// Tool description, when provided. - [JsonPropertyName("description")] - public string? Description { get; set; } + /// Human-readable reason for terminal cancellation. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("cancellationReason")] + public string? CancellationReason { get; set; } - /// Tool name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Owner-scoped registration and reclaim key. + [JsonPropertyName("clientTaskId")] + public required string ClientTaskId { get; set; } - /// Normalized MCP Apps discovery metadata. An empty object indicates that a valid `_meta.ui` block was present without recognized fields. - [JsonPropertyName("ui")] - public McpToolUi? Ui { get; set; } -} + /// ISO 8601 timestamp when the task reached a terminal status. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("completedAt")] + public DateTimeOffset? CompletedAt { get; set; } -/// Tools exposed by the connected MCP server. Throws when the server is not connected. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpListToolsResult -{ - /// Tools exposed by the server. - [JsonPropertyName("tools")] - public IList Tools { get => field ??= []; set; } -} + /// Task description. + [JsonPropertyName("description")] + public required string Description { get; set; } -/// Server name whose tool list should be returned. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpListToolsRequest -{ - /// Name of the connected MCP server whose tools to list. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Optional task display name. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("displayName")] + public string? DisplayName { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Human-readable terminal failure message. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("error")] + public string? Error { get; set; } -/// Name of the MCP server to enable for the session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpEnableRequest -{ - /// Exact receipt identity for explicit owned activation in this session. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Optional owner-supplied terminal failure code. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("errorCode")] + public string? ErrorCode { get; set; } - /// Name of the MCP server to enable. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("serverName")] - public required string ServerName { get; set; } -} + /// Execution mode, which is always background for client-owned tasks. + [JsonPropertyName("executionMode")] + public required TaskClientExecutionMode ExecutionMode { get; set; } -/// Name of the MCP server to enable for the session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpEnableRequestWithSession -{ - /// Exact receipt identity for explicit owned activation in this session. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Canonical runtime-generated task identifier. + [JsonPropertyName("id")] + public required string Id { get; set; } - /// Name of the MCP server to enable. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; + /// ISO 8601 timestamp when the connected owner entered idle status. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("idleSince")] + public DateTimeOffset? IdleSince { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// ISO 8601 timestamp of the most recent orphan transition. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("orphanedAt")] + public DateTimeOffset? OrphanedAt { get; set; } -/// Name of the MCP server to disable for the session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpDisableRequest -{ - /// Required for an owned installation; omission preserves only manual-server behaviour. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Public attribution and presence for the task owner. + [JsonPropertyName("owner")] + public required TaskClientOwner Owner { get; set; } - /// Name of the MCP server to disable. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("serverName")] - public required string ServerName { get; set; } -} + /// ISO 8601 timestamp of the most recent successful reclaim. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("reclaimedAt")] + public DateTimeOffset? ReclaimedAt { get; set; } -/// Name of the MCP server to disable for the session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpDisableRequestWithSession -{ - /// Required for an owned installation; omission preserves only manual-server behaviour. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Opaque successful terminal result supplied by the task owner. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("result")] + public JsonElement? Result { get; set; } - /// Name of the MCP server to disable. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Sequence number of the latest accepted owner update. + [JsonPropertyName("sequence")] + public required long Sequence { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// ISO 8601 timestamp when the task started. + [JsonPropertyName("startedAt")] + public required DateTimeOffset StartedAt { get; set; } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMcpReloadRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Client task lifecycle status. + [JsonPropertyName("status")] + public required TaskClientStatus Status { get; set; } -/// Result of moving in-flight MCP loading to the background. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MoveMcpLoadingToBackgroundResult -{ - /// Whether an in-flight MCP load was moved to the background, releasing turns that were waiting on it. False when no MCP load was in flight or the waiting turns had already been released. - [JsonPropertyName("movedToBackground")] - public bool MovedToBackground { get; set; } + /// ISO 8601 timestamp of the latest accepted lifecycle change. + [JsonPropertyName("updatedAt")] + public required DateTimeOffset UpdatedAt { get; set; } } -/// Identifies the target session. +/// Tracked shell task metadata, including ID, command, status, timing, attachment/execution mode, log path, and PID. +/// The shell variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMcpMoveLoadingToBackgroundRequest +public partial class TaskInfoShell : TaskInfo { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// + [JsonIgnore] + public override string Type => "shell"; -/// MCP server allowed by policy, with server name and optional PII-free explanatory note. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpAllowedServer -{ - /// Allowed server name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Whether the shell runs inside a managed PTY session or as an independent background process. + [JsonPropertyName("attachmentMode")] + public required TaskShellInfoAttachmentMode AttachmentMode { get; set; } - /// PII-free note explaining why the server was allowed. - [JsonPropertyName("redactedNote")] - public string? RedactedNote { get; set; } -} + /// Whether this shell task can be promoted to background mode. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("canPromoteToBackground")] + public bool? CanPromoteToBackground { get; set; } -/// MCP server whose connection attempt failed. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpFailedServer -{ - /// The captured connection failure detail. - [JsonPropertyName("error")] - public string? Error { get; set; } + /// Command being executed. + [JsonPropertyName("command")] + public required string Command { get; set; } - /// The config key of the server that failed to connect. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; -} + /// ISO 8601 timestamp when the task finished. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("completedAt")] + public DateTimeOffset? CompletedAt { get; set; } -/// MCP server filtered by policy, with name, reason, and optional redacted reason. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpFilteredServer -{ - /// Deprecated. This field is no longer populated. - [EditorBrowsable(EditorBrowsableState.Never)] -#if NET5_0_OR_GREATER - [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] -#else - [Obsolete("This member is deprecated and will be removed in a future version.")] -#endif - [JsonPropertyName("enterpriseName")] - public string? EnterpriseName { get; set; } + /// Short description of the task. + [JsonPropertyName("description")] + public required string Description { get; set; } - /// Filtered server name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Whether task execution is synchronously awaited or managed in the background. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("executionMode")] + public TaskExecutionMode? ExecutionMode { get; set; } - /// Human-readable filter reason. - [JsonPropertyName("reason")] - public string Reason { get; set; } = string.Empty; + /// Unique task identifier. + [JsonPropertyName("id")] + public required string Id { get; set; } - /// PII-free filter reason. - [JsonPropertyName("redactedReason")] - public string? RedactedReason { get; set; } + /// Path to the detached shell log, when available. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("logPath")] + public string? LogPath { get; set; } + + /// Process ID when available. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("pid")] + public long? Pid { get; set; } + + /// ISO 8601 timestamp when the task was started. + [JsonPropertyName("startedAt")] + public required DateTimeOffset StartedAt { get; set; } + + /// Current lifecycle status of the task. + [JsonPropertyName("status")] + public required TaskStatus Status { get; set; } } -/// MCP server startup filtering result. +/// Background tasks currently tracked by the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpStartServersResult +public sealed class TaskList { - /// Non-default servers allowed by policy. - [JsonPropertyName("allowedServers")] - public IList? AllowedServers { get; set; } - - /// Servers whose connection attempt failed. - [JsonPropertyName("failedServers")] - public IList? FailedServers { get; set; } - - /// Servers filtered out before startup. - [JsonPropertyName("filteredServers")] - public IList FilteredServers { get => field ??= []; set; } + /// Currently tracked tasks. + [JsonPropertyName("tasks")] + public IList Tasks { get => field ??= []; set; } } -/// Opaque MCP reload configuration. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpReloadWithConfigRequest +internal sealed class SessionTasksListRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// MCP CreateMessageResult payload (with optional 'tools' extension), present when action='success'. Treated as opaque at the schema layer; consumers should construct/consume it per the MCP CreateMessageResult shape. +/// Tracked client-owned task metadata. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpExecuteSamplingResult +public sealed class TaskClientInfo { -} + /// ISO 8601 timestamp when the current active segment started. + [JsonPropertyName("activeStartedAt")] + public DateTimeOffset? ActiveStartedAt { get; set; } -/// Outcome of an MCP sampling execution: success result, failure error, or cancellation. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpSamplingExecutionResult -{ - /// Outcome of the sampling inference. 'success' produced a response; 'failure' encountered an error (including agent-side rejection by content filter or criteria); 'cancelled' the caller cancelled this execution via cancelSamplingExecution. - [JsonPropertyName("action")] - public McpSamplingExecutionAction Action { get; set; } + /// Accumulated active execution time in milliseconds. + [JsonPropertyName("activeTimeMs")] + public long ActiveTimeMs { get; set; } - /// Error description, present when action='failure'. - [JsonPropertyName("error")] - public string? Error { get; set; } + /// Whether the currently bound owner can receive a cancellation request. + [JsonPropertyName("canCancel")] + public bool CanCancel { get; set; } - /// MCP CreateMessageResult payload (with optional 'tools' extension), present when action='success'. Treated as opaque at the schema layer; consumers should construct/consume it per the MCP CreateMessageResult shape. - [JsonPropertyName("result")] - public McpExecuteSamplingResult? Result { get; set; } -} + /// Human-readable reason for terminal cancellation. + [JsonPropertyName("cancellationReason")] + public string? CancellationReason { get; set; } -/// Raw MCP CreateMessageRequest params, as received in the `sampling.requested` event. Treated as opaque at the schema layer; the runtime converts the embedded MCP messages into the OpenAI chat-completion shape internally. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpExecuteSamplingRequest -{ -} + /// Owner-scoped registration and reclaim key. + [JsonPropertyName("clientTaskId")] + public string ClientTaskId { get; set; } = string.Empty; -/// Identifiers and raw MCP CreateMessageRequest params used to run a sampling inference. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpExecuteSamplingParams -{ - /// The original MCP JSON-RPC request ID (string or number). Used by the runtime to correlate the inference with the originating MCP request for telemetry; this is distinct from `requestId` (which is the schema-level cancellation handle). - [JsonPropertyName("mcpRequestId")] - public JsonElement McpRequestId { get; set; } + /// ISO 8601 timestamp when the task reached a terminal status. + [JsonPropertyName("completedAt")] + public DateTimeOffset? CompletedAt { get; set; } - /// Raw MCP CreateMessageRequest params, as received in the `sampling.requested` event. Treated as opaque at the schema layer; the runtime converts the embedded MCP messages into the OpenAI chat-completion shape internally. - [JsonPropertyName("request")] - public McpExecuteSamplingRequest Request { get => field ??= new(); set; } + /// Task description. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// Caller-provided unique identifier for this sampling execution. Use this same ID with cancelSamplingExecution to cancel the in-flight call. Must be unique within the session for the lifetime of the call. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// Optional task display name. + [JsonPropertyName("displayName")] + public string? DisplayName { get; set; } - /// Name of the MCP server that initiated the sampling request. - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Human-readable terminal failure message. + [JsonPropertyName("error")] + public string? Error { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Optional owner-supplied terminal failure code. + [JsonPropertyName("errorCode")] + public string? ErrorCode { get; set; } -/// Indicates whether an in-flight sampling execution with the given requestId was found and cancelled. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpCancelSamplingExecutionResult -{ - /// True if an in-flight execution with the given requestId was found and signalled to cancel. False when no such execution is in flight (already completed, never started, or cancelled by another caller). - [JsonPropertyName("cancelled")] - public bool Cancelled { get; set; } -} + /// Execution mode, which is always background for client-owned tasks. + [JsonPropertyName("executionMode")] + public TaskClientExecutionMode ExecutionMode { get; set; } -/// The requestId previously passed to executeSampling that should be cancelled. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpCancelSamplingExecutionParams -{ - /// The requestId previously passed to executeSampling that should be cancelled. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// Canonical runtime-generated task identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// ISO 8601 timestamp when the connected owner entered idle status. + [JsonPropertyName("idleSince")] + public DateTimeOffset? IdleSince { get; set; } + + /// ISO 8601 timestamp of the most recent orphan transition. + [JsonPropertyName("orphanedAt")] + public DateTimeOffset? OrphanedAt { get; set; } + + /// Public attribution and presence for the task owner. + [JsonPropertyName("owner")] + public TaskClientOwner Owner { get => field ??= new(); set; } + + /// ISO 8601 timestamp of the most recent successful reclaim. + [JsonPropertyName("reclaimedAt")] + public DateTimeOffset? ReclaimedAt { get; set; } + + /// Opaque successful terminal result supplied by the task owner. + [JsonPropertyName("result")] + public JsonElement? Result { get; set; } + + /// Sequence number of the latest accepted owner update. + [JsonPropertyName("sequence")] + public long Sequence { get; set; } + + /// ISO 8601 timestamp when the task started. + [JsonPropertyName("startedAt")] + public DateTimeOffset StartedAt { get; set; } + + /// Client task lifecycle status. + [JsonPropertyName("status")] + public TaskClientStatus Status { get; set; } + + /// Task kind. + [JsonPropertyName("type")] + public TaskClientType Type { get; set; } + + /// ISO 8601 timestamp of the latest accepted lifecycle change. + [JsonPropertyName("updatedAt")] + public DateTimeOffset UpdatedAt { get; set; } } -/// Env-value mode recorded on the session after the update. +/// Result of registering or reclaiming a client-owned task. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpSetEnvValueModeResult +public sealed class TasksRegisterResult { - /// Mode recorded on the session after the update. - [JsonPropertyName("mode")] - public McpSetEnvValueModeDetails Mode { get; set; } + /// True only when this invocation created a new task. + [JsonPropertyName("created")] + public bool Created { get; set; } + + /// True only when this invocation reclaimed an orphaned task. + [JsonPropertyName("reclaimed")] + public bool Reclaimed { get; set; } + + /// Authoritative registered or reclaimed task. + [JsonPropertyName("task")] + public TaskClientInfo Task { get => field ??= new(); set; } } -/// Mode controlling how MCP server env values are resolved (`direct` or `indirect`). +/// Registers or reclaims a client-owned task. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpSetEnvValueModeParams +internal sealed class TasksRegisterRequest { - /// How environment-variable values supplied to MCP servers are resolved. "direct" passes literal string values; "indirect" treats values as references (e.g. names of environment variables on the host) that the runtime resolves before launch. Defaults to the runtime's startup mode; clients that intentionally launch MCP servers with literal values (e.g. CLI prompt mode and ACP) set this to "direct". - [JsonPropertyName("mode")] - public McpSetEnvValueModeDetails Mode { get; set; } + /// Whether the owner supports runtime cancellation requests. + [JsonPropertyName("cancellable")] + public bool Cancellable { get; set; } + + /// Owner-scoped idempotency key used for registration and reclaim. + [JsonPropertyName("clientTaskId")] + public string ClientTaskId { get; set; } = string.Empty; + + /// Human-readable description of the external work. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; + + /// Optional short display name for the external work. + [JsonPropertyName("displayName")] + public string? DisplayName { get; set; } + + /// Expected current sequence for idempotent registration or orphan reclaim. + [JsonPropertyName("expectedSequence")] + public long? ExpectedSequence { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; -} -/// Indicates whether the auto-managed `github` MCP server was removed (false when nothing to remove). -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpRemoveGitHubResult -{ - /// True when the auto-managed `github` MCP server was removed; false when no removal happened (e.g. user has explicitly configured a `github` server, or the server was not registered). - [JsonPropertyName("removed")] - public bool Removed { get; set; } + /// Task kind. + [JsonPropertyName("type")] + public TaskClientType Type { get; set; } } -/// Identifies the target session. +/// Result of publishing a client-owned task update. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMcpRemoveGitHubRequest +public sealed class TasksUpdateResult { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether this invocation changed task state. + [JsonPropertyName("applied")] + public bool Applied { get; set; } + + /// Whether this invocation repeated the latest accepted update. + [JsonPropertyName("duplicate")] + public bool Duplicate { get; set; } + + /// Authoritative task after processing the update. + [JsonPropertyName("task")] + public TaskClientInfo Task { get => field ??= new(); set; } } -/// Result of configuring GitHub MCP. +/// Progress or terminal update for a client-owned task. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpConfigureGitHubResult +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(TaskClientUpdateProgress), "progress")] +[JsonDerivedType(typeof(TaskClientUpdateCompleted), "completed")] +[JsonDerivedType(typeof(TaskClientUpdateFailed), "failed")] +[JsonDerivedType(typeof(TaskClientUpdateCancelled), "cancelled")] +public partial class TaskClientUpdate { - /// Whether GitHub MCP configuration changed. - [JsonPropertyName("changed")] - public bool Changed { get; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Credential-free authentication identity used to configure GitHub MCP. + +/// Publishes nonterminal progress for a running or idle client task. +/// The progress variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpConfigureGitHubRequest +public partial class TaskClientUpdateProgress : TaskClientUpdate { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "progress"; + + /// Optional progress message appended to recent activity when nonempty. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("message")] + public string? Message { get; set; } + + /// Optional completion percentage; null clears the current percentage. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("percentage")] + public double? Percentage { get; set; } + + /// Optional progress phase; null clears the current phase. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("phase")] + public string? Phase { get; set; } + + /// Optional active status transition. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("status")] + public TaskClientActiveStatus? Status { get; set; } } -/// Server name and optional configuration for an individual MCP server start. Omit `config` for a config-free start-by-name of an already-configured server. +/// Reports successful terminal completion. +/// The completed variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpStartServerRequest +public partial class TaskClientUpdateCompleted : TaskClientUpdate { - /// MCP server configuration (stdio process or remote HTTP/SSE). Omit to start the server with its already-registered configuration (config-free start-by-name). - [JsonPropertyName("config")] - public JsonElement? Config { get; set; } + /// + [JsonIgnore] + public override string Kind => "completed"; - /// Exact receipt identity for explicit owned activation in this session. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Optional final progress message. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("message")] + public string? Message { get; set; } - /// Name of the MCP server to start. - [JsonPropertyName("serverName")] - public required string ServerName { get; set; } + /// Optional opaque successful terminal result. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("result")] + public JsonElement? Result { get; set; } } -/// Server name and optional configuration for an individual MCP server start. Omit `config` for a config-free start-by-name of an already-configured server. +/// Reports terminal failure. +/// The failed variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpStartServerRequestWithSession +public partial class TaskClientUpdateFailed : TaskClientUpdate { - /// MCP server configuration (stdio process or remote HTTP/SSE). Omit to start the server with its already-registered configuration (config-free start-by-name). - [JsonPropertyName("config")] - public JsonElement? Config { get; set; } + /// + [JsonIgnore] + public override string Kind => "failed"; - /// Exact receipt identity for explicit owned activation in this session. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Optional owner-supplied terminal failure code. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("code")] + public string? Code { get; set; } - /// Name of the MCP server to start. - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Human-readable terminal failure message. + [JsonPropertyName("error")] + public required string Error { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Optional final progress message. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("message")] + public string? Message { get; set; } } -/// Server name and optional replacement configuration for an individual MCP server restart. Omit `config` for a config-free restart-by-name of an already-configured server. +/// Reports terminal cancellation after external work stopped. +/// The cancelled variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpRestartServerRequest +public partial class TaskClientUpdateCancelled : TaskClientUpdate { - /// Replacement MCP server configuration (stdio process or remote HTTP/SSE). Omit to restart the server with its already-registered configuration (config-free restart-by-name). - [JsonPropertyName("config")] - public JsonElement? Config { get; set; } + /// + [JsonIgnore] + public override string Kind => "cancelled"; - /// Exact receipt identity for an explicit owned restart; configuration overrides are refused. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Optional final progress message. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("message")] + public string? Message { get; set; } - /// Name of the MCP server to restart. - [JsonPropertyName("serverName")] - public required string ServerName { get; set; } + /// Optional human-readable cancellation reason. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("reason")] + public string? Reason { get; set; } } -/// Server name and optional replacement configuration for an individual MCP server restart. Omit `config` for a config-free restart-by-name of an already-configured server. +/// Updates a client-owned task. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpRestartServerRequestWithSession +internal sealed class TasksUpdateRequest { - /// Replacement MCP server configuration (stdio process or remote HTTP/SSE). Omit to restart the server with its already-registered configuration (config-free restart-by-name). - [JsonPropertyName("config")] - public JsonElement? Config { get; set; } - - /// Exact receipt identity for an explicit owned restart; configuration overrides are refused. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Canonical runtime-generated task identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Name of the MCP server to restart. - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Owner update sequence to apply. + [JsonPropertyName("sequence")] + public long Sequence { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Progress or terminal update payload. + [JsonPropertyName("update")] + public TaskClientUpdate Update { get => field ??= new(); set; } } -/// Server name for an individual MCP server stop. +/// Refresh metadata for any detached background shells the runtime knows about. Use after a long pause to pick up exit/output state for shells running outside the agent loop. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpStopServerRequest +public sealed class TasksRefreshResult { - /// Exact owned receipt identity. Stop also forgets this session's durable activation. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } - - /// Name of the MCP server to stop. - [JsonPropertyName("serverName")] - public required string ServerName { get; set; } } -/// Server name for an individual MCP server stop. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpStopServerRequestWithSession +internal sealed class SessionTasksRefreshRequest { - /// Exact owned receipt identity. Stop also forgets this session's durable activation. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } - - /// Name of the MCP server to stop. - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Registration parameters for an external MCP client. +/// Wait until all in-flight background tasks (agents + shells) and any follow-up turns scheduled by their completions have settled. Returns when the runtime is fully drained or after an internal timeout (default 10 minutes; configurable via COPILOT_TASK_WAIT_TIMEOUT_SECONDS). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpRegisterExternalClientRequest +public sealed class TasksWaitForPendingResult { - /// Logical server name for the external client. - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; } -/// Server name identifying the external client to remove. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpUnregisterExternalClientRequest +internal sealed class SessionTasksWaitForPendingRequest { - /// Server name of the external client to unregister. - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Whether the named MCP server is running. +/// Progress information for the task, discriminated by type. Returns null when no task with this ID is currently tracked. +/// Polymorphic base type discriminated by type. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpIsServerRunningResult +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "type", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(TaskProgressAgent), "agent")] +[JsonDerivedType(typeof(TaskProgressClient), "client")] +[JsonDerivedType(typeof(TaskProgressShell), "shell")] +public partial class TaskProgress { - /// True if the server has an active client and transport. - [JsonPropertyName("running")] - public bool Running { get; set; } + /// The type discriminator. + [JsonPropertyName("type")] + public virtual string Type { get; set; } = string.Empty; } -/// Server name to check running status for. + +/// Timestamped display line for task progress output or recent agent activity. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpIsServerRunningRequest +public sealed class TaskProgressLine { - /// Name of the MCP server to check. - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Display message, e.g., "▸ bash", "✓ edit src/foo.ts". + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// ISO 8601 timestamp when this event occurred. + [JsonPropertyName("timestamp")] + public DateTimeOffset Timestamp { get; set; } } -/// Indicates whether the pending MCP OAuth response was accepted. +/// Progress snapshot for an agent task, with recent activity lines and optional latest intent. +/// The agent variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpOauthHandlePendingResult +public partial class TaskProgressAgent : TaskProgress { - /// Whether the response was accepted. False if the request was unknown, timed out, or already resolved. - [JsonPropertyName("success")] - public bool Success { get; set; } -} + /// + [JsonIgnore] + public override string Type => "agent"; -/// Host response to the pending OAuth request. -/// Polymorphic base type discriminated by kind. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpOauthPendingRequestResponseToken), "token")] -[JsonDerivedType(typeof(McpOauthPendingRequestResponseCancelled), "cancelled")] -public partial class McpOauthPendingRequestResponse -{ - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// The most recent intent reported by the agent. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("latestIntent")] + public string? LatestIntent { get; set; } + /// Recent tool execution events converted to display lines. + [JsonPropertyName("recentActivity")] + public required IList RecentActivity { get; set; } +} -/// The token variant of . +/// Generic progress for a client-owned task. +/// The client variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpOauthPendingRequestResponseToken : McpOauthPendingRequestResponse +public partial class TaskProgressClient : TaskProgress { /// [JsonIgnore] - public override string Kind => "token"; + public override string Type => "client"; - /// Access token acquired by the SDK host. - [JsonPropertyName("accessToken")] - public required string AccessToken { get; set; } + /// Most recent nonempty progress message. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("lastMessage")] + public string? LastMessage { get; set; } - /// Token lifetime in seconds, if known. + /// Current completion percentage from zero through one hundred. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("expiresIn")] - public long? ExpiresIn { get; set; } + [JsonPropertyName("percentage")] + public double? Percentage { get; set; } - /// OAuth token type. Defaults to bearer when omitted. + /// Current owner-defined progress phase. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("tokenType")] - public string? TokenType { get; set; } + [JsonPropertyName("phase")] + public string? Phase { get; set; } + + /// Recent server-timestamped progress messages. + [JsonPropertyName("recentActivity")] + public required IList RecentActivity { get; set; } + + /// Sequence number of the latest accepted owner update. + [JsonPropertyName("sequence")] + public required long Sequence { get; set; } + + /// Current client task lifecycle status. + [JsonPropertyName("status")] + public required TaskClientStatus Status { get; set; } + + /// ISO 8601 timestamp of the latest accepted lifecycle change. + [JsonPropertyName("updatedAt")] + public required DateTimeOffset UpdatedAt { get; set; } } -/// The cancelled variant of . +/// Progress snapshot for a shell task, with recent stdout/stderr output and optional process ID. +/// The shell variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpOauthPendingRequestResponseCancelled : McpOauthPendingRequestResponse +public partial class TaskProgressShell : TaskProgress { /// [JsonIgnore] - public override string Kind => "cancelled"; + public override string Type => "shell"; + + /// Process ID when available. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("pid")] + public long? Pid { get; set; } + + /// Recent stdout/stderr lines from the running shell command. + [JsonPropertyName("recentOutput")] + public required string RecentOutput { get; set; } } -/// Pending MCP OAuth request ID and host-provided token or cancellation response. +/// Progress information for the task, or null when no task with that ID is tracked. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpOauthHandlePendingRequest +public sealed class TasksGetProgressResult { - /// OAuth request identifier from the mcp.oauth_required event. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// Progress information for the task, discriminated by type. Returns null when no task with this ID is currently tracked. + [JsonPropertyName("progress")] + public TaskProgress? Progress { get; set; } +} - /// Host response to the pending OAuth request. - [JsonPropertyName("result")] - public McpOauthPendingRequestResponse Result { get => field ??= new(); set; } +/// Identifier of the background task to fetch progress for. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class TasksGetProgressRequest +{ + /// Task identifier (agent ID or shell ID). + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Identifies the MCP server whose persisted OAuth credentials were updated. +/// The first sync-waiting task that can currently be promoted to background mode. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpOauthAuthenticationStateChangedRequest +public sealed class TasksGetCurrentPromotableResult { - /// Whether the target session must mint a session-scoped access token instead of reusing a shared access token persisted by another session. - [JsonPropertyName("refreshSessionToken")] - public bool? RefreshSessionToken { get; set; } - - /// Name of the MCP server whose OAuth credentials were updated. Omit only when the host cannot identify the server. - [JsonPropertyName("serverName")] - public string? ServerName { get; set; } + /// The first sync-waiting task (agent first, then shell) that can currently be promoted to background mode. Omitted if no such task exists. The returned task is guaranteed to have executionMode='sync' and canPromoteToBackground=true at the time of the call. + [JsonPropertyName("task")] + public TaskInfo? Task { get; set; } +} +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionTasksGetCurrentPromotableRequest +{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// An inert runtime-issued login handle. Preparation alone performs no activation or OAuth work. +/// Indicates whether the task was successfully promoted to background mode. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionMcpOauthPrepareLoginResult +public sealed class TasksPromoteToBackgroundResult { - /// Original expiry, not extended by consumption, retries or cancellation. - [JsonPropertyName("expiresAt")] - public DateTimeOffset ExpiresAt { get; set; } - - /// Retain with the original requester and use for one login or cancellation. - [JsonPropertyName("loginId")] - public string LoginId { get; set; } = string.Empty; + /// Whether the task was successfully promoted to background mode. + [JsonPropertyName("promoted")] + public bool Promoted { get; set; } } -/// Effect-free preparation bound to the existing local session, requester and installation, with frozen options. +/// Identifier of the task to promote to background mode. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMcpOauthPrepareLoginRequest +internal sealed class TasksPromoteToBackgroundRequest { - /// Text shown on the loopback callback page after successful authorisation. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(2048)] - [JsonPropertyName("callbackSuccessMessage")] - public string? CallbackSuccessMessage { get; set; } - - /// Display name used by the incumbent OAuth client-registration flow. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(2048)] - [JsonPropertyName("clientName")] - public string? ClientName { get; set; } - - /// Exact installation identity from owned inventory, never a server-name alias. - [JsonPropertyName("expectedInstallationId")] - public string ExpectedInstallationId { get; set; } = string.Empty; - - /// Request a new authorisation rather than accepting a usable cached grant. - [JsonPropertyName("forceReauth")] - public bool? ForceReauth { get; set; } - - /// Name recorded by the authoritative owned installation receipt. - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Task identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// OAuth authorization URL the caller should open, or empty when cached tokens already authenticated the server. +/// The promoted task as it now exists in background mode, omitted if no promotable task was waiting. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpOauthLoginResult +public sealed class TasksPromoteCurrentToBackgroundResult { - /// Opaque authorization identifier returned only for a host-managed redirect URI. The runtime also sends it as the OAuth state value, so the callback endpoint can read state and pass it with the full callback URL to session.mcp.oauth.complete. - [JsonPropertyName("authorizationId")] - public string? AuthorizationId { get; set; } - - /// URL the caller should open in a browser to complete OAuth. Omitted when cached tokens were still valid and no browser interaction was needed — the server is already reconnected in that case. For the default loopback flow, the runtime starts its listener before returning. With redirectUri, the host receives the callback and completes it through session.mcp.oauth.complete. The runtime continues the flow in the background and signals completion via session.mcp_server_status_changed. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("authorizationUrl")] - public string? AuthorizationUrl { get; set; } + /// The promoted task as it now exists in background mode, omitted if no promotable task was waiting. Atomic operation: avoids the race window of getCurrentPromotable + promoteToBackground. + [JsonPropertyName("task")] + public TaskInfo? Task { get; set; } +} - /// Runtime-issued owned flow identity; never a server name or installation operation ID. - [JsonPropertyName("loginId")] - public string? LoginId { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionTasksPromoteCurrentToBackgroundRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Explicit outcome for owned sign-in. Manual callers retain their legacy response shape. - [JsonPropertyName("status")] - public McpOwnedOauthLoginStatus? Status { get; set; } +/// Indicates whether the background task was successfully cancelled. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class TasksCancelResult +{ + /// Whether the task was successfully cancelled. + [JsonPropertyName("cancelled")] + public bool Cancelled { get; set; } } -/// Remote MCP server name and optional overrides controlling reauthentication, OAuth client display name, callback handling, and static OAuth client selection. +/// Identifier of the background task to cancel. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpOauthLoginRequest +internal sealed class TasksCancelRequest { - /// Optional override for the body text shown on the OAuth loopback callback success page. When omitted, the runtime applies a neutral fallback; callers driving interactive auth should pass surface-specific copy telling the user where to return. - [JsonPropertyName("callbackSuccessMessage")] - public string? CallbackSuccessMessage { get; set; } + /// Task identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Optional OAuth client ID override for this login. When set, the runtime uses this pre-registered static client instead of dynamic client registration. - [JsonPropertyName("clientId")] - public string? ClientId { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Optional override for the OAuth client display name shown on the consent screen. Applies to newly registered dynamic clients only — existing registrations keep the name they were created with. When omitted, the runtime applies a neutral fallback; callers driving interactive auth should pass their own surface-specific label so the consent screen matches the product the user sees. - [JsonPropertyName("clientName")] - public string? ClientName { get; set; } +/// Indicates whether the task was removed. False when the task does not exist or is still running/idle. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class TasksRemoveResult +{ + /// Whether the task was removed. Returns false if the task does not exist or is still running/idle (cancel it first). + [JsonPropertyName("removed")] + public bool Removed { get; set; } +} - /// Optional OAuth client secret override for this login. The runtime treats this as an ephemeral host-owned secret, uses it for this authentication attempt and does not persist it. - [JsonPropertyName("clientSecret")] - public string? ClientSecret { get; set; } +/// Identifier of the completed or cancelled task to remove from tracking. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class TasksRemoveRequest +{ + /// Task identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Exact owned receipt identity. Owned login never uses an implicit helper session. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// When true, clears any cached OAuth token for the server and runs a full new authorization. Use when the user explicitly wants to switch accounts or believes their session is stuck. - [JsonPropertyName("forceReauth")] - public bool? ForceReauth { get; set; } +/// Indicates whether the message was delivered, with an error message when delivery failed. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class TasksSendMessageResult +{ + /// Error message if delivery failed. + [JsonPropertyName("error")] + public string? Error { get; set; } - /// Optional OAuth grant type override for this login. Defaults to the server configuration, or authorization_code when no grant type is specified. - [JsonPropertyName("grantType")] - public McpOauthLoginGrantType? GrantType { get; set; } + /// Whether the message was successfully delivered or steered. + [JsonPropertyName("sent")] + public bool Sent { get; set; } +} - /// - /// Required for owned login. Consumes the exact prepareLogin handle once. - /// Set forceReauth and display options during preparation, not consumption. - /// - [JsonPropertyName("loginId")] - public string? LoginId { get; set; } +/// Identifier of the target agent task, message content, and optional sender agent ID. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class TasksSendMessageRequest +{ + /// Agent ID of the sender, if sent on behalf of another agent. + [JsonPropertyName("fromAgentId")] + public string? FromAgentId { get; set; } - /// Optional override indicating whether the static OAuth client is public. When false, the runtime treats it as confidential and uses the per-login clientSecret if provided, otherwise retrieving the client secret from the MCP OAuth secret store. - [JsonPropertyName("publicClient")] - public bool? PublicClient { get; set; } + /// Agent task identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Optional externally visible HTTPS redirect URI for a host-managed callback endpoint. When supplied, the runtime still owns discovery, PKCE, token exchange, persistence, and reconnect, but does not bind a loopback listener or terminate HTTPS. The URI must not contain query parameters or a fragment and must be registered for the selected CIMD, DCR, or static OAuth client. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("redirectUri")] - public string? RedirectUri { get; set; } + /// Message content to send to the agent. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; - /// Name of the remote MCP server to authenticate. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("serverName")] - public required string ServerName { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Remote MCP server name and optional overrides controlling reauthentication, OAuth client display name, callback handling, and static OAuth client selection. +/// Skill metadata available to a session, with name, description, source, enabled/invocable state, path, plugin, and argument hint. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpOauthLoginRequestWithSession +public sealed class Skill { - /// Optional override for the body text shown on the OAuth loopback callback success page. When omitted, the runtime applies a neutral fallback; callers driving interactive auth should pass surface-specific copy telling the user where to return. - [JsonPropertyName("callbackSuccessMessage")] - public string? CallbackSuccessMessage { get; set; } - - /// Optional OAuth client ID override for this login. When set, the runtime uses this pre-registered static client instead of dynamic client registration. - [JsonPropertyName("clientId")] - public string? ClientId { get; set; } - - /// Optional override for the OAuth client display name shown on the consent screen. Applies to newly registered dynamic clients only — existing registrations keep the name they were created with. When omitted, the runtime applies a neutral fallback; callers driving interactive auth should pass their own surface-specific label so the consent screen matches the product the user sees. - [JsonPropertyName("clientName")] - public string? ClientName { get; set; } - - /// Optional OAuth client secret override for this login. The runtime treats this as an ephemeral host-owned secret, uses it for this authentication attempt and does not persist it. - [JsonPropertyName("clientSecret")] - public string? ClientSecret { get; set; } + /// Optional freeform hint describing the skill's expected arguments, from the `argument-hint` frontmatter field. + [JsonPropertyName("argumentHint")] + public string? ArgumentHint { get; set; } - /// Exact owned receipt identity. Owned login never uses an implicit helper session. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Canonical slash command name used to invoke the skill, without the leading '/'. + [JsonPropertyName("commandName")] + public string? CommandName { get; set; } - /// When true, clears any cached OAuth token for the server and runs a full new authorization. Use when the user explicitly wants to switch accounts or believes their session is stuck. - [JsonPropertyName("forceReauth")] - public bool? ForceReauth { get; set; } + /// Description of what the skill does. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// Optional OAuth grant type override for this login. Defaults to the server configuration, or authorization_code when no grant type is specified. - [JsonPropertyName("grantType")] - public McpOauthLoginGrantType? GrantType { get; set; } + /// Whether the skill is currently enabled. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } - /// - /// Required for owned login. Consumes the exact prepareLogin handle once. - /// Set forceReauth and display options during preparation, not consumption. - /// - [JsonPropertyName("loginId")] - public string? LoginId { get; set; } + /// Unique identifier for the skill. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Optional override indicating whether the static OAuth client is public. When false, the runtime treats it as confidential and uses the per-login clientSecret if provided, otherwise retrieving the client secret from the MCP OAuth secret store. - [JsonPropertyName("publicClient")] - public bool? PublicClient { get; set; } + /// Absolute path to the skill file. + [JsonPropertyName("path")] + public string? Path { get; set; } - /// Optional externally visible HTTPS redirect URI for a host-managed callback endpoint. When supplied, the runtime still owns discovery, PKCE, token exchange, persistence, and reconnect, but does not bind a loopback listener or terminate HTTPS. The URI must not contain query parameters or a fragment and must be registered for the selected CIMD, DCR, or static OAuth client. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("redirectUri")] - public string? RedirectUri { get; set; } + /// Name of the plugin that provides the skill, when source is 'plugin'. + [JsonPropertyName("pluginName")] + public string? PluginName { get; set; } - /// Name of the remote MCP server to authenticate. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Source location type (e.g., project, personal-copilot, plugin, builtin). + [JsonPropertyName("source")] + public SkillSource Source { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether the skill can be invoked by the user as a slash command. + [JsonPropertyName("userInvocable")] + public bool UserInvocable { get; set; } } -/// Host-delivered callback for a runtime-managed MCP OAuth login. +/// Skills available to the session, with their enabled state. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpOauthCompleteRequest +public sealed class SkillList { - /// Opaque identifier returned by session.mcp.oauth.login for the pending external callback. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("authorizationId")] - public string AuthorizationId { get; set; } = string.Empty; - - /// Full externally visible HTTPS callback URL received by the host, including the authorization response query parameters. Applications behind a reverse proxy must reconstruct the public URL rather than passing an internal proxy URL. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("callbackUrl")] - public string CallbackUrl { get; set; } = string.Empty; + /// Available skills. + [JsonPropertyName("skills")] + public IList Skills { get => field ??= []; set; } +} +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionSkillsListRequest +{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Passive MCP OAuth probe result. `authenticated` means the server accepted the probe request while an OAuth-origin access token was attached; it does not prove the server required or independently validated that token. The probe does not make a second unauthenticated request. Failed is an expected probe-domain outcome; JSON-RPC errors are reserved for API-call failures. -/// Polymorphic base type discriminated by status. +/// Skill invocation record with name, path, content, allowed tools, and turn number. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "status", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpOauthProbeResultNoAuthRequired), "no-auth-required")] -[JsonDerivedType(typeof(McpOauthProbeResultAuthenticated), "authenticated")] -[JsonDerivedType(typeof(McpOauthProbeResultNeedsAuth), "needs-auth")] -[JsonDerivedType(typeof(McpOauthProbeResultFailed), "failed")] -public partial class McpOauthProbeResult +public sealed class SkillsInvokedSkill { - /// The type discriminator. - [JsonPropertyName("status")] - public virtual string Status { get; set; } = string.Empty; -} + /// Tools that should be auto-approved when this skill is active, captured at invocation time. + [JsonPropertyName("allowedTools")] + public IList? AllowedTools { get; set; } + /// Full content of the skill file. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; -/// The no-auth-required variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpOauthProbeResultNoAuthRequired : McpOauthProbeResult -{ - /// - [JsonIgnore] - public override string Status => "no-auth-required"; + /// Whether model invocation was disabled when this skill was invoked. + [JsonPropertyName("disableModelInvocation")] + public bool? DisableModelInvocation { get; set; } - /// HTTP response returned by the server. - [JsonPropertyName("httpResponse")] - public required McpOauthHttpResponse HttpResponse { get; set; } -} + /// Turn number when the skill was invoked. + [JsonPropertyName("invokedAtTurn")] + public long InvokedAtTurn { get; set; } -/// The authenticated variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpOauthProbeResultAuthenticated : McpOauthProbeResult -{ - /// - [JsonIgnore] - public override string Status => "authenticated"; + /// Unique identifier for the skill. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// HTTP response returned by the server. - [JsonPropertyName("httpResponse")] - public required McpOauthHttpResponse HttpResponse { get; set; } + /// Path to the SKILL.md file, or an empty string for an SDK-provided skill without a filesystem identity. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; } -/// The needs-auth variant of . +/// Skills invoked during this session, ordered by invocation time (most recent last). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpOauthProbeResultNeedsAuth : McpOauthProbeResult +public sealed class SkillsGetInvokedResult { - /// - [JsonIgnore] - public override string Status => "needs-auth"; - - /// HTTP 401 or 403 response returned by the server. - [JsonPropertyName("httpResponse")] - public required McpOauthHttpResponse HttpResponse { get; set; } - - /// Why authentication is needed. - [JsonPropertyName("reason")] - public required McpOauthProbeNeedsAuthReason Reason { get; set; } - - /// Parsed WWW-Authenticate challenge parameters, when present and parseable. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("wwwAuthenticateParams")] - public McpOauthWWWAuthenticateParams? WwwAuthenticateParams { get; set; } + /// Skills invoked during this session, ordered by invocation time (most recent last). + [JsonPropertyName("skills")] + public IList Skills { get => field ??= []; set; } } -/// The failed variant of . +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpOauthProbeResultFailed : McpOauthProbeResult +internal sealed class SessionSkillsGetInvokedRequest { - /// - [JsonIgnore] - public override string Status => "failed"; - - /// Human-readable probe failure detail. - [JsonPropertyName("error")] - public required string Error { get; set; } - - /// HTTP response returned by the server, when the probe reached the server and captured the complete response. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("httpResponse")] - public McpOauthHttpResponse? HttpResponse { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Remote MCP server name for a passive OAuth status probe. +/// Name of the skill to enable for the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpOauthProbeRequest +internal sealed class SkillsEnableRequest { - /// Exact owned receipt identity; probing never activates a dormant installation. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } + /// Name of the skill to enable. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Name of the configured remote MCP server to probe. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("serverName")] - public required string ServerName { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Remote MCP server name for a passive OAuth status probe. +/// Name of the skill to disable for the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpOauthProbeRequestWithSession +internal sealed class SkillsDisableRequest { - /// Exact owned receipt identity; probing never activates a dormant installation. - [JsonPropertyName("expectedInstallationId")] - public string? ExpectedInstallationId { get; set; } - - /// Name of the configured remote MCP server to probe. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; + /// Name of the skill to disable. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Honest terminal cancellation result; persistence or recovery failures remain RPC errors. +/// Diagnostics from reloading skill definitions, with warnings and errors as separate lists. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionMcpOauthCancelLoginResult +public sealed class SkillsLoadDiagnostics { - /// True after cancellation settles, false when the original login already connected successfully. - [JsonPropertyName("cancelled")] - public bool Cancelled { get; set; } + /// Errors emitted while loading skills (e.g. skills that failed to load entirely). + [JsonPropertyName("errors")] + public IList Errors { get => field ??= []; set; } + + /// Warnings emitted while loading skills (e.g. skills that loaded but had issues). + [JsonPropertyName("warnings")] + public IList Warnings { get => field ??= []; set; } } -/// Targets only the original prepared/applying owned login on this exact session requester. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMcpOauthCancelLoginRequest +internal sealed class SessionSkillsReloadRequest { - /// The same authoritative installation identity supplied during preparation. - [JsonPropertyName("expectedInstallationId")] - public string ExpectedInstallationId { get; set; } = string.Empty; - - /// Runtime-issued login handle known before the effectful login request begins. - [JsonPropertyName("loginId")] - public string LoginId { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionSkillsEnsureLoadedRequest +{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the pending MCP OAuth response was accepted. +/// The IDE a host is connected to, as reported to the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpOauthRespondResult +public sealed class SessionConnectedIdeInfo { - /// Whether the response was accepted. False if the request was unknown, timed out, or already resolved. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Display name of the connected IDE, for example `VS Code`. + [JsonPropertyName("ideName")] + public string IdeName { get; set; } = string.Empty; + + /// Absolute path of the workspace folder the IDE has open. + [JsonPropertyName("workspaceFolder")] + public string WorkspaceFolder { get; set; } = string.Empty; } -/// Pending MCP OAuth request id to respond to. +/// Records which IDE the host is connected to, or clears it. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpOauthRespondRequest +internal sealed class SessionMcpSetConnectedIdeInfoParams { - /// OAuth request identifier from the mcp.oauth_required event. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// The connected IDE. Null or omitted clears the recorded IDE, which is how a host reports that it is disconnected. + [JsonPropertyName("ide")] + public SessionConnectedIdeInfo? Ide { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the pending MCP headers refresh response was accepted. +/// Recorded MCP server connection failure. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpHeadersHandlePendingHeadersRefreshRequestResult +public sealed class McpServerFailureInfo { - /// Whether the response was accepted. False if the request was unknown, timed out, or already resolved. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Failure message produced when the MCP server connection failed. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; + + /// epoch-ms timestamp at which the failure was recorded. + [JsonPropertyName("timestamp")] + public long Timestamp { get; set; } } -/// Host response: supply dynamic headers or decline this refresh. -/// Polymorphic base type discriminated by kind. +/// Recorded MCP server pending-auth state. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpHeadersHandlePendingHeadersRefreshRequestHeaders), "headers")] -[JsonDerivedType(typeof(McpHeadersHandlePendingHeadersRefreshRequestNone), "none")] -[JsonDerivedType(typeof(McpHeadersHandlePendingHeadersRefreshRequestError), "error")] -public partial class McpHeadersHandlePendingHeadersRefreshRequest +public sealed class McpServerNeedsAuthInfo { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; + /// epoch-ms timestamp at which the server signalled it needs authentication. + [JsonPropertyName("timestamp")] + public long Timestamp { get; set; } } - -/// The headers variant of . +/// Host-level state, omitted when no MCP host is initialized. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpHeadersHandlePendingHeadersRefreshRequestHeaders : McpHeadersHandlePendingHeadersRefreshRequest +public sealed class McpHostState { - /// - [JsonIgnore] - public override string Kind => "headers"; + /// Names of currently-connected MCP clients. + [JsonPropertyName("clients")] + public IList Clients { get => field ??= []; set; } - /// Headers to overlay onto the MCP request. Dynamic headers override static config headers but do not replace SDK-managed request headers. - [JsonPropertyName("headers")] - public required IDictionary Headers { get; set; } + /// Configured servers that are explicitly disabled. + [JsonPropertyName("disabledServers")] + public IList DisabledServers { get => field ??= []; set; } - /// Optional lifetime in milliseconds for these returned headers. The runtime clamps its configured cache lifetime to this value. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("ttlMs")] - public long? TtlMs { get; set; } + /// Map of server name to recorded connection failure. + [JsonPropertyName("failedServers")] + public IDictionary FailedServers { get => field ??= new Dictionary(); set; } + + /// Configured servers filtered out by MCP server policy. + [JsonPropertyName("filteredServers")] + public IList FilteredServers { get => field ??= []; set; } + + /// Whether third-party MCP servers are policy-enabled for this session. + [JsonPropertyName("mcp3pEnabled")] + public bool Mcp3pEnabled { get; set; } + + /// Map of server name to recorded pending-auth state. + [JsonPropertyName("needsAuthServers")] + public IDictionary NeedsAuthServers { get => field ??= new Dictionary(); set; } + + /// Names of servers with in-flight connection attempts. + [JsonPropertyName("pendingConnections")] + public IList PendingConnections { get => field ??= []; set; } } -/// The none variant of . +/// Owned installation that a listed MCP server's live configuration came from. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpHeadersHandlePendingHeadersRefreshRequestNone : McpHeadersHandlePendingHeadersRefreshRequest +public sealed class McpServerOwnership { - /// - [JsonIgnore] - public override string Kind => "none"; + /// Stable installation identifier from the owned installation receipt. + [JsonPropertyName("installationId")] + public string InstallationId { get; set; } = string.Empty; } -/// The error variant of . +/// MCP server status entry, including config source/plugin source and any connection error. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpHeadersHandlePendingHeadersRefreshRequestError : McpHeadersHandlePendingHeadersRefreshRequest +public sealed class McpServer { - /// - [JsonIgnore] - public override string Kind => "error"; + /// Human-readable display name supplied by a managed server catalog. + [JsonPropertyName("displayName")] + public string? DisplayName { get; set; } - /// Host credential broker failure, denial, or revocation reason. - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Error message if the server failed to connect. + [JsonPropertyName("error")] + public string? Error { get; set; } + + /// Server name (config key). + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Owned installation this entry's live configuration came from. Absent for manual, workspace, plugin, builtin and same-name servers, and on runtimes without owned installations. + [JsonPropertyName("owned")] + public McpServerOwnership? Owned { get; set; } + + /// Server-advertised metadata for a connected server. Omitted when no live connection metadata is available, including while pending or when failed, disabled, stopped, or not configured. + [JsonPropertyName("serverMetadata")] + public McpServerMetadata? ServerMetadata { get; set; } + + /// Configuration source: user, workspace, plugin, builtin, or managed. + [JsonPropertyName("source")] + public McpServerSource? Source { get; set; } + + /// Plugin name that provided this server, when source is plugin. + [JsonPropertyName("sourcePlugin")] + public string? SourcePlugin { get; set; } + + /// Plugin version that provided this server, when source is plugin. + [JsonPropertyName("sourcePluginVersion")] + public string? SourcePluginVersion { get; set; } + + /// Connection status: connected, failed, needs-auth, pending, disabled, stopped, or not_configured. + [JsonPropertyName("status")] + public McpServerStatus Status { get; set; } + + /// Configured URL for an HTTP/SSE server, regardless of configuration source. Omitted for local and in-memory servers. + [JsonPropertyName("url")] + public string? Url { get; set; } } -/// MCP headers refresh request id and the host response. +/// MCP servers configured for the session, with their connection status and host-level state. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpHeadersHandlePendingHeadersRefreshRequestRequest +public sealed class McpServerList { - /// Headers refresh request identifier from mcp.headers_refresh_required. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// Host-level state, omitted when no MCP host is initialized. + [JsonPropertyName("host")] + public McpHostState? Host { get; set; } - /// Host response: supply dynamic headers or decline this refresh. - [JsonPropertyName("result")] - public McpHeadersHandlePendingHeadersRefreshRequest Result { get => field ??= new(); set; } + /// Configured MCP servers. + [JsonPropertyName("servers")] + public IList Servers { get => field ??= []; set; } +} +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionMcpListRequest +{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// MCP Apps resource content with URI, optional MIME type, text or base64 blob, and resource metadata. +/// Observational state for a matching already materialized MCP server. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpAppsResourceContent +public sealed class McpConfiguredServerState { - /// Resource-level metadata (CSP, permissions, etc.). - [JsonPropertyName("_meta")] - public IDictionary? Meta { get; set; } + /// Observed connection error, when the materialized server failed. + [JsonPropertyName("error")] + public string? Error { get; set; } - /// Base64-encoded binary content. - [JsonPropertyName("blob")] - public string? Blob { get; set; } + /// Observed connection status. This is not a configuration or readiness guarantee. + [JsonPropertyName("status")] + public McpServerStatus Status { get; set; } +} - /// MIME type of the content. - [JsonPropertyName("mimeType")] - public string? MimeType { get; set; } +/// Effective MCP configuration entry. Configuration enablement is distinct from the optional live observation. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpConfiguredServer +{ + /// Human-readable display name supplied by configuration. + [JsonPropertyName("displayName")] + public string? DisplayName { get; set; } - /// Text content (e.g. HTML). - [JsonPropertyName("text")] - public string? Text { get; set; } + /// Whether this configured server is enabled after session configuration and policy filtering. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } - /// The resource URI (typically ui://...). - [JsonPropertyName("uri")] - public string Uri { get; set; } = string.Empty; + /// Observed state from an already materialized matching server. Omitted when no live graph has this configured server; it never determines configuration enablement. + [JsonPropertyName("live")] + public McpConfiguredServerState Live { get => field ??= new(); set; } + + /// Server name (config key). + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Configuration provenance: user, workspace, plugin, builtin, or managed. + [JsonPropertyName("source")] + public McpServerSource? Source { get; set; } + + /// Plugin name that provided this server, when source is plugin. + [JsonPropertyName("sourcePlugin")] + public string? SourcePlugin { get; set; } + + /// Plugin version that provided this server, when source is plugin. + [JsonPropertyName("sourcePluginVersion")] + public string? SourcePluginVersion { get; set; } } -/// Resource contents returned by the MCP server. +/// Effective MCP configuration with optional live observations from matching already materialized servers. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpAppsReadResourceResult +public sealed class McpConfiguredServerList { - /// Resource contents returned by the server. - [JsonPropertyName("contents")] - public IList Contents { get => field ??= []; set; } + /// Effective configured MCP servers. + [JsonPropertyName("servers")] + public IList Servers { get => field ??= []; set; } } -/// MCP server and resource URI to fetch. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpAppsReadResourceRequest +internal sealed class SessionMcpListConfiguredRequest { - /// Name of the MCP server hosting the resource. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; +} - /// Resource URI (typically ui://...). - [JsonPropertyName("uri")] - public string Uri { get; set; } = string.Empty; +/// Normalized MCP Apps discovery metadata from a tool's `_meta.ui` block. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpToolUi +{ + /// URI of the tool's MCP App resource, typically a `ui://` resource identifier. Use `session.mcp.resources.read` to fetch its HTML and resource metadata. + [JsonPropertyName("resourceUri")] + public string? ResourceUri { get; set; } + + /// Tool visibility advertised by the server. When absent, MCP Apps defaults apply. + [JsonPropertyName("visibility")] + public IList? Visibility { get; set; } } -/// App-callable tools from the named MCP server. +/// MCP tool metadata with tool name, optional description, and normalized MCP Apps discovery metadata. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpAppsListToolsResult +public sealed class McpTools { - /// App-callable tools from the server. - [JsonPropertyName("tools")] - public IList> Tools { get => field ??= []; set; } + /// Tool description, when provided. + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Tool name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Normalized MCP Apps discovery metadata. An empty object indicates that a valid `_meta.ui` block was present without recognized fields. + [JsonPropertyName("ui")] + public McpToolUi? Ui { get; set; } } -/// MCP server to list app-callable tools for. +/// Tools exposed by the connected MCP server. Throws when the server is not connected. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpAppsListToolsRequest +public sealed class McpListToolsResult { - /// **Required.** Server whose ui:// view issued the request. Per SEP-1865 ('callable by the app from this server only'), the call is rejected when this differs from `serverName`, and rejected outright when missing. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("originServerName")] - public string OriginServerName { get; set; } = string.Empty; + /// Tools exposed by the server. + [JsonPropertyName("tools")] + public IList Tools { get => field ??= []; set; } +} - /// MCP server hosting the app. +/// Server name whose tool list should be returned. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpListToolsRequest +{ + /// Name of the connected MCP server whose tools to list. [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] [MinLength(1)] @@ -18802,22 +18995,31 @@ internal sealed class McpAppsListToolsRequest public string SessionId { get; set; } = string.Empty; } -/// MCP server, tool name, and arguments to invoke from an MCP App view. +/// Name of the MCP server to enable for the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpAppsCallToolRequest +public sealed class McpEnableRequest { - /// Tool arguments. - [JsonPropertyName("arguments")] - public IDictionary? Arguments { get; set; } + /// Exact receipt identity for explicit owned activation in this session. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } - /// **Required.** Server whose ui:// view issued the request. Per SEP-1865 ('callable by the app from this server only'), the call is rejected when this differs from `serverName`, and rejected outright when missing. + /// Name of the MCP server to enable. [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] [MinLength(1)] - [JsonPropertyName("originServerName")] - public string OriginServerName { get; set; } = string.Empty; + [JsonPropertyName("serverName")] + public required string ServerName { get; set; } +} - /// MCP server hosting the tool. +/// Name of the MCP server to enable for the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpEnableRequestWithSession +{ + /// Exact receipt identity for explicit owned activation in this session. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } + + /// Name of the MCP server to enable. [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] [MinLength(1)] @@ -18827,420 +19029,302 @@ internal sealed class McpAppsCallToolRequest /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// MCP tool name. - [JsonPropertyName("toolName")] - public string ToolName { get; set; } = string.Empty; } -/// Host context advertised to MCP App guests. +/// Name of the MCP server to disable for the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpAppsSetHostContextDetails +public sealed class McpDisableRequest { - /// Display modes the host supports. - [JsonPropertyName("availableDisplayModes")] - public IList? AvailableDisplayModes { get; set; } - - /// Current display mode (SEP-1865). - [JsonPropertyName("displayMode")] - public McpAppsSetHostContextDetailsDisplayMode? DisplayMode { get; set; } - - /// BCP-47 locale, e.g. 'en-US'. - [JsonPropertyName("locale")] - public string? Locale { get; set; } - - /// Platform type for responsive design. - [JsonPropertyName("platform")] - public McpAppsSetHostContextDetailsPlatform? Platform { get; set; } - - /// UI theme preference per SEP-1865. - [JsonPropertyName("theme")] - public McpAppsSetHostContextDetailsTheme? Theme { get; set; } - - /// IANA timezone, e.g. 'America/New_York'. - [JsonPropertyName("timeZone")] - public string? TimeZone { get; set; } + /// Required for an owned installation; omission preserves only manual-server behaviour. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } - /// Host application identifier. - [JsonPropertyName("userAgent")] - public string? UserAgent { get; set; } + /// Name of the MCP server to disable. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("serverName")] + public required string ServerName { get; set; } } -/// Host context to advertise to MCP App guests. +/// Name of the MCP server to disable for the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpAppsSetHostContextRequest +internal sealed class McpDisableRequestWithSession { - /// Host context advertised to MCP App guests. - [JsonPropertyName("context")] - public McpAppsSetHostContextDetails Context { get => field ??= new(); set; } + /// Required for an owned installation; omission preserves only manual-server behaviour. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } + + /// Name of the MCP server to disable. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Current host context. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpAppsHostContextDetails +internal sealed class SessionMcpReloadRequest { - /// Display modes the host supports. - [JsonPropertyName("availableDisplayModes")] - public IList? AvailableDisplayModes { get; set; } - - /// Current display mode (SEP-1865). - [JsonPropertyName("displayMode")] - public McpAppsHostContextDetailsDisplayMode? DisplayMode { get; set; } - - /// BCP-47 locale, e.g. 'en-US'. - [JsonPropertyName("locale")] - public string? Locale { get; set; } - - /// Platform type for responsive design. - [JsonPropertyName("platform")] - public McpAppsHostContextDetailsPlatform? Platform { get; set; } - - /// UI theme preference per SEP-1865. - [JsonPropertyName("theme")] - public McpAppsHostContextDetailsTheme? Theme { get; set; } - - /// IANA timezone, e.g. 'America/New_York'. - [JsonPropertyName("timeZone")] - public string? TimeZone { get; set; } - - /// Host application identifier. - [JsonPropertyName("userAgent")] - public string? UserAgent { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Current host context advertised to MCP App guests. +/// Result of moving in-flight MCP loading to the background. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpAppsHostContext +public sealed class MoveMcpLoadingToBackgroundResult { - /// Current host context. - [JsonPropertyName("context")] - public McpAppsHostContextDetails Context { get => field ??= new(); set; } + /// Whether an in-flight MCP load was moved to the background, releasing turns that were waiting on it. False when no MCP load was in flight or the waiting turns had already been released. + [JsonPropertyName("movedToBackground")] + public bool MovedToBackground { get; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMcpAppsGetHostContextRequest +internal sealed class SessionMcpMoveLoadingToBackgroundRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Capability negotiation snapshot. +/// MCP server allowed by policy, with server name and optional PII-free explanatory note. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpAppsDiagnoseCapability +public sealed class McpAllowedServer { - /// Whether the runtime advertises `extensions.io.modelcontextprotocol/ui` to MCP servers. - [JsonPropertyName("advertised")] - public bool Advertised { get; set; } + /// Allowed server name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Whether the MCP_APPS feature flag (or COPILOT_MCP_APPS env override) is on. - [JsonPropertyName("featureFlagEnabled")] - public bool FeatureFlagEnabled { get; set; } + /// PII-free note explaining why the server was allowed. + [JsonPropertyName("redactedNote")] + public string? RedactedNote { get; set; } +} - /// Whether the session has the `mcp-apps` capability. - [JsonPropertyName("sessionHasMcpApps")] - public bool SessionHasMcpApps { get; set; } +/// MCP server whose connection attempt failed. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpFailedServer +{ + /// The captured connection failure detail. + [JsonPropertyName("error")] + public string? Error { get; set; } + + /// The config key of the server that failed to connect. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// What the server returned for this session. +/// MCP server filtered by policy, with name, reason, and optional redacted reason. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpAppsDiagnoseServer +public sealed class McpFilteredServer { - /// Whether the named server is currently connected. - [JsonPropertyName("connected")] - public bool Connected { get; set; } + /// Deprecated. This field is no longer populated. + [EditorBrowsable(EditorBrowsableState.Never)] +#if NET5_0_OR_GREATER + [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] +#else + [Obsolete("This member is deprecated and will be removed in a future version.")] +#endif + [JsonPropertyName("enterpriseName")] + public string? EnterpriseName { get; set; } - /// Up to 5 tool names with `_meta.ui` for quick inspection. - [JsonPropertyName("sampleToolNames")] - public IList SampleToolNames { get => field ??= []; set; } + /// Filtered server name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// Total tools returned by the server's tools/list. - [JsonPropertyName("toolCount")] - public double ToolCount { get; set; } + /// Human-readable filter reason. + [JsonPropertyName("reason")] + public string Reason { get; set; } = string.Empty; - /// Tools whose `_meta.ui` is populated (resourceUri and/or visibility set). - [JsonPropertyName("toolsWithUiMeta")] - public double ToolsWithUiMeta { get; set; } + /// PII-free filter reason. + [JsonPropertyName("redactedReason")] + public string? RedactedReason { get; set; } } -/// Diagnostic snapshot of MCP Apps wiring for the named server. +/// MCP server startup filtering result. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpAppsDiagnoseResult +internal sealed class McpStartServersResult { - /// Capability negotiation snapshot. - [JsonPropertyName("capability")] - public McpAppsDiagnoseCapability Capability { get => field ??= new(); set; } + /// Non-default servers allowed by policy. + [JsonPropertyName("allowedServers")] + public IList? AllowedServers { get; set; } - /// What the server returned for this session. - [JsonPropertyName("server")] - public McpAppsDiagnoseServer Server { get => field ??= new(); set; } + /// Servers whose connection attempt failed. + [JsonPropertyName("failedServers")] + public IList? FailedServers { get; set; } + + /// Servers filtered out before startup. + [JsonPropertyName("filteredServers")] + public IList FilteredServers { get => field ??= []; set; } } -/// MCP server to diagnose MCP Apps wiring for. +/// Opaque MCP reload configuration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpAppsDiagnoseRequest +internal sealed class McpReloadWithConfigRequest { - /// MCP server to probe. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// MCP resource content with URI, optional MIME type, text or base64 blob, and resource metadata. +/// Outcome of an MCP sampling execution: success result, failure error, or cancellation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpResourceContent +public sealed class McpSamplingExecutionResult { - /// Resource-level metadata (CSP, permissions, etc.). - [JsonPropertyName("_meta")] - public IDictionary? Meta { get; set; } - - /// Base64-encoded binary content. - [JsonPropertyName("blob")] - public string? Blob { get; set; } + /// Outcome of the sampling inference. 'success' produced a response; 'failure' encountered an error (including agent-side rejection by content filter or criteria); 'cancelled' the caller cancelled this execution via cancelSamplingExecution. + [JsonPropertyName("action")] + public McpSamplingExecutionAction Action { get; set; } - /// MIME type of the content. - [JsonPropertyName("mimeType")] - public string? MimeType { get; set; } + /// Error description, present when action='failure'. + [JsonPropertyName("error")] + public string? Error { get; set; } - /// Text content (e.g. HTML). - [JsonPropertyName("text")] - public string? Text { get; set; } - - /// The resource URI. - [JsonPropertyName("uri")] - public string Uri { get; set; } = string.Empty; + /// MCP CreateMessageResult payload (with optional 'tools' extension), present when action='success'. Treated as opaque at the schema layer; consumers should construct/consume it per the MCP CreateMessageResult shape. + [JsonPropertyName("result")] + public JsonElement? Result { get; set; } } -/// Resource contents returned by the MCP server. +/// Identifiers and raw MCP CreateMessageRequest params used to run a sampling inference. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpResourcesReadResult +internal sealed class McpExecuteSamplingParams { - /// Resource contents returned by the server. - [JsonPropertyName("contents")] - public IList Contents { get => field ??= []; set; } -} + /// The original MCP JSON-RPC request ID (string or number). Used by the runtime to correlate the inference with the originating MCP request for telemetry; this is distinct from `requestId` (which is the schema-level cancellation handle). + [JsonPropertyName("mcpRequestId")] + public JsonElement McpRequestId { get; set; } -/// MCP server and resource URI to fetch. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpResourcesReadRequest -{ - /// Name of the MCP server hosting the resource. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] + /// Raw MCP CreateMessageRequest params, as received in the `sampling.requested` event. Treated as opaque at the schema layer; the runtime converts the embedded MCP messages into the OpenAI chat-completion shape internally. + [JsonPropertyName("request")] + public JsonElement Request { get; set; } + + /// Caller-provided unique identifier for this sampling execution. Use this same ID with cancelSamplingExecution to cancel the in-flight call. Must be unique within the session for the lifetime of the call. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; + + /// Name of the MCP server that initiated the sampling request. [JsonPropertyName("serverName")] public string ServerName { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// Resource URI. - [JsonPropertyName("uri")] - public string Uri { get; set; } = string.Empty; } -/// Standard MCP resource annotations plus preserved non-standard annotation fields. +/// Indicates whether an in-flight sampling execution with the given requestId was found and cancelled. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpResourceAnnotations +public sealed class McpCancelSamplingExecutionResult { - /// Server-provided non-standard annotation fields preserved from the MCP response. - [JsonPropertyName("additionalProperties")] - public IDictionary? AdditionalProperties { get; set; } - - /// Intended audience roles for this resource. - [JsonPropertyName("audience")] - public IList? Audience { get; set; } - - /// Last-modified timestamp hint. - [JsonPropertyName("lastModified")] - public string? LastModified { get; set; } - - /// Priority hint for model/client use. - [JsonPropertyName("priority")] - public double? Priority { get; set; } + /// True if an in-flight execution with the given requestId was found and signalled to cancel. False when no such execution is in flight (already completed, never started, or cancelled by another caller). + [JsonPropertyName("cancelled")] + public bool Cancelled { get; set; } } -/// A resource icon descriptor plus preserved non-standard icon fields. +/// The requestId previously passed to executeSampling that should be cancelled. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpResourceIcon +internal sealed class McpCancelSamplingExecutionParams { - /// Server-provided non-standard icon fields preserved from the MCP response. - [JsonPropertyName("additionalProperties")] - public IDictionary? AdditionalProperties { get; set; } - - /// Icon MIME type, when known. - [JsonPropertyName("mimeType")] - public string? MimeType { get; set; } - - /// Icon sizes hint. - [JsonPropertyName("sizes")] - public string? Sizes { get; set; } - - /// Icon URI. - [JsonPropertyName("src")] - public string Src { get; set; } = string.Empty; + /// The requestId previously passed to executeSampling that should be cancelled. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; - /// Theme hint for this icon. - [JsonPropertyName("theme")] - public string? Theme { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// An MCP resource descriptor (spec `Resource`): URI, name, and optional title, description, MIME type, size, icons, annotations, and metadata. Server-provided fields outside the standard descriptor shape are exposed under `additionalProperties`. +/// Env-value mode recorded on the session after the update. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpResource +public sealed class McpSetEnvValueModeResult { - /// Resource-level metadata. - [JsonPropertyName("_meta")] - public IDictionary? Meta { get; set; } - - /// Server-provided non-standard descriptor fields preserved from the MCP response. - [JsonPropertyName("additionalProperties")] - public IDictionary? AdditionalProperties { get; set; } - - /// Model/client annotations associated with this resource. - [JsonPropertyName("annotations")] - public McpResourceAnnotations? Annotations { get; set; } - - /// Optional description of what this resource represents. - [JsonPropertyName("description")] - public string? Description { get; set; } - - /// Icons associated with this resource. - [JsonPropertyName("icons")] - public IList? Icons { get; set; } - - /// MIME type of the resource, if known. - [JsonPropertyName("mimeType")] - public string? MimeType { get; set; } - - /// The programmatic name of the resource. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - - /// Resource size in bytes, when known. - [JsonPropertyName("size")] - public long? Size { get; set; } - - /// Optional human-readable display title. - [JsonPropertyName("title")] - public string? Title { get; set; } - - /// The resource URI (e.g. ui://... or file:///...). - [JsonPropertyName("uri")] - public string Uri { get; set; } = string.Empty; + /// Mode recorded on the session after the update. + [JsonPropertyName("mode")] + public McpSetEnvValueModeDetails Mode { get; set; } } -/// One page of resources advertised by the named MCP server. +/// Mode controlling how MCP server env values are resolved (`direct` or `indirect`). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpResourcesListResult +internal sealed class McpSetEnvValueModeParams { - /// Opaque cursor for the next page, if the server has more resources. - [JsonPropertyName("nextCursor")] - public string? NextCursor { get; set; } + /// How environment-variable values supplied to MCP servers are resolved. "direct" passes literal string values; "indirect" treats values as references (e.g. names of environment variables on the host) that the runtime resolves before launch. Defaults to the runtime's startup mode; clients that intentionally launch MCP servers with literal values (e.g. CLI prompt mode and ACP) set this to "direct". + [JsonPropertyName("mode")] + public McpSetEnvValueModeDetails Mode { get; set; } - /// Resources advertised by the server (proxied MCP `resources/list`). - [JsonPropertyName("resources")] - public IList Resources { get => field ??= []; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// MCP server whose resources to enumerate. +/// Indicates whether the auto-managed `github` MCP server was removed (false when nothing to remove). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpResourcesListRequest +public sealed class McpRemoveGitHubResult { - /// Opaque MCP pagination cursor from a prior `nextCursor` value. - [JsonPropertyName("cursor")] - public string? Cursor { get; set; } - - /// Name of the MCP server whose resources to enumerate. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; + /// True when the auto-managed `github` MCP server was removed; false when no removal happened (e.g. user has explicitly configured a `github` server, or the server was not registered). + [JsonPropertyName("removed")] + public bool Removed { get; set; } +} +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionMcpRemoveGitHubRequest +{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// An MCP resource template descriptor (spec `ResourceTemplate`): an RFC 6570 URI template, name, and optional title, description, MIME type, icons, annotations, and metadata. Server-provided fields outside the standard descriptor shape are exposed under `additionalProperties`. +/// Result of configuring GitHub MCP. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpResourceTemplate +internal sealed class McpConfigureGitHubResult { - /// Resource-template-level metadata. - [JsonPropertyName("_meta")] - public IDictionary? Meta { get; set; } - - /// Server-provided non-standard descriptor fields preserved from the MCP response. - [JsonPropertyName("additionalProperties")] - public IDictionary? AdditionalProperties { get; set; } - - /// Model/client annotations associated with this template. - [JsonPropertyName("annotations")] - public McpResourceAnnotations? Annotations { get; set; } - - /// Optional description of what this template is for. - [JsonPropertyName("description")] - public string? Description { get; set; } - - /// Icons associated with resources matching this template. - [JsonPropertyName("icons")] - public IList? Icons { get; set; } - - /// MIME type for resources matching this template, if uniform. - [JsonPropertyName("mimeType")] - public string? MimeType { get; set; } - - /// The programmatic name of the resource template. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - - /// Optional human-readable display title. - [JsonPropertyName("title")] - public string? Title { get; set; } + /// Whether GitHub MCP configuration changed. + [JsonPropertyName("changed")] + public bool Changed { get; set; } +} - /// An RFC 6570 URI template for constructing resource URIs. - [JsonPropertyName("uriTemplate")] - public string UriTemplate { get; set; } = string.Empty; +/// Credential-free authentication identity used to configure GitHub MCP. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpConfigureGitHubRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// One page of resource templates advertised by the named MCP server. +/// Server name and optional configuration for an individual MCP server start. Omit `config` for a config-free start-by-name of an already-configured server. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpResourcesListTemplatesResult +public sealed class McpStartServerRequest { - /// Opaque cursor for the next page, if the server has more resource templates. - [JsonPropertyName("nextCursor")] - public string? NextCursor { get; set; } + /// MCP server configuration (stdio process or remote HTTP/SSE). Omit to start the server with its already-registered configuration (config-free start-by-name). + [JsonPropertyName("config")] + public JsonElement? Config { get; set; } - /// Resource templates advertised by the server (proxied MCP `resources/templates/list`). - [JsonPropertyName("resourceTemplates")] - public IList ResourceTemplates { get => field ??= []; set; } + /// Exact receipt identity for explicit owned activation in this session. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } + + /// Name of the MCP server to start. + [JsonPropertyName("serverName")] + public required string ServerName { get; set; } } -/// MCP server whose resource templates to enumerate. +/// Server name and optional configuration for an individual MCP server start. Omit `config` for a config-free start-by-name of an already-configured server. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpResourcesListTemplatesRequest +internal sealed class McpStartServerRequestWithSession { - /// Opaque MCP pagination cursor from a prior `nextCursor` value. - [JsonPropertyName("cursor")] - public string? Cursor { get; set; } + /// MCP server configuration (stdio process or remote HTTP/SSE). Omit to start the server with its already-registered configuration (config-free start-by-name). + [JsonPropertyName("config")] + public JsonElement? Config { get; set; } - /// Name of the MCP server whose resource templates to enumerate. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] + /// Exact receipt identity for explicit owned activation in this session. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } + + /// Name of the MCP server to start. [JsonPropertyName("serverName")] public string ServerName { get; set; } = string.Empty; @@ -19249,122 +19333,79 @@ internal sealed class McpResourcesListTemplatesRequest public string SessionId { get; set; } = string.Empty; } -/// An argument accepted by an MCP prompt. +/// Server name and optional replacement configuration for an individual MCP server restart. Omit `config` for a config-free restart-by-name of an already-configured server. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPromptArgument +public sealed class McpRestartServerRequest { - /// Argument-level metadata. - [JsonPropertyName("_meta")] - public IDictionary? Meta { get; set; } - - /// Server-provided non-standard argument fields. - [JsonPropertyName("additionalProperties")] - public IDictionary? AdditionalProperties { get; set; } - - /// Description of the argument. - [JsonPropertyName("description")] - public string? Description { get; set; } + /// Replacement MCP server configuration (stdio process or remote HTTP/SSE). Omit to restart the server with its already-registered configuration (config-free restart-by-name). + [JsonPropertyName("config")] + public JsonElement? Config { get; set; } - /// Name of the argument. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Exact receipt identity for an explicit owned restart; configuration overrides are refused. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } - /// Whether the argument is required; omission is distinct from false. - [JsonPropertyName("required")] - public bool? Required { get; set; } + /// Name of the MCP server to restart. + [JsonPropertyName("serverName")] + public required string ServerName { get; set; } } -/// An MCP prompt icon with standard size hints and preserved non-standard fields. +/// Server name and optional replacement configuration for an individual MCP server restart. Omit `config` for a config-free restart-by-name of an already-configured server. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPromptIcon +internal sealed class McpRestartServerRequestWithSession { - /// Server-provided non-standard icon fields. - [JsonPropertyName("additionalProperties")] - public IDictionary? AdditionalProperties { get; set; } - - /// Icon MIME type, when known. - [JsonPropertyName("mimeType")] - public string? MimeType { get; set; } + /// Replacement MCP server configuration (stdio process or remote HTTP/SSE). Omit to restart the server with its already-registered configuration (config-free restart-by-name). + [JsonPropertyName("config")] + public JsonElement? Config { get; set; } - /// Icon sizes, such as `48x48` or `any`. - [JsonPropertyName("sizes")] - public IList? Sizes { get; set; } + /// Exact receipt identity for an explicit owned restart; configuration overrides are refused. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } - /// Icon URI. - [JsonPropertyName("src")] - public string Src { get; set; } = string.Empty; + /// Name of the MCP server to restart. + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; - /// Theme hint for this icon. - [JsonPropertyName("theme")] - public string? Theme { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// An MCP prompt descriptor. Server-provided non-standard fields are exposed under `additionalProperties`. +/// Server name for an individual MCP server stop. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPrompt +public sealed class McpStopServerRequest { - /// Prompt-level metadata. - [JsonPropertyName("_meta")] - public IDictionary? Meta { get; set; } - - /// Server-provided non-standard descriptor fields. - [JsonPropertyName("additionalProperties")] - public IDictionary? AdditionalProperties { get; set; } - - /// Arguments accepted by the prompt. - [JsonPropertyName("arguments")] - public IList? Arguments { get; set; } - - /// Description of what this prompt provides. - [JsonPropertyName("description")] - public string? Description { get; set; } - - /// Icons associated with this prompt. - [JsonPropertyName("icons")] - public IList? Icons { get; set; } - - /// The programmatic name of the prompt. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Exact owned receipt identity. Stop also forgets this session's durable activation. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } - /// Human-readable display title. - [JsonPropertyName("title")] - public string? Title { get; set; } + /// Name of the MCP server to stop. + [JsonPropertyName("serverName")] + public required string ServerName { get; set; } } -/// One page of prompts advertised by the named MCP server. +/// Server name for an individual MCP server stop. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPromptsListResult +internal sealed class McpStopServerRequestWithSession { - /// MCP result metadata. - [JsonPropertyName("_meta")] - public IDictionary? Meta { get; set; } - - /// Server-provided non-standard result fields. - [JsonPropertyName("additionalProperties")] - public IDictionary? AdditionalProperties { get; set; } + /// Exact owned receipt identity. Stop also forgets this session's durable activation. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } - /// Opaque cursor for the next page, if the server has more prompts. - [JsonPropertyName("nextCursor")] - public string? NextCursor { get; set; } + /// Name of the MCP server to stop. + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; - /// Prompts advertised by the server. - [JsonPropertyName("prompts")] - public IList Prompts { get => field ??= []; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// MCP server whose prompts to enumerate. +/// Registration parameters for an external MCP client. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpPromptsListRequest +internal sealed class McpRegisterExternalClientRequest { - /// Opaque MCP pagination cursor from a prior `nextCursor` value. - [JsonPropertyName("cursor")] - public string? Cursor { get; set; } - - /// Name of the MCP server whose prompts to enumerate. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] + /// Logical server name for the external client. [JsonPropertyName("serverName")] public string ServerName { get; set; } = string.Empty; @@ -19373,66 +19414,33 @@ internal sealed class McpPromptsListRequest public string SessionId { get; set; } = string.Empty; } -/// An MCP prompt message with opaque JSON content preserved without flattening or content-type filtering. +/// Server name identifying the external client to remove. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPromptMessage +internal sealed class McpUnregisterExternalClientRequest { - /// Message-level metadata. - [JsonPropertyName("_meta")] - public IDictionary? Meta { get; set; } - - /// Server-provided non-standard message fields. - [JsonPropertyName("additionalProperties")] - public IDictionary? AdditionalProperties { get; set; } - - /// The original MCP content block, including nested metadata and unfamiliar content types. - [JsonPropertyName("content")] - public JsonElement Content { get; set; } + /// Server name of the external client to unregister. + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; - /// The role of the message sender. - [JsonPropertyName("role")] - public McpPromptRole Role { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Prompt messages returned by the MCP server without sending them to the model. +/// Whether the named MCP server is running. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpPromptsGetResult +public sealed class McpIsServerRunningResult { - /// MCP result metadata. - [JsonPropertyName("_meta")] - public IDictionary? Meta { get; set; } - - /// Server-provided non-standard result fields. - [JsonPropertyName("additionalProperties")] - public IDictionary? AdditionalProperties { get; set; } - - /// Description of the prompt. - [JsonPropertyName("description")] - public string? Description { get; set; } - - /// Ordered prompt messages. - [JsonPropertyName("messages")] - public IList Messages { get => field ??= []; set; } + /// True if the server has an active client and transport. + [JsonPropertyName("running")] + public bool Running { get; set; } } -/// MCP server, prompt name, and optional string-valued arguments. +/// Server name to check running status for. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class McpPromptsGetRequest +internal sealed class McpIsServerRunningRequest { - /// String-valued arguments to pass to the prompt. - [JsonPropertyName("arguments")] - public IDictionary? Arguments { get; set; } - - /// The programmatic name of the prompt. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("promptName")] - public string PromptName { get; set; } = string.Empty; - - /// Name of the MCP server hosting the prompt. - [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] + /// Name of the MCP server to check. [JsonPropertyName("serverName")] public string ServerName { get; set; } = string.Empty; @@ -19441,1743 +19449,3753 @@ internal sealed class McpPromptsGetRequest public string SessionId { get; set; } = string.Empty; } -/// MCP diagnostic source configuration. +/// Indicates whether the pending MCP OAuth response was accepted. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpDiagnosticSourceConfiguration +public sealed class McpOauthHandlePendingResult { - /// Threshold to apply to MCP diagnostic producers in this session. - [JsonPropertyName("level")] - public DiagnosticLogLevel Level { get; set; } + /// Whether the response was accepted. False if the request was unknown, timed out, or already resolved. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Typed diagnostic source configuration. At least one source is required by diagnostics configuration methods. +/// Host response to the pending OAuth request. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DiagnosticSourcesConfiguration +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(McpOauthPendingRequestResponseToken), "token")] +[JsonDerivedType(typeof(McpOauthPendingRequestResponseCancelled), "cancelled")] +public partial class McpOauthPendingRequestResponse { - /// MCP diagnostic capture threshold. Omit to leave the current threshold unchanged. - [JsonPropertyName("mcp")] - public McpDiagnosticSourceConfiguration? Mcp { get; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Per-source session diagnostics configuration. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DiagnosticsConfiguration -{ - /// Diagnostic thresholds keyed by supported source. - [JsonPropertyName("sources")] - public DiagnosticSourcesConfiguration Sources { get => field ??= new(); set; } -} -/// Patch session diagnostic thresholds for explicitly supplied sources. +/// The token variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class DiagnosticsConfigureRequest +public partial class McpOauthPendingRequestResponseToken : McpOauthPendingRequestResponse { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "token"; - /// Sources to configure. At least one supported source must be supplied. - [JsonPropertyName("sources")] - public DiagnosticSourcesConfiguration Sources { get => field ??= new(); set; } -} - -/// One retained session-scoped diagnostic record. Potentially content-bearing diagnostic data is opt-in and must not be exported automatically as telemetry. -/// Polymorphic base type discriminated by source. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "source", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(DiagnosticEntryMcp), "mcp")] -public partial class DiagnosticEntry -{ - /// The type discriminator. - [JsonPropertyName("source")] - public virtual string Source { get; set; } = string.Empty; -} - - -/// MCP-specific detail for a source-discriminated diagnostic entry. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpDiagnosticDetails -{ - /// Fresh identifier for the MCP connection attempt, including failed starts. - [JsonPropertyName("connectionId")] - public string ConnectionId { get; set; } = string.Empty; - - /// Serialized diagnostic detail. Protocol and HTTP records use JSON when detail is present. - [JsonPropertyName("data")] - public string? Data { get; set; } - - /// Protocol-frame direction when kind is protocol. - [JsonPropertyName("direction")] - public McpDiagnosticDirection? Direction { get; set; } - - /// Diagnostic record category. - [JsonPropertyName("kind")] - public McpDiagnosticKind Kind { get; set; } - - /// Configured MCP server name. - [JsonPropertyName("serverName")] - public string ServerName { get; set; } = string.Empty; -} - -/// The mcp variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class DiagnosticEntryMcp : DiagnosticEntry -{ - /// - [JsonIgnore] - public override string Source => "mcp"; - - /// Agent identifier for a subagent host. Omitted for the root agent. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("agentId")] - public string? AgentId { get; set; } - - /// Typed MCP diagnostic detail. - [JsonPropertyName("details")] - public required McpDiagnosticDetails Details { get; set; } - - /// Severity of this emitted diagnostic record. - [JsonPropertyName("level")] - public required DiagnosticSeverity Level { get; set; } - - /// Human-readable diagnostic summary. - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Access token acquired by the SDK host. + [JsonPropertyName("accessToken")] + public required string AccessToken { get; set; } - /// Original byte count when a known-size message or data value was truncated. + /// Token lifetime in seconds, if known. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("originalBytes")] - public long? OriginalBytes { get; set; } - - /// UTC RFC 3339 timestamp captured at the diagnostic source. - [JsonPropertyName("timestamp")] - public required string Timestamp { get; set; } + [JsonPropertyName("expiresIn")] + public long? ExpiresIn { get; set; } - /// Whether message or data was truncated to the record-size bound. + /// OAuth token type. Defaults to bearer when omitted. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("truncated")] - public bool? Truncated { get; set; } + [JsonPropertyName("tokenType")] + public string? TokenType { get; set; } } -/// One cursor-addressed page of retained session diagnostics. +/// The cancelled variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class DiagnosticsReadResult +public partial class McpOauthPendingRequestResponseCancelled : McpOauthPendingRequestResponse { - /// Opaque cursor for the next independent read. - [JsonPropertyName("cursor")] - public string Cursor { get; set; } = string.Empty; - - /// Whether the requested cursor remained within the retained buffer window. - [JsonPropertyName("cursorStatus")] - public DiagnosticCursorStatus CursorStatus { get; set; } - - /// Number of records lost before this page when known. Omitted when a buffer generation change makes the count unknowable. - [JsonPropertyName("droppedCount")] - public long? DroppedCount { get; set; } - - /// Retained records beginning at the requested cursor. - [JsonPropertyName("entries")] - public IList Entries { get => field ??= []; set; } - - /// Whether additional retained records follow this page. - [JsonPropertyName("hasMore")] - public bool HasMore { get; set; } + /// + [JsonIgnore] + public override string Kind => "cancelled"; } -/// Cursor-based request for session diagnostics. The default limit is 100 (maximum 500); the default waitMs is zero (maximum 30000). +/// Pending MCP OAuth request ID and host-provided token or cancellation response. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class DiagnosticsReadRequest +internal sealed class McpOauthHandlePendingRequest { - /// Opaque cursor returned by an earlier read. Omit to start at the oldest retained record. - [JsonPropertyName("cursor")] - public string? Cursor { get; set; } + /// OAuth request identifier from the mcp.oauth_required event. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; - /// Maximum number of records to return, from 1 through 500. Omit for 100. - [JsonPropertyName("max")] - public long? Max { get; set; } + /// Host response to the pending OAuth request. + [JsonPropertyName("result")] + public McpOauthPendingRequestResponse Result { get => field ??= new(); set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// Nonempty selection of sources to read. Each source may be listed once. - [JsonPropertyName("sources")] - public IList Sources { get => field ??= []; set; } - - /// Maximum time in milliseconds to wait for a new record, from 0 through 30000. - [JsonPropertyName("waitMs")] - public int? WaitMs { get; set; } } -/// Feature detection and hard polling limits for the EXPERIMENTAL session connector API. +/// Identifies the MCP server whose persisted OAuth credentials were updated. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorCapabilities +internal sealed class McpOauthAuthenticationStateChangedRequest { - /// Connector API contract version. - [JsonPropertyName("apiVersion")] - public long ApiVersion { get; set; } - - /// Current session availability. Disabled availability is reported without making a Connector request. - [JsonPropertyName("availability")] - public ConnectorAvailability Availability { get; set; } - - /// Whether connect and reconnect can return an opaque continuation for bounded consent polling. - [JsonPropertyName("consentContinuation")] - public bool ConsentContinuation { get; set; } - - /// Maximum accepted wall-clock deadline in milliseconds for one continuation call. - [JsonPropertyName("maxDeadlineMs")] - public long MaxDeadlineMs { get; set; } - - /// Maximum accepted polling attempts for one continuation call. - [JsonPropertyName("maxPollAttempts")] - public long MaxPollAttempts { get; set; } - - /// Maximum accepted delay in milliseconds between polling attempts. - [JsonPropertyName("maxPollIntervalMs")] - public long MaxPollIntervalMs { get; set; } - - /// Whether callers select a host-owned GitHub account through an opaque selection ID rather than supplying a provider token. - [JsonPropertyName("opaqueAccountSelection")] - public bool OpaqueAccountSelection { get; set; } - - /// Whether getAccount is supported. Absence means false. - [JsonPropertyName("sessionAccountSelection")] - public bool? SessionAccountSelection { get; set; } + /// Whether the target session must mint a session-scoped access token instead of reusing a shared access token persisted by another session. + [JsonPropertyName("refreshSessionToken")] + public bool? RefreshSessionToken { get; set; } - /// Whether reconcile accepts forceConnectorName. Absence means false. - [JsonPropertyName("targetedReconcile")] - public bool? TargetedReconcile { get; set; } -} + /// Name of the MCP server whose OAuth credentials were updated. Omit only when the host cannot identify the server. + [JsonPropertyName("serverName")] + public string? ServerName { get; set; } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionConnectorsGetCapabilitiesRequest -{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Credential-free identity metadata. +/// An inert runtime-issued login handle. Preparation alone performs no activation or OAuth work. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class AuthIdentityMetadata +public sealed class SessionMcpOauthPrepareLoginResult { - /// Identity host. - [JsonPropertyName("host")] - public string Host { get; set; } = string.Empty; - - /// User login. - [JsonPropertyName("login")] - public string Login { get; set; } = string.Empty; + /// Original expiry, not extended by consumption, retries or cancellation. + [JsonPropertyName("expiresAt")] + public DateTimeOffset ExpiresAt { get; set; } - /// Authentication type. - [JsonPropertyName("type")] - public AuthInfoType Type { get; set; } + /// Retain with the original requester and use for one login or cancellation. + [JsonPropertyName("loginId")] + public string LoginId { get; set; } = string.Empty; } -/// Session account selection. +/// Effect-free preparation bound to the existing local session, requester and installation, with frozen options. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorSessionAccount +internal sealed class SessionMcpOauthPrepareLoginRequest { - /// Opaque session-scoped account selection ID. - [JsonPropertyName("accountId")] - public string AccountId { get; set; } = string.Empty; + /// Text shown on the loopback callback page after successful authorisation. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(2048)] + [JsonPropertyName("callbackSuccessMessage")] + public string? CallbackSuccessMessage { get; set; } - /// Credential-free identity metadata. - [JsonPropertyName("authInfo")] - public AuthIdentityMetadata AuthInfo { get => field ??= new(); set; } -} + /// Display name used by the incumbent OAuth client-registration flow. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(2048)] + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } + + /// Exact installation identity from owned inventory, never a server-name alias. + [JsonPropertyName("expectedInstallationId")] + public string ExpectedInstallationId { get; set; } = string.Empty; + + /// Request a new authorisation rather than accepting a usable cached grant. + [JsonPropertyName("forceReauth")] + public bool? ForceReauth { get; set; } + + /// Name recorded by the authoritative owned installation receipt. + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionConnectorsGetAccountRequest -{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Account-targeted authorization update required by the Connector service. The account ID is an opaque host routing identifier; no credential is included. +/// OAuth authorization URL the caller should open, or empty when cached tokens already authenticated the server. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorAuthorizationRequirement +public sealed class McpOauthLoginResult { - /// Exact opaque account selection that made the Connector request. - [JsonPropertyName("accountId")] - public string AccountId { get; set; } = string.Empty; + /// Opaque authorization identifier returned only for a host-managed redirect URI. The runtime also sends it as the OAuth state value, so the callback endpoint can read state and pass it with the full callback URL to session.mcp.oauth.complete. + [JsonPropertyName("authorizationId")] + public string? AuthorizationId { get; set; } - /// Stable OAuth scope the selected account must grant. - [JsonPropertyName("scope")] - public ConnectorAuthorizationScope Scope { get; set; } + /// URL the caller should open in a browser to complete OAuth. Omitted when cached tokens were still valid and no browser interaction was needed — the server is already reconnected in that case. For the default loopback flow, the runtime starts its listener before returning. With redirectUri, the host receives the callback and completes it through session.mcp.oauth.complete. The runtime continues the flow in the background and signals completion via session.mcp_server_status_changed. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("authorizationUrl")] + public string? AuthorizationUrl { get; set; } + + /// Runtime-issued owned flow identity; never a server name or installation operation ID. + [JsonPropertyName("loginId")] + public string? LoginId { get; set; } + + /// Explicit outcome for owned sign-in. Manual callers retain their legacy response shape. + [JsonPropertyName("status")] + public McpOwnedOauthLoginStatus? Status { get; set; } } -/// Credential-free Connector catalog entry. +/// Remote MCP server name and optional overrides controlling reauthentication, OAuth client display name, callback handling, and static OAuth client selection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorCatalogEntry +public sealed class McpOauthLoginRequest { - /// Untrusted service description, when present. - [JsonPropertyName("description")] - public string? Description { get; set; } + /// Optional override for the body text shown on the OAuth loopback callback success page. When omitted, the runtime applies a neutral fallback; callers driving interactive auth should pass surface-specific copy telling the user where to return. + [JsonPropertyName("callbackSuccessMessage")] + public string? CallbackSuccessMessage { get; set; } - /// Untrusted display label from the service. - [JsonPropertyName("displayName")] - public string DisplayName { get; set; } = string.Empty; + /// Optional OAuth client ID override for this login. When set, the runtime uses this pre-registered static client instead of dynamic client registration. + [JsonPropertyName("clientId")] + public string? ClientId { get; set; } - /// Optional catalog logo. - [JsonPropertyName("logo")] - public string? Logo { get; set; } + /// Optional override for the OAuth client display name shown on the consent screen. Applies to newly registered dynamic clients only — existing registrations keep the name they were created with. When omitted, the runtime applies a neutral fallback; callers driving interactive auth should pass their own surface-specific label so the consent screen matches the product the user sees. + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } - /// Canonical Connector name used by lifecycle methods. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Optional OAuth client secret override for this login. The runtime treats this as an ephemeral host-owned secret, uses it for this authentication attempt and does not persist it. + [JsonPropertyName("clientSecret")] + public string? ClientSecret { get; set; } - /// Optional catalog release tag. - [JsonPropertyName("releaseTag")] - public string? ReleaseTag { get; set; } + /// Exact owned receipt identity. Owned login never uses an implicit helper session. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } - /// Opaque stable runtime IDs currently projected into the session for this Connector. - [JsonPropertyName("runtimeServerIds")] - public IList RuntimeServerIds { get => field ??= []; set; } + /// When true, clears any cached OAuth token for the server and runs a full new authorization. Use when the user explicitly wants to switch accounts or believes their session is stuck. + [JsonPropertyName("forceReauth")] + public bool? ForceReauth { get; set; } - /// Current authoritative service connection state. - [JsonPropertyName("status")] - public ConnectorCatalogStatus Status { get; set; } + /// Optional OAuth grant type override for this login. Defaults to the server configuration, or authorization_code when no grant type is specified. + [JsonPropertyName("grantType")] + public McpOauthLoginGrantType? GrantType { get; set; } - /// Optional catalog tier. - [JsonPropertyName("tier")] - public string? Tier { get; set; } -} + /// + /// Required for owned login. Consumes the exact prepareLogin handle once. + /// Set forceReauth and display options during preparation, not consumption. + /// + [JsonPropertyName("loginId")] + public string? LoginId { get; set; } -/// Validated Connector catalog snapshot cached by the session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorCatalogResult -{ - /// Validated catalog entries in service order. - [JsonPropertyName("connectors")] - public IList Connectors { get => field ??= []; set; } + /// Optional override indicating whether the static OAuth client is public. When false, the runtime treats it as confidential and uses the per-login clientSecret if provided, otherwise retrieving the client secret from the MCP OAuth secret store. + [JsonPropertyName("publicClient")] + public bool? PublicClient { get; set; } - /// Unix epoch milliseconds when this snapshot was accepted. - [JsonPropertyName("refreshedAtMs")] - public long RefreshedAtMs { get; set; } + /// Optional externally visible HTTPS redirect URI for a host-managed callback endpoint. When supplied, the runtime still owns discovery, PKCE, token exchange, persistence, and reconnect, but does not bind a loopback listener or terminate HTTPS. The URI must not contain query parameters or a fragment and must be registered for the selected CIMD, DCR, or static OAuth client. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("redirectUri")] + public string? RedirectUri { get; set; } - /// Monotonically increasing session-local catalog revision. - [JsonPropertyName("revision")] - public long Revision { get; set; } + /// Name of the remote MCP server to authenticate. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("serverName")] + public required string ServerName { get; set; } } -/// Live status of one session-owned MCP projection. +/// Remote MCP server name and optional overrides controlling reauthentication, OAuth client display name, callback handling, and static OAuth client selection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorRuntimeStatus +internal sealed class McpOauthLoginRequestWithSession { - /// Canonical Connector name that owns this server. - [JsonPropertyName("connectorName")] - public string ConnectorName { get; set; } = string.Empty; + /// Optional override for the body text shown on the OAuth loopback callback success page. When omitted, the runtime applies a neutral fallback; callers driving interactive auth should pass surface-specific copy telling the user where to return. + [JsonPropertyName("callbackSuccessMessage")] + public string? CallbackSuccessMessage { get; set; } - /// Opaque runtime server ID. - [JsonPropertyName("runtimeServerId")] - public string RuntimeServerId { get; set; } = string.Empty; + /// Optional OAuth client ID override for this login. When set, the runtime uses this pre-registered static client instead of dynamic client registration. + [JsonPropertyName("clientId")] + public string? ClientId { get; set; } - /// Current live MCP host status. - [JsonPropertyName("status")] - public ConnectorMcpStatus Status { get; set; } -} + /// Optional override for the OAuth client display name shown on the consent screen. Applies to newly registered dynamic clients only — existing registrations keep the name they were created with. When omitted, the runtime applies a neutral fallback; callers driving interactive auth should pass their own surface-specific label so the consent screen matches the product the user sees. + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } -/// Authoritative session connector state. Account IDs are opaque routing identifiers and credentials are never included. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorStatus -{ - /// Opaque account selection pinned to this session, when one has been selected. - [JsonPropertyName("accountId")] - public string? AccountId { get; set; } + /// Optional OAuth client secret override for this login. The runtime treats this as an ephemeral host-owned secret, uses it for this authentication attempt and does not persist it. + [JsonPropertyName("clientSecret")] + public string? ClientSecret { get; set; } - /// Connector API contract version. - [JsonPropertyName("apiVersion")] - public long ApiVersion { get; set; } + /// Exact owned receipt identity. Owned login never uses an implicit helper session. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } - /// Exact selected account and stable scope requiring an authorization update, when proven by the Connector service. - [JsonPropertyName("authorizationRequirement")] - public ConnectorAuthorizationRequirement? AuthorizationRequirement { get; set; } + /// When true, clears any cached OAuth token for the server and runs a full new authorization. Use when the user explicitly wants to switch accounts or believes their session is stuck. + [JsonPropertyName("forceReauth")] + public bool? ForceReauth { get; set; } - /// Current feature and session availability. - [JsonPropertyName("availability")] - public ConnectorAvailability Availability { get; set; } + /// Optional OAuth grant type override for this login. Defaults to the server configuration, or authorization_code when no grant type is specified. + [JsonPropertyName("grantType")] + public McpOauthLoginGrantType? GrantType { get; set; } - /// Latest validated catalog snapshot, when available. - [JsonPropertyName("catalog")] - public ConnectorCatalogResult? Catalog { get; set; } + /// + /// Required for owned login. Consumes the exact prepareLogin handle once. + /// Set forceReauth and display options during preparation, not consumption. + /// + [JsonPropertyName("loginId")] + public string? LoginId { get; set; } - /// Number of active opaque connection continuations. - [JsonPropertyName("pendingConnections")] - public long PendingConnections { get; set; } + /// Optional override indicating whether the static OAuth client is public. When false, the runtime treats it as confidential and uses the per-login clientSecret if provided, otherwise retrieving the client secret from the MCP OAuth secret store. + [JsonPropertyName("publicClient")] + public bool? PublicClient { get; set; } - /// Live MCP status for every Connector-owned runtime server. - [JsonPropertyName("runtimeServers")] - public IList RuntimeServers { get => field ??= []; set; } -} + /// Optional externally visible HTTPS redirect URI for a host-managed callback endpoint. When supplied, the runtime still owns discovery, PKCE, token exchange, persistence, and reconnect, but does not bind a loopback listener or terminate HTTPS. The URI must not contain query parameters or a fragment and must be registered for the selected CIMD, DCR, or static OAuth client. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("redirectUri")] + public string? RedirectUri { get; set; } + + /// Name of the remote MCP server to authenticate. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionConnectorsGetStatusRequest -{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Pins a Connector operation to one host-owned GitHub account through its opaque selection ID. Provider tokens are never accepted. +/// Host-delivered callback for a runtime-managed MCP OAuth login. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ConnectorAccountRequest +internal sealed class McpOauthCompleteRequest { - /// Opaque account selection ID previously returned by an account discovery API. - [JsonPropertyName("accountId")] - public string AccountId { get; set; } = string.Empty; + /// Opaque identifier returned by session.mcp.oauth.login for the pending external callback. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("authorizationId")] + public string AuthorizationId { get; set; } = string.Empty; + + /// Full externally visible HTTPS callback URL received by the host, including the authorization response query parameters. Applications behind a reverse proxy must reconstruct the public URL rather than passing an internal proxy URL. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("callbackUrl")] + public string CallbackUrl { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Typed result of initiating or continuing a Connector connection. -/// Polymorphic base type discriminated by kind. +/// Passive MCP OAuth probe result. `authenticated` means the server accepted the probe request while an OAuth-origin access token was attached; it does not prove the server required or independently validated that token. The probe does not make a second unauthenticated request. Failed is an expected probe-domain outcome; JSON-RPC errors are reserved for API-call failures. +/// Polymorphic base type discriminated by status. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", + TypeDiscriminatorPropertyName = "status", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(ConnectorConnectResultConnected), "connected")] -[JsonDerivedType(typeof(ConnectorConnectResultConsentRequired), "consent_required")] -[JsonDerivedType(typeof(ConnectorConnectResultPending), "pending")] -public partial class ConnectorConnectResult +[JsonDerivedType(typeof(McpOauthProbeResultNoAuthRequired), "no-auth-required")] +[JsonDerivedType(typeof(McpOauthProbeResultAuthenticated), "authenticated")] +[JsonDerivedType(typeof(McpOauthProbeResultNeedsAuth), "needs-auth")] +[JsonDerivedType(typeof(McpOauthProbeResultFailed), "failed")] +public partial class McpOauthProbeResult { /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; + [JsonPropertyName("status")] + public virtual string Status { get; set; } = string.Empty; } -/// The service is connected and the session MCP graph was reconciled. -/// The connected variant of . +/// The no-auth-required variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ConnectorConnectResultConnected : ConnectorConnectResult +public partial class McpOauthProbeResultNoAuthRequired : McpOauthProbeResult { /// [JsonIgnore] - public override string Kind => "connected"; + public override string Status => "no-auth-required"; - /// Fresh authoritative Connector state after MCP reconciliation. - [JsonPropertyName("status")] - public required ConnectorStatus Status { get; set; } + /// HTTP response returned by the server. + [JsonPropertyName("httpResponse")] + public required McpOauthHttpResponse HttpResponse { get; set; } } -/// Host-owned consent is required before bounded continuation can complete. -/// The consent_required variant of . +/// The authenticated variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ConnectorConnectResultConsentRequired : ConnectorConnectResult +public partial class McpOauthProbeResultAuthenticated : McpOauthProbeResult { /// [JsonIgnore] - public override string Kind => "consent_required"; - - /// Validated HTTPS consent URL. The runtime does not open it. - [JsonPropertyName("consentUrl")] - public required string ConsentUrl { get; set; } + public override string Status => "authenticated"; - /// Opaque ID accepted by continueConnection. - [JsonPropertyName("continuationId")] - public required string ContinuationId { get; set; } + /// HTTP response returned by the server. + [JsonPropertyName("httpResponse")] + public required McpOauthHttpResponse HttpResponse { get; set; } } -/// The service is still completing the connection without a consent URL. -/// The pending variant of . +/// The needs-auth variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ConnectorConnectResultPending : ConnectorConnectResult +public partial class McpOauthProbeResultNeedsAuth : McpOauthProbeResult { /// [JsonIgnore] - public override string Kind => "pending"; + public override string Status => "needs-auth"; - /// Opaque ID accepted by continueConnection. - [JsonPropertyName("continuationId")] - public required string ContinuationId { get; set; } + /// HTTP 401 or 403 response returned by the server. + [JsonPropertyName("httpResponse")] + public required McpOauthHttpResponse HttpResponse { get; set; } + + /// Why authentication is needed. + [JsonPropertyName("reason")] + public required McpOauthProbeNeedsAuthReason Reason { get; set; } + + /// Parsed WWW-Authenticate challenge parameters, when present and parseable. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("wwwAuthenticateParams")] + public McpOauthWWWAuthenticateParams? WwwAuthenticateParams { get; set; } } -/// Selects one Connector and the pinned host-owned account used for its service and MCP authorization. +/// The failed variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ConnectorConnectRequest +public partial class McpOauthProbeResultFailed : McpOauthProbeResult { - /// Opaque account selection ID. It must match the account already pinned to the session, if any. - [JsonPropertyName("accountId")] - public string AccountId { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Status => "failed"; - /// Canonical Connector name from the current catalog. - [JsonPropertyName("connectorName")] - public string ConnectorName { get; set; } = string.Empty; + /// Human-readable probe failure detail. + [JsonPropertyName("error")] + public required string Error { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// HTTP response returned by the server, when the probe reached the server and captured the complete response. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("httpResponse")] + public McpOauthHttpResponse? HttpResponse { get; set; } } -/// Explicitly bounded continuation of a pending Connector connection. +/// Remote MCP server name for a passive OAuth status probe. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ConnectorContinueRequest +public sealed class McpOauthProbeRequest { - /// Opaque continuation ID returned by connect, reconnect, or an earlier continuation. - [JsonPropertyName("continuationId")] - public string ContinuationId { get; set; } = string.Empty; + /// Exact owned receipt identity; probing never activates a dormant installation. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } - /// Maximum wall-clock duration in milliseconds for this call. Must be between one and the capability limit. - [JsonPropertyName("deadlineMs")] - public int DeadlineMs { get; set; } + /// Name of the configured remote MCP server to probe. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("serverName")] + public required string ServerName { get; set; } +} - /// Maximum catalog requests made by this call. Must be between one and the capability limit. - [JsonPropertyName("maxAttempts")] - public int MaxAttempts { get; set; } +/// Remote MCP server name for a passive OAuth status probe. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpOauthProbeRequestWithSession +{ + /// Exact owned receipt identity; probing never activates a dormant installation. + [JsonPropertyName("expectedInstallationId")] + public string? ExpectedInstallationId { get; set; } - /// Delay in milliseconds between attempts. Must not exceed the capability limit. - [JsonPropertyName("pollIntervalMs")] - public int PollIntervalMs { get; set; } + /// Name of the configured remote MCP server to probe. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Authoritative result after disconnect and MCP reconciliation. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorDisconnectResult -{ - /// Whether the service accepted the idempotent disconnect. - [JsonPropertyName("disconnected")] - public bool Disconnected { get; set; } - - /// Fresh authoritative session state after removing Connector-owned MCP servers. - [JsonPropertyName("status")] - public ConnectorStatus Status { get => field ??= new(); set; } -} - -/// Requests authoritative Connector-to-MCP reconciliation for the pinned account. +/// Honest terminal cancellation result; persistence or recovery failures remain RPC errors. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ConnectorReconcileRequest +public sealed class SessionMcpOauthCancelLoginResult { - /// Opaque account selection ID. It must match the account already pinned to the session, if any. - [JsonPropertyName("accountId")] - public required string AccountId { get; set; } - - /// Optional Connector name to reinitialize. Requires the targetedReconcile capability. - [JsonPropertyName("forceConnectorName")] - public string? ForceConnectorName { get; set; } - - /// When true, refresh the catalog before reconciling. A disabled Connector API performs no service request. - [JsonPropertyName("refreshCatalog")] - public bool? RefreshCatalog { get; set; } + /// True after cancellation settles, false when the original login already connected successfully. + [JsonPropertyName("cancelled")] + public bool Cancelled { get; set; } } -/// Requests authoritative Connector-to-MCP reconciliation for the pinned account. +/// Targets only the original prepared/applying owned login on this exact session requester. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ConnectorReconcileRequestWithSession +internal sealed class SessionMcpOauthCancelLoginRequest { - /// Opaque account selection ID. It must match the account already pinned to the session, if any. - [JsonPropertyName("accountId")] - public string AccountId { get; set; } = string.Empty; - - /// Optional Connector name to reinitialize. Requires the targetedReconcile capability. - [JsonPropertyName("forceConnectorName")] - public string? ForceConnectorName { get; set; } + /// The same authoritative installation identity supplied during preparation. + [JsonPropertyName("expectedInstallationId")] + public string ExpectedInstallationId { get; set; } = string.Empty; - /// When true, refresh the catalog before reconciling. A disabled Connector API performs no service request. - [JsonPropertyName("refreshCatalog")] - public bool? RefreshCatalog { get; set; } + /// Runtime-issued login handle known before the effectful login request begins. + [JsonPropertyName("loginId")] + public string LoginId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Identifies the target session. +/// Indicates whether the pending MCP OAuth response was accepted. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionConnectorsWithdrawProjectionRequest +public sealed class McpOauthRespondResult { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether the response was accepted. False if the request was unknown, timed out, or already resolved. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Identifies the target session. +/// Pending MCP OAuth request id to respond to. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionManagedSettingsGetRequest +internal sealed class McpOauthRespondRequest { + /// OAuth request identifier from the mcp.oauth_required event. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Session plugin metadata, with name, marketplace, optional version, and enabled state. +/// Indicates whether the pending MCP headers refresh response was accepted. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class Plugin +public sealed class McpHeadersHandlePendingHeadersRefreshRequestResult { - /// Opaque stable identity for a direct plugin source. - [JsonPropertyName("directSourceId")] - public string? DirectSourceId { get; set; } - - /// Whether the plugin is currently enabled. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } - - /// Whether this managed desired plugin has an installed or live record. - [JsonPropertyName("installed")] - public bool? Installed { get; set; } - - /// Absolute marketplace directory for a live plugin. - [JsonPropertyName("installedFrom")] - public string? InstalledFrom { get; set; } + /// Whether the response was accepted. False if the request was unknown, timed out, or already resolved. + [JsonPropertyName("success")] + public bool Success { get; set; } +} - /// Whether enterprise managed settings control this plugin. - [JsonPropertyName("managed")] - public bool? Managed { get; set; } +/// Host response: supply dynamic headers or decline this refresh. +/// Polymorphic base type discriminated by kind. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(McpHeadersHandlePendingHeadersRefreshRequestHeaders), "headers")] +[JsonDerivedType(typeof(McpHeadersHandlePendingHeadersRefreshRequestNone), "none")] +[JsonDerivedType(typeof(McpHeadersHandlePendingHeadersRefreshRequestError), "error")] +public partial class McpHeadersHandlePendingHeadersRefreshRequest +{ + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} - /// Enabled state required by enterprise managed settings. - [JsonPropertyName("managedDesiredEnabled")] - public bool? ManagedDesiredEnabled { get; set; } - /// Marketplace the plugin came from. - [JsonPropertyName("marketplace")] - public string Marketplace { get; set; } = string.Empty; +/// The headers variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class McpHeadersHandlePendingHeadersRefreshRequestHeaders : McpHeadersHandlePendingHeadersRefreshRequest +{ + /// + [JsonIgnore] + public override string Kind => "headers"; - /// Plugin name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Headers to overlay onto the MCP request. Dynamic headers override static config headers but do not replace SDK-managed request headers. + [JsonPropertyName("headers")] + public required IDictionary Headers { get; set; } - /// Runtime plugin provenance, such as "builtin". - [JsonPropertyName("source")] - public string? Source { get; set; } + /// Optional lifetime in milliseconds for these returned headers. The runtime clamps its configured cache lifetime to this value. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("ttlMs")] + public long? TtlMs { get; set; } +} - /// Installed version. - [JsonPropertyName("version")] - public string? Version { get; set; } +/// The none variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class McpHeadersHandlePendingHeadersRefreshRequestNone : McpHeadersHandlePendingHeadersRefreshRequest +{ + /// + [JsonIgnore] + public override string Kind => "none"; } -/// Plugins installed for the session, with their enabled state and version metadata. +/// The error variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PluginList +public partial class McpHeadersHandlePendingHeadersRefreshRequestError : McpHeadersHandlePendingHeadersRefreshRequest { - /// Installed plugins. - [JsonPropertyName("plugins")] - public IList Plugins { get => field ??= []; set; } + /// + [JsonIgnore] + public override string Kind => "error"; + + /// Host credential broker failure, denial, or revocation reason. + [JsonPropertyName("message")] + public required string Message { get; set; } } -/// Identifies the target session. +/// MCP headers refresh request id and the host response. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPluginsListRequest +internal sealed class McpHeadersHandlePendingHeadersRefreshRequestRequest { + /// Headers refresh request identifier from mcp.headers_refresh_required. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; + + /// Host response: supply dynamic headers or decline this refresh. + [JsonPropertyName("result")] + public McpHeadersHandlePendingHeadersRefreshRequest Result { get => field ??= new(); set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Plugin source resolved relative to the session's authoritative working directory. +/// MCP Apps resource content with URI, optional MIME type, text or base64 blob, and resource metadata. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPluginsInstallRequest +public sealed class McpAppsResourceContent { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Resource-level metadata (CSP, permissions, etc.). + [JsonPropertyName("_meta")] + public IDictionary? Meta { get; set; } - /// Plugin install spec. Accepts the same forms as the CLI: "plugin@marketplace" (marketplace install), "owner/repo" or "owner/repo:subpath" (GitHub direct), an http/https/ssh URL, or a local path. Direct (non-marketplace) installs are deprecated and will produce a deprecationWarning in the result. - [JsonPropertyName("source")] - public string Source { get; set; } = string.Empty; + /// Base64-encoded binary content. + [JsonPropertyName("blob")] + public string? Blob { get; set; } + + /// MIME type of the content. + [JsonPropertyName("mimeType")] + public string? MimeType { get; set; } + + /// Text content (e.g. HTML). + [JsonPropertyName("text")] + public string? Text { get; set; } + + /// The resource URI (typically ui://...). + [JsonPropertyName("uri")] + public string Uri { get; set; } = string.Empty; } -/// Name (or spec) of the plugin to uninstall. +/// Resource contents returned by the MCP server. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsUninstallRequestWithSession +public sealed class McpAppsReadResourceResult { - /// Stable source identity for a direct (non-marketplace) install. Disambiguates uninstall when multiple installed plugins share the same name. - [JsonPropertyName("directSourceId")] - public string? DirectSourceId { get; set; } + /// Resource contents returned by the server. + [JsonPropertyName("contents")] + public IList Contents { get => field ??= []; set; } +} - /// Plugin name or "plugin@marketplace" spec to uninstall. When ambiguous, prefer the fully-qualified spec. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; +/// MCP server and resource URI to fetch. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpAppsReadResourceRequest +{ + /// Name of the MCP server hosting the resource. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Resource URI (typically ui://...). + [JsonPropertyName("uri")] + public string Uri { get; set; } = string.Empty; } -/// Name (or spec) of the plugin to update. +/// App-callable tools from the named MCP server. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsUpdateRequestWithSession +public sealed class McpAppsListToolsResult { - /// Plugin name or "plugin@marketplace" spec to update. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// App-callable tools from the server. + [JsonPropertyName("tools")] + public IList> Tools { get => field ??= []; set; } } -/// Plugin names (or specs) to enable in the session's authoritative working directory. +/// MCP server to list app-callable tools for. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPluginsEnableRequest +internal sealed class McpAppsListToolsRequest { - /// Plugin names or "plugin@marketplace" specs to enable. Unknown names are ignored. Non-marketplace direct installs are always enabled and cannot be toggled via this API. - [JsonPropertyName("names")] - public IList Names { get => field ??= []; set; } + /// **Required.** Server whose ui:// view issued the request. Per SEP-1865 ('callable by the app from this server only'), the call is rejected when this differs from `serverName`, and rejected outright when missing. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("originServerName")] + public string OriginServerName { get; set; } = string.Empty; + + /// MCP server hosting the app. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Plugin names (or specs) to disable in the session's authoritative working directory. +/// MCP server, tool name, and arguments to invoke from an MCP App view. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPluginsDisableRequest +internal sealed class McpAppsCallToolRequest { - /// Plugin names or "plugin@marketplace" specs to disable. Unknown names are ignored. Non-marketplace direct installs cannot be disabled via this API; uninstall them instead. Plugin-owned MCP servers are stopped in active sessions immediately; other plugin contributions remain available until each session reloads plugins. - [JsonPropertyName("names")] - public IList Names { get => field ??= []; set; } + /// Tool arguments. + [JsonPropertyName("arguments")] + public IDictionary? Arguments { get; set; } + + /// **Required.** Server whose ui:// view issued the request. Per SEP-1865 ('callable by the app from this server only'), the call is rejected when this differs from `serverName`, and rejected outright when missing. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("originServerName")] + public string OriginServerName { get; set; } = string.Empty; + + /// MCP server hosting the tool. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// MCP tool name. + [JsonPropertyName("toolName")] + public string ToolName { get; set; } = string.Empty; } -/// RPC data type for SessionPluginsReload operations. +/// Host context advertised to MCP App guests. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionPluginsReloadRequest +public sealed class McpAppsSetHostContextDetails { - /// When true, skip repo-level hooks during the hook reload. Use before folder trust is confirmed; load them post-trust via `sessions.loadDeferredRepoHooks`. - [JsonPropertyName("deferRepoHooks")] - public bool? DeferRepoHooks { get; set; } + /// Display modes the host supports. + [JsonPropertyName("availableDisplayModes")] + public IList? AvailableDisplayModes { get; set; } - /// Re-run custom-agent discovery after refreshing plugins. Defaults to true. - [JsonPropertyName("reloadCustomAgents")] - public bool? ReloadCustomAgents { get; set; } + /// Current display mode (SEP-1865). + [JsonPropertyName("displayMode")] + public McpAppsSetHostContextDetailsDisplayMode? DisplayMode { get; set; } - /// Re-discover and relaunch subprocess extensions (including plugin-shipped extensions) after refreshing plugins. Defaults to true. Has no effect when the session has no active extension controller (e.g. extensions were not requested for the session). - [JsonPropertyName("reloadExtensions")] - public bool? ReloadExtensions { get; set; } + /// BCP-47 locale, e.g. 'en-US'. + [JsonPropertyName("locale")] + public string? Locale { get; set; } - /// Re-load user, plugin, and (subject to `deferRepoHooks`) repo hooks. Defaults to true. Has no effect when the host has not registered a hook reloader (e.g. remote sessions). - [JsonPropertyName("reloadHooks")] - public bool? ReloadHooks { get; set; } + /// Platform type for responsive design. + [JsonPropertyName("platform")] + public McpAppsSetHostContextDetailsPlatform? Platform { get; set; } - /// Reload MCP server connections after refreshing plugins. Defaults to true. - [JsonPropertyName("reloadMcp")] - public bool? ReloadMcp { get; set; } + /// UI theme preference per SEP-1865. + [JsonPropertyName("theme")] + public McpAppsSetHostContextDetailsTheme? Theme { get; set; } + + /// IANA timezone, e.g. 'America/New_York'. + [JsonPropertyName("timeZone")] + public string? TimeZone { get; set; } + + /// Host application identifier. + [JsonPropertyName("userAgent")] + public string? UserAgent { get; set; } } -/// RPC data type for SessionPluginsReloadRequestWithSession operations. +/// Host context to advertise to MCP App guests. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPluginsReloadRequestWithSession +internal sealed class McpAppsSetHostContextRequest { - /// When true, skip repo-level hooks during the hook reload. Use before folder trust is confirmed; load them post-trust via `sessions.loadDeferredRepoHooks`. - [JsonPropertyName("deferRepoHooks")] - public bool? DeferRepoHooks { get; set; } - - /// Re-run custom-agent discovery after refreshing plugins. Defaults to true. - [JsonPropertyName("reloadCustomAgents")] - public bool? ReloadCustomAgents { get; set; } - - /// Re-discover and relaunch subprocess extensions (including plugin-shipped extensions) after refreshing plugins. Defaults to true. Has no effect when the session has no active extension controller (e.g. extensions were not requested for the session). - [JsonPropertyName("reloadExtensions")] - public bool? ReloadExtensions { get; set; } - - /// Re-load user, plugin, and (subject to `deferRepoHooks`) repo hooks. Defaults to true. Has no effect when the host has not registered a hook reloader (e.g. remote sessions). - [JsonPropertyName("reloadHooks")] - public bool? ReloadHooks { get; set; } - - /// Reload MCP server connections after refreshing plugins. Defaults to true. - [JsonPropertyName("reloadMcp")] - public bool? ReloadMcp { get; set; } + /// Host context advertised to MCP App guests. + [JsonPropertyName("context")] + public McpAppsSetHostContextDetails Context { get => field ??= new(); set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Retry outcome for one plugin required by managed settings. +/// Current host context. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ManagedPluginRetryEntry +public sealed class McpAppsHostContextDetails { - /// Why the plugin was not prepared. Present when `status` is `failed` or `deferred`. - [JsonPropertyName("error")] - public string? Error { get; set; } + /// Display modes the host supports. + [JsonPropertyName("availableDisplayModes")] + public IList? AvailableDisplayModes { get; set; } - /// Plugin spec in "plugin@marketplace" form. - [JsonPropertyName("spec")] - public string Spec { get; set; } = string.Empty; + /// Current display mode (SEP-1865). + [JsonPropertyName("displayMode")] + public McpAppsHostContextDetailsDisplayMode? DisplayMode { get; set; } - /// What the retry did for this plugin. - [JsonPropertyName("status")] - public ManagedPluginRetryStatus Status { get; set; } -} + /// BCP-47 locale, e.g. 'en-US'. + [JsonPropertyName("locale")] + public string? Locale { get; set; } -/// Per-plugin outcomes of retrying the plugins required by the session's managed settings. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionPluginsRetryManagedResult -{ - /// One entry per requested plugin, in request order. When no plugins were requested, one entry per plugin the managed settings require. - [JsonPropertyName("plugins")] - public IList Plugins { get => field ??= []; set; } -} + /// Platform type for responsive design. + [JsonPropertyName("platform")] + public McpAppsHostContextDetailsPlatform? Platform { get; set; } -/// RPC data type for SessionPluginsRetryManaged operations. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionPluginsRetryManagedRequest -{ - /// "plugin@marketplace" specs to retry. Omit to retry every plugin the session's managed settings require. - [JsonPropertyName("plugins")] - public IList? Plugins { get; set; } + /// UI theme preference per SEP-1865. + [JsonPropertyName("theme")] + public McpAppsHostContextDetailsTheme? Theme { get; set; } + + /// IANA timezone, e.g. 'America/New_York'. + [JsonPropertyName("timeZone")] + public string? TimeZone { get; set; } + + /// Host application identifier. + [JsonPropertyName("userAgent")] + public string? UserAgent { get; set; } } -/// RPC data type for SessionPluginsRetryManagedRequestWithSession operations. +/// Current host context advertised to MCP App guests. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPluginsRetryManagedRequestWithSession +public sealed class McpAppsHostContext { - /// "plugin@marketplace" specs to retry. Omit to retry every plugin the session's managed settings require. - [JsonPropertyName("plugins")] - public IList? Plugins { get; set; } - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Current host context. + [JsonPropertyName("context")] + public McpAppsHostContextDetails Context { get => field ??= new(); set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPluginsMarketplacesListRequest +internal sealed class SessionMcpAppsGetHostContextRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Marketplace source and optional working directory for relative-path resolution. +/// Capability negotiation snapshot. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsMarketplacesAddRequestWithSession +public sealed class McpAppsDiagnoseCapability { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether the runtime advertises `extensions.io.modelcontextprotocol/ui` to MCP servers. + [JsonPropertyName("advertised")] + public bool Advertised { get; set; } - /// Marketplace source. Accepts the same forms as the CLI: "owner/repo" or "owner/repo#ref" (GitHub), an http/https/ssh URL (optionally with #ref), a git scp-style URL (user@host:path), or a local path. The marketplace's own name (from its manifest) is used as the registration key. - [JsonPropertyName("source")] - public string Source { get; set; } = string.Empty; + /// Whether the MCP_APPS feature flag (or COPILOT_MCP_APPS env override) is on. + [JsonPropertyName("featureFlagEnabled")] + public bool FeatureFlagEnabled { get; set; } - /// Working directory used to resolve relative local paths in `source`. Defaults to the server's current working directory. - [JsonPropertyName("workingDirectory")] - public string? WorkingDirectory { get; set; } + /// Whether the session has the `mcp-apps` capability. + [JsonPropertyName("sessionHasMcpApps")] + public bool SessionHasMcpApps { get; set; } } -/// Name of the marketplace to remove and an optional force flag. +/// What the server returned for this session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsMarketplacesRemoveRequestWithSession +public sealed class McpAppsDiagnoseServer { - /// When true, also uninstall every plugin sourced from this marketplace. When false (default), removal is a no-op if any plugin from this marketplace is installed and the dependent plugin names are returned in the result. - [JsonPropertyName("force")] - public bool? Force { get; set; } + /// Whether the named server is currently connected. + [JsonPropertyName("connected")] + public bool Connected { get; set; } - /// Marketplace name to remove. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Up to 5 tool names with `_meta.ui` for quick inspection. + [JsonPropertyName("sampleToolNames")] + public IList SampleToolNames { get => field ??= []; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Total tools returned by the server's tools/list. + [JsonPropertyName("toolCount")] + public double ToolCount { get; set; } + + /// Tools whose `_meta.ui` is populated (resourceUri and/or visibility set). + [JsonPropertyName("toolsWithUiMeta")] + public double ToolsWithUiMeta { get; set; } } -/// Name of the marketplace whose plugin catalog to fetch. +/// Diagnostic snapshot of MCP Apps wiring for the named server. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PluginsMarketplacesBrowseRequestWithSession +public sealed class McpAppsDiagnoseResult { - /// Marketplace name to browse. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Capability negotiation snapshot. + [JsonPropertyName("capability")] + public McpAppsDiagnoseCapability Capability { get => field ??= new(); set; } + + /// What the server returned for this session. + [JsonPropertyName("server")] + public McpAppsDiagnoseServer Server { get => field ??= new(); set; } +} + +/// MCP server to diagnose MCP Apps wiring for. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpAppsDiagnoseRequest +{ + /// MCP server to probe. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// RPC data type for SessionPluginsMarketplacesRefresh operations. +/// MCP resource content with URI, optional MIME type, text or base64 blob, and resource metadata. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionPluginsMarketplacesRefreshRequest +public sealed class McpResourceContent { - /// Marketplace name to refresh. When omitted, every registered marketplace is refreshed. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Resource-level metadata (CSP, permissions, etc.). + [JsonPropertyName("_meta")] + public IDictionary? Meta { get; set; } + + /// Base64-encoded binary content. + [JsonPropertyName("blob")] + public string? Blob { get; set; } + + /// MIME type of the content. + [JsonPropertyName("mimeType")] + public string? MimeType { get; set; } + + /// Text content (e.g. HTML). + [JsonPropertyName("text")] + public string? Text { get; set; } + + /// The resource URI. + [JsonPropertyName("uri")] + public string Uri { get; set; } = string.Empty; } -/// RPC data type for SessionPluginsMarketplacesRefreshRequestWithSession operations. +/// Resource contents returned by the MCP server. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionPluginsMarketplacesRefreshRequestWithSession +public sealed class McpResourcesReadResult { - /// Marketplace name to refresh. When omitted, every registered marketplace is refreshed. - [JsonPropertyName("name")] - public string? Name { get; set; } + /// Resource contents returned by the server. + [JsonPropertyName("contents")] + public IList Contents { get => field ??= []; set; } +} + +/// MCP server and resource URI to fetch. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpResourcesReadRequest +{ + /// Name of the MCP server hosting the resource. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Resource URI. + [JsonPropertyName("uri")] + public string Uri { get; set; } = string.Empty; } -/// Short-lived, rotating credential the caller must send on every request, in addition to `apiKey` if one is present. Omitted when the endpoint does not require one. +/// Standard MCP resource annotations plus preserved non-standard annotation fields. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProviderSessionToken +public sealed class McpResourceAnnotations { - /// When the token expires, if known. Callers should refresh by calling `getEndpoint` again before this time, or reactively on any 401/403 response from `baseUrl`. - [JsonPropertyName("expiresAt")] - public DateTimeOffset? ExpiresAt { get; set; } + /// Server-provided non-standard annotation fields preserved from the MCP response. + [JsonPropertyName("additionalProperties")] + public IDictionary? AdditionalProperties { get; set; } - /// HTTP header name the token must be sent under. - [JsonPropertyName("header")] - public string Header { get; set; } = string.Empty; + /// Intended audience roles for this resource. + [JsonPropertyName("audience")] + public IList? Audience { get; set; } - /// The model the token is bound to, when applicable. When set, the token is only valid for requests against this model. - [JsonPropertyName("model")] - public string? Model { get; set; } + /// Last-modified timestamp hint. + [JsonPropertyName("lastModified")] + public string? LastModified { get; set; } - /// The short-lived token value. - [JsonPropertyName("token")] - public string Token { get; set; } = string.Empty; + /// Priority hint for model/client use. + [JsonPropertyName("priority")] + public double? Priority { get; set; } } -/// A snapshot of the provider endpoint the session is currently configured to talk to. +/// A resource icon descriptor plus preserved non-standard icon fields. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProviderEndpoint +public sealed class McpResourceIcon { - /// A credential the caller should use with this endpoint. Omitted only when the endpoint accepts unauthenticated requests. - [JsonPropertyName("apiKey")] - public string? ApiKey { get; set; } - - /// Base URL to pass to the LLM client library. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("baseUrl")] - public string BaseUrl { get; set; } = string.Empty; - - /// HTTP headers the caller must include on every outbound request. - [JsonPropertyName("headers")] - public IDictionary Headers { get => field ??= new Dictionary(); set; } + /// Server-provided non-standard icon fields preserved from the MCP response. + [JsonPropertyName("additionalProperties")] + public IDictionary? AdditionalProperties { get; set; } - /// Short-lived, rotating credential the caller must send on every request, in addition to `apiKey` if one is present. Omitted when the endpoint does not require one. - [JsonPropertyName("sessionToken")] - public ProviderSessionToken? SessionToken { get; set; } + /// Icon MIME type, when known. + [JsonPropertyName("mimeType")] + public string? MimeType { get; set; } - /// Transport to be used for provider requests. - [JsonPropertyName("transport")] - public ProviderEndpointTransport? Transport { get; set; } + /// Icon sizes hint. + [JsonPropertyName("sizes")] + public string? Sizes { get; set; } - /// Provider family. Matches the `type` field of a BYOK provider config. - [JsonPropertyName("type")] - public ProviderEndpointType Type { get; set; } + /// Icon URI. + [JsonPropertyName("src")] + public string Src { get; set; } = string.Empty; - /// Wire API to be used, when required for the provider type. - [JsonPropertyName("wireApi")] - public ProviderEndpointWireApi? WireApi { get; set; } + /// Theme hint for this icon. + [JsonPropertyName("theme")] + public string? Theme { get; set; } } -/// RPC data type for SessionProviderGetEndpoint operations. +/// An MCP resource descriptor (spec `Resource`): URI, name, and optional title, description, MIME type, size, icons, annotations, and metadata. Server-provided fields outside the standard descriptor shape are exposed under `additionalProperties`. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionProviderGetEndpointRequest +public sealed class McpResource { - /// Model identifier the caller intends to use against the returned endpoint. Used to pick the correct wire shape. Omit to use whichever model the session is currently using. - [JsonPropertyName("modelId")] - public string? ModelId { get; set; } -} + /// Resource-level metadata. + [JsonPropertyName("_meta")] + public IDictionary? Meta { get; set; } -/// RPC data type for SessionProviderGetEndpointRequestWithSession operations. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionProviderGetEndpointRequestWithSession -{ - /// Model identifier the caller intends to use against the returned endpoint. Used to pick the correct wire shape. Omit to use whichever model the session is currently using. - [JsonPropertyName("modelId")] - public string? ModelId { get; set; } + /// Server-provided non-standard descriptor fields preserved from the MCP response. + [JsonPropertyName("additionalProperties")] + public IDictionary? AdditionalProperties { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Model/client annotations associated with this resource. + [JsonPropertyName("annotations")] + public McpResourceAnnotations? Annotations { get; set; } + + /// Optional description of what this resource represents. + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Icons associated with this resource. + [JsonPropertyName("icons")] + public IList? Icons { get; set; } + + /// MIME type of the resource, if known. + [JsonPropertyName("mimeType")] + public string? MimeType { get; set; } + + /// The programmatic name of the resource. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Resource size in bytes, when known. + [JsonPropertyName("size")] + public long? Size { get; set; } + + /// Optional human-readable display title. + [JsonPropertyName("title")] + public string? Title { get; set; } + + /// The resource URI (e.g. ui://... or file:///...). + [JsonPropertyName("uri")] + public string Uri { get; set; } = string.Empty; } -/// The selectable model entries synthesized for the models added by this call. +/// One page of resources advertised by the named MCP server. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProviderAddResult +public sealed class McpResourcesListResult { - /// Synthesized selectable model entries for the newly added BYOK models, each under its provider-qualified selection id (`provider/id`). Empty when only providers were added. - [JsonPropertyName("models")] - public IList Models { get => field ??= []; set; } + /// Opaque cursor for the next page, if the server has more resources. + [JsonPropertyName("nextCursor")] + public string? NextCursor { get; set; } + + /// Resources advertised by the server (proxied MCP `resources/list`). + [JsonPropertyName("resources")] + public IList Resources { get => field ??= []; set; } } -/// BYOK providers and/or models to add to the session's registry at runtime. Both fields are optional; provide providers, models, or both. +/// MCP server whose resources to enumerate. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ProviderAddRequest +internal sealed class McpResourcesListRequest { - /// BYOK model definitions to register. Each must reference a provider that is already registered or included in this same call. Selection ids (`provider/id`) must be unique across the registry. - [JsonPropertyName("models")] - public IList? Models { get; set; } + /// Opaque MCP pagination cursor from a prior `nextCursor` value. + [JsonPropertyName("cursor")] + public string? Cursor { get; set; } - /// Named BYOK provider connections to register, additive to any providers already in the registry. Each name must be unique across the registry and must not contain '/'. - [JsonPropertyName("providers")] - public IList? Providers { get; set; } + /// Name of the MCP server whose resources to enumerate. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// The selectable model entries and selection ids synthesized for the synchronized BYOK models. +/// An MCP resource template descriptor (spec `ResourceTemplate`): an RFC 6570 URI template, name, and optional title, description, MIME type, icons, annotations, and metadata. Server-provided fields outside the standard descriptor shape are exposed under `additionalProperties`. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProviderSyncResult +public sealed class McpResourceTemplate { - /// True when synchronization withdrew the selected host-managed model, leaving the session with no explicit selection, so ordinary model resolution picks the session default. Synchronization never promotes a surviving host model in its place: publishing a model offers it, and the choice of which model to use stays with the user. - [JsonPropertyName("modelDeselected")] - public bool? ModelDeselected { get; set; } + /// Resource-template-level metadata. + [JsonPropertyName("_meta")] + public IDictionary? Meta { get; set; } - /// Synthesized selectable model entries for the synchronized BYOK models. - [JsonPropertyName("models")] - public IList Models { get => field ??= []; set; } + /// Server-provided non-standard descriptor fields preserved from the MCP response. + [JsonPropertyName("additionalProperties")] + public IDictionary? AdditionalProperties { get; set; } - /// Provider-qualified model selection ids present after synchronization. - [JsonPropertyName("selectionIds")] - public IList SelectionIds { get => field ??= []; set; } -} + /// Model/client annotations associated with this template. + [JsonPropertyName("annotations")] + public McpResourceAnnotations? Annotations { get; set; } -/// Authoritative BYOK provider and model registry snapshot to apply atomically to the session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ProviderSyncRequest -{ - /// BYOK model definition snapshot. Models absent from this list are removed. - [JsonPropertyName("models")] - public IList? Models { get; set; } + /// Optional description of what this template is for. + [JsonPropertyName("description")] + public string? Description { get; set; } - /// Named BYOK provider connection snapshot. Providers absent from this list are removed. - [JsonPropertyName("providers")] - public IList? Providers { get; set; } + /// Icons associated with resources matching this template. + [JsonPropertyName("icons")] + public IList? Icons { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// MIME type for resources matching this template, if uniform. + [JsonPropertyName("mimeType")] + public string? MimeType { get; set; } + + /// The programmatic name of the resource template. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Optional human-readable display title. + [JsonPropertyName("title")] + public string? Title { get; set; } + + /// An RFC 6570 URI template for constructing resource URIs. + [JsonPropertyName("uriTemplate")] + public string UriTemplate { get; set; } = string.Empty; } -/// What the withdrawal actually removed from the registry. +/// One page of resource templates advertised by the named MCP server. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProviderWithdrawResult +public sealed class McpResourcesListTemplatesResult { - /// True when withdrawal removed the selected host-managed model, leaving the session with no explicit selection, so ordinary model resolution picks the session default. Withdrawal never promotes a surviving model in its place: the choice of which model to use stays with the user. - [JsonPropertyName("modelDeselected")] - public bool? ModelDeselected { get; set; } - - /// Providers removed because one of the withdrawn models was the last entry referencing them. A provider that merely has no models is not removed. - [JsonPropertyName("providersRemoved")] - public IList ProvidersRemoved { get => field ??= []; set; } + /// Opaque cursor for the next page, if the server has more resource templates. + [JsonPropertyName("nextCursor")] + public string? NextCursor { get; set; } - /// Selection ids that were registered and are now withdrawn. Excludes requested ids that were not present. - [JsonPropertyName("withdrawn")] - public IList Withdrawn { get => field ??= []; set; } + /// Resource templates advertised by the server (proxied MCP `resources/templates/list`). + [JsonPropertyName("resourceTemplates")] + public IList ResourceTemplates { get => field ??= []; set; } } -/// Host-managed model selection ids to withdraw from the session's BYOK registry. +/// MCP server whose resource templates to enumerate. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ProviderWithdrawRequest +internal sealed class McpResourcesListTemplatesRequest { - /// Provider-qualified selection ids to withdraw. Ids that are not registered are ignored, so withdrawal is idempotent. A provider left with no models referencing it is removed too. - [JsonPropertyName("models")] - public IList Models { get => field ??= []; set; } + /// Opaque MCP pagination cursor from a prior `nextCursor` value. + [JsonPropertyName("cursor")] + public string? Cursor { get; set; } + + /// Name of the MCP server whose resource templates to enumerate. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the session options patch was applied successfully. +/// An argument accepted by an MCP prompt. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionUpdateOptionsResult +public sealed class McpPromptArgument { - /// Number of hooks loaded from installed plugins, returned when installedPlugins is updated. - [JsonPropertyName("pluginHookCount")] - public long? PluginHookCount { get; set; } + /// Argument-level metadata. + [JsonPropertyName("_meta")] + public IDictionary? Meta { get; set; } - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } -} + /// Server-provided non-standard argument fields. + [JsonPropertyName("additionalProperties")] + public IDictionary? AdditionalProperties { get; set; } -/// Source descriptor for a `session.options.update` content-exclusion rule, with source name and type. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class OptionsUpdateAdditionalContentExclusionPolicyRuleSource -{ - /// Name of the policy source. + /// Description of the argument. + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Name of the argument. [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; - /// Type of the policy source. - [JsonPropertyName("type")] - public string Type { get; set; } = string.Empty; + /// Whether the argument is required; omission is distinct from false. + [JsonPropertyName("required")] + public bool? Required { get; set; } } -/// Single content-exclusion rule supplied to `session.options.update`, with paths, match conditions, and source. +/// An MCP prompt icon with standard size hints and preserved non-standard fields. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class OptionsUpdateAdditionalContentExclusionPolicyRule +public sealed class McpPromptIcon { - /// Conditions of which at least one must match. - [JsonPropertyName("ifAnyMatch")] - public IList? IfAnyMatch { get; set; } + /// Server-provided non-standard icon fields. + [JsonPropertyName("additionalProperties")] + public IDictionary? AdditionalProperties { get; set; } - /// Conditions none of which may match. - [JsonPropertyName("ifNoneMatch")] - public IList? IfNoneMatch { get; set; } + /// Icon MIME type, when known. + [JsonPropertyName("mimeType")] + public string? MimeType { get; set; } - /// Path patterns covered by this rule. - [JsonPropertyName("paths")] - public IList Paths { get => field ??= []; set; } + /// Icon sizes, such as `48x48` or `any`. + [JsonPropertyName("sizes")] + public IList? Sizes { get; set; } - /// Source descriptor for a `session.options.update` content-exclusion rule, with source name and type. - [JsonPropertyName("source")] - public OptionsUpdateAdditionalContentExclusionPolicyRuleSource Source { get => field ??= new(); set; } + /// Icon URI. + [JsonPropertyName("src")] + public string Src { get; set; } = string.Empty; + + /// Theme hint for this icon. + [JsonPropertyName("theme")] + public string? Theme { get; set; } } -/// Content-exclusion policy supplied to `session.options.update`, with rules, last-updated data, and scope. +/// An MCP prompt descriptor. Server-provided non-standard fields are exposed under `additionalProperties`. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class OptionsUpdateAdditionalContentExclusionPolicy +public sealed class McpPrompt { - /// Opaque policy update timestamp supplied by the host. - [JsonPropertyName("last_updated_at")] - public JsonElement LastUpdatedAt { get; set; } + /// Prompt-level metadata. + [JsonPropertyName("_meta")] + public IDictionary? Meta { get; set; } - /// Content-exclusion rules to apply. - [JsonPropertyName("rules")] - public IList Rules { get => field ??= []; set; } + /// Server-provided non-standard descriptor fields. + [JsonPropertyName("additionalProperties")] + public IDictionary? AdditionalProperties { get; set; } - /// Allowed values for the `OptionsUpdateAdditionalContentExclusionPolicyScope` enumeration. - [JsonPropertyName("scope")] - public OptionsUpdateAdditionalContentExclusionPolicyScope Scope { get; set; } -} + /// Arguments accepted by the prompt. + [JsonPropertyName("arguments")] + public IList? Arguments { get; set; } -/// Options scoped to the built-in CAPI (Copilot API) provider. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CapiSessionOptions -{ - /// Routing preference for sessions whose model is `auto`. On create or cold resume, this establishes the preference sent as `tier` on CAPI `/auto` requests; when omitted on cold resume, the runtime restores the last committed preference. On resident resume, a different value requests a safe switch after resume succeeds and cannot change an in-flight turn. Successful switches are persisted for later cold resume. When no preference is supplied or restored, CAPI default routing is used. `fast` is an integrator-only latency preset, not a first-party GitHub Copilot product preference. - [JsonPropertyName("autoTier")] - public AutoTier? AutoTier { get; set; } + /// Description of what this prompt provides. + [JsonPropertyName("description")] + public string? Description { get; set; } - /// Whether to use WebSocket transport for the CAPI Responses API. Enabled by default when the model advertises `ws:/responses` support; set to `false` to force the HTTP Responses transport in environments where WebSockets are blocked (e.g. behind a proxy). Setting this to `false` is equivalent to the `COPILOT_CLI_DISABLE_WEBSOCKET_RESPONSES` environment variable. - [JsonPropertyName("enableWebSocketResponses")] - public bool? EnableWebSocketResponses { get; set; } + /// Icons associated with this prompt. + [JsonPropertyName("icons")] + public IList? Icons { get; set; } + + /// The programmatic name of the prompt. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Human-readable display title. + [JsonPropertyName("title")] + public string? Title { get; set; } } -/// Installed plugin record for a session, with marketplace, version, install time, enabled state, cache path, and source. +/// One page of prompts advertised by the named MCP server. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionInstalledPlugin +public sealed class McpPromptsListResult { - /// Path where the plugin is cached locally. - [JsonPropertyName("cache_path")] - public string? CachePath { get; set; } + /// MCP result metadata. + [JsonPropertyName("_meta")] + public IDictionary? Meta { get; set; } - /// Whether the plugin is currently enabled. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// Server-provided non-standard result fields. + [JsonPropertyName("additionalProperties")] + public IDictionary? AdditionalProperties { get; set; } - /// Installation timestamp (ISO-8601). - [JsonPropertyName("installed_at")] - public string InstalledAt { get; set; } = string.Empty; + /// Opaque cursor for the next page, if the server has more prompts. + [JsonPropertyName("nextCursor")] + public string? NextCursor { get; set; } - /// Absolute path of the marketplace directory a live plugin was resolved from. Present only on live, never-persisted records — those synthesized at session start for a directory/local marketplace, whose cache_path points at the real plugin directory on disk rather than a copy under the installed-plugins cache. Its presence is what marks a record as live, and no record carrying it is ever written to the persisted installedPlugins key. - [JsonPropertyName("installed_from")] - public string? InstalledFrom { get; set; } + /// Prompts advertised by the server. + [JsonPropertyName("prompts")] + public IList Prompts { get => field ??= []; set; } +} - /// Marketplace the plugin came from (empty string for direct repo installs). +/// MCP server whose prompts to enumerate. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpPromptsListRequest +{ + /// Opaque MCP pagination cursor from a prior `nextCursor` value. + [JsonPropertyName("cursor")] + public string? Cursor { get; set; } + + /// Name of the MCP server whose prompts to enumerate. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// An MCP prompt message with opaque JSON content preserved without flattening or content-type filtering. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpPromptMessage +{ + /// Message-level metadata. + [JsonPropertyName("_meta")] + public IDictionary? Meta { get; set; } + + /// Server-provided non-standard message fields. + [JsonPropertyName("additionalProperties")] + public IDictionary? AdditionalProperties { get; set; } + + /// The original MCP content block, including nested metadata and unfamiliar content types. + [JsonPropertyName("content")] + public JsonElement Content { get; set; } + + /// The role of the message sender. + [JsonPropertyName("role")] + public McpPromptRole Role { get; set; } +} + +/// Prompt messages returned by the MCP server without sending them to the model. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpPromptsGetResult +{ + /// MCP result metadata. + [JsonPropertyName("_meta")] + public IDictionary? Meta { get; set; } + + /// Server-provided non-standard result fields. + [JsonPropertyName("additionalProperties")] + public IDictionary? AdditionalProperties { get; set; } + + /// Description of the prompt. + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Ordered prompt messages. + [JsonPropertyName("messages")] + public IList Messages { get => field ??= []; set; } +} + +/// MCP server, prompt name, and optional string-valued arguments. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class McpPromptsGetRequest +{ + /// String-valued arguments to pass to the prompt. + [JsonPropertyName("arguments")] + public IDictionary? Arguments { get; set; } + + /// The programmatic name of the prompt. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("promptName")] + public string PromptName { get; set; } = string.Empty; + + /// Name of the MCP server hosting the prompt. + [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// MCP diagnostic source configuration. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpDiagnosticSourceConfiguration +{ + /// Threshold to apply to MCP diagnostic producers in this session. + [JsonPropertyName("level")] + public DiagnosticLogLevel Level { get; set; } +} + +/// Typed diagnostic source configuration. At least one source is required by diagnostics configuration methods. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class DiagnosticSourcesConfiguration +{ + /// MCP diagnostic capture threshold. Omit to leave the current threshold unchanged. + [JsonPropertyName("mcp")] + public McpDiagnosticSourceConfiguration? Mcp { get; set; } +} + +/// Per-source session diagnostics configuration. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class DiagnosticsConfiguration +{ + /// Diagnostic thresholds keyed by supported source. + [JsonPropertyName("sources")] + public DiagnosticSourcesConfiguration Sources { get => field ??= new(); set; } +} + +/// Patch session diagnostic thresholds for explicitly supplied sources. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class DiagnosticsConfigureRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Sources to configure. At least one supported source must be supplied. + [JsonPropertyName("sources")] + public DiagnosticSourcesConfiguration Sources { get => field ??= new(); set; } +} + +/// One retained session-scoped diagnostic record. Potentially content-bearing diagnostic data is opt-in and must not be exported automatically as telemetry. +/// Polymorphic base type discriminated by source. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "source", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(DiagnosticEntryMcp), "mcp")] +public partial class DiagnosticEntry +{ + /// The type discriminator. + [JsonPropertyName("source")] + public virtual string Source { get; set; } = string.Empty; +} + + +/// MCP-specific detail for a source-discriminated diagnostic entry. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpDiagnosticDetails +{ + /// Fresh identifier for the MCP connection attempt, including failed starts. + [JsonPropertyName("connectionId")] + public string ConnectionId { get; set; } = string.Empty; + + /// Serialized diagnostic detail. Protocol and HTTP records use JSON when detail is present. + [JsonPropertyName("data")] + public string? Data { get; set; } + + /// Protocol-frame direction when kind is protocol. + [JsonPropertyName("direction")] + public McpDiagnosticDirection? Direction { get; set; } + + /// Diagnostic record category. + [JsonPropertyName("kind")] + public McpDiagnosticKind Kind { get; set; } + + /// Configured MCP server name. + [JsonPropertyName("serverName")] + public string ServerName { get; set; } = string.Empty; +} + +/// The mcp variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class DiagnosticEntryMcp : DiagnosticEntry +{ + /// + [JsonIgnore] + public override string Source => "mcp"; + + /// Agent identifier for a subagent host. Omitted for the root agent. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("agentId")] + public string? AgentId { get; set; } + + /// Typed MCP diagnostic detail. + [JsonPropertyName("details")] + public required McpDiagnosticDetails Details { get; set; } + + /// Severity of this emitted diagnostic record. + [JsonPropertyName("level")] + public required DiagnosticSeverity Level { get; set; } + + /// Human-readable diagnostic summary. + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// Original byte count when a known-size message or data value was truncated. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("originalBytes")] + public long? OriginalBytes { get; set; } + + /// UTC RFC 3339 timestamp captured at the diagnostic source. + [JsonPropertyName("timestamp")] + public required string Timestamp { get; set; } + + /// Whether message or data was truncated to the record-size bound. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("truncated")] + public bool? Truncated { get; set; } +} + +/// One cursor-addressed page of retained session diagnostics. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class DiagnosticsReadResult +{ + /// Opaque cursor for the next independent read. + [JsonPropertyName("cursor")] + public string Cursor { get; set; } = string.Empty; + + /// Whether the requested cursor remained within the retained buffer window. + [JsonPropertyName("cursorStatus")] + public DiagnosticCursorStatus CursorStatus { get; set; } + + /// Number of records lost before this page when known. Omitted when a buffer generation change makes the count unknowable. + [JsonPropertyName("droppedCount")] + public long? DroppedCount { get; set; } + + /// Retained records beginning at the requested cursor. + [JsonPropertyName("entries")] + public IList Entries { get => field ??= []; set; } + + /// Whether additional retained records follow this page. + [JsonPropertyName("hasMore")] + public bool HasMore { get; set; } +} + +/// Cursor-based request for session diagnostics. The default limit is 100 (maximum 500); the default waitMs is zero (maximum 30000). +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class DiagnosticsReadRequest +{ + /// Opaque cursor returned by an earlier read. Omit to start at the oldest retained record. + [JsonPropertyName("cursor")] + public string? Cursor { get; set; } + + /// Maximum number of records to return, from 1 through 500. Omit for 100. + [JsonPropertyName("max")] + public long? Max { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Nonempty selection of sources to read. Each source may be listed once. + [JsonPropertyName("sources")] + public IList Sources { get => field ??= []; set; } + + /// Maximum time in milliseconds to wait for a new record, from 0 through 30000. + [JsonPropertyName("waitMs")] + public int? WaitMs { get; set; } +} + +/// Feature detection and hard polling limits for the EXPERIMENTAL session connector API. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorCapabilities +{ + /// Connector API contract version. + [JsonPropertyName("apiVersion")] + public long ApiVersion { get; set; } + + /// Current session availability. Disabled availability is reported without making a Connector request. + [JsonPropertyName("availability")] + public ConnectorAvailability Availability { get; set; } + + /// Whether connect and reconnect can return an opaque continuation for bounded consent polling. + [JsonPropertyName("consentContinuation")] + public bool ConsentContinuation { get; set; } + + /// Maximum accepted wall-clock deadline in milliseconds for one continuation call. + [JsonPropertyName("maxDeadlineMs")] + public long MaxDeadlineMs { get; set; } + + /// Maximum accepted polling attempts for one continuation call. + [JsonPropertyName("maxPollAttempts")] + public long MaxPollAttempts { get; set; } + + /// Maximum accepted delay in milliseconds between polling attempts. + [JsonPropertyName("maxPollIntervalMs")] + public long MaxPollIntervalMs { get; set; } + + /// Whether callers select a host-owned GitHub account through an opaque selection ID rather than supplying a provider token. + [JsonPropertyName("opaqueAccountSelection")] + public bool OpaqueAccountSelection { get; set; } + + /// Whether getAccount is supported. Absence means false. + [JsonPropertyName("sessionAccountSelection")] + public bool? SessionAccountSelection { get; set; } + + /// Whether reconcile accepts forceConnectorName. Absence means false. + [JsonPropertyName("targetedReconcile")] + public bool? TargetedReconcile { get; set; } +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionConnectorsGetCapabilitiesRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Credential-free identity metadata. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class AuthIdentityMetadata +{ + /// Identity host. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; + + /// User login. + [JsonPropertyName("login")] + public string Login { get; set; } = string.Empty; + + /// Authentication type. + [JsonPropertyName("type")] + public AuthInfoType Type { get; set; } +} + +/// Session account selection. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorSessionAccount +{ + /// Opaque session-scoped account selection ID. + [JsonPropertyName("accountId")] + public string AccountId { get; set; } = string.Empty; + + /// Credential-free identity metadata. + [JsonPropertyName("authInfo")] + public AuthIdentityMetadata AuthInfo { get => field ??= new(); set; } +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionConnectorsGetAccountRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Account-targeted authorization update required by the Connector service. The account ID is an opaque host routing identifier; no credential is included. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorAuthorizationRequirement +{ + /// Exact opaque account selection that made the Connector request. + [JsonPropertyName("accountId")] + public string AccountId { get; set; } = string.Empty; + + /// Stable OAuth scope the selected account must grant. + [JsonPropertyName("scope")] + public ConnectorAuthorizationScope Scope { get; set; } +} + +/// Credential-free Connector catalog entry. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorCatalogEntry +{ + /// Untrusted service description, when present. + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Untrusted display label from the service. + [JsonPropertyName("displayName")] + public string DisplayName { get; set; } = string.Empty; + + /// Optional catalog logo. + [JsonPropertyName("logo")] + public string? Logo { get; set; } + + /// Canonical Connector name used by lifecycle methods. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Optional catalog release tag. + [JsonPropertyName("releaseTag")] + public string? ReleaseTag { get; set; } + + /// Opaque stable runtime IDs currently projected into the session for this Connector. + [JsonPropertyName("runtimeServerIds")] + public IList RuntimeServerIds { get => field ??= []; set; } + + /// Current authoritative service connection state. + [JsonPropertyName("status")] + public ConnectorCatalogStatus Status { get; set; } + + /// Optional catalog tier. + [JsonPropertyName("tier")] + public string? Tier { get; set; } +} + +/// Validated Connector catalog snapshot cached by the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorCatalogResult +{ + /// Validated catalog entries in service order. + [JsonPropertyName("connectors")] + public IList Connectors { get => field ??= []; set; } + + /// Unix epoch milliseconds when this snapshot was accepted. + [JsonPropertyName("refreshedAtMs")] + public long RefreshedAtMs { get; set; } + + /// Monotonically increasing session-local catalog revision. + [JsonPropertyName("revision")] + public long Revision { get; set; } +} + +/// Live status of one session-owned MCP projection. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorRuntimeStatus +{ + /// Canonical Connector name that owns this server. + [JsonPropertyName("connectorName")] + public string ConnectorName { get; set; } = string.Empty; + + /// Opaque runtime server ID. + [JsonPropertyName("runtimeServerId")] + public string RuntimeServerId { get; set; } = string.Empty; + + /// Current live MCP host status. + [JsonPropertyName("status")] + public ConnectorMcpStatus Status { get; set; } +} + +/// Authoritative session connector state. Account IDs are opaque routing identifiers and credentials are never included. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorStatus +{ + /// Opaque account selection pinned to this session, when one has been selected. + [JsonPropertyName("accountId")] + public string? AccountId { get; set; } + + /// Connector API contract version. + [JsonPropertyName("apiVersion")] + public long ApiVersion { get; set; } + + /// Exact selected account and stable scope requiring an authorization update, when proven by the Connector service. + [JsonPropertyName("authorizationRequirement")] + public ConnectorAuthorizationRequirement? AuthorizationRequirement { get; set; } + + /// Current feature and session availability. + [JsonPropertyName("availability")] + public ConnectorAvailability Availability { get; set; } + + /// Latest validated catalog snapshot, when available. + [JsonPropertyName("catalog")] + public ConnectorCatalogResult? Catalog { get; set; } + + /// Number of active opaque connection continuations. + [JsonPropertyName("pendingConnections")] + public long PendingConnections { get; set; } + + /// Live MCP status for every Connector-owned runtime server. + [JsonPropertyName("runtimeServers")] + public IList RuntimeServers { get => field ??= []; set; } +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionConnectorsGetStatusRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Pins a Connector operation to one host-owned GitHub account through its opaque selection ID. Provider tokens are never accepted. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ConnectorAccountRequest +{ + /// Opaque account selection ID previously returned by an account discovery API. + [JsonPropertyName("accountId")] + public string AccountId { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Typed result of initiating or continuing a Connector connection. +/// Polymorphic base type discriminated by kind. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(ConnectorConnectResultConnected), "connected")] +[JsonDerivedType(typeof(ConnectorConnectResultConsentRequired), "consent_required")] +[JsonDerivedType(typeof(ConnectorConnectResultPending), "pending")] +public partial class ConnectorConnectResult +{ + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} + + +/// The service is connected and the session MCP graph was reconciled. +/// The connected variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class ConnectorConnectResultConnected : ConnectorConnectResult +{ + /// + [JsonIgnore] + public override string Kind => "connected"; + + /// Fresh authoritative Connector state after MCP reconciliation. + [JsonPropertyName("status")] + public required ConnectorStatus Status { get; set; } +} + +/// Host-owned consent is required before bounded continuation can complete. +/// The consent_required variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class ConnectorConnectResultConsentRequired : ConnectorConnectResult +{ + /// + [JsonIgnore] + public override string Kind => "consent_required"; + + /// Validated HTTPS consent URL. The runtime does not open it. + [JsonPropertyName("consentUrl")] + public required string ConsentUrl { get; set; } + + /// Opaque ID accepted by continueConnection. + [JsonPropertyName("continuationId")] + public required string ContinuationId { get; set; } +} + +/// The service is still completing the connection without a consent URL. +/// The pending variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class ConnectorConnectResultPending : ConnectorConnectResult +{ + /// + [JsonIgnore] + public override string Kind => "pending"; + + /// Opaque ID accepted by continueConnection. + [JsonPropertyName("continuationId")] + public required string ContinuationId { get; set; } +} + +/// Selects one Connector and the pinned host-owned account used for its service and MCP authorization. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ConnectorConnectRequest +{ + /// Opaque account selection ID. It must match the account already pinned to the session, if any. + [JsonPropertyName("accountId")] + public string AccountId { get; set; } = string.Empty; + + /// Canonical Connector name from the current catalog. + [JsonPropertyName("connectorName")] + public string ConnectorName { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Explicitly bounded continuation of a pending Connector connection. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ConnectorContinueRequest +{ + /// Opaque continuation ID returned by connect, reconnect, or an earlier continuation. + [JsonPropertyName("continuationId")] + public string ContinuationId { get; set; } = string.Empty; + + /// Maximum wall-clock duration in milliseconds for this call. Must be between one and the capability limit. + [JsonPropertyName("deadlineMs")] + public int DeadlineMs { get; set; } + + /// Maximum catalog requests made by this call. Must be between one and the capability limit. + [JsonPropertyName("maxAttempts")] + public int MaxAttempts { get; set; } + + /// Delay in milliseconds between attempts. Must not exceed the capability limit. + [JsonPropertyName("pollIntervalMs")] + public int PollIntervalMs { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Authoritative result after disconnect and MCP reconciliation. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorDisconnectResult +{ + /// Whether the service accepted the idempotent disconnect. + [JsonPropertyName("disconnected")] + public bool Disconnected { get; set; } + + /// Fresh authoritative session state after removing Connector-owned MCP servers. + [JsonPropertyName("status")] + public ConnectorStatus Status { get => field ??= new(); set; } +} + +/// Requests authoritative Connector-to-MCP reconciliation for the pinned account. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ConnectorReconcileRequest +{ + /// Opaque account selection ID. It must match the account already pinned to the session, if any. + [JsonPropertyName("accountId")] + public required string AccountId { get; set; } + + /// Optional Connector name to reinitialize. Requires the targetedReconcile capability. + [JsonPropertyName("forceConnectorName")] + public string? ForceConnectorName { get; set; } + + /// When true, refresh the catalog before reconciling. A disabled Connector API performs no service request. + [JsonPropertyName("refreshCatalog")] + public bool? RefreshCatalog { get; set; } +} + +/// Requests authoritative Connector-to-MCP reconciliation for the pinned account. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ConnectorReconcileRequestWithSession +{ + /// Opaque account selection ID. It must match the account already pinned to the session, if any. + [JsonPropertyName("accountId")] + public string AccountId { get; set; } = string.Empty; + + /// Optional Connector name to reinitialize. Requires the targetedReconcile capability. + [JsonPropertyName("forceConnectorName")] + public string? ForceConnectorName { get; set; } + + /// When true, refresh the catalog before reconciling. A disabled Connector API performs no service request. + [JsonPropertyName("refreshCatalog")] + public bool? RefreshCatalog { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionConnectorsWithdrawProjectionRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionManagedSettingsGetRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Session plugin metadata, with name, marketplace, optional version, and enabled state. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class Plugin +{ + /// Opaque stable identity for a direct plugin source. + [JsonPropertyName("directSourceId")] + public string? DirectSourceId { get; set; } + + /// Whether the plugin is currently enabled. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } + + /// Whether this managed desired plugin has an installed or live record. + [JsonPropertyName("installed")] + public bool? Installed { get; set; } + + /// Absolute marketplace directory for a live plugin. + [JsonPropertyName("installedFrom")] + public string? InstalledFrom { get; set; } + + /// Whether enterprise managed settings control this plugin. + [JsonPropertyName("managed")] + public bool? Managed { get; set; } + + /// Enabled state required by enterprise managed settings. + [JsonPropertyName("managedDesiredEnabled")] + public bool? ManagedDesiredEnabled { get; set; } + + /// Marketplace the plugin came from. + [JsonPropertyName("marketplace")] + public string Marketplace { get; set; } = string.Empty; + + /// Plugin name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Runtime plugin provenance, such as "builtin". + [JsonPropertyName("source")] + public string? Source { get; set; } + + /// Installed version. + [JsonPropertyName("version")] + public string? Version { get; set; } +} + +/// Plugins installed for the session, with their enabled state and version metadata. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class PluginList +{ + /// Installed plugins. + [JsonPropertyName("plugins")] + public IList Plugins { get => field ??= []; set; } +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionPluginsListRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Plugin source resolved relative to the session's authoritative working directory. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionPluginsInstallRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Plugin install spec. Accepts the same forms as the CLI: "plugin@marketplace" (marketplace install), "owner/repo" or "owner/repo:subpath" (GitHub direct), an http/https/ssh URL, or a local path. Direct (non-marketplace) installs are deprecated and will produce a deprecationWarning in the result. + [JsonPropertyName("source")] + public string Source { get; set; } = string.Empty; +} + +/// Name (or spec) of the plugin to uninstall. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PluginsUninstallRequestWithSession +{ + /// Stable source identity for a direct (non-marketplace) install. Disambiguates uninstall when multiple installed plugins share the same name. + [JsonPropertyName("directSourceId")] + public string? DirectSourceId { get; set; } + + /// Plugin name or "plugin@marketplace" spec to uninstall. When ambiguous, prefer the fully-qualified spec. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Name (or spec) of the plugin to update. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PluginsUpdateRequestWithSession +{ + /// Plugin name or "plugin@marketplace" spec to update. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Plugin names (or specs) to enable in the session's authoritative working directory. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionPluginsEnableRequest +{ + /// Plugin names or "plugin@marketplace" specs to enable. Unknown names are ignored. Non-marketplace direct installs are always enabled and cannot be toggled via this API. + [JsonPropertyName("names")] + public IList Names { get => field ??= []; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Plugin names (or specs) to disable in the session's authoritative working directory. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionPluginsDisableRequest +{ + /// Plugin names or "plugin@marketplace" specs to disable. Unknown names are ignored. Non-marketplace direct installs cannot be disabled via this API; uninstall them instead. Plugin-owned MCP servers are stopped in active sessions immediately; other plugin contributions remain available until each session reloads plugins. + [JsonPropertyName("names")] + public IList Names { get => field ??= []; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// RPC data type for SessionPluginsReload operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionPluginsReloadRequest +{ + /// When true, skip repo-level hooks during the hook reload. Use before folder trust is confirmed; load them post-trust via `sessions.loadDeferredRepoHooks`. + [JsonPropertyName("deferRepoHooks")] + public bool? DeferRepoHooks { get; set; } + + /// Re-run custom-agent discovery after refreshing plugins. Defaults to true. + [JsonPropertyName("reloadCustomAgents")] + public bool? ReloadCustomAgents { get; set; } + + /// Re-discover and relaunch subprocess extensions (including plugin-shipped extensions) after refreshing plugins. Defaults to true. Has no effect when the session has no active extension controller (e.g. extensions were not requested for the session). + [JsonPropertyName("reloadExtensions")] + public bool? ReloadExtensions { get; set; } + + /// Re-load user, plugin, and (subject to `deferRepoHooks`) repo hooks. Defaults to true. Has no effect when the host has not registered a hook reloader (e.g. remote sessions). + [JsonPropertyName("reloadHooks")] + public bool? ReloadHooks { get; set; } + + /// Reload MCP server connections after refreshing plugins. Defaults to true. + [JsonPropertyName("reloadMcp")] + public bool? ReloadMcp { get; set; } +} + +/// RPC data type for SessionPluginsReloadRequestWithSession operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionPluginsReloadRequestWithSession +{ + /// When true, skip repo-level hooks during the hook reload. Use before folder trust is confirmed; load them post-trust via `sessions.loadDeferredRepoHooks`. + [JsonPropertyName("deferRepoHooks")] + public bool? DeferRepoHooks { get; set; } + + /// Re-run custom-agent discovery after refreshing plugins. Defaults to true. + [JsonPropertyName("reloadCustomAgents")] + public bool? ReloadCustomAgents { get; set; } + + /// Re-discover and relaunch subprocess extensions (including plugin-shipped extensions) after refreshing plugins. Defaults to true. Has no effect when the session has no active extension controller (e.g. extensions were not requested for the session). + [JsonPropertyName("reloadExtensions")] + public bool? ReloadExtensions { get; set; } + + /// Re-load user, plugin, and (subject to `deferRepoHooks`) repo hooks. Defaults to true. Has no effect when the host has not registered a hook reloader (e.g. remote sessions). + [JsonPropertyName("reloadHooks")] + public bool? ReloadHooks { get; set; } + + /// Reload MCP server connections after refreshing plugins. Defaults to true. + [JsonPropertyName("reloadMcp")] + public bool? ReloadMcp { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Retry outcome for one plugin required by managed settings. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ManagedPluginRetryEntry +{ + /// Why the plugin was not prepared. Present when `status` is `failed` or `deferred`. + [JsonPropertyName("error")] + public string? Error { get; set; } + + /// Plugin spec in "plugin@marketplace" form. + [JsonPropertyName("spec")] + public string Spec { get; set; } = string.Empty; + + /// What the retry did for this plugin. + [JsonPropertyName("status")] + public ManagedPluginRetryStatus Status { get; set; } +} + +/// Per-plugin outcomes of retrying the plugins required by the session's managed settings. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionPluginsRetryManagedResult +{ + /// One entry per requested plugin, in request order. When no plugins were requested, one entry per plugin the managed settings require. + [JsonPropertyName("plugins")] + public IList Plugins { get => field ??= []; set; } +} + +/// RPC data type for SessionPluginsRetryManaged operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionPluginsRetryManagedRequest +{ + /// "plugin@marketplace" specs to retry. Omit to retry every plugin the session's managed settings require. + [JsonPropertyName("plugins")] + public IList? Plugins { get; set; } +} + +/// RPC data type for SessionPluginsRetryManagedRequestWithSession operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionPluginsRetryManagedRequestWithSession +{ + /// "plugin@marketplace" specs to retry. Omit to retry every plugin the session's managed settings require. + [JsonPropertyName("plugins")] + public IList? Plugins { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionPluginsMarketplacesListRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Marketplace source and optional working directory for relative-path resolution. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PluginsMarketplacesAddRequestWithSession +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Marketplace source. Accepts the same forms as the CLI: "owner/repo" or "owner/repo#ref" (GitHub), an http/https/ssh URL (optionally with #ref), a git scp-style URL (user@host:path), or a local path. The marketplace's own name (from its manifest) is used as the registration key. + [JsonPropertyName("source")] + public string Source { get; set; } = string.Empty; + + /// Working directory used to resolve relative local paths in `source`. Defaults to the server's current working directory. + [JsonPropertyName("workingDirectory")] + public string? WorkingDirectory { get; set; } +} + +/// Name of the marketplace to remove and an optional force flag. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PluginsMarketplacesRemoveRequestWithSession +{ + /// When true, also uninstall every plugin sourced from this marketplace. When false (default), removal is a no-op if any plugin from this marketplace is installed and the dependent plugin names are returned in the result. + [JsonPropertyName("force")] + public bool? Force { get; set; } + + /// Marketplace name to remove. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Name of the marketplace whose plugin catalog to fetch. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PluginsMarketplacesBrowseRequestWithSession +{ + /// Marketplace name to browse. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// RPC data type for SessionPluginsMarketplacesRefresh operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionPluginsMarketplacesRefreshRequest +{ + /// Marketplace name to refresh. When omitted, every registered marketplace is refreshed. + [JsonPropertyName("name")] + public string? Name { get; set; } +} + +/// RPC data type for SessionPluginsMarketplacesRefreshRequestWithSession operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionPluginsMarketplacesRefreshRequestWithSession +{ + /// Marketplace name to refresh. When omitted, every registered marketplace is refreshed. + [JsonPropertyName("name")] + public string? Name { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Short-lived, rotating credential the caller must send on every request, in addition to `apiKey` if one is present. Omitted when the endpoint does not require one. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ProviderSessionToken +{ + /// When the token expires, if known. Callers should refresh by calling `getEndpoint` again before this time, or reactively on any 401/403 response from `baseUrl`. + [JsonPropertyName("expiresAt")] + public DateTimeOffset? ExpiresAt { get; set; } + + /// HTTP header name the token must be sent under. + [JsonPropertyName("header")] + public string Header { get; set; } = string.Empty; + + /// The model the token is bound to, when applicable. When set, the token is only valid for requests against this model. + [JsonPropertyName("model")] + public string? Model { get; set; } + + /// The short-lived token value. + [JsonPropertyName("token")] + public string Token { get; set; } = string.Empty; +} + +/// A snapshot of the provider endpoint the session is currently configured to talk to. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ProviderEndpoint +{ + /// A credential the caller should use with this endpoint. Omitted only when the endpoint accepts unauthenticated requests. + [JsonPropertyName("apiKey")] + public string? ApiKey { get; set; } + + /// Base URL to pass to the LLM client library. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("baseUrl")] + public string BaseUrl { get; set; } = string.Empty; + + /// HTTP headers the caller must include on every outbound request. + [JsonPropertyName("headers")] + public IDictionary Headers { get => field ??= new Dictionary(); set; } + + /// Short-lived, rotating credential the caller must send on every request, in addition to `apiKey` if one is present. Omitted when the endpoint does not require one. + [JsonPropertyName("sessionToken")] + public ProviderSessionToken? SessionToken { get; set; } + + /// Transport to be used for provider requests. + [JsonPropertyName("transport")] + public ProviderEndpointTransport? Transport { get; set; } + + /// Provider family. Matches the `type` field of a BYOK provider config. + [JsonPropertyName("type")] + public ProviderEndpointType Type { get; set; } + + /// Wire API to be used, when required for the provider type. + [JsonPropertyName("wireApi")] + public ProviderEndpointWireApi? WireApi { get; set; } +} + +/// RPC data type for SessionProviderGetEndpoint operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionProviderGetEndpointRequest +{ + /// Model identifier the caller intends to use against the returned endpoint. Used to pick the correct wire shape. Omit to use whichever model the session is currently using. + [JsonPropertyName("modelId")] + public string? ModelId { get; set; } +} + +/// RPC data type for SessionProviderGetEndpointRequestWithSession operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionProviderGetEndpointRequestWithSession +{ + /// Model identifier the caller intends to use against the returned endpoint. Used to pick the correct wire shape. Omit to use whichever model the session is currently using. + [JsonPropertyName("modelId")] + public string? ModelId { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// The selectable model entries synthesized for the models added by this call. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ProviderAddResult +{ + /// Synthesized selectable model entries for the newly added BYOK models, each under its provider-qualified selection id (`provider/id`). Empty when only providers were added. + [JsonPropertyName("models")] + public IList Models { get => field ??= []; set; } +} + +/// BYOK providers and/or models to add to the session's registry at runtime. Both fields are optional; provide providers, models, or both. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ProviderAddRequest +{ + /// BYOK model definitions to register. Each must reference a provider that is already registered or included in this same call. Selection ids (`provider/id`) must be unique across the registry. + [JsonPropertyName("models")] + public IList? Models { get; set; } + + /// Named BYOK provider connections to register, additive to any providers already in the registry. Each name must be unique across the registry and must not contain '/'. + [JsonPropertyName("providers")] + public IList? Providers { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// The selectable model entries and selection ids synthesized for the synchronized BYOK models. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ProviderSyncResult +{ + /// True when synchronization withdrew the selected host-managed model, leaving the session with no explicit selection, so ordinary model resolution picks the session default. Synchronization never promotes a surviving host model in its place: publishing a model offers it, and the choice of which model to use stays with the user. + [JsonPropertyName("modelDeselected")] + public bool? ModelDeselected { get; set; } + + /// Synthesized selectable model entries for the synchronized BYOK models. + [JsonPropertyName("models")] + public IList Models { get => field ??= []; set; } + + /// Provider-qualified model selection ids present after synchronization. + [JsonPropertyName("selectionIds")] + public IList SelectionIds { get => field ??= []; set; } +} + +/// Authoritative BYOK provider and model registry snapshot to apply atomically to the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ProviderSyncRequest +{ + /// BYOK model definition snapshot. Models absent from this list are removed. + [JsonPropertyName("models")] + public IList? Models { get; set; } + + /// Named BYOK provider connection snapshot. Providers absent from this list are removed. + [JsonPropertyName("providers")] + public IList? Providers { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// What the withdrawal actually removed from the registry. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ProviderWithdrawResult +{ + /// True when withdrawal removed the selected host-managed model, leaving the session with no explicit selection, so ordinary model resolution picks the session default. Withdrawal never promotes a surviving model in its place: the choice of which model to use stays with the user. + [JsonPropertyName("modelDeselected")] + public bool? ModelDeselected { get; set; } + + /// Providers removed because one of the withdrawn models was the last entry referencing them. A provider that merely has no models is not removed. + [JsonPropertyName("providersRemoved")] + public IList ProvidersRemoved { get => field ??= []; set; } + + /// Selection ids that were registered and are now withdrawn. Excludes requested ids that were not present. + [JsonPropertyName("withdrawn")] + public IList Withdrawn { get => field ??= []; set; } +} + +/// Host-managed model selection ids to withdraw from the session's BYOK registry. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ProviderWithdrawRequest +{ + /// Provider-qualified selection ids to withdraw. Ids that are not registered are ignored, so withdrawal is idempotent. A provider left with no models referencing it is removed too. + [JsonPropertyName("models")] + public IList Models { get => field ??= []; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// Indicates whether the session options patch was applied successfully. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionUpdateOptionsResult +{ + /// Number of hooks loaded from installed plugins, returned when installedPlugins is updated. + [JsonPropertyName("pluginHookCount")] + public long? PluginHookCount { get; set; } + + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } +} + +/// Source descriptor for a `session.options.update` content-exclusion rule, with source name and type. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class OptionsUpdateAdditionalContentExclusionPolicyRuleSource +{ + /// Name of the policy source. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Type of the policy source. + [JsonPropertyName("type")] + public string Type { get; set; } = string.Empty; +} + +/// Single content-exclusion rule supplied to `session.options.update`, with paths, match conditions, and source. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class OptionsUpdateAdditionalContentExclusionPolicyRule +{ + /// Conditions of which at least one must match. + [JsonPropertyName("ifAnyMatch")] + public IList? IfAnyMatch { get; set; } + + /// Conditions none of which may match. + [JsonPropertyName("ifNoneMatch")] + public IList? IfNoneMatch { get; set; } + + /// Path patterns covered by this rule. + [JsonPropertyName("paths")] + public IList Paths { get => field ??= []; set; } + + /// Source descriptor for a `session.options.update` content-exclusion rule, with source name and type. + [JsonPropertyName("source")] + public OptionsUpdateAdditionalContentExclusionPolicyRuleSource Source { get => field ??= new(); set; } +} + +/// Content-exclusion policy supplied to `session.options.update`, with rules, last-updated data, and scope. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class OptionsUpdateAdditionalContentExclusionPolicy +{ + /// Opaque policy update timestamp supplied by the host. + [JsonPropertyName("last_updated_at")] + public JsonElement LastUpdatedAt { get; set; } + + /// Content-exclusion rules to apply. + [JsonPropertyName("rules")] + public IList Rules { get => field ??= []; set; } + + /// Allowed values for the `OptionsUpdateAdditionalContentExclusionPolicyScope` enumeration. + [JsonPropertyName("scope")] + public OptionsUpdateAdditionalContentExclusionPolicyScope Scope { get; set; } +} + +/// Options scoped to the built-in CAPI (Copilot API) provider. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class CapiSessionOptions +{ + /// Routing preference for sessions whose model is `auto`. On create or cold resume, this establishes the preference sent as `tier` on CAPI `/auto` requests; when omitted on cold resume, the runtime restores the last committed preference. On resident resume, a different value requests a safe switch after resume succeeds and cannot change an in-flight turn. Successful switches are persisted for later cold resume. When no preference is supplied or restored, CAPI default routing is used. `fast` is an integrator-only latency preset, not a first-party GitHub Copilot product preference. + [JsonPropertyName("autoTier")] + public AutoTier? AutoTier { get; set; } + + /// Whether to use WebSocket transport for the CAPI Responses API. Enabled by default when the model advertises `ws:/responses` support; set to `false` to force the HTTP Responses transport in environments where WebSockets are blocked (e.g. behind a proxy). Setting this to `false` is equivalent to the `COPILOT_CLI_DISABLE_WEBSOCKET_RESPONSES` environment variable. + [JsonPropertyName("enableWebSocketResponses")] + public bool? EnableWebSocketResponses { get; set; } +} + +/// Installed plugin record for a session, with marketplace, version, install time, enabled state, cache path, and source. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionInstalledPlugin +{ + /// Path where the plugin is cached locally. + [JsonPropertyName("cache_path")] + public string? CachePath { get; set; } + + /// Whether the plugin is currently enabled. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } + + /// Installation timestamp (ISO-8601). + [JsonPropertyName("installed_at")] + public string InstalledAt { get; set; } = string.Empty; + + /// Absolute path of the marketplace directory a live plugin was resolved from. Present only on live, never-persisted records — those synthesized at session start for a directory/local marketplace, whose cache_path points at the real plugin directory on disk rather than a copy under the installed-plugins cache. Its presence is what marks a record as live, and no record carrying it is ever written to the persisted installedPlugins key. + [JsonPropertyName("installed_from")] + public string? InstalledFrom { get; set; } + + /// Marketplace the plugin came from (empty string for direct repo installs). [JsonPropertyName("marketplace")] public string Marketplace { get; set; } = string.Empty; - /// Plugin name. + /// Plugin name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Source descriptor for direct repo installs (when marketplace is empty). + [JsonPropertyName("source")] + public JsonElement? Source { get; set; } + + /// Per-plugin source fingerprint (a SHA-256 hash of the plugin's catalog source spec plus its resolved source subtree — NOT a Git commit SHA) captured at marketplace install/update time. Auto-update compares it against the freshly recomputed fingerprint to detect a content change that does not bump the version. Absent for pre-existing installs and for direct (non-marketplace) installs. + [JsonPropertyName("source_sha")] + public string? SourceSha { get; set; } + + /// Installed version, if known. + [JsonPropertyName("version")] + public string? Version { get; set; } +} + +/// Custom model-provider configuration (BYOK). +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ProviderConfig +{ + /// API key. Optional for local providers like Ollama. + [JsonPropertyName("apiKey")] + public string? ApiKey { get; set; } + + /// Azure-specific provider options. + [JsonPropertyName("azure")] + public ProviderConfigAzure? Azure { get; set; } + + /// API endpoint URL. + [JsonPropertyName("baseUrl")] + public string BaseUrl { get; set; } = string.Empty; + + /// Bearer token for authentication. Sets the Authorization header directly. Takes precedence over apiKey when both are set. + [JsonPropertyName("bearerToken")] + public string? BearerToken { get; set; } + + /// When true, the SDK client supplies bearer tokens on demand: the runtime calls the client-session `providerToken.getToken` callback before each request and applies the returned token as an `Authorization: Bearer <token>` header. This is the bearer/OAuth scheme used by Azure AD / managed-identity tokens and provider OAuth access tokens (including Anthropic's), not a provider-specific API-key header such as Anthropic's `x-api-key`. The token-acquiring function itself stays on the SDK side and is never serialized; only this flag crosses the wire. When set alongside `apiKey`/`bearerToken`, the callback takes precedence: the runtime applies the token returned by `providerToken.getToken` as the `Authorization: Bearer` header for each request and does not send the static credential. + [JsonPropertyName("hasBearerTokenProvider")] + public bool? HasBearerTokenProvider { get; set; } + + /// Custom HTTP headers to include in all outbound requests to the provider. + [JsonPropertyName("headers")] + public IDictionary? Headers { get; set; } + + /// Maximum context window tokens for the model. + [JsonPropertyName("maxContextWindowTokens")] + public double? MaxContextWindowTokens { get; set; } + + /// Maximum output tokens for the model. + [JsonPropertyName("maxOutputTokens")] + public double? MaxOutputTokens { get; set; } + + /// Maximum prompt/input tokens for the model. + [JsonPropertyName("maxPromptTokens")] + public double? MaxPromptTokens { get; set; } + + /// Overrides for model capabilities when they cannot be inferred from modelId. + [JsonPropertyName("modelCapabilities")] + public ModelCapabilitiesOverride? ModelCapabilities { get; set; } + + /// Well-known model ID used for capability lookup. When set, agent behavior config and token limits are inferred from this model. + [JsonPropertyName("modelId")] + public string? ModelId { get; set; } + + /// The product serving the model, reported in telemetry as `model_provider`. Set it when `type` alone cannot identify the product, such as Ollama or LM Studio behind an OpenAI-compatible endpoint. Only affects telemetry. + [JsonPropertyName("modelProvider")] + public ProviderConfigModelProvider? ModelProvider { get; set; } + + /// Provider name used for model and telemetry attribution. + [JsonPropertyName("providerName")] + public string? ProviderName { get; set; } + + /// Provider transport. Defaults to "http". + [JsonPropertyName("transport")] + public ProviderConfigTransport? Transport { get; set; } + + /// Provider type. Defaults to "openai" for generic OpenAI-compatible APIs. + [JsonPropertyName("type")] + public ProviderConfigType? Type { get; set; } + + /// Wire API format (openai/azure only). Defaults to "completions". + [JsonPropertyName("wireApi")] + public ProviderConfigWireApi? WireApi { get; set; } + + /// The model identifier sent to the provider API for inference (the "wire" model), as opposed to modelId which is the well-known base. + [JsonPropertyName("wireModel")] + public string? WireModel { get; set; } +} + +/// +/// Command-scoped GitHub credential injection for the shell commands an agent runs. +/// +/// Each channel is opt-in and independent, and injection is scoped to the individual command +/// spawn: the credential is resolved from the session's *current* authentication at every spawn +/// and reaches only spawns whose script actually invokes `git` or `gh`. Because nothing is +/// retained between spawns, replacing the session credential (`session.gitHubAuth.setCredentials`) +/// changes what the next spawned command presents — which seeding a credential into the runtime +/// process's own environment cannot do, since a child's environment is fixed at `exec`. +/// +/// The credential is matched to the host it authenticates to, so a github.com credential is never +/// presented to a GitHub Enterprise host and vice versa. Where a channel cannot express that +/// boundary it injects nothing rather than crossing it -- see `gh` below. +/// +/// This is independent of `sandboxConfig`: it is a decision about which identity the agent +/// presents, not about what the agent may touch, and it works on every platform whether or not +/// an OS sandboxing backend is available. `sandboxConfig.auth` remains the sandbox-scoped +/// spelling and is additive with this one. +/// +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ShellCredentials +{ + /// + /// Whether to authenticate the agent's `gh` commands as the session's GitHub credential, by + /// exporting `GH_TOKEN` to a spawn that runs `gh`. Any inherited `gh` credential is removed from + /// spawns that do not, so the credential stays command-scoped. + /// + /// Applies to a github.com credential only. `gh` picks its credential variable from the host a + /// command targets rather than the one the credential belongs to, and the command can choose that + /// target, so `GH_ENTERPRISE_TOKEN` would offer a single-tenant enterprise credential to every + /// other enterprise host. A session whose credential is enterprise-scoped therefore runs `gh` + /// unauthenticated; its `git` commands are unaffected, because `http.<host>.extraheader` is scoped + /// to one host by construction. Default: false (opt-in). + /// + [JsonPropertyName("gh")] + public bool? Gh { get; set; } + + /// + /// Whether to authenticate the agent's `git` commands as the session's GitHub credential, by + /// injecting an `http.<host>.extraheader` (plus `insteadOf` rewrites so SSH-spelled remotes for + /// that host use the authenticated HTTPS transport). Applied only to a spawn that runs a + /// remote-contacting `git` subcommand. Default: false (opt-in). + /// + [JsonPropertyName("git")] + public bool? Git { get; set; } +} + +/// A host-provided script sourced before each built-in shell command when its shell target matches the active shell. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ShellInitScript +{ + /// Path to the script to source. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// Built-in shell that may source this script. + [JsonPropertyName("shell")] + public ShellInitScriptShell Shell { get; set; } +} + +/// Per-session settings for built-in shell tools. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ShellOptions +{ + /// Command-scoped GitHub credential injection for shell commands. + [JsonPropertyName("credentials")] + public ShellCredentials? Credentials { get; set; } + + /// Controls automatic non-interactive profile loading where supported. Explicit initScripts are unaffected. + [JsonPropertyName("initProfile")] + public ShellInitProfile? InitProfile { get; set; } + + /// + /// Ordered host-provided script paths sourced before each built-in shell command when the + /// entry's shell target matches the active shell. Use these for rc files, environment setup scripts, + /// or other custom scripts. A script that returns a nonzero status is reported, and later scripts + /// and the user command continue while the shell remains running. Because scripts are sourced into + /// the command shell, `exit`, `exec`, failures under `set -e`, or other shell-terminating behavior + /// can prevent continuation. Script standard output is preserved; Bash script stderr is discarded, + /// PowerShell exception messages are replaced, and runtime-generated failure notices omit + /// configured script paths. When sandboxing is enabled, each script must already be readable under + /// the active sandbox filesystem policy. Pass an empty array to clear the list. + /// + [JsonPropertyName("initScripts")] + public IList? InitScripts { get; set; } + + /// + /// Flags passed to the active built-in shell process on startup, replacing its default flags. + /// When omitted, the built-in Bash shell uses `--norc --noprofile`, + /// and the built-in PowerShell shell uses `-NoProfile -NoLogo`. + /// + [JsonPropertyName("processFlags")] + public IList? ProcessFlags { get; set; } +} + +/// Patch of mutable session options to apply to the running session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionUpdateOptionsParams +{ + /// Additional content-exclusion policies to merge into the session's policy set. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + [JsonPropertyName("additionalContentExclusionPolicies")] + public IList? AdditionalContentExclusionPolicies { get; set; } + + /// Runtime context discriminator (e.g., `cli`, `actions`). + [JsonPropertyName("agentContext")] + public string? AgentContext { get; set; } + + /// Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + [JsonPropertyName("agentDirectories")] + public IList? AgentDirectories { get; set; } + + /// Whether to include instructions from every MCP server in the system prompt instead of only allowlisted servers. + [JsonPropertyName("allowAllMcpServerInstructions")] + public bool? AllowAllMcpServerInstructions { get; set; } + + /// Whether to disable the `ask_user` tool (encourages autonomous behavior). + [JsonPropertyName("askUserDisabled")] + public bool? AskUserDisabled { get; set; } + + /// Allowlist of tool names available to this session. + [JsonPropertyName("availableTools")] + public IList? AvailableTools { get; set; } + + /// Options scoped to the built-in CAPI (Copilot API) provider. + [JsonPropertyName("capi")] + public CapiSessionOptions? Capi { get; set; } + + /// Identifier of the client driving the session. + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } + + /// Whether to include the `Co-authored-by` trailer in commit messages. + [JsonPropertyName("coauthorEnabled")] + public bool? CoauthorEnabled { get; set; } + + /// Context tier for models with tiered pricing. The session uses this to derive effective `modelCapabilitiesOverrides` so compaction, truncation, token display, and request limits honor the selected tier. + [JsonPropertyName("contextTier")] + public OptionsUpdateContextTier? ContextTier { get; set; } + + /// Whether to allow auto-mode continuation across turns. + [JsonPropertyName("continueOnAutoMode")] + public bool? ContinueOnAutoMode { get; set; } + + /// Override URL for the Copilot API endpoint. + [JsonPropertyName("copilotUrl")] + public string? CopilotUrl { get; set; } + + /// Whether to default custom agents to local-only execution. + [JsonPropertyName("customAgentsLocalOnly")] + public bool? CustomAgentsLocalOnly { get; set; } + + /// Instruction source IDs to exclude from the system prompt. + [JsonPropertyName("disabledInstructionSources")] + public IList? DisabledInstructionSources { get; set; } + + /// Skill IDs that should be excluded from this session. + [JsonPropertyName("disabledSkills")] + public IList? DisabledSkills { get; set; } + + /// Whether to enable repository-origin file hooks from `.github/hooks/` and trusted repository-configured roots. Does not control explicit hookDirectories or SDK callback hooks. + [JsonPropertyName("enableFileHooks")] + public bool? EnableFileHooks { get; set; } + + /// Whether to enable host git operations (context resolution, child repo scanning, git info in system prompt). + [JsonPropertyName("enableHostGitOperations")] + public bool? EnableHostGitOperations { get; set; } + + /// Whether to discover custom instructions on demand after successful file views (AGENTS.md / CLAUDE.md / .github/copilot-instructions.md surfacing). Combined with `skipCustomInstructions`. + [JsonPropertyName("enableOnDemandInstructionDiscovery")] + public bool? EnableOnDemandInstructionDiscovery { get; set; } + + /// Whether to surface reasoning-summary events from the model. + [JsonPropertyName("enableReasoningSummaries")] + public bool? EnableReasoningSummaries { get; set; } + + /// Whether shell-script safety heuristics are enabled. + [JsonPropertyName("enableScriptSafety")] + public bool? EnableScriptSafety { get; set; } + + /// Whether to enable cross-session store writes and reads. + [JsonPropertyName("enableSessionStore")] + public bool? EnableSessionStore { get; set; } + + /// Whether skill loading is enabled. Explicit false disables every source, including explicit SDK roots and a bound SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless explicit SDK skill roots or an SDK skill provider are supplied. + [JsonPropertyName("enableSkills")] + public bool? EnableSkills { get; set; } + + /// Whether to stream model responses. + [JsonPropertyName("enableStreaming")] + public bool? EnableStreaming { get; set; } + + /// How env values are passed to MCP servers (`direct` inlines literal values; `indirect` resolves at launch). + [JsonPropertyName("envValueMode")] + public OptionsUpdateEnvValueMode? EnvValueMode { get; set; } + + /// Override directory for the session-events log. When unset, the runtime's default events log directory is used. + [JsonPropertyName("eventsLogDirectory")] + public string? EventsLogDirectory { get; set; } + + /// Whether subagent callback events should be forwarded into the session event log sink. + [JsonPropertyName("eventsLogIncludesSubagents")] + public bool? EventsLogIncludesSubagents { get; set; } + + /// Built-in subagent names to exclude from this session. Excluded built-ins are hidden from agent discovery and cannot be dispatched unless a custom agent with the same name is available. + [JsonPropertyName("excludedBuiltinAgents")] + public IList? ExcludedBuiltinAgents { get; set; } + + /// Denylist of tool names for this session. + [JsonPropertyName("excludedTools")] + public IList? ExcludedTools { get; set; } + + /// Map of feature-flag IDs to their boolean enabled state. + [JsonPropertyName("featureFlags")] + public IDictionary? FeatureFlags { get; set; } + + /// Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without enableConfigDiscovery or enableFileHooks, which controls repository-origin hooks only; hook/managed disables still apply. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + [JsonPropertyName("hookDirectories")] + public IList? HookDirectories { get; set; } + + /// Skill scan directories and descendants excluded from discovery. Supports `~`-relative paths. + [JsonPropertyName("ignoredSkillsLocations")] + public IList? IgnoredSkillsLocations { get; set; } + + /// Built-in subagent names to include in this session. When specified, only these built-ins are available, subject to runtime availability and exclusions. Custom agents with the same name remain available. Set to null to remove the allowlist restriction. + [JsonPropertyName("includedBuiltinAgents")] + public IList? IncludedBuiltinAgents { get; set; } + + /// Built-in skill names to include in this session. When specified, only these runtime-bundled skills are available. Skills from other sources with the same name remain available. Set to null to remove the allowlist restriction. + [JsonPropertyName("includedBuiltinSkills")] + public IList? IncludedBuiltinSkills { get; set; } + + /// Full set of installed plugins for the session. Replaces the existing list; the runtime invalidates the skills cache only when the list materially changes. + [JsonPropertyName("installedPlugins")] + public IList? InstalledPlugins { get; set; } + + /// Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without enableConfigDiscovery, subject to instruction/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + [JsonPropertyName("instructionDirectories")] + public IList? InstructionDirectories { get; set; } + + /// Stable integration identifier used for analytics and rate-limit attribution. + [JsonPropertyName("integrationId")] + public string? IntegrationId { get; set; } + + /// Whether experimental capabilities are enabled. + [JsonPropertyName("isExperimentalMode")] + public bool? IsExperimentalMode { get; set; } + + /// Whether interactive shell sessions are logged. + [JsonPropertyName("logInteractiveShells")] + public bool? LogInteractiveShells { get; set; } + + /// Identifier sent to LSP-style integrations. + [JsonPropertyName("lspClientName")] + public string? LspClientName { get; set; } + + /// Whether to expose the `manage_schedule` tool to the agent. The runtime always owns the per-session schedule registry; this flag only controls tool exposure (typically gated to staff users). + [JsonPropertyName("manageScheduleEnabled")] + public bool? ManageScheduleEnabled { get; set; } + + /// Maximum decoded byte size of a single model-facing binary tool result (e.g. an image) persisted inline in session events and re-presented to the model on later turns / resume. Larger results are persisted as a metadata-only marker and shown to the model as a short text note. Defaults to 10 MB. + [JsonPropertyName("maxInlineBinaryBytes")] + public long? MaxInlineBinaryBytes { get; set; } + + /// The model ID to use for assistant turns. + [JsonPropertyName("model")] + public string? Model { get; set; } + + /// Per-property model capability overrides for the selected model. + [JsonPropertyName("modelCapabilitiesOverrides")] + public ModelCapabilitiesOverride? ModelCapabilitiesOverrides { get; set; } + + /// Organization-level custom instructions to inject into the system prompt. + [JsonPropertyName("organizationCustomInstructions")] + public string? OrganizationCustomInstructions { get; set; } + + /// Custom model-provider configuration (BYOK). + [JsonPropertyName("provider")] + public ProviderConfig? Provider { get; set; } + + /// Reasoning effort for the selected model. CAPI values are model-defined and validated against the selected model; BYOK providers may define additional values. When omitted, no effort override is applied. + [JsonPropertyName("reasoningEffort")] + public string? ReasoningEffort { get; set; } + + /// Reasoning summary mode for supported model clients. + [JsonPropertyName("reasoningSummary")] + public OptionsUpdateReasoningSummary? ReasoningSummary { get; set; } + + /// Whether the session is running in an interactive UI. + [JsonPropertyName("runningInInteractiveMode")] + public bool? RunningInInteractiveMode { get; set; } + + /// Resolved sandbox configuration. + [JsonPropertyName("sandboxConfig")] + public SandboxConfig? SandboxConfig { get; set; } + + /// Origin of the sandbox choice. Settings-derived origins (never_configured, user_enabled, user_disabled, repository_policy) let managed policy floor a host preference; explicit below-floor changes remain policy conflicts unless a session opt-out is authorized. Also used for telemetry provenance. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + [JsonPropertyName("sandboxConfigSource")] + public SandboxConfigSource? SandboxConfigSource { get; set; } + + /// Replaces the session's capability set with the given list. Use to enable or disable capabilities mid-session (e.g., remove `memory` for reproducible scripted runs). Omit the field to leave the existing capability set unchanged. + [JsonPropertyName("sessionCapabilities")] + public IList? SessionCapabilities { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Optional session limits. Pass null to clear the session limits. + [JsonPropertyName("sessionLimits")] + public SessionLimitsConfig? SessionLimits { get; set; } + + /// Per-session settings for built-in shell tools. + [JsonPropertyName("shell")] + public ShellOptions? Shell { get; set; } + + /// Use shell.initProfile instead. Shell init profile (`None` or `NonInteractive`). + [EditorBrowsable(EditorBrowsableState.Never)] +#if NET5_0_OR_GREATER + [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] +#else + [Obsolete("This member is deprecated and will be removed in a future version.")] +#endif + [JsonPropertyName("shellInitProfile")] + public string? ShellInitProfile { get; set; } + + /// PowerShell process flags applied to built-in and user-requested shell commands. + [JsonPropertyName("shellProcessFlags")] + public IList? ShellProcessFlags { get; set; } + + /// Explicit discovery-only skill roots, not filesystem grants. Available without enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + [JsonPropertyName("skillDirectories")] + public IList? SkillDirectories { get; set; } + + /// Whether to skip loading custom instruction sources. + [JsonPropertyName("skipCustomInstructions")] + public bool? SkipCustomInstructions { get; set; } + + /// Whether to skip embedding retrieval pipeline initialization and execution. + [JsonPropertyName("skipEmbeddingRetrieval")] + public bool? SkipEmbeddingRetrieval { get; set; } + + /// When true, the selected custom agent's prompt is not injected into the user message (skill context is still injected). Used by automation triggers where the agent prompt is already in the problem statement. + [JsonPropertyName("suppressCustomAgentPrompt")] + public bool? SuppressCustomAgentPrompt { get; set; } + + /// Controls how availableTools (allowlist) and excludedTools (denylist) combine when both are set. + [JsonPropertyName("toolFilterPrecedence")] + public OptionsUpdateToolFilterPrecedence? ToolFilterPrecedence { get; set; } + + /// Optional path for trajectory output. + [JsonPropertyName("trajectoryFile")] + public string? TrajectoryFile { get; set; } + + /// Output verbosity level for supported models. + [JsonPropertyName("verbosity")] + public Verbosity? Verbosity { get; set; } + + /// Absolute working-directory path for shell tools. + [JsonPropertyName("workingDirectory")] + public string? WorkingDirectory { get; set; } +} + +/// Parameters for (re)loading the merged LSP configuration set. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class LspInitializeRequest +{ + /// Force re-initialization even when LSP configs were already loaded for the working directory. + [JsonPropertyName("force")] + public bool? Force { get; set; } + + /// Git root used as the boundary when traversing for project-level LSP configs (supports monorepos). + [JsonPropertyName("gitRoot")] + public string? GitRoot { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Working directory used to load project-level LSP configs. Defaults to the session working directory when omitted. + [JsonPropertyName("workingDirectory")] + public string? WorkingDirectory { get; set; } +} + +/// Discovered extension metadata, including source-qualified ID, name, discovery source, status, and optional process ID. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class Extension +{ + /// Source-qualified ID (e.g., 'project:my-ext', 'user:auth-helper', 'plugin:my-plugin:my-ext'). + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + /// Extension name (directory name). [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; - /// Source descriptor for direct repo installs (when marketplace is empty). + /// Process ID if the extension is running. + [JsonPropertyName("pid")] + public long? Pid { get; set; } + + /// Discovery source: project (.github/extensions/), user (~/.copilot/extensions/), plugin (installed plugin), or session (session-state/<id>/extensions/). [JsonPropertyName("source")] - public JsonElement? Source { get; set; } + public ExtensionSource Source { get; set; } - /// Per-plugin source fingerprint (a SHA-256 hash of the plugin's catalog source spec plus its resolved source subtree — NOT a Git commit SHA) captured at marketplace install/update time. Auto-update compares it against the freshly recomputed fingerprint to detect a content change that does not bump the version. Absent for pre-existing installs and for direct (non-marketplace) installs. - [JsonPropertyName("source_sha")] - public string? SourceSha { get; set; } + /// Current status: running, disabled, failed, or starting. + [JsonPropertyName("status")] + public ExtensionStatus Status { get; set; } +} - /// Installed version, if known. - [JsonPropertyName("version")] - public string? Version { get; set; } +/// Extensions discovered for the session, with their current status. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ExtensionList +{ + /// Discovered extensions and their current status. + [JsonPropertyName("extensions")] + public IList Extensions { get => field ??= []; set; } } -/// Custom model-provider configuration (BYOK). +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProviderConfig +internal sealed class SessionExtensionsListRequest { - /// API key. Optional for local providers like Ollama. - [JsonPropertyName("apiKey")] - public string? ApiKey { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Azure-specific provider options. - [JsonPropertyName("azure")] - public ProviderConfigAzure? Azure { get; set; } +/// Source-qualified extension identifier to enable for the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ExtensionsEnableRequest +{ + /// Source-qualified extension ID to enable. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// API endpoint URL. - [JsonPropertyName("baseUrl")] - public string BaseUrl { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Bearer token for authentication. Sets the Authorization header directly. Takes precedence over apiKey when both are set. - [JsonPropertyName("bearerToken")] - public string? BearerToken { get; set; } +/// Source-qualified extension identifier to disable for the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ExtensionsDisableRequest +{ + /// Source-qualified extension ID to disable. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// When true, the SDK client supplies bearer tokens on demand: the runtime calls the client-session `providerToken.getToken` callback before each request and applies the returned token as an `Authorization: Bearer <token>` header. This is the bearer/OAuth scheme used by Azure AD / managed-identity tokens and provider OAuth access tokens (including Anthropic's), not a provider-specific API-key header such as Anthropic's `x-api-key`. The token-acquiring function itself stays on the SDK side and is never serialized; only this flag crosses the wire. When set alongside `apiKey`/`bearerToken`, the callback takes precedence: the runtime applies the token returned by `providerToken.getToken` as the `Authorization: Bearer` header for each request and does not send the static credential. - [JsonPropertyName("hasBearerTokenProvider")] - public bool? HasBearerTokenProvider { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Custom HTTP headers to include in all outbound requests to the provider. - [JsonPropertyName("headers")] - public IDictionary? Headers { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionExtensionsReloadRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Maximum context window tokens for the model. - [JsonPropertyName("maxContextWindowTokens")] - public double? MaxContextWindowTokens { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionExtensionsReconcileRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Maximum output tokens for the model. - [JsonPropertyName("maxOutputTokens")] - public double? MaxOutputTokens { get; set; } +/// Attachment union accepted by push input, covering files, directories, GitHub objects, blobs, snippets, and extension context. +/// Polymorphic base type discriminated by type. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "type", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(PushAttachmentFile), "file")] +[JsonDerivedType(typeof(PushAttachmentDirectory), "directory")] +[JsonDerivedType(typeof(PushAttachmentSelection), "selection")] +[JsonDerivedType(typeof(PushAttachmentGitHubReference), "github_reference")] +[JsonDerivedType(typeof(PushAttachmentGitHubCommit), "github_commit")] +[JsonDerivedType(typeof(PushAttachmentGitHubRelease), "github_release")] +[JsonDerivedType(typeof(PushAttachmentGitHubActionsJob), "github_actions_job")] +[JsonDerivedType(typeof(PushAttachmentGitHubRepository), "github_repository")] +[JsonDerivedType(typeof(PushAttachmentGitHubFileDiff), "github_file_diff")] +[JsonDerivedType(typeof(PushAttachmentGitHubTreeComparison), "github_tree_comparison")] +[JsonDerivedType(typeof(PushAttachmentGitHubUrl), "github_url")] +[JsonDerivedType(typeof(PushAttachmentGitHubFile), "github_file")] +[JsonDerivedType(typeof(PushAttachmentGitHubSnippet), "github_snippet")] +[JsonDerivedType(typeof(PushAttachmentBlob), "blob")] +[JsonDerivedType(typeof(PushAttachmentExtensionContext), "extension_context")] +public partial class PushAttachment +{ + /// The type discriminator. + [JsonPropertyName("type")] + public virtual string Type { get; set; } = string.Empty; +} - /// Maximum prompt/input tokens for the model. - [JsonPropertyName("maxPromptTokens")] - public double? MaxPromptTokens { get; set; } - /// Overrides for model capabilities when they cannot be inferred from modelId. - [JsonPropertyName("modelCapabilities")] - public ModelCapabilitiesOverride? ModelCapabilities { get; set; } +/// Optional line range to scope the attachment to a specific section of the file. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class PushAttachmentFileLineRange +{ + /// End line number (1-based, inclusive). + [JsonPropertyName("end")] + public long End { get; set; } - /// Well-known model ID used for capability lookup. When set, agent behavior config and token limits are inferred from this model. - [JsonPropertyName("modelId")] - public string? ModelId { get; set; } + /// Start line number (1-based). + [JsonPropertyName("start")] + public long Start { get; set; } +} - /// The product serving the model, reported in telemetry as `model_provider`. Set it when `type` alone cannot identify the product, such as Ollama or LM Studio behind an OpenAI-compatible endpoint. Only affects telemetry. - [JsonPropertyName("modelProvider")] - public ProviderConfigModelProvider? ModelProvider { get; set; } +/// File attachment. +/// The file variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentFile : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "file"; - /// Provider name used for model and telemetry attribution. - [JsonPropertyName("providerName")] - public string? ProviderName { get; set; } + /// User-facing display name for the attachment. + [JsonPropertyName("displayName")] + public required string DisplayName { get; set; } - /// Provider transport. Defaults to "http". - [JsonPropertyName("transport")] - public ProviderConfigTransport? Transport { get; set; } + /// Optional line range to scope the attachment to a specific section of the file. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("lineRange")] + public PushAttachmentFileLineRange? LineRange { get; set; } - /// Provider type. Defaults to "openai" for generic OpenAI-compatible APIs. - [JsonPropertyName("type")] - public ProviderConfigType? Type { get; set; } + /// Absolute file path. + [JsonPropertyName("path")] + public required string Path { get; set; } +} - /// Wire API format (openai/azure only). Defaults to "completions". - [JsonPropertyName("wireApi")] - public ProviderConfigWireApi? WireApi { get; set; } +/// Directory attachment. +/// The directory variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentDirectory : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "directory"; - /// The model identifier sent to the provider API for inference (the "wire" model), as opposed to modelId which is the well-known base. - [JsonPropertyName("wireModel")] - public string? WireModel { get; set; } + /// User-facing display name for the attachment. + [JsonPropertyName("displayName")] + public required string DisplayName { get; set; } + + /// Absolute directory path. + [JsonPropertyName("path")] + public required string Path { get; set; } } -/// -/// Command-scoped GitHub credential injection for the shell commands an agent runs. -/// -/// Each channel is opt-in and independent, and injection is scoped to the individual command -/// spawn: the credential is resolved from the session's *current* authentication at every spawn -/// and reaches only spawns whose script actually invokes `git` or `gh`. Because nothing is -/// retained between spawns, replacing the session credential (`session.gitHubAuth.setCredentials`) -/// changes what the next spawned command presents — which seeding a credential into the runtime -/// process's own environment cannot do, since a child's environment is fixed at `exec`. -/// -/// The credential is matched to the host it authenticates to, so a github.com credential is never -/// presented to a GitHub Enterprise host and vice versa. Where a channel cannot express that -/// boundary it injects nothing rather than crossing it -- see `gh` below. -/// -/// This is independent of `sandboxConfig`: it is a decision about which identity the agent -/// presents, not about what the agent may touch, and it works on every platform whether or not -/// an OS sandboxing backend is available. `sandboxConfig.auth` remains the sandbox-scoped -/// spelling and is additive with this one. -/// +/// End position of the selection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ShellCredentials +public sealed class PushAttachmentSelectionDetailsEnd { - /// - /// Whether to authenticate the agent's `gh` commands as the session's GitHub credential, by - /// exporting `GH_TOKEN` to a spawn that runs `gh`. Any inherited `gh` credential is removed from - /// spawns that do not, so the credential stays command-scoped. - /// - /// Applies to a github.com credential only. `gh` picks its credential variable from the host a - /// command targets rather than the one the credential belongs to, and the command can choose that - /// target, so `GH_ENTERPRISE_TOKEN` would offer a single-tenant enterprise credential to every - /// other enterprise host. A session whose credential is enterprise-scoped therefore runs `gh` - /// unauthenticated; its `git` commands are unaffected, because `http.<host>.extraheader` is scoped - /// to one host by construction. Default: false (opt-in). - /// - [JsonPropertyName("gh")] - public bool? Gh { get; set; } + /// End character offset within the line (0-based). + [JsonPropertyName("character")] + public long Character { get; set; } - /// - /// Whether to authenticate the agent's `git` commands as the session's GitHub credential, by - /// injecting an `http.<host>.extraheader` (plus `insteadOf` rewrites so SSH-spelled remotes for - /// that host use the authenticated HTTPS transport). Applied only to a spawn that runs a - /// remote-contacting `git` subcommand. Default: false (opt-in). - /// - [JsonPropertyName("git")] - public bool? Git { get; set; } + /// End line number (0-based). + [JsonPropertyName("line")] + public long Line { get; set; } } -/// A host-provided script sourced before each built-in shell command when its shell target matches the active shell. +/// Start position of the selection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ShellInitScript +public sealed class PushAttachmentSelectionDetailsStart { - /// Path to the script to source. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Start character offset within the line (0-based). + [JsonPropertyName("character")] + public long Character { get; set; } - /// Built-in shell that may source this script. - [JsonPropertyName("shell")] - public ShellInitScriptShell Shell { get; set; } + /// Start line number (0-based). + [JsonPropertyName("line")] + public long Line { get; set; } } -/// Per-session settings for built-in shell tools. +/// Position range of the selection within the file. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ShellOptions +public sealed class PushAttachmentSelectionDetails { - /// Command-scoped GitHub credential injection for shell commands. - [JsonPropertyName("credentials")] - public ShellCredentials? Credentials { get; set; } + /// End position of the selection. + [JsonPropertyName("end")] + public PushAttachmentSelectionDetailsEnd End { get => field ??= new(); set; } - /// Controls automatic non-interactive profile loading where supported. Explicit initScripts are unaffected. - [JsonPropertyName("initProfile")] - public ShellInitProfile? InitProfile { get; set; } + /// Start position of the selection. + [JsonPropertyName("start")] + public PushAttachmentSelectionDetailsStart Start { get => field ??= new(); set; } +} - /// - /// Ordered host-provided script paths sourced before each built-in shell command when the - /// entry's shell target matches the active shell. Use these for rc files, environment setup scripts, - /// or other custom scripts. A script that returns a nonzero status is reported, and later scripts - /// and the user command continue while the shell remains running. Because scripts are sourced into - /// the command shell, `exit`, `exec`, failures under `set -e`, or other shell-terminating behavior - /// can prevent continuation. Script standard output is preserved; Bash script stderr is discarded, - /// PowerShell exception messages are replaced, and runtime-generated failure notices omit - /// configured script paths. When sandboxing is enabled, each script must already be readable under - /// the active sandbox filesystem policy. Pass an empty array to clear the list. - /// - [JsonPropertyName("initScripts")] - public IList? InitScripts { get; set; } +/// Code selection attachment from an editor. +/// The selection variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentSelection : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "selection"; - /// - /// Flags passed to the active built-in shell process on startup, replacing its default flags. - /// When omitted, the built-in Bash shell uses `--norc --noprofile`, - /// and the built-in PowerShell shell uses `-NoProfile -NoLogo`. - /// - [JsonPropertyName("processFlags")] - public IList? ProcessFlags { get; set; } + /// User-facing display name for the selection. + [JsonPropertyName("displayName")] + public required string DisplayName { get; set; } + + /// Absolute path to the file containing the selection. + [JsonPropertyName("filePath")] + public required string FilePath { get; set; } + + /// Position range of the selection within the file. + [JsonPropertyName("selection")] + public required PushAttachmentSelectionDetails Selection { get; set; } + + /// The selected text content. + [JsonPropertyName("text")] + public required string Text { get; set; } } -/// Patch of mutable session options to apply to the running session. +/// GitHub issue, pull request, or discussion reference. +/// The github_reference variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionUpdateOptionsParams +public partial class PushAttachmentGitHubReference : PushAttachment { - /// Additional content-exclusion policies to merge into the session's policy set. - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] - [JsonPropertyName("additionalContentExclusionPolicies")] - public IList? AdditionalContentExclusionPolicies { get; set; } + /// + [JsonIgnore] + public override string Type => "github_reference"; - /// Runtime context discriminator (e.g., `cli`, `actions`). - [JsonPropertyName("agentContext")] - public string? AgentContext { get; set; } + /// Issue, pull request, or discussion number. + [JsonPropertyName("number")] + public required long Number { get; set; } - /// Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. - [JsonPropertyName("agentDirectories")] - public IList? AgentDirectories { get; set; } + /// Type of GitHub reference. + [JsonPropertyName("referenceType")] + public required PushAttachmentGitHubReferenceType ReferenceType { get; set; } - /// Whether to include instructions from every MCP server in the system prompt instead of only allowlisted servers. - [JsonPropertyName("allowAllMcpServerInstructions")] - public bool? AllowAllMcpServerInstructions { get; set; } + /// Current state of the referenced item (e.g., open, closed, merged). + [JsonPropertyName("state")] + public required string State { get; set; } - /// Whether to disable the `ask_user` tool (encourages autonomous behavior). - [JsonPropertyName("askUserDisabled")] - public bool? AskUserDisabled { get; set; } + /// Title of the referenced item. + [JsonPropertyName("title")] + public required string Title { get; set; } - /// Allowlist of tool names available to this session. - [JsonPropertyName("availableTools")] - public IList? AvailableTools { get; set; } + /// URL to the referenced item on GitHub. + [JsonPropertyName("url")] + public required string Url { get; set; } +} + +/// Pointer to a GitHub repository. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class PushGitHubRepoRef +{ + /// Numeric GitHub repository id. + [JsonPropertyName("id")] + public long? Id { get; set; } + + /// Repository name (without owner). + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Repository owner login (user or organization). + [JsonPropertyName("owner")] + public string Owner { get; set; } = string.Empty; +} + +/// Pointer to a GitHub commit. +/// The github_commit variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentGitHubCommit : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "github_commit"; + + /// First line of the commit message. + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// Full commit SHA. + [JsonPropertyName("oid")] + public required string Oid { get; set; } + + /// Repository the commit belongs to. + [JsonPropertyName("repo")] + public required PushGitHubRepoRef Repo { get; set; } + + /// URL to the commit on GitHub. + [JsonPropertyName("url")] + public required string Url { get; set; } +} + +/// Pointer to a GitHub release. +/// The github_release variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentGitHubRelease : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "github_release"; + + /// Human-readable release name. + [JsonPropertyName("name")] + public required string Name { get; set; } + + /// Repository the release belongs to. + [JsonPropertyName("repo")] + public required PushGitHubRepoRef Repo { get; set; } + + /// Git tag the release is anchored to. + [JsonPropertyName("tagName")] + public required string TagName { get; set; } + + /// URL to the release on GitHub. + [JsonPropertyName("url")] + public required string Url { get; set; } +} + +/// Pointer to a GitHub Actions job. +/// The github_actions_job variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentGitHubActionsJob : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "github_actions_job"; + + /// Terminal conclusion of the job when finished (e.g., success, failure, cancelled). Absent for in-progress jobs. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("conclusion")] + public string? Conclusion { get; set; } + + /// Job id within the workflow run. + [JsonPropertyName("jobId")] + public required long JobId { get; set; } + + /// Display name of the job. + [JsonPropertyName("jobName")] + public required string JobName { get; set; } + + /// Repository the workflow run belongs to. + [JsonPropertyName("repo")] + public required PushGitHubRepoRef Repo { get; set; } - /// Options scoped to the built-in CAPI (Copilot API) provider. - [JsonPropertyName("capi")] - public CapiSessionOptions? Capi { get; set; } + /// URL to the job on GitHub. + [JsonPropertyName("url")] + public required string Url { get; set; } - /// Identifier of the client driving the session. - [JsonPropertyName("clientName")] - public string? ClientName { get; set; } + /// Display name of the workflow the job ran in. + [JsonPropertyName("workflowName")] + public required string WorkflowName { get; set; } +} - /// Whether to include the `Co-authored-by` trailer in commit messages. - [JsonPropertyName("coauthorEnabled")] - public bool? CoauthorEnabled { get; set; } +/// Pointer to a GitHub repository. +/// The github_repository variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentGitHubRepository : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "github_repository"; - /// Context tier for models with tiered pricing. The session uses this to derive effective `modelCapabilitiesOverrides` so compaction, truncation, token display, and request limits honor the selected tier. - [JsonPropertyName("contextTier")] - public OptionsUpdateContextTier? ContextTier { get; set; } + /// Short description of the repository. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } - /// Whether to allow auto-mode continuation across turns. - [JsonPropertyName("continueOnAutoMode")] - public bool? ContinueOnAutoMode { get; set; } + /// Git ref this attachment is anchored at (branch, tag, or commit). When absent the default branch is implied. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("ref")] + public string? Ref { get; set; } - /// Override URL for the Copilot API endpoint. - [JsonPropertyName("copilotUrl")] - public string? CopilotUrl { get; set; } + /// Repository pointer. + [JsonPropertyName("repo")] + public required PushGitHubRepoRef Repo { get; set; } - /// Whether to default custom agents to local-only execution. - [JsonPropertyName("customAgentsLocalOnly")] - public bool? CustomAgentsLocalOnly { get; set; } + /// URL to the repository on GitHub. + [JsonPropertyName("url")] + public required string Url { get; set; } +} - /// Instruction source IDs to exclude from the system prompt. - [JsonPropertyName("disabledInstructionSources")] - public IList? DisabledInstructionSources { get; set; } +/// One side of a file diff (head or base). +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class PushAttachmentGitHubFileDiffSide +{ + /// Repository-relative path to the file. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Skill IDs that should be excluded from this session. - [JsonPropertyName("disabledSkills")] - public IList? DisabledSkills { get; set; } + /// Git ref (branch, tag, or commit SHA) the file is read at. + [JsonPropertyName("ref")] + public string Ref { get; set; } = string.Empty; - /// Whether to enable repository-origin file hooks from `.github/hooks/` and trusted repository-configured roots. Does not control explicit hookDirectories or SDK callback hooks. - [JsonPropertyName("enableFileHooks")] - public bool? EnableFileHooks { get; set; } + /// Repository the file lives in. + [JsonPropertyName("repo")] + public PushGitHubRepoRef Repo { get => field ??= new(); set; } +} - /// Whether to enable host git operations (context resolution, child repo scanning, git info in system prompt). - [JsonPropertyName("enableHostGitOperations")] - public bool? EnableHostGitOperations { get; set; } +/// Pointer to a single-file diff. At least one of `head` and `base` must be present. +/// The github_file_diff variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentGitHubFileDiff : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "github_file_diff"; - /// Whether to discover custom instructions on demand after successful file views (AGENTS.md / CLAUDE.md / .github/copilot-instructions.md surfacing). Combined with `skipCustomInstructions`. - [JsonPropertyName("enableOnDemandInstructionDiscovery")] - public bool? EnableOnDemandInstructionDiscovery { get; set; } + /// File location on the base side of the diff. Absent for additions. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("base")] + public PushAttachmentGitHubFileDiffSide? Base { get; set; } - /// Whether to surface reasoning-summary events from the model. - [JsonPropertyName("enableReasoningSummaries")] - public bool? EnableReasoningSummaries { get; set; } + /// File location on the head side of the diff. Absent for deletions. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("head")] + public PushAttachmentGitHubFileDiffSide? Head { get; set; } - /// Whether shell-script safety heuristics are enabled. - [JsonPropertyName("enableScriptSafety")] - public bool? EnableScriptSafety { get; set; } + /// URL to the diff on GitHub (e.g., a commit, compare, or PR-file URL). + [JsonPropertyName("url")] + public required string Url { get; set; } +} - /// Whether to enable cross-session store writes and reads. - [JsonPropertyName("enableSessionStore")] - public bool? EnableSessionStore { get; set; } +/// One side of a tree comparison (head or base). +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class PushAttachmentGitHubTreeComparisonSide +{ + /// Repository the revision belongs to. + [JsonPropertyName("repo")] + public PushGitHubRepoRef Repo { get => field ??= new(); set; } - /// Whether skill loading is enabled. Explicit false disables every source, including explicit SDK roots and a bound SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless explicit SDK skill roots or an SDK skill provider are supplied. - [JsonPropertyName("enableSkills")] - public bool? EnableSkills { get; set; } + /// Git revision (branch, tag, or commit SHA). + [JsonPropertyName("revision")] + public string Revision { get; set; } = string.Empty; +} - /// Whether to stream model responses. - [JsonPropertyName("enableStreaming")] - public bool? EnableStreaming { get; set; } +/// Pointer to a comparison between two git revisions. +/// The github_tree_comparison variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentGitHubTreeComparison : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "github_tree_comparison"; - /// How env values are passed to MCP servers (`direct` inlines literal values; `indirect` resolves at launch). - [JsonPropertyName("envValueMode")] - public OptionsUpdateEnvValueMode? EnvValueMode { get; set; } + /// Base side of the comparison. + [JsonPropertyName("base")] + public required PushAttachmentGitHubTreeComparisonSide Base { get; set; } - /// Override directory for the session-events log. When unset, the runtime's default events log directory is used. - [JsonPropertyName("eventsLogDirectory")] - public string? EventsLogDirectory { get; set; } + /// Head side of the comparison. + [JsonPropertyName("head")] + public required PushAttachmentGitHubTreeComparisonSide Head { get; set; } - /// Whether subagent callback events should be forwarded into the session event log sink. - [JsonPropertyName("eventsLogIncludesSubagents")] - public bool? EventsLogIncludesSubagents { get; set; } + /// URL to the comparison on GitHub. + [JsonPropertyName("url")] + public required string Url { get; set; } +} - /// Built-in subagent names to exclude from this session. Excluded built-ins are hidden from agent discovery and cannot be dispatched unless a custom agent with the same name is available. - [JsonPropertyName("excludedBuiltinAgents")] - public IList? ExcludedBuiltinAgents { get; set; } +/// Generic GitHub URL reference. +/// The github_url variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentGitHubUrl : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "github_url"; - /// Denylist of tool names for this session. - [JsonPropertyName("excludedTools")] - public IList? ExcludedTools { get; set; } + /// URL to the GitHub resource. + [JsonPropertyName("url")] + public required string Url { get; set; } +} - /// Map of feature-flag IDs to their boolean enabled state. - [JsonPropertyName("featureFlags")] - public IDictionary? FeatureFlags { get; set; } +/// Pointer to a file in a GitHub repository at a specific ref. +/// The github_file variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentGitHubFile : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "github_file"; - /// Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without enableConfigDiscovery or enableFileHooks, which controls repository-origin hooks only; hook/managed disables still apply. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. - [JsonPropertyName("hookDirectories")] - public IList? HookDirectories { get; set; } + /// Repository-relative path to the file. + [JsonPropertyName("path")] + public required string Path { get; set; } - /// Skill scan directories and descendants excluded from discovery. Supports `~`-relative paths. - [JsonPropertyName("ignoredSkillsLocations")] - public IList? IgnoredSkillsLocations { get; set; } + /// Git ref the file is read at (branch, tag, or commit SHA). + [JsonPropertyName("ref")] + public required string Ref { get; set; } - /// Built-in subagent names to include in this session. When specified, only these built-ins are available, subject to runtime availability and exclusions. Custom agents with the same name remain available. Set to null to remove the allowlist restriction. - [JsonPropertyName("includedBuiltinAgents")] - public IList? IncludedBuiltinAgents { get; set; } + /// Repository the file lives in. + [JsonPropertyName("repo")] + public required PushGitHubRepoRef Repo { get; set; } - /// Built-in skill names to include in this session. When specified, only these runtime-bundled skills are available. Skills from other sources with the same name remain available. Set to null to remove the allowlist restriction. - [JsonPropertyName("includedBuiltinSkills")] - public IList? IncludedBuiltinSkills { get; set; } + /// URL to the file on GitHub. + [JsonPropertyName("url")] + public required string Url { get; set; } +} - /// Full set of installed plugins for the session. Replaces the existing list; the runtime invalidates the skills cache only when the list materially changes. - [JsonPropertyName("installedPlugins")] - public IList? InstalledPlugins { get; set; } +/// Pointer to a line range inside a file in a GitHub repository. +/// The github_snippet variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentGitHubSnippet : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "github_snippet"; - /// Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without enableConfigDiscovery, subject to instruction/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. - [JsonPropertyName("instructionDirectories")] - public IList? InstructionDirectories { get; set; } + /// Line range the snippet covers. + [JsonPropertyName("lineRange")] + public required PushAttachmentFileLineRange LineRange { get; set; } - /// Stable integration identifier used for analytics and rate-limit attribution. - [JsonPropertyName("integrationId")] - public string? IntegrationId { get; set; } + /// Repository-relative path to the file. + [JsonPropertyName("path")] + public required string Path { get; set; } - /// Whether experimental capabilities are enabled. - [JsonPropertyName("isExperimentalMode")] - public bool? IsExperimentalMode { get; set; } + /// Git ref the file is read at (branch, tag, or commit SHA). + [JsonPropertyName("ref")] + public required string Ref { get; set; } - /// Whether interactive shell sessions are logged. - [JsonPropertyName("logInteractiveShells")] - public bool? LogInteractiveShells { get; set; } + /// Repository the file lives in. + [JsonPropertyName("repo")] + public required PushGitHubRepoRef Repo { get; set; } - /// Identifier sent to LSP-style integrations. - [JsonPropertyName("lspClientName")] - public string? LspClientName { get; set; } + /// URL to the snippet on GitHub (with line anchor). + [JsonPropertyName("url")] + public required string Url { get; set; } +} - /// Whether to expose the `manage_schedule` tool to the agent. The runtime always owns the per-session schedule registry; this flag only controls tool exposure (typically gated to staff users). - [JsonPropertyName("manageScheduleEnabled")] - public bool? ManageScheduleEnabled { get; set; } +/// Blob attachment with inline base64-encoded data. +/// The blob variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentBlob : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "blob"; - /// Maximum decoded byte size of a single model-facing binary tool result (e.g. an image) persisted inline in session events and re-presented to the model on later turns / resume. Larger results are persisted as a metadata-only marker and shown to the model as a short text note. Defaults to 10 MB. - [JsonPropertyName("maxInlineBinaryBytes")] - public long? MaxInlineBinaryBytes { get; set; } + /// Base64-encoded content. + [Base64String] + [JsonPropertyName("data")] + public required string Data { get; set; } - /// The model ID to use for assistant turns. - [JsonPropertyName("model")] - public string? Model { get; set; } + /// User-facing display name for the attachment. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("displayName")] + public string? DisplayName { get; set; } - /// Per-property model capability overrides for the selected model. - [JsonPropertyName("modelCapabilitiesOverrides")] - public ModelCapabilitiesOverride? ModelCapabilitiesOverrides { get; set; } + /// MIME type of the inline data. + [JsonPropertyName("mimeType")] + public required string MimeType { get; set; } +} - /// Organization-level custom instructions to inject into the system prompt. - [JsonPropertyName("organizationCustomInstructions")] - public string? OrganizationCustomInstructions { get; set; } +/// Slim input shape for extension_context attachments; identity fields are runtime-derived. +/// The extension_context variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PushAttachmentExtensionContext : PushAttachment +{ + /// + [JsonIgnore] + public override string Type => "extension_context"; - /// Custom model-provider configuration (BYOK). - [JsonPropertyName("provider")] - public ProviderConfig? Provider { get; set; } + /// Caller-supplied JSON payload (required, may be null but not undefined). + [JsonPropertyName("payload")] + public required JsonElement Payload { get; set; } - /// Reasoning effort for the selected model. CAPI values are model-defined and validated against the selected model; BYOK providers may define additional values. When omitted, no effort override is applied. - [JsonPropertyName("reasoningEffort")] - public string? ReasoningEffort { get; set; } + /// Human-readable composer pill label. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("title")] + public required string Title { get; set; } +} - /// Reasoning summary mode for supported model clients. - [JsonPropertyName("reasoningSummary")] - public OptionsUpdateReasoningSummary? ReasoningSummary { get; set; } +/// Parameters for session.extensions.sendAttachmentsToMessage. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SendAttachmentsToMessageParams +{ + /// Attachments to push into the next user-message turn. extension_context entries take the slim shape; standard variants take their full AttachmentSchema shape. + [JsonPropertyName("attachments")] + public IList Attachments { get => field ??= []; set; } - /// Whether the session is running in an interactive UI. - [JsonPropertyName("runningInInteractiveMode")] - public bool? RunningInInteractiveMode { get; set; } + /// Optional canvas instance binding the push for provenance. When supplied, the runtime resolves the canvas, verifies it is owned by the calling extension, and stamps canvasId/instanceId onto each extension_context entry. When omitted, no resolution runs and those fields stay unset on the attachment. + [JsonPropertyName("instanceId")] + public string? InstanceId { get; set; } - /// Resolved sandbox configuration. - [JsonPropertyName("sandboxConfig")] - public SandboxConfig? SandboxConfig { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Origin of the sandbox choice. Settings-derived origins (never_configured, user_enabled, user_disabled, repository_policy) let managed policy floor a host preference; explicit below-floor changes remain policy conflicts unless a session opt-out is authorized. Also used for telemetry provenance. - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] - [JsonPropertyName("sandboxConfigSource")] - public SandboxConfigSource? SandboxConfigSource { get; set; } +/// A tool name and arguments to execute through the session's native invocation pipeline. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ToolsExecuteRequest +{ + /// Arguments supplied to the tool. + [JsonPropertyName("arguments")] + public JsonElement Arguments { get; set; } - /// Replaces the session's capability set with the given list. Use to enable or disable capabilities mid-session (e.g., remove `memory` for reproducible scripted runs). Omit the field to leave the existing capability set unchanged. - [JsonPropertyName("sessionCapabilities")] - public IList? SessionCapabilities { get; set; } + /// Name of the currently offered tool to execute. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - /// Optional session limits. Pass null to clear the session limits. - [JsonPropertyName("sessionLimits")] - public SessionLimitsConfig? SessionLimits { get; set; } + /// Optional identifier used to correlate this invocation with its tool call. + [JsonPropertyName("toolCallId")] + public string? ToolCallId { get; set; } +} - /// Per-session settings for built-in shell tools. - [JsonPropertyName("shell")] - public ShellOptions? Shell { get; set; } +/// Custom grammar input format accepted by a built-in tool. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class BuiltinToolFormat +{ + /// Grammar definition accepted by the tool. + [JsonPropertyName("definition")] + public string Definition { get; set; } = string.Empty; - /// Use shell.initProfile instead. Shell init profile (`None` or `NonInteractive`). - [EditorBrowsable(EditorBrowsableState.Never)] -#if NET5_0_OR_GREATER - [Obsolete("This member is deprecated and will be removed in a future version.", DiagnosticId = "GHCP001")] -#else - [Obsolete("This member is deprecated and will be removed in a future version.")] -#endif - [JsonPropertyName("shellInitProfile")] - public string? ShellInitProfile { get; set; } + /// Grammar syntax used by the format definition. + [JsonPropertyName("syntax")] + public string Syntax { get; set; } = string.Empty; - /// PowerShell process flags applied to built-in and user-requested shell commands. - [JsonPropertyName("shellProcessFlags")] - public IList? ShellProcessFlags { get; set; } + /// Custom input-format discriminator. + [JsonPropertyName("type")] + public BuiltinToolFormatType Type { get; set; } +} - /// Explicit discovery-only skill roots, not filesystem grants. Available without enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. - [JsonPropertyName("skillDirectories")] - public IList? SkillDirectories { get; set; } +/// JSON Schema object accepted by a built-in tool. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class BuiltinToolInputSchema +{ + /// Root type of the tool input schema. + [JsonPropertyName("type")] + public BuiltinToolInputSchemaType Type { get; set; } +} - /// Whether to skip loading custom instruction sources. - [JsonPropertyName("skipCustomInstructions")] - public bool? SkipCustomInstructions { get; set; } +/// Rust-owned metadata and input schema for a built-in tool. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class BuiltinToolDescriptor +{ + /// Model-facing description of the tool's behavior. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// Whether to skip embedding retrieval pipeline initialization and execution. - [JsonPropertyName("skipEmbeddingRetrieval")] - public bool? SkipEmbeddingRetrieval { get; set; } + /// Optional custom input format used instead of a JSON Schema. + [JsonPropertyName("format")] + public BuiltinToolFormat? Format { get; set; } - /// When true, the selected custom agent's prompt is not injected into the user message (skill context is still injected). Used by automation triggers where the agent prompt is already in the problem statement. - [JsonPropertyName("suppressCustomAgentPrompt")] - public bool? SuppressCustomAgentPrompt { get; set; } + /// Whether the tool provides a specialized intention summary. + [JsonPropertyName("hasSummariseIntention")] + public bool HasSummariseIntention { get; set; } - /// Controls how availableTools (allowlist) and excludedTools (denylist) combine when both are set. - [JsonPropertyName("toolFilterPrecedence")] - public OptionsUpdateToolFilterPrecedence? ToolFilterPrecedence { get; set; } + /// JSON Schema for the tool input, or null when the tool uses a custom format. + [JsonPropertyName("inputSchema")] + public BuiltinToolInputSchema? InputSchema { get; set; } - /// Optional path for trajectory output. - [JsonPropertyName("trajectoryFile")] - public string? TrajectoryFile { get; set; } + /// Optional supplemental usage instructions for the tool. + [JsonPropertyName("instructions")] + public string? Instructions { get; set; } - /// Output verbosity level for supported models. - [JsonPropertyName("verbosity")] - public Verbosity? Verbosity { get; set; } + /// Whether the tool executes commands in a terminal. + [JsonPropertyName("isTerminal")] + public bool IsTerminal { get; set; } - /// Absolute working-directory path for shell tools. - [JsonPropertyName("workingDirectory")] - public string? WorkingDirectory { get; set; } -} + /// Stable name used to invoke the built-in tool. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; -/// Parameters for (re)loading the merged LSP configuration set. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class LspInitializeRequest -{ - /// Force re-initialization even when LSP configs were already loaded for the working directory. - [JsonPropertyName("force")] - public bool? Force { get; set; } + /// Policy describing which tool metadata may be recorded without obfuscation. + [JsonPropertyName("safeForTelemetry")] + public JsonElement SafeForTelemetry { get; set; } - /// Git root used as the boundary when traversing for project-level LSP configs (supports monorepos). - [JsonPropertyName("gitRoot")] - public string? GitRoot { get; set; } + /// Optional human-readable title for the tool. + [JsonPropertyName("title")] + public string? Title { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Optional tool category discriminator. + [JsonPropertyName("type")] + public string? Type { get; set; } +} - /// Working directory used to load project-level LSP configs. Defaults to the session working directory when omitted. - [JsonPropertyName("workingDirectory")] - public string? WorkingDirectory { get; set; } +/// Rust-owned built-in tool descriptors for the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ToolsGetBuiltinDescriptorsResult +{ + /// Built-in tool descriptors materialized for the session. + [JsonPropertyName("tools")] + public IList Tools { get => field ??= []; set; } } -/// Discovered extension metadata, including source-qualified ID, name, discovery source, status, and optional process ID. +/// Shell-specific names and description lines used to materialize built-in shell tool descriptors. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class Extension +public sealed class ToolsShellDescriptorConfig { - /// Source-qualified ID (e.g., 'project:my-ext', 'user:auth-helper', 'plugin:my-plugin:my-ext'). - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Additional model-facing shell description lines. + [JsonPropertyName("descriptionLines")] + public IList DescriptionLines { get => field ??= []; set; } - /// Extension name (directory name). - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Human-readable shell name. + [JsonPropertyName("displayName")] + public string DisplayName { get; set; } = string.Empty; - /// Process ID if the extension is running. - [JsonPropertyName("pid")] - public long? Pid { get; set; } + /// Tool name used to list active shells. + [JsonPropertyName("listShellsToolName")] + public string ListShellsToolName { get; set; } = string.Empty; - /// Discovery source: project (.github/extensions/), user (~/.copilot/extensions/), plugin (installed plugin), or session (session-state/<id>/extensions/). - [JsonPropertyName("source")] - public ExtensionSource Source { get; set; } + /// Tool name used to read shell output. + [JsonPropertyName("readShellToolName")] + public string ReadShellToolName { get; set; } = string.Empty; - /// Current status: running, disabled, failed, or starting. - [JsonPropertyName("status")] - public ExtensionStatus Status { get; set; } -} + /// Tool name used to start shell commands. + [JsonPropertyName("shellToolName")] + public string ShellToolName { get; set; } = string.Empty; + + /// Stable shell type identifier. + [JsonPropertyName("shellType")] + public string ShellType { get; set; } = string.Empty; -/// Extensions discovered for the session, with their current status. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ExtensionList -{ - /// Discovered extensions and their current status. - [JsonPropertyName("extensions")] - public IList Extensions { get => field ??= []; set; } + /// Tool name used to stop shell commands. + [JsonPropertyName("stopShellToolName")] + public string StopShellToolName { get; set; } = string.Empty; } -/// Identifies the target session. +/// Options controlling how Rust-owned built-in tool descriptors are materialized. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionExtensionsListRequest +internal sealed class ToolsGetBuiltinDescriptorsRequest { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Whether background task completion notifications are enabled. + [JsonPropertyName("backgroundTaskNotificationsEnabled")] + public bool? BackgroundTaskNotificationsEnabled { get; set; } -/// Source-qualified extension identifier to enable for the session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ExtensionsEnableRequest -{ - /// Source-qualified extension ID to enable. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Whether tool descriptors should include authoring metadata. + [JsonPropertyName("includeAuthor")] + public bool? IncludeAuthor { get; set; } + + /// Whether descriptors should favor fewer user-intervention prompts. + [JsonPropertyName("reduceUserIntervention")] + public bool? ReduceUserIntervention { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; -} -/// Source-qualified extension identifier to disable for the session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ExtensionsDisableRequest -{ - /// Source-qualified extension ID to disable. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Shell-specific names and description lines for shell tools. + [JsonPropertyName("shellConfig")] + public ToolsShellDescriptorConfig? ShellConfig { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether the configured shell supports PowerShell 7 syntax. + [JsonPropertyName("shellSupportsPowerShell7Syntax")] + public bool? ShellSupportsPowerShell7Syntax { get; set; } + + /// Default shell timeout in milliseconds. + [JsonPropertyName("shellTimeoutMs")] + public double? ShellTimeoutMs { get; set; } + + /// Whether semantic skill lookup is available. + [JsonPropertyName("skillEmbeddingEnabled")] + public bool? SkillEmbeddingEnabled { get; set; } } -/// Identifies the target session. +/// Task completion notification with summary from the agent. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionExtensionsReloadRequest +public sealed class TaskCompleteData { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Structured blocker details when outcome is blocked. + [JsonPropertyName("blocker")] + public TaskBlocker? Blocker { get; set; } + + /// Active autopilot objective ID evaluated by the completion reviewer. + [JsonPropertyName("objectiveId")] + public long? ObjectiveId { get; set; } + + /// Semantic completion decision. Absent on legacy events and invalid tool calls. + [JsonPropertyName("outcome")] + public TaskCompletionOutcome? Outcome { get; set; } + + /// Label-safe runtime rationale for the completion decision (e.g. a cancellation or pause/resume downgrade), when one applies. Reviewer-authored rationale is intentionally omitted here because this event has no IFC label channel; the reviewer's findings remain available through its own labeled sub-agent events. + [JsonPropertyName("reason")] + public string? Reason { get; set; } + + /// Whether the task was accepted as complete. False when validation failed or completion was rejected or blocked by the reviewer. + [JsonPropertyName("success")] + public bool? Success { get; set; } + + /// Summary of the completed task, provided by the agent. + [JsonPropertyName("summary")] + public string? Summary { get; set; } } -/// Identifies the target session. +/// Binary result returned by a tool for the model. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionExtensionsReconcileRequest +public sealed class ExternalToolTextResultForLlmBinaryResultsForLlm { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Base64-encoded binary data. + [Base64String] + [JsonPropertyName("data")] + public string Data { get; set; } = string.Empty; + + /// Human-readable description of the binary data. + [JsonPropertyName("description")] + public string? Description { get; set; } + + /// Optional metadata from the producing tool. + [JsonPropertyName("metadata")] + public IDictionary? Metadata { get; set; } + + /// MIME type of the binary data. + [JsonPropertyName("mimeType")] + public string MimeType { get; set; } = string.Empty; + + /// Binary result type discriminator. Use "image" for images and "resource" for other binary data. + [JsonPropertyName("type")] + public ExternalToolTextResultForLlmBinaryResultsForLlmType Type { get; set; } } -/// Attachment union accepted by push input, covering files, directories, GitHub objects, blobs, snippets, and extension context. +/// A content block within a tool result, which may be text, terminal output, image, audio, or a resource. /// Polymorphic base type discriminated by type. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( TypeDiscriminatorPropertyName = "type", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(PushAttachmentFile), "file")] -[JsonDerivedType(typeof(PushAttachmentDirectory), "directory")] -[JsonDerivedType(typeof(PushAttachmentSelection), "selection")] -[JsonDerivedType(typeof(PushAttachmentGitHubReference), "github_reference")] -[JsonDerivedType(typeof(PushAttachmentGitHubCommit), "github_commit")] -[JsonDerivedType(typeof(PushAttachmentGitHubRelease), "github_release")] -[JsonDerivedType(typeof(PushAttachmentGitHubActionsJob), "github_actions_job")] -[JsonDerivedType(typeof(PushAttachmentGitHubRepository), "github_repository")] -[JsonDerivedType(typeof(PushAttachmentGitHubFileDiff), "github_file_diff")] -[JsonDerivedType(typeof(PushAttachmentGitHubTreeComparison), "github_tree_comparison")] -[JsonDerivedType(typeof(PushAttachmentGitHubUrl), "github_url")] -[JsonDerivedType(typeof(PushAttachmentGitHubFile), "github_file")] -[JsonDerivedType(typeof(PushAttachmentGitHubSnippet), "github_snippet")] -[JsonDerivedType(typeof(PushAttachmentBlob), "blob")] -[JsonDerivedType(typeof(PushAttachmentExtensionContext), "extension_context")] -public partial class PushAttachment +[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentText), "text")] +[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentTerminal), "terminal")] +[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentShellExit), "shell_exit")] +[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentImage), "image")] +[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentAudio), "audio")] +[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentResourceLink), "resource_link")] +[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentResource), "resource")] +public partial class ExternalToolTextResultForLlmContent { /// The type discriminator. [JsonPropertyName("type")] @@ -21185,1389 +23203,1639 @@ public partial class PushAttachment } -/// Optional line range to scope the attachment to a specific section of the file. +/// Plain text content block. +/// The text variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PushAttachmentFileLineRange +public partial class ExternalToolTextResultForLlmContentText : ExternalToolTextResultForLlmContent { - /// End line number (1-based, inclusive). - [JsonPropertyName("end")] - public long End { get; set; } + /// + [JsonIgnore] + public override string Type => "text"; - /// Start line number (1-based). - [JsonPropertyName("start")] - public long Start { get; set; } + /// The text content. + [JsonPropertyName("text")] + public required string Text { get; set; } } -/// File attachment. -/// The file variant of . +/// Terminal/shell output content block with optional exit code and working directory. +/// The terminal variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentFile : PushAttachment +public partial class ExternalToolTextResultForLlmContentTerminal : ExternalToolTextResultForLlmContent { /// [JsonIgnore] - public override string Type => "file"; + public override string Type => "terminal"; - /// User-facing display name for the attachment. - [JsonPropertyName("displayName")] - public required string DisplayName { get; set; } + /// Working directory where the command was executed. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("cwd")] + public string? Cwd { get; set; } - /// Optional line range to scope the attachment to a specific section of the file. + /// Process exit code, if the command has completed. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("lineRange")] - public PushAttachmentFileLineRange? LineRange { get; set; } + [JsonPropertyName("exitCode")] + public long? ExitCode { get; set; } - /// Absolute file path. - [JsonPropertyName("path")] - public required string Path { get; set; } + /// Terminal/shell output text. + [JsonPropertyName("text")] + public required string Text { get; set; } } -/// Directory attachment. -/// The directory variant of . +/// Shell command exit metadata with optional output preview. +/// The shell_exit variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentDirectory : PushAttachment +public partial class ExternalToolTextResultForLlmContentShellExit : ExternalToolTextResultForLlmContent { /// [JsonIgnore] - public override string Type => "directory"; + public override string Type => "shell_exit"; - /// User-facing display name for the attachment. - [JsonPropertyName("displayName")] - public required string DisplayName { get; set; } + /// Working directory where the shell command was executed. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("cwd")] + public string? Cwd { get; set; } - /// Absolute directory path. - [JsonPropertyName("path")] - public required string Path { get; set; } -} + /// Exit code from the completed shell command. + [JsonPropertyName("exitCode")] + public required long ExitCode { get; set; } -/// End position of the selection. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PushAttachmentSelectionDetailsEnd -{ - /// End character offset within the line (0-based). - [JsonPropertyName("character")] - public long Character { get; set; } + /// Path reported in the shell session's filesystem namespace when shell output exceeded the configured large-output threshold. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("outputFilePath")] + public string? OutputFilePath { get; set; } - /// End line number (0-based). - [JsonPropertyName("line")] - public long Line { get; set; } -} + /// Output associated with this shell command, if available. May be partial, truncated, or a preview; not guaranteed to be full output. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("outputPreview")] + public string? OutputPreview { get; set; } -/// Start position of the selection. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PushAttachmentSelectionDetailsStart -{ - /// Start character offset within the line (0-based). - [JsonPropertyName("character")] - public long Character { get; set; } + /// Whether outputPreview is known to be incomplete or truncated. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("outputTruncated")] + public bool? OutputTruncated { get; set; } - /// Start line number (0-based). - [JsonPropertyName("line")] - public long Line { get; set; } + /// Shell id, as assigned by Copilot runtime. + [JsonPropertyName("shellId")] + public required string ShellId { get; set; } } -/// Position range of the selection within the file. +/// Image content block with base64-encoded data. +/// The image variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PushAttachmentSelectionDetails +public partial class ExternalToolTextResultForLlmContentImage : ExternalToolTextResultForLlmContent { - /// End position of the selection. - [JsonPropertyName("end")] - public PushAttachmentSelectionDetailsEnd End { get => field ??= new(); set; } + /// + [JsonIgnore] + public override string Type => "image"; - /// Start position of the selection. - [JsonPropertyName("start")] - public PushAttachmentSelectionDetailsStart Start { get => field ??= new(); set; } + /// Base64-encoded image data. + [Base64String] + [JsonPropertyName("data")] + public required string Data { get; set; } + + /// MIME type of the image (e.g., image/png, image/jpeg). + [JsonPropertyName("mimeType")] + public required string MimeType { get; set; } } -/// Code selection attachment from an editor. -/// The selection variant of . +/// Audio content block with base64-encoded data. +/// The audio variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentSelection : PushAttachment +public partial class ExternalToolTextResultForLlmContentAudio : ExternalToolTextResultForLlmContent { /// [JsonIgnore] - public override string Type => "selection"; + public override string Type => "audio"; - /// User-facing display name for the selection. - [JsonPropertyName("displayName")] - public required string DisplayName { get; set; } + /// Base64-encoded audio data. + [Base64String] + [JsonPropertyName("data")] + public required string Data { get; set; } - /// Absolute path to the file containing the selection. - [JsonPropertyName("filePath")] - public required string FilePath { get; set; } + /// MIME type of the audio (e.g., audio/wav, audio/mpeg). + [JsonPropertyName("mimeType")] + public required string MimeType { get; set; } +} - /// Position range of the selection within the file. - [JsonPropertyName("selection")] - public required PushAttachmentSelectionDetails Selection { get; set; } +/// Icon image for a resource. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ExternalToolTextResultForLlmContentResourceLinkIcon +{ + /// MIME type of the icon image. + [JsonPropertyName("mimeType")] + public string? MimeType { get; set; } - /// The selected text content. - [JsonPropertyName("text")] - public required string Text { get; set; } + /// Available icon sizes (e.g., ['16x16', '32x32']). + [JsonPropertyName("sizes")] + public IList? Sizes { get; set; } + + /// URL or path to the icon image. + [JsonPropertyName("src")] + public string Src { get; set; } = string.Empty; + + /// Theme variant this icon is intended for. + [JsonPropertyName("theme")] + public ExternalToolTextResultForLlmContentResourceLinkIconTheme? Theme { get; set; } } -/// GitHub issue, pull request, or discussion reference. -/// The github_reference variant of . +/// Resource link content block referencing an external resource. +/// The resource_link variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentGitHubReference : PushAttachment +public partial class ExternalToolTextResultForLlmContentResourceLink : ExternalToolTextResultForLlmContent { /// [JsonIgnore] - public override string Type => "github_reference"; + public override string Type => "resource_link"; - /// Issue, pull request, or discussion number. - [JsonPropertyName("number")] - public required long Number { get; set; } + /// Human-readable description of the resource. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("description")] + public string? Description { get; set; } - /// Type of GitHub reference. - [JsonPropertyName("referenceType")] - public required PushAttachmentGitHubReferenceType ReferenceType { get; set; } + /// Icons associated with this resource. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("icons")] + public IList? Icons { get; set; } - /// Current state of the referenced item (e.g., open, closed, merged). - [JsonPropertyName("state")] - public required string State { get; set; } + /// MIME type of the resource content. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("mimeType")] + public string? MimeType { get; set; } - /// Title of the referenced item. + /// Resource name identifier. + [JsonPropertyName("name")] + public required string Name { get; set; } + + /// Size of the resource in bytes. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("size")] + public long? Size { get; set; } + + /// Human-readable display title for the resource. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("title")] - public required string Title { get; set; } + public string? Title { get; set; } - /// URL to the referenced item on GitHub. - [JsonPropertyName("url")] - public required string Url { get; set; } + /// URI identifying the resource. + [JsonPropertyName("uri")] + public required string Uri { get; set; } } -/// Pointer to a GitHub repository. +/// Embedded resource content block with inline text or binary data. +/// The resource variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PushGitHubRepoRef +public partial class ExternalToolTextResultForLlmContentResource : ExternalToolTextResultForLlmContent { - /// Numeric GitHub repository id. - [JsonPropertyName("id")] - public long? Id { get; set; } + /// + [JsonIgnore] + public override string Type => "resource"; - /// Repository name (without owner). - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// The embedded resource contents, either text or base64-encoded binary. + [JsonPropertyName("resource")] + public required JsonElement Resource { get; set; } +} - /// Repository owner login (user or organization). - [JsonPropertyName("owner")] - public string Owner { get; set; } = string.Empty; +/// A message injected by a tool result. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ToolResultNewMessage +{ + /// Message content to inject after the tool result. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; + + /// Source attributed to the injected message. + [JsonPropertyName("source")] + public string Source { get; set; } = string.Empty; } -/// Pointer to a GitHub commit. -/// The github_commit variant of . +/// RPC data type for TaskCompletionDecision operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentGitHubCommit : PushAttachment +public sealed class TaskCompletionDecision { - /// - [JsonIgnore] - public override string Type => "github_commit"; + /// Objective eligibility token captured when the decision was evaluated. + [JsonPropertyName("completionEligibilityToken")] + public long? CompletionEligibilityToken { get; set; } - /// First line of the commit message. - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Whether completion was accepted after the reviewer-rejection budget was exhausted. + [JsonPropertyName("completionRejectionBudgetExhausted")] + public bool? CompletionRejectionBudgetExhausted { get; set; } - /// Full commit SHA. - [JsonPropertyName("oid")] - public required string Oid { get; set; } + /// Active autopilot objective evaluated by the completion reviewer. + [JsonPropertyName("objectiveId")] + public long? ObjectiveId { get; set; } - /// Repository the commit belongs to. - [JsonPropertyName("repo")] - public required PushGitHubRepoRef Repo { get; set; } + /// Semantic result of evaluating the task completion request. + [JsonPropertyName("outcome")] + public TaskCompletionOutcome Outcome { get; set; } - /// URL to the commit on GitHub. - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Rationale for the completion decision, when one is available. + [JsonPropertyName("reason")] + public string? Reason { get; set; } + + /// Whether the rationale was derived from completion-reviewer output. + [JsonPropertyName("reviewerDerived")] + public bool? ReviewerDerived { get; set; } + + /// Information-flow metadata captured from the completion reviewer. + [JsonPropertyName("reviewerResultMeta")] + public JsonElement? ReviewerResultMeta { get; set; } } -/// Pointer to a GitHub release. -/// The github_release variant of . +/// Expanded canonical result returned by a session tool. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentGitHubRelease : PushAttachment +public sealed class ToolResultExpanded { - /// - [JsonIgnore] - public override string Type => "github_release"; + /// Base64-encoded binary results returned to the model. + [JsonPropertyName("binaryResultsForLlm")] + public IList? BinaryResultsForLlm { get; set; } - /// Human-readable release name. - [JsonPropertyName("name")] - public required string Name { get; set; } + /// Sources returned by the tool that the model may cite. + [JsonPropertyName("citableSources")] + public IList? CitableSources { get; set; } - /// Repository the release belongs to. - [JsonPropertyName("repo")] - public required PushGitHubRepoRef Repo { get; set; } + /// Structured content blocks returned to the model. + [JsonPropertyName("contents")] + public IList? Contents { get; set; } - /// Git tag the release is anchored to. - [JsonPropertyName("tagName")] - public required string TagName { get; set; } + /// Error message for an unsuccessful execution. + [JsonPropertyName("error")] + public string? Error { get; set; } - /// URL to the release on GitHub. - [JsonPropertyName("url")] - public required string Url { get; set; } -} + /// Metadata propagated with the tool result, including information-flow labels. + [JsonPropertyName("mcpMeta")] + public IDictionary? McpMeta { get; set; } -/// Pointer to a GitHub Actions job. -/// The github_actions_job variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentGitHubActionsJob : PushAttachment -{ - /// - [JsonIgnore] - public override string Type => "github_actions_job"; + /// Messages to inject after the tool result. + [JsonPropertyName("newMessages")] + public IList? NewMessages { get; set; } - /// Terminal conclusion of the job when finished (e.g., success, failure, cancelled). Absent for in-progress jobs. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("conclusion")] - public string? Conclusion { get; set; } + /// Whether post-tool-use failure hooks have already processed this result. + [JsonPropertyName("postToolUseFailureHooksProcessed")] + public bool? PostToolUseFailureHooksProcessed { get; set; } + + /// Execution outcome classification. + [JsonPropertyName("resultType")] + public ToolResultType ResultType { get; set; } + + /// Detailed log content available for session display. + [JsonPropertyName("sessionLog")] + public string? SessionLog { get; set; } + + /// Skill invocation metadata produced by the tool. + [JsonPropertyName("skillInvocation")] + public JsonElement? SkillInvocation { get; set; } + + /// Whether large-output post-processing should be skipped. + [JsonPropertyName("skipLargeOutputProcessing")] + public bool? SkipLargeOutputProcessing { get; set; } + + /// Structured result content in addition to the model-facing text. + [JsonPropertyName("structuredContent")] + public JsonElement? StructuredContent { get; set; } - /// Job id within the workflow run. - [JsonPropertyName("jobId")] - public required long JobId { get; set; } + /// Completion-review decision produced by the task-completion tool. + [JsonPropertyName("taskCompletionDecision")] + public TaskCompletionDecision? TaskCompletionDecision { get; set; } - /// Display name of the job. - [JsonPropertyName("jobName")] - public required string JobName { get; set; } + /// Text result returned to the model. + [JsonPropertyName("textResultForLlm")] + public string TextResultForLlm { get; set; } = string.Empty; - /// Repository the workflow run belongs to. - [JsonPropertyName("repo")] - public required PushGitHubRepoRef Repo { get; set; } + /// Deferred tool names made available by this result. + [JsonPropertyName("toolReferences")] + public IList? ToolReferences { get; set; } - /// URL to the job on GitHub. - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Tool-specific telemetry payload. + [JsonPropertyName("toolTelemetry")] + public JsonElement? ToolTelemetry { get; set; } - /// Display name of the workflow the job ran in. - [JsonPropertyName("workflowName")] - public required string WorkflowName { get; set; } + /// Optional UI resource produced by the tool. + [JsonPropertyName("uiResource")] + public JsonElement? UiResource { get; set; } } -/// Pointer to a GitHub repository. -/// The github_repository variant of . +/// Task-completion tool arguments and final result used to build a label-safe session event payload. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentGitHubRepository : PushAttachment +internal sealed class ToolsTaskCompleteEventDataRequest { - /// - [JsonIgnore] - public override string Type => "github_repository"; - - /// Short description of the repository. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } - - /// Git ref this attachment is anchored at (branch, tag, or commit). When absent the default branch is implied. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("ref")] - public string? Ref { get; set; } + /// Final expanded result returned by the task_complete tool. + [JsonPropertyName("finalResult")] + public ToolResultExpanded FinalResult { get => field ??= new(); set; } - /// Repository pointer. - [JsonPropertyName("repo")] - public required PushGitHubRepoRef Repo { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// URL to the repository on GitHub. - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Arguments supplied to the completed task_complete tool call. + [JsonPropertyName("toolArgs")] + public JsonElement ToolArgs { get; set; } } -/// One side of a file diff (head or base). +/// Indicates whether the external tool call result was handled successfully. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PushAttachmentGitHubFileDiffSide +public sealed class HandlePendingToolCallResult { - /// Repository-relative path to the file. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; - - /// Git ref (branch, tag, or commit SHA) the file is read at. - [JsonPropertyName("ref")] - public string Ref { get; set; } = string.Empty; - - /// Repository the file lives in. - [JsonPropertyName("repo")] - public PushGitHubRepoRef Repo { get => field ??= new(); set; } + /// Whether the tool call result was handled successfully. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Pointer to a single-file diff. At least one of `head` and `base` must be present. -/// The github_file_diff variant of . +/// Pending external tool call request ID, with the tool result or an error describing why it failed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentGitHubFileDiff : PushAttachment +internal sealed class HandlePendingToolCallRequest { - /// - [JsonIgnore] - public override string Type => "github_file_diff"; + /// Error message if the tool call failed. + [JsonPropertyName("error")] + public string? Error { get; set; } - /// File location on the base side of the diff. Absent for additions. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("base")] - public PushAttachmentGitHubFileDiffSide? Base { get; set; } + /// Request ID of the pending tool call. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; - /// File location on the head side of the diff. Absent for deletions. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("head")] - public PushAttachmentGitHubFileDiffSide? Head { get; set; } + /// Tool call result (string or expanded result object). + [JsonPropertyName("result")] + public JsonElement? Result { get; set; } - /// URL to the diff on GitHub (e.g., a commit, compare, or PR-file URL). - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// One side of a tree comparison (head or base). +/// External tool call of the session or one of its sub-agents that is still waiting for session.tools.handlePendingToolCall. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PushAttachmentGitHubTreeComparisonSide +public sealed class PendingExternalToolRequest { - /// Repository the revision belongs to. - [JsonPropertyName("repo")] - public PushGitHubRepoRef Repo { get => field ??= new(); set; } + /// Sub-agent instance identifier (the envelope agentId of its events) of the agent that issued the call; absent for calls issued by the root agent. + [JsonPropertyName("agentId")] + public string? AgentId { get; set; } - /// Git revision (branch, tag, or commit SHA). - [JsonPropertyName("revision")] - public string Revision { get; set; } = string.Empty; -} + /// Arguments to pass to the external tool. + [JsonPropertyName("arguments")] + public JsonElement? Arguments { get; set; } -/// Pointer to a comparison between two git revisions. -/// The github_tree_comparison variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentGitHubTreeComparison : PushAttachment -{ - /// - [JsonIgnore] - public override string Type => "github_tree_comparison"; + /// Stable identity of the provider that offered the tool, for hosts that route extension-owned tools by provider. + [JsonPropertyName("providerId")] + public string? ProviderId { get; set; } - /// Base side of the comparison. - [JsonPropertyName("base")] - public required PushAttachmentGitHubTreeComparisonSide Base { get; set; } + /// Request ID to pass to session.tools.handlePendingToolCall. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; - /// Head side of the comparison. - [JsonPropertyName("head")] - public required PushAttachmentGitHubTreeComparisonSide Head { get; set; } + /// Tool call ID assigned to this external tool invocation. + [JsonPropertyName("toolCallId")] + public string ToolCallId { get; set; } = string.Empty; - /// URL to the comparison on GitHub. - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Name of the external tool to invoke. + [JsonPropertyName("toolName")] + public string ToolName { get; set; } = string.Empty; } -/// Generic GitHub URL reference. -/// The github_url variant of . +/// External tool calls still waiting for a result. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentGitHubUrl : PushAttachment +public sealed class PendingExternalToolRequestList { - /// - [JsonIgnore] - public override string Type => "github_url"; - - /// URL to the GitHub resource. - [JsonPropertyName("url")] - public required string Url { get; set; } + /// External tool calls of the session and its sub-agents that session.tools.handlePendingToolCall would still accept, in the order they were requested. Includes calls that were pending when the session was last suspended and resumed with pending work continued, so a host that did not observe the original external_tool.requested event can answer them. + [JsonPropertyName("items")] + public IList Items { get => field ??= []; set; } } -/// Pointer to a file in a GitHub repository at a specific ref. -/// The github_file variant of . +/// No parameters; returns the external tool calls of the session and its sub-agents that are still waiting for a result. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentGitHubFile : PushAttachment +internal sealed class ToolsListPendingRequestsRequest { - /// - [JsonIgnore] - public override string Type => "github_file"; - - /// Repository-relative path to the file. - [JsonPropertyName("path")] - public required string Path { get; set; } - - /// Git ref the file is read at (branch, tag, or commit SHA). - [JsonPropertyName("ref")] - public required string Ref { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Repository the file lives in. - [JsonPropertyName("repo")] - public required PushGitHubRepoRef Repo { get; set; } +/// Resolve, build, and validate the runtime tool list for this session. Subagent sessions and consumer flows that need an initialized tool set before `send` invoke this. Default base-class implementation is a no-op for sessions that don't support tool validation. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ToolsInitializeAndValidateResult +{ +} - /// URL to the file on GitHub. - [JsonPropertyName("url")] - public required string Url { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionToolsInitializeAndValidateRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Pointer to a line range inside a file in a GitHub repository. -/// The github_snippet variant of . +/// Lightweight metadata for a currently initialized session tool. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentGitHubSnippet : PushAttachment +public sealed class CurrentToolMetadata { - /// - [JsonIgnore] - public override string Type => "github_snippet"; + /// Whether the tool is loaded on demand via tool search. + [JsonPropertyName("deferLoading")] + public bool? DeferLoading { get; set; } - /// Line range the snippet covers. - [JsonPropertyName("lineRange")] - public required PushAttachmentFileLineRange LineRange { get; set; } + /// Tool description. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// Repository-relative path to the file. - [JsonPropertyName("path")] - public required string Path { get; set; } + /// JSON Schema for tool input. + [JsonPropertyName("input_schema")] + public IDictionary? InputSchema { get; set; } - /// Git ref the file is read at (branch, tag, or commit SHA). - [JsonPropertyName("ref")] - public required string Ref { get; set; } + /// MCP server name for MCP-backed tools. + [JsonPropertyName("mcpServerName")] + public string? McpServerName { get; set; } - /// Repository the file lives in. - [JsonPropertyName("repo")] - public required PushGitHubRepoRef Repo { get; set; } + /// Raw MCP tool name for MCP-backed tools. + [JsonPropertyName("mcpToolName")] + public string? McpToolName { get; set; } - /// URL to the snippet on GitHub (with line anchor). - [JsonPropertyName("url")] - public required string Url { get; set; } + /// Model-facing tool name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Optional MCP/config namespaced tool name. + [JsonPropertyName("namespacedName")] + public string? NamespacedName { get; set; } } -/// Blob attachment with inline base64-encoded data. -/// The blob variant of . +/// Current lightweight tool metadata snapshot for the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentBlob : PushAttachment +public sealed class ToolsGetCurrentMetadataResult { - /// - [JsonIgnore] - public override string Type => "blob"; - - /// Base64-encoded content. - [Base64String] - [JsonPropertyName("data")] - public required string Data { get; set; } + /// Current tool metadata, or null when tools have not been initialized yet. + [JsonPropertyName("tools")] + public IList? Tools { get; set; } +} - /// User-facing display name for the attachment. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("displayName")] - public string? DisplayName { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionToolsGetCurrentMetadataRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// MIME type of the inline data. - [JsonPropertyName("mimeType")] - public required string MimeType { get; set; } +/// Empty result after replacing the calling connection's externally implemented tools. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ToolsSetResult +{ } -/// Slim input shape for extension_context attachments; identity fields are runtime-derived. -/// The extension_context variant of . +/// Serializable definition of a caller-implemented tool whose execution is handled over the SDK connection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PushAttachmentExtensionContext : PushAttachment +public sealed class ProtocolExternalToolDefinition { - /// - [JsonIgnore] - public override string Type => "extension_context"; + /// Tool-loading deferral policy. + [JsonPropertyName("defer")] + public ProtocolExternalToolDefer? Defer { get; set; } - /// Caller-supplied JSON payload (required, may be null but not undefined). - [JsonPropertyName("payload")] - public required JsonElement Payload { get; set; } + /// Model-visible explanation of what the tool does. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// Human-readable composer pill label. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] + /// Whether the tool executes commands in a terminal. + [JsonPropertyName("isTerminal")] + public bool? IsTerminal { get; set; } + + /// Optional caller-defined metadata associated with the tool. + [JsonPropertyName("metadata")] + public IDictionary? Metadata { get; set; } + + /// Unique model-visible tool name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Whether this definition replaces a built-in tool with the same name. + [JsonPropertyName("overridesBuiltInTool")] + public bool? OverridesBuiltInTool { get; set; } + + /// JSON Schema describing the tool's input arguments. + [JsonPropertyName("parameters")] + public IDictionary? Parameters { get; set; } + + /// Whether execution bypasses the normal tool permission prompt. + [JsonPropertyName("skipPermission")] + public bool? SkipPermission { get; set; } + + /// Optional human-readable display title. [JsonPropertyName("title")] - public required string Title { get; set; } + public string? Title { get; set; } } -/// Parameters for session.extensions.sendAttachmentsToMessage. +/// Complete externally implemented tool list for the calling connection. An empty list removes every tool previously supplied by that connection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SendAttachmentsToMessageParams +internal sealed class ToolsSetRequest { - /// Attachments to push into the next user-message turn. extension_context entries take the slim shape; standard variants take their full AttachmentSchema shape. - [JsonPropertyName("attachments")] - public IList Attachments { get => field ??= []; set; } - - /// Optional canvas instance binding the push for provenance. When supplied, the runtime resolves the canvas, verifies it is owned by the calling extension, and stamps canvasId/instanceId onto each extension_context entry. When omitted, no resolution runs and those fields stay unset on the attachment. - [JsonPropertyName("instanceId")] - public string? InstanceId { get; set; } - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Complete replacement list for the calling connection. + [JsonPropertyName("tools")] + public IList Tools { get => field ??= []; set; } } -/// A tool name and arguments to execute through the session's native invocation pipeline. +/// Empty result after applying subagent settings. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ToolsExecuteRequest +public sealed class ToolsUpdateSubagentSettingsResult { - /// Arguments supplied to the tool. - [JsonPropertyName("arguments")] - public JsonElement Arguments { get; set; } +} - /// Name of the currently offered tool to execute. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; +/// Subagent model, reasoning effort, context tier, and auto-invocation settings. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SubagentSettingsEntry +{ + /// Whether this agent's runtime-defined proactive invocation prompting is enabled, if supported. Currently consumed by the built-in rubber-duck agent. + [JsonPropertyName("autoInvoke")] + public bool? AutoInvoke { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Context tier override for matching subagents. + [JsonPropertyName("contextTier")] + public SubagentSettingsEntryContextTier? ContextTier { get; set; } - /// Optional identifier used to correlate this invocation with its tool call. - [JsonPropertyName("toolCallId")] - public string? ToolCallId { get; set; } + /// Reasoning effort override for matching subagents. + [JsonPropertyName("effortLevel")] + public string? EffortLevel { get; set; } + + /// Model override for matching subagents. + [JsonPropertyName("model")] + public string? Model { get; set; } + + /// Whether the configured model strategy is preferred or required. + [JsonPropertyName("modelPolicy")] + public AgentModelPolicy? ModelPolicy { get; set; } } -/// Custom grammar input format accepted by a built-in tool. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class BuiltinToolFormat +/// Configured per-agent subagent overrides. +public sealed class UpdateSubagentSettingsRequestSubagents { - /// Grammar definition accepted by the tool. - [JsonPropertyName("definition")] - public string Definition { get; set; } = string.Empty; + /// Per-agent settings keyed by subagent agent_type. + [JsonPropertyName("agents")] + public IDictionary? Agents { get; set; } - /// Grammar syntax used by the format definition. - [JsonPropertyName("syntax")] - public string Syntax { get; set; } = string.Empty; + /// Names of subagents the user has turned off; they cannot be dispatched. + [JsonPropertyName("disabledSubagents")] + public IList? DisabledSubagents { get; set; } - /// Custom input-format discriminator. - [JsonPropertyName("type")] - public BuiltinToolFormatType Type { get; set; } + /// Maximum number of subagents that can run concurrently; applies to usage-based billing users only. + [JsonPropertyName("maxConcurrency")] + public int? MaxConcurrency { get; set; } + + /// Maximum subagent nesting depth; applies to usage-based billing users only. + [JsonPropertyName("maxDepth")] + public int? MaxDepth { get; set; } } -/// JSON Schema object accepted by a built-in tool. +/// Subagent settings to apply to the current session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class BuiltinToolInputSchema +internal sealed class UpdateSubagentSettingsRequest { - /// Root type of the tool input schema. - [JsonPropertyName("type")] - public BuiltinToolInputSchemaType Type { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Subagent settings to apply, or null to clear the live session override. + [JsonPropertyName("subagents")] + public UpdateSubagentSettingsRequestSubagents? Subagents { get; set; } } -/// Rust-owned metadata and input schema for a built-in tool. +/// RPC data type for SessionCommandsList operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class BuiltinToolDescriptor +public sealed class SessionCommandsListRequest { - /// Model-facing description of the tool's behavior. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; - - /// Optional custom input format used instead of a JSON Schema. - [JsonPropertyName("format")] - public BuiltinToolFormat? Format { get; set; } - - /// Whether the tool provides a specialized intention summary. - [JsonPropertyName("hasSummariseIntention")] - public bool HasSummariseIntention { get; set; } - - /// JSON Schema for the tool input, or null when the tool uses a custom format. - [JsonPropertyName("inputSchema")] - public BuiltinToolInputSchema? InputSchema { get; set; } + /// Include runtime built-in commands. + [JsonPropertyName("includeBuiltins")] + public bool? IncludeBuiltins { get; set; } - /// Optional supplemental usage instructions for the tool. - [JsonPropertyName("instructions")] - public string? Instructions { get; set; } + /// Include commands registered by protocol clients, including SDK clients and extensions. + [JsonPropertyName("includeClientCommands")] + public bool? IncludeClientCommands { get; set; } - /// Whether the tool executes commands in a terminal. - [JsonPropertyName("isTerminal")] - public bool IsTerminal { get; set; } + /// Include enabled user-invocable skills and commands. + [JsonPropertyName("includeSkills")] + public bool? IncludeSkills { get; set; } +} - /// Stable name used to invoke the built-in tool. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; +/// RPC data type for SessionCommandsListRequestWithSession operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionCommandsListRequestWithSession +{ + /// Include runtime built-in commands. + [JsonPropertyName("includeBuiltins")] + public bool? IncludeBuiltins { get; set; } - /// Policy describing which tool metadata may be recorded without obfuscation. - [JsonPropertyName("safeForTelemetry")] - public JsonElement SafeForTelemetry { get; set; } + /// Include commands registered by protocol clients, including SDK clients and extensions. + [JsonPropertyName("includeClientCommands")] + public bool? IncludeClientCommands { get; set; } - /// Optional human-readable title for the tool. - [JsonPropertyName("title")] - public string? Title { get; set; } + /// Include enabled user-invocable skills and commands. + [JsonPropertyName("includeSkills")] + public bool? IncludeSkills { get; set; } - /// Optional tool category discriminator. - [JsonPropertyName("type")] - public string? Type { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Rust-owned built-in tool descriptors for the session. +/// Result of invoking the slash command (text output, prompt to send to the agent, completion, or subcommand selection). +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ToolsGetBuiltinDescriptorsResult +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(SlashCommandInvocationResultText), "text")] +[JsonDerivedType(typeof(SlashCommandInvocationResultAgentPrompt), "agent-prompt")] +[JsonDerivedType(typeof(SlashCommandInvocationResultCompleted), "completed")] +[JsonDerivedType(typeof(SlashCommandInvocationResultSelectSubcommand), "select-subcommand")] +[JsonDerivedType(typeof(SlashCommandInvocationResultAddTimelineEntry), "add-timeline-entry")] +[JsonDerivedType(typeof(SlashCommandInvocationResultShowDialog), "show-dialog")] +[JsonDerivedType(typeof(SlashCommandInvocationResultSetModel), "set-model")] +[JsonDerivedType(typeof(SlashCommandInvocationResultSetPlanModel), "set-plan-model")] +public partial class SlashCommandInvocationResult { - /// Built-in tool descriptors materialized for the session. - [JsonPropertyName("tools")] - public IList Tools { get => field ??= []; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Shell-specific names and description lines used to materialize built-in shell tool descriptors. + +/// Slash-command invocation result containing text output plus Markdown/ANSI rendering flags. +/// The text variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ToolsShellDescriptorConfig +public partial class SlashCommandInvocationResultText : SlashCommandInvocationResult { - /// Additional model-facing shell description lines. - [JsonPropertyName("descriptionLines")] - public IList DescriptionLines { get => field ??= []; set; } - - /// Human-readable shell name. - [JsonPropertyName("displayName")] - public string DisplayName { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "text"; - /// Tool name used to list active shells. - [JsonPropertyName("listShellsToolName")] - public string ListShellsToolName { get; set; } = string.Empty; + /// Whether text contains Markdown. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("markdown")] + public bool? Markdown { get; set; } - /// Tool name used to read shell output. - [JsonPropertyName("readShellToolName")] - public string ReadShellToolName { get; set; } = string.Empty; + /// Whether ANSI sequences should be preserved. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("preserveAnsi")] + public bool? PreserveAnsi { get; set; } - /// Tool name used to start shell commands. - [JsonPropertyName("shellToolName")] - public string ShellToolName { get; set; } = string.Empty; + /// True when the invocation mutated user runtime settings; consumers caching settings should refresh. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("runtimeSettingsChanged")] + public bool? RuntimeSettingsChanged { get; set; } - /// Stable shell type identifier. - [JsonPropertyName("shellType")] - public string ShellType { get; set; } = string.Empty; + /// Present when the invocation changed the sandbox for this session only. Nothing was persisted, so consumers must mirror the change onto the live session rather than reloading settings, and must not treat it as a settings change. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("sandboxSessionChange")] + public SandboxSessionChange? SandboxSessionChange { get; set; } - /// Tool name used to stop shell commands. - [JsonPropertyName("stopShellToolName")] - public string StopShellToolName { get; set; } = string.Empty; + /// Text output for the client to render. + [JsonPropertyName("text")] + public required string Text { get; set; } } -/// Options controlling how Rust-owned built-in tool descriptors are materialized. +/// Slash-command invocation result that submits an agent prompt, with display prompt, optional mode, optional user-facing notice, and settings-change flag. +/// The agent-prompt variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ToolsGetBuiltinDescriptorsRequest +public partial class SlashCommandInvocationResultAgentPrompt : SlashCommandInvocationResult { - /// Whether background task completion notifications are enabled. - [JsonPropertyName("backgroundTaskNotificationsEnabled")] - public bool? BackgroundTaskNotificationsEnabled { get; set; } - - /// Whether tool descriptors should include authoring metadata. - [JsonPropertyName("includeAuthor")] - public bool? IncludeAuthor { get; set; } - - /// Whether descriptors should favor fewer user-intervention prompts. - [JsonPropertyName("reduceUserIntervention")] - public bool? ReduceUserIntervention { get; set; } + /// + [JsonIgnore] + public override string Kind => "agent-prompt"; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Prompt text to display to the user. + [JsonPropertyName("displayPrompt")] + public required string DisplayPrompt { get; set; } - /// Shell-specific names and description lines for shell tools. - [JsonPropertyName("shellConfig")] - public ToolsShellDescriptorConfig? ShellConfig { get; set; } + /// Optional target session mode for the agent prompt. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("mode")] + public SessionMode? Mode { get; set; } - /// Whether the configured shell supports PowerShell 7 syntax. - [JsonPropertyName("shellSupportsPowerShell7Syntax")] - public bool? ShellSupportsPowerShell7Syntax { get; set; } + /// Optional user-facing notice to show before the prompt is submitted. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("notice")] + public string? Notice { get; set; } - /// Default shell timeout in milliseconds. - [JsonPropertyName("shellTimeoutMs")] - public double? ShellTimeoutMs { get; set; } + /// Prompt to submit to the agent. + [JsonPropertyName("prompt")] + public required string Prompt { get; set; } - /// Whether semantic skill lookup is available. - [JsonPropertyName("skillEmbeddingEnabled")] - public bool? SkillEmbeddingEnabled { get; set; } + /// True when the invocation mutated user runtime settings; consumers caching settings should refresh. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("runtimeSettingsChanged")] + public bool? RuntimeSettingsChanged { get; set; } } -/// Task completion notification with summary from the agent. +/// Slash-command invocation result indicating completion, with optional message and settings-change flag. +/// The completed variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TaskCompleteData +public partial class SlashCommandInvocationResultCompleted : SlashCommandInvocationResult { - /// Structured blocker details when outcome is blocked. - [JsonPropertyName("blocker")] - public TaskBlocker? Blocker { get; set; } + /// + [JsonIgnore] + public override string Kind => "completed"; - /// Active autopilot objective ID evaluated by the completion reviewer. - [JsonPropertyName("objectiveId")] - public long? ObjectiveId { get; set; } + /// Optional user-facing message describing the completed command. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("message")] + public string? Message { get; set; } - /// Semantic completion decision. Absent on legacy events and invalid tool calls. - [JsonPropertyName("outcome")] - public TaskCompletionOutcome? Outcome { get; set; } + /// Optional target session mode applied without submitting an agent prompt. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("mode")] + public SessionMode? Mode { get; set; } - /// Label-safe runtime rationale for the completion decision (e.g. a cancellation or pause/resume downgrade), when one applies. Reviewer-authored rationale is intentionally omitted here because this event has no IFC label channel; the reviewer's findings remain available through its own labeled sub-agent events. - [JsonPropertyName("reason")] - public string? Reason { get; set; } + /// True when the invocation mutated user runtime settings; consumers caching settings should refresh. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("runtimeSettingsChanged")] + public bool? RuntimeSettingsChanged { get; set; } +} - /// Whether the task was accepted as complete. False when validation failed or completion was rejected or blocked by the reviewer. - [JsonPropertyName("success")] - public bool? Success { get; set; } +/// Selectable slash-command subcommand option with name, description, and optional group label. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SlashCommandSelectSubcommandOption +{ + /// Human-readable description of the subcommand. + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; - /// Summary of the completed task, provided by the agent. - [JsonPropertyName("summary")] - public string? Summary { get; set; } + /// Optional group label for organizing options. + [JsonPropertyName("group")] + public string? Group { get; set; } + + /// Subcommand name to invoke. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; } -/// Binary result returned by a tool for the model. +/// Slash-command invocation result asking the client to present subcommand options for a parent command. +/// The select-subcommand variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ExternalToolTextResultForLlmBinaryResultsForLlm +public partial class SlashCommandInvocationResultSelectSubcommand : SlashCommandInvocationResult { - /// Base64-encoded binary data. - [Base64String] - [JsonPropertyName("data")] - public string Data { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "select-subcommand"; - /// Human-readable description of the binary data. - [JsonPropertyName("description")] - public string? Description { get; set; } + /// Parent command name that requires subcommand selection. + [JsonPropertyName("command")] + public required string Command { get; set; } - /// Optional metadata from the producing tool. - [JsonPropertyName("metadata")] - public IDictionary? Metadata { get; set; } + /// Available subcommand options for the client to present. + [JsonPropertyName("options")] + public required IList Options { get; set; } - /// MIME type of the binary data. - [JsonPropertyName("mimeType")] - public string MimeType { get; set; } = string.Empty; + /// True when the invocation mutated user runtime settings; consumers caching settings should refresh. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("runtimeSettingsChanged")] + public bool? RuntimeSettingsChanged { get; set; } - /// Binary result type discriminator. Use "image" for images and "resource" for other binary data. - [JsonPropertyName("type")] - public ExternalToolTextResultForLlmBinaryResultsForLlmType Type { get; set; } + /// Human-readable title for the selection UI. + [JsonPropertyName("title")] + public required string Title { get; set; } } -/// A content block within a tool result, which may be text, terminal output, image, audio, or a resource. -/// Polymorphic base type discriminated by type. +/// RPC data type for SlashCommandTimelineEntry operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "type", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentText), "text")] -[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentTerminal), "terminal")] -[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentShellExit), "shell_exit")] -[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentImage), "image")] -[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentAudio), "audio")] -[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentResourceLink), "resource_link")] -[JsonDerivedType(typeof(ExternalToolTextResultForLlmContentResource), "resource")] -public partial class ExternalToolTextResultForLlmContent +public sealed class SlashCommandTimelineEntry { - /// The type discriminator. + /// What the user must do to recover, when the entry reports a failure the runtime knows an action for. The `text` never names a client affordance, so a client that offers one renders it from this value. + [JsonPropertyName("remediation")] + public RemediationAction? Remediation { get; set; } + + /// Text displayed for the timeline entry. + [JsonPropertyName("text")] + public string Text { get; set; } = string.Empty; + + /// Timeline entry presentation type. [JsonPropertyName("type")] - public virtual string Type { get; set; } = string.Empty; -} + public string Type { get; set; } = string.Empty; + /// Optional URL associated with the timeline entry. + [JsonPropertyName("url")] + public string? Url { get; set; } +} -/// Plain text content block. -/// The text variant of . +/// The add-timeline-entry variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ExternalToolTextResultForLlmContentText : ExternalToolTextResultForLlmContent +public partial class SlashCommandInvocationResultAddTimelineEntry : SlashCommandInvocationResult { /// [JsonIgnore] - public override string Type => "text"; + public override string Kind => "add-timeline-entry"; - /// The text content. - [JsonPropertyName("text")] - public required string Text { get; set; } + /// Timeline entry the host should append. + [JsonPropertyName("entry")] + public required SlashCommandTimelineEntry Entry { get; set; } + + /// Optional text the host should prefill into the input editor. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("prefillInput")] + public string? PrefillInput { get; set; } + + /// Whether command execution changed persisted runtime settings. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("runtimeSettingsChanged")] + public bool? RuntimeSettingsChanged { get; set; } } -/// Terminal/shell output content block with optional exit code and working directory. -/// The terminal variant of . +/// RPC data type for SlashCommandModelPickerDialog operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ExternalToolTextResultForLlmContentTerminal : ExternalToolTextResultForLlmContent +public sealed class SlashCommandModelPickerDialog +{ + /// Discriminator for a model-picker dialog. + [JsonPropertyName("kind")] + public string Kind { get; set; } = string.Empty; + + /// Model that should be enabled before it can be selected. + [JsonPropertyName("modelToEnable")] + public string? ModelToEnable { get; set; } + + /// Settings scope the picker should modify. + [JsonPropertyName("scope")] + public string? Scope { get; set; } + + /// Model-selection target represented by the picker. + [JsonPropertyName("target")] + public string? Target { get; set; } +} + +/// The show-dialog variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class SlashCommandInvocationResultShowDialog : SlashCommandInvocationResult { /// [JsonIgnore] - public override string Type => "terminal"; + public override string Kind => "show-dialog"; - /// Working directory where the command was executed. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("cwd")] - public string? Cwd { get; set; } + /// Dialog the host should display. + [JsonPropertyName("dialog")] + public required SlashCommandModelPickerDialog Dialog { get; set; } - /// Process exit code, if the command has completed. + /// Whether command execution changed persisted runtime settings. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("exitCode")] - public long? ExitCode { get; set; } - - /// Terminal/shell output text. - [JsonPropertyName("text")] - public required string Text { get; set; } + [JsonPropertyName("runtimeSettingsChanged")] + public bool? RuntimeSettingsChanged { get; set; } } -/// Shell command exit metadata with optional output preview. -/// The shell_exit variant of . +/// The set-model variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ExternalToolTextResultForLlmContentShellExit : ExternalToolTextResultForLlmContent +public partial class SlashCommandInvocationResultSetModel : SlashCommandInvocationResult { /// [JsonIgnore] - public override string Type => "shell_exit"; + public override string Kind => "set-model"; - /// Working directory where the shell command was executed. + /// Auto routing profile selected by the command, when the model is Auto. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("cwd")] - public string? Cwd { get; set; } + [JsonPropertyName("autoTier")] + public AutoTier? AutoTier { get; set; } - /// Exit code from the completed shell command. - [JsonPropertyName("exitCode")] - public required long ExitCode { get; set; } + /// Model selected by the command. + [JsonPropertyName("model")] + public required string Model { get; set; } - /// Path reported in the shell session's filesystem namespace when shell output exceeded the configured large-output threshold. + /// Reasoning effort selected for the model. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("outputFilePath")] - public string? OutputFilePath { get; set; } + [JsonPropertyName("reasoningEffort")] + public string? ReasoningEffort { get; set; } - /// Output associated with this shell command, if available. May be partial, truncated, or a preview; not guaranteed to be full output. + /// Repository settings scope modified by the command. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("outputPreview")] - public string? OutputPreview { get; set; } + [JsonPropertyName("repoScope")] + public string? RepoScope { get; set; } - /// Whether outputPreview is known to be incomplete or truncated. + /// User-settings snapshot to restore if the host cancels the model switch. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("outputTruncated")] - public bool? OutputTruncated { get; set; } + [JsonPropertyName("revertOnCancel")] + public IDictionary? RevertOnCancel { get; set; } - /// Shell id, as assigned by Copilot runtime. - [JsonPropertyName("shellId")] - public required string ShellId { get; set; } + /// Whether command execution changed persisted runtime settings. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("runtimeSettingsChanged")] + public bool? RuntimeSettingsChanged { get; set; } + + /// Settings scope modified by the command. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("scope")] + public string? Scope { get; set; } + + /// User-facing warning produced while selecting the model. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("warning")] + public string? Warning { get; set; } } -/// Image content block with base64-encoded data. -/// The image variant of . +/// The set-plan-model variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ExternalToolTextResultForLlmContentImage : ExternalToolTextResultForLlmContent +public partial class SlashCommandInvocationResultSetPlanModel : SlashCommandInvocationResult { /// [JsonIgnore] - public override string Type => "image"; + public override string Kind => "set-plan-model"; - /// Base64-encoded image data. - [Base64String] - [JsonPropertyName("data")] - public required string Data { get; set; } + /// User-facing confirmation message for the plan-model selection. + [JsonPropertyName("message")] + public required string Message { get; set; } - /// MIME type of the image (e.g., image/png, image/jpeg). - [JsonPropertyName("mimeType")] - public required string MimeType { get; set; } + /// Dedicated model selected for plan mode. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("planModel")] + public string? PlanModel { get; set; } + + /// Whether command execution changed persisted runtime settings. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("runtimeSettingsChanged")] + public bool? RuntimeSettingsChanged { get; set; } } -/// Audio content block with base64-encoded data. -/// The audio variant of . +/// Slash command name and optional raw input string to invoke. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ExternalToolTextResultForLlmContentAudio : ExternalToolTextResultForLlmContent +internal sealed class CommandsInvokeRequest { - /// - [JsonIgnore] - public override string Type => "audio"; + /// Raw input after the command name. + [JsonPropertyName("input")] + public string? Input { get; set; } - /// Base64-encoded audio data. - [Base64String] - [JsonPropertyName("data")] - public required string Data { get; set; } + /// Command name. Leading slashes are stripped and the name is matched case-insensitively. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// MIME type of the audio (e.g., audio/wav, audio/mpeg). - [JsonPropertyName("mimeType")] - public required string MimeType { get; set; } + /// Optional client surface that initiated the invocation. + [JsonPropertyName("origin")] + public CommandsInvocationOrigin? Origin { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Icon image for a resource. +/// Whether finalizing the invocation effect succeeded, and the failure reason when it did not. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ExternalToolTextResultForLlmContentResourceLinkIcon +internal sealed class CommandsFinalizeInvocationEffectResult { - /// MIME type of the icon image. - [JsonPropertyName("mimeType")] - public string? MimeType { get; set; } + /// Failure reason when the invocation effect could not be finalized. + [JsonPropertyName("error")] + public string? Error { get; set; } - /// Available icon sizes (e.g., ['16x16', '32x32']). - [JsonPropertyName("sizes")] - public IList? Sizes { get; set; } + /// Whether the pending invocation effect was finalized successfully. + [JsonPropertyName("success")] + public bool Success { get; set; } +} - /// URL or path to the icon image. - [JsonPropertyName("src")] - public string Src { get; set; } = string.Empty; +/// The pending slash-command invocation effect to finalize, plus whether the host applied or cancelled it. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class CommandsFinalizeInvocationEffectRequest +{ + /// The slash-command result object that produced the pending effect, echoed back unchanged. + [JsonPropertyName("effect")] + public IDictionary Effect { get => field ??= new Dictionary(); set; } - /// Theme variant this icon is intended for. - [JsonPropertyName("theme")] - public ExternalToolTextResultForLlmContentResourceLinkIconTheme? Theme { get; set; } + /// Whether the host applied or cancelled the pending invocation effect. + [JsonPropertyName("outcome")] + public CommandsInvocationEffectOutcome Outcome { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Resource link content block referencing an external resource. -/// The resource_link variant of . +/// Indicates whether the pending client-handled command was completed successfully. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ExternalToolTextResultForLlmContentResourceLink : ExternalToolTextResultForLlmContent +public sealed class CommandsHandlePendingCommandResult { - /// - [JsonIgnore] - public override string Type => "resource_link"; + /// Whether the command was handled successfully. + [JsonPropertyName("success")] + public bool Success { get; set; } +} - /// Human-readable description of the resource. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("description")] - public string? Description { get; set; } +/// Pending command request ID and an optional error if the client handler failed. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class CommandsHandlePendingCommandRequest +{ + /// Error message if the command handler failed. + [JsonPropertyName("error")] + public string? Error { get; set; } - /// Icons associated with this resource. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("icons")] - public IList? Icons { get; set; } + /// Request ID from the command invocation event. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; - /// MIME type of the resource content. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("mimeType")] - public string? MimeType { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Resource name identifier. - [JsonPropertyName("name")] - public required string Name { get; set; } +/// Error message produced while executing the command, if any. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ExecuteCommandResult +{ + /// Error message produced while executing the command, if any. Omitted when the handler succeeded. + [JsonPropertyName("error")] + public string? Error { get; set; } +} - /// Size of the resource in bytes. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("size")] - public long? Size { get; set; } +/// Slash command name and argument string to execute synchronously. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ExecuteCommandParams +{ + /// Argument string to pass to the command (empty string if none). + [JsonPropertyName("args")] + public string Args { get; set; } = string.Empty; - /// Human-readable display title for the resource. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("title")] - public string? Title { get; set; } + /// Name of the slash command to invoke (without the leading '/'). + [JsonPropertyName("commandName")] + public string CommandName { get; set; } = string.Empty; - /// URI identifying the resource. - [JsonPropertyName("uri")] - public required string Uri { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Embedded resource content block with inline text or binary data. -/// The resource variant of . +/// Indicates whether the command was accepted into the local execution queue. +/// Data type discriminated by queued. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class ExternalToolTextResultForLlmContentResource : ExternalToolTextResultForLlmContent +public partial class EnqueueCommandResult { - /// - [JsonIgnore] - public override string Type => "resource"; + /// The boolean discriminator. + [JsonPropertyName("queued")] + public bool Queued { get; set; } - /// The embedded resource contents, either text or base64-encoded binary. - [JsonPropertyName("resource")] - public required JsonElement Resource { get; set; } + /// Stable opaque ID of the queued command. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("queueId")] + public string? QueueId { get; set; } } -/// A message injected by a tool result. +/// Slash-prefixed command string to enqueue for FIFO processing. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ToolResultNewMessage +internal sealed class EnqueueCommandParams { - /// Message content to inject after the tool result. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// Slash-prefixed command string to enqueue, e.g. '/compact' or '/model gpt-4'. Queued FIFO with any in-flight items; if the session is idle, processing kicks off immediately. + [JsonPropertyName("command")] + public string Command { get; set; } = string.Empty; - /// Source attributed to the injected message. - [JsonPropertyName("source")] - public string Source { get; set; } = string.Empty; + /// Optional user-facing text for the queue row. The command string is shown when omitted. + [JsonPropertyName("displayText")] + public string? DisplayText { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// RPC data type for TaskCompletionDecision operations. +/// Indicates whether the queued-command response was matched to a pending request. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class TaskCompletionDecision +public sealed class CommandsRespondToQueuedCommandResult { - /// Objective eligibility token captured when the decision was evaluated. - [JsonPropertyName("completionEligibilityToken")] - public long? CompletionEligibilityToken { get; set; } - - /// Whether completion was accepted after the reviewer-rejection budget was exhausted. - [JsonPropertyName("completionRejectionBudgetExhausted")] - public bool? CompletionRejectionBudgetExhausted { get; set; } - - /// Active autopilot objective evaluated by the completion reviewer. - [JsonPropertyName("objectiveId")] - public long? ObjectiveId { get; set; } - - /// Semantic result of evaluating the task completion request. - [JsonPropertyName("outcome")] - public TaskCompletionOutcome Outcome { get; set; } - - /// Rationale for the completion decision, when one is available. - [JsonPropertyName("reason")] - public string? Reason { get; set; } + /// Whether a pending queued command with the given request ID was found and resolved. False when the request was already resolved, cancelled, or unknown. + [JsonPropertyName("success")] + public bool Success { get; set; } +} - /// Whether the rationale was derived from completion-reviewer output. - [JsonPropertyName("reviewerDerived")] - public bool? ReviewerDerived { get; set; } +/// Result of the queued command execution. +/// Data type discriminated by handled. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class QueuedCommandResult +{ + /// The boolean discriminator. + [JsonPropertyName("handled")] + public bool Handled { get; set; } - /// Information-flow metadata captured from the completion reviewer. - [JsonPropertyName("reviewerResultMeta")] - public JsonElement? ReviewerResultMeta { get; set; } + /// When true, the runtime will not process subsequent queued commands until a new request comes in. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("stopProcessingQueue")] + public bool? StopProcessingQueue { get; set; } } -/// Expanded canonical result returned by a session tool. +/// Queued-command request ID and the result indicating whether the host executed it (and whether to stop processing further queued commands). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ToolResultExpanded +internal sealed class CommandsRespondToQueuedCommandRequest { - /// Base64-encoded binary results returned to the model. - [JsonPropertyName("binaryResultsForLlm")] - public IList? BinaryResultsForLlm { get; set; } + /// Request ID from the `command.queued` event the host is responding to. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; - /// Sources returned by the tool that the model may cite. - [JsonPropertyName("citableSources")] - public IList? CitableSources { get; set; } + /// Result of the queued command execution. + [JsonPropertyName("result")] + public QueuedCommandResult Result { get => field ??= new(); set; } - /// Structured content blocks returned to the model. - [JsonPropertyName("contents")] - public IList? Contents { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Error message for an unsuccessful execution. - [JsonPropertyName("error")] - public string? Error { get; set; } +/// Telemetry engagement ID for the session, when available. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionTelemetryEngagement +{ + /// Current telemetry engagement ID, when available. + [JsonPropertyName("engagementId")] + public string? EngagementId { get; set; } +} - /// Metadata propagated with the tool result, including information-flow labels. - [JsonPropertyName("mcpMeta")] - public IDictionary? McpMeta { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionTelemetryGetEngagementIdRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Messages to inject after the tool result. - [JsonPropertyName("newMessages")] - public IList? NewMessages { get; set; } +/// Feature override key/value pairs to attach to subsequent telemetry events from this session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class TelemetrySetFeatureOverridesRequest +{ + /// Override key/value pairs to attach to subsequent telemetry events from this session. Replaces any previously-set overrides. + [JsonPropertyName("features")] + public IDictionary Features { get => field ??= new Dictionary(); set; } - /// Whether post-tool-use failure hooks have already processed this result. - [JsonPropertyName("postToolUseFailureHooksProcessed")] - public bool? PostToolUseFailureHooksProcessed { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Execution outcome classification. - [JsonPropertyName("resultType")] - public ToolResultType ResultType { get; set; } +/// Completed transient query. Ordered chunks and the terminal outcome are also delivered through `ui.ephemeral_query` session events while it runs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class UIEphemeralQueryResult +{ + /// Answer returned by the model. + [JsonPropertyName("answer")] + public string Answer { get; set; } = string.Empty; +} - /// Detailed log content available for session display. - [JsonPropertyName("sessionLog")] - public string? SessionLog { get; set; } +/// Transient question to answer without adding it to conversation history. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UIEphemeralQueryRequest +{ + /// Question to answer from the current conversation context. + [JsonPropertyName("question")] + public string Question { get; set; } = string.Empty; - /// Skill invocation metadata produced by the tool. - [JsonPropertyName("skillInvocation")] - public JsonElement? SkillInvocation { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Whether large-output post-processing should be skipped. - [JsonPropertyName("skipLargeOutputProcessing")] - public bool? SkipLargeOutputProcessing { get; set; } +/// The elicitation response (accept with form values, decline, or cancel). +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class UIElicitationResponse +{ + /// MCP response metadata. + [JsonPropertyName("_meta")] + public IDictionary? Meta { get; set; } - /// Structured result content in addition to the model-facing text. - [JsonPropertyName("structuredContent")] - public JsonElement? StructuredContent { get; set; } + /// The user's response: accept (submitted), decline (rejected), or cancel (dismissed). + [JsonPropertyName("action")] + public UIElicitationResponseAction Action { get; set; } - /// Completion-review decision produced by the task-completion tool. - [JsonPropertyName("taskCompletionDecision")] - public TaskCompletionDecision? TaskCompletionDecision { get; set; } + /// The form values submitted by the user (present when action is 'accept'). + [JsonPropertyName("content")] + public IDictionary? Content { get; set; } +} - /// Text result returned to the model. - [JsonPropertyName("textResultForLlm")] - public string TextResultForLlm { get; set; } = string.Empty; +/// JSON Schema describing the form fields to present to the user. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class UIElicitationSchema +{ + /// Form field definitions, keyed by field name. + [JsonPropertyName("properties")] + public IDictionary Properties { get => field ??= new Dictionary(); set; } - /// Deferred tool names made available by this result. - [JsonPropertyName("toolReferences")] - public IList? ToolReferences { get; set; } + /// List of required field names. + [JsonPropertyName("required")] + public IList? Required { get; set; } - /// Tool-specific telemetry payload. - [JsonPropertyName("toolTelemetry")] - public JsonElement? ToolTelemetry { get; set; } + /// Schema type indicator (always 'object'). + [JsonPropertyName("type")] + public string Type { get; set; } = string.Empty; +} - /// Optional UI resource produced by the tool. - [JsonPropertyName("uiResource")] - public JsonElement? UiResource { get; set; } +/// Metadata controlling an MCP task's lifetime. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class McpTaskMetadata +{ + /// Task time-to-live. + [JsonPropertyName("ttl")] + public long? Ttl { get; set; } } -/// Task-completion tool arguments and final result used to build a label-safe session event payload. +/// Prompt message and JSON schema describing the form fields to elicit from the user. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ToolsTaskCompleteEventDataRequest +internal sealed class UIElicitationRequest { - /// Final expanded result returned by the task_complete tool. - [JsonPropertyName("finalResult")] - public ToolResultExpanded FinalResult { get => field ??= new(); set; } + /// MCP request metadata. + [JsonPropertyName("_meta")] + public IDictionary? Meta { get; set; } + + /// Message describing what information is needed from the user. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; + + /// Elicitation mode. Omitted and form are equivalent for structured elicitation. + [JsonPropertyName("mode")] + public McpElicitationFormMode? Mode { get; set; } + + /// JSON Schema describing the form fields to present to the user. + [JsonPropertyName("requestedSchema")] + public UIElicitationSchema RequestedSchema { get => field ??= new(); set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - /// Arguments supplied to the completed task_complete tool call. - [JsonPropertyName("toolArgs")] - public JsonElement ToolArgs { get; set; } + /// MCP task metadata. + [JsonPropertyName("task")] + public McpTaskMetadata? Task { get; set; } } -/// Indicates whether the external tool call result was handled successfully. +/// Indicates whether the elicitation response was accepted; false if it was already resolved by another client. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HandlePendingToolCallResult +public sealed class UIElicitationResult { - /// Whether the tool call result was handled successfully. + /// Whether the response was accepted. False if the request was already resolved by another client. [JsonPropertyName("success")] public bool Success { get; set; } } -/// Pending external tool call request ID, with the tool result or an error describing why it failed. +/// Pending elicitation request ID and the user's response (accept/decline/cancel + form values). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HandlePendingToolCallRequest +internal sealed class UIHandlePendingElicitationRequest { - /// Error message if the tool call failed. - [JsonPropertyName("error")] - public string? Error { get; set; } - - /// Request ID of the pending tool call. + /// The unique request ID from the elicitation.requested event. [JsonPropertyName("requestId")] public string RequestId { get; set; } = string.Empty; - /// Tool call result (string or expanded result object). + /// The elicitation response (accept with form values, decline, or cancel). [JsonPropertyName("result")] - public JsonElement? Result { get; set; } + public UIElicitationResponse Result { get => field ??= new(); set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// External tool call of the session or one of its sub-agents that is still waiting for session.tools.handlePendingToolCall. +/// Indicates whether the pending UI request was resolved by this call. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PendingExternalToolRequest +public sealed class UIHandlePendingResult { - /// Sub-agent instance identifier (the envelope agentId of its events) of the agent that issued the call; absent for calls issued by the root agent. - [JsonPropertyName("agentId")] - public string? AgentId { get; set; } + /// True if the request was still pending and was resolved by this call. False if the request ID was unknown, already resolved by another client (e.g. GitHub), expired, or otherwise no longer pending. + [JsonPropertyName("success")] + public bool Success { get; set; } +} - /// Arguments to pass to the external tool. - [JsonPropertyName("arguments")] - public JsonElement? Arguments { get; set; } +/// User response for a pending user-input request, with answer text and whether it was typed freeform. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class UIUserInputResponse +{ + /// The user's answer text. + [JsonPropertyName("answer")] + public string Answer { get; set; } = string.Empty; - /// Stable identity of the provider that offered the tool, for hosts that route extension-owned tools by provider. - [JsonPropertyName("providerId")] - public string? ProviderId { get; set; } + /// True if the user typed a freeform response, false if they selected a presented choice. Used by telemetry to differentiate between free text input and choice selection. + [JsonPropertyName("wasFreeform")] + public bool WasFreeform { get; set; } +} - /// Request ID to pass to session.tools.handlePendingToolCall. +/// Request ID of a pending `user_input.requested` event and the user's response. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UIHandlePendingUserInputRequest +{ + /// The unique request ID from the user_input.requested event. [JsonPropertyName("requestId")] public string RequestId { get; set; } = string.Empty; - /// Tool call ID assigned to this external tool invocation. - [JsonPropertyName("toolCallId")] - public string ToolCallId { get; set; } = string.Empty; + /// User response for a pending user-input request, with answer text and whether it was typed freeform. + [JsonPropertyName("response")] + public UIUserInputResponse Response { get => field ??= new(); set; } - /// Name of the external tool to invoke. - [JsonPropertyName("toolName")] - public string ToolName { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// External tool calls still waiting for a result. +/// Request ID of a pending `sampling.requested` event and an optional sampling result payload (omit to reject). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PendingExternalToolRequestList +internal sealed class UIHandlePendingSamplingRequest { - /// External tool calls of the session and its sub-agents that session.tools.handlePendingToolCall would still accept, in the order they were requested. Includes calls that were pending when the session was last suspended and resumed with pending work continued, so a host that did not observe the original external_tool.requested event can answer them. - [JsonPropertyName("items")] - public IList Items { get => field ??= []; set; } + /// The unique request ID from the sampling.requested event. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; + + /// Optional sampling result payload. Omit to reject/cancel the sampling request without providing a result. + [JsonPropertyName("response")] + public JsonElement? Response { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// No parameters; returns the external tool calls of the session and its sub-agents that are still waiting for a result. +/// Request ID of a pending `auto_mode_switch.requested` event and the user's response. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ToolsListPendingRequestsRequest +internal sealed class UIHandlePendingAutoModeSwitchRequest { + /// The unique request ID from the auto_mode_switch.requested event. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; + + /// User's choice for auto-mode switching: yes (allow this turn), yes_always (allow + persist as setting), or no (decline). + [JsonPropertyName("response")] + public UIAutoModeSwitchResponse Response { get; set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Resolve, build, and validate the runtime tool list for this session. Subagent sessions and consumer flows that need an initialized tool set before `send` invoke this. Default base-class implementation is a no-op for sessions that don't support tool validation. +/// The user's selected action for an exhausted session limit. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ToolsInitializeAndValidateResult +public sealed class UISessionLimitsExhaustedResponse { + /// Action selected by the user. + [JsonPropertyName("action")] + public UISessionLimitsExhaustedResponseAction Action { get; set; } + + /// AI Credits to add to the current max when action is 'add'. + [JsonPropertyName("additionalAiCredits")] + public double? AdditionalAiCredits { get; set; } + + /// New absolute max AI Credits when action is 'set'. + [JsonPropertyName("maxAiCredits")] + public double? MaxAiCredits { get; set; } } -/// Identifies the target session. +/// Request ID of a pending `session_limits_exhausted.requested` event and the user's selected limit action. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionToolsInitializeAndValidateRequest +internal sealed class UIHandlePendingSessionLimitsExhaustedRequest { + /// The unique request ID from the session_limits_exhausted.requested event. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; + + /// The selected session-limit action. + [JsonPropertyName("response")] + public UISessionLimitsExhaustedResponse Response { get => field ??= new(); set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Lightweight metadata for a currently initialized session tool. +/// User response for a pending exit-plan-mode request, with approval state, selected action, auto-approve flag, and feedback. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CurrentToolMetadata +public sealed class UIExitPlanModeResponse { - /// Whether the tool is loaded on demand via tool search. - [JsonPropertyName("deferLoading")] - public bool? DeferLoading { get; set; } + /// Whether the plan was approved. + [JsonPropertyName("approved")] + public bool Approved { get; set; } - /// Tool description. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; + /// Whether subsequent edits should be auto-approved without confirmation. + [JsonPropertyName("autoApproveEdits")] + public bool? AutoApproveEdits { get; set; } - /// JSON Schema for tool input. - [JsonPropertyName("input_schema")] - public IDictionary? InputSchema { get; set; } + /// When true, the agent is instructed to end its turn without starting implementation so the client can restore the session model and auto-submit a fresh implementation turn on it. Set only when a distinct plan configuration (a different model, reasoning effort, or context tier) actually ran the planning turn. + [JsonPropertyName("deferImplementation")] + public bool? DeferImplementation { get; set; } - /// MCP server name for MCP-backed tools. - [JsonPropertyName("mcpServerName")] - public string? McpServerName { get; set; } + /// Feedback from the user when they declined the plan or requested changes. + [JsonPropertyName("feedback")] + public string? Feedback { get; set; } - /// Raw MCP tool name for MCP-backed tools. - [JsonPropertyName("mcpToolName")] - public string? McpToolName { get; set; } + /// The action the user selected. Defaults to 'autopilot' when autoApproveEdits is true, otherwise 'interactive'. + [JsonPropertyName("selectedAction")] + public UIExitPlanModeAction? SelectedAction { get; set; } +} - /// Model-facing tool name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; +/// Request ID of a pending `exit_plan_mode.requested` event and the user's response. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class UIHandlePendingExitPlanModeRequest +{ + /// The unique request ID from the exit_plan_mode.requested event. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; - /// Optional MCP/config namespaced tool name. - [JsonPropertyName("namespacedName")] - public string? NamespacedName { get; set; } + /// User response for a pending exit-plan-mode request, with approval state, selected action, auto-approve flag, and feedback. + [JsonPropertyName("response")] + public UIExitPlanModeResponse Response { get => field ??= new(); set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Current lightweight tool metadata snapshot for the session. +/// Register an in-process handler for `auto_mode_switch.requested` events. The caller still attaches the actual listener via the standard event-subscription mechanism; this registration solely tells the server bridge to skip its own dispatch (so a remote client doesn't race the in-process handler for the same requestId). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ToolsGetCurrentMetadataResult +public sealed class UIRegisterDirectAutoModeSwitchHandlerResult { - /// Current tool metadata, or null when tools have not been initialized yet. - [JsonPropertyName("tools")] - public IList? Tools { get; set; } + /// Opaque handle representing the registration. Pass this same handle to `unregisterDirectAutoModeSwitchHandler` when the in-process handler is no longer active. Multiple registrations are reference-counted; the server bridge will only dispatch auto-mode-switch requests when no handles are active. + [JsonPropertyName("handle")] + public string Handle { get; set; } = string.Empty; } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionToolsGetCurrentMetadataRequest +internal sealed class SessionUiRegisterDirectAutoModeSwitchHandlerRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Empty result after replacing the calling connection's externally implemented tools. +/// Indicates whether the handle was active and the registration count was decremented. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ToolsSetResult +public sealed class UIUnregisterDirectAutoModeSwitchHandlerResult { + /// True if the handle was active and decremented the counter; false if the handle was unknown. + [JsonPropertyName("unregistered")] + public bool Unregistered { get; set; } } -/// Serializable definition of a caller-implemented tool whose execution is handled over the SDK connection. +/// Opaque handle previously returned by `registerDirectAutoModeSwitchHandler` to release. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProtocolExternalToolDefinition +internal sealed class UIUnregisterDirectAutoModeSwitchHandlerRequest { - /// Tool-loading deferral policy. - [JsonPropertyName("defer")] - public ProtocolExternalToolDefer? Defer { get; set; } - - /// Model-visible explanation of what the tool does. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; - - /// Whether the tool executes commands in a terminal. - [JsonPropertyName("isTerminal")] - public bool? IsTerminal { get; set; } - - /// Optional caller-defined metadata associated with the tool. - [JsonPropertyName("metadata")] - public IDictionary? Metadata { get; set; } - - /// Unique model-visible tool name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - - /// Whether this definition replaces a built-in tool with the same name. - [JsonPropertyName("overridesBuiltInTool")] - public bool? OverridesBuiltInTool { get; set; } - - /// JSON Schema describing the tool's input arguments. - [JsonPropertyName("parameters")] - public IDictionary? Parameters { get; set; } - - /// Whether execution bypasses the normal tool permission prompt. - [JsonPropertyName("skipPermission")] - public bool? SkipPermission { get; set; } - - /// Optional human-readable display title. - [JsonPropertyName("title")] - public string? Title { get; set; } -} + /// Handle previously returned by `registerDirectAutoModeSwitchHandler`. + [JsonPropertyName("handle")] + public string Handle { get; set; } = string.Empty; -/// Complete externally implemented tool list for the calling connection. An empty list removes every tool previously supplied by that connection. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ToolsSetRequest -{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; +} - /// Complete replacement list for the calling connection. - [JsonPropertyName("tools")] - public IList Tools { get => field ??= []; set; } +/// Indicates whether the operation succeeded. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class PermissionsConfigureResult +{ + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Empty result after applying subagent settings. +/// Source descriptor for a `session.permissions.configure` content-exclusion rule, with source name and type. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ToolsUpdateSubagentSettingsResult +public sealed class PermissionsConfigureAdditionalContentExclusionPolicyRuleSource { + /// Name of the policy source. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Type of the policy source. + [JsonPropertyName("type")] + public string Type { get; set; } = string.Empty; } -/// Subagent model, reasoning effort, context tier, and auto-invocation settings. +/// Single content-exclusion rule supplied to `session.permissions.configure`, with paths, match conditions, and source. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SubagentSettingsEntry +public sealed class PermissionsConfigureAdditionalContentExclusionPolicyRule { - /// Whether this agent's runtime-defined proactive invocation prompting is enabled, if supported. Currently consumed by the built-in rubber-duck agent. - [JsonPropertyName("autoInvoke")] - public bool? AutoInvoke { get; set; } + /// Conditions of which at least one must match. + [JsonPropertyName("ifAnyMatch")] + public IList? IfAnyMatch { get; set; } - /// Context tier override for matching subagents. - [JsonPropertyName("contextTier")] - public SubagentSettingsEntryContextTier? ContextTier { get; set; } + /// Conditions none of which may match. + [JsonPropertyName("ifNoneMatch")] + public IList? IfNoneMatch { get; set; } - /// Reasoning effort override for matching subagents. - [JsonPropertyName("effortLevel")] - public string? EffortLevel { get; set; } + /// Path patterns covered by this rule. + [JsonPropertyName("paths")] + public IList Paths { get => field ??= []; set; } - /// Model override for matching subagents. - [JsonPropertyName("model")] - public string? Model { get; set; } + /// Source descriptor for a `session.permissions.configure` content-exclusion rule, with source name and type. + [JsonPropertyName("source")] + public PermissionsConfigureAdditionalContentExclusionPolicyRuleSource Source { get => field ??= new(); set; } +} - /// Whether the configured model strategy is preferred or required. - [JsonPropertyName("modelPolicy")] - public AgentModelPolicy? ModelPolicy { get; set; } +/// Content-exclusion policy supplied to `session.permissions.configure`, with rules, last-updated data, and scope. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class PermissionsConfigureAdditionalContentExclusionPolicy +{ + /// Opaque policy update timestamp supplied by the host. + [JsonPropertyName("last_updated_at")] + public JsonElement LastUpdatedAt { get; set; } + + /// Content-exclusion rules to apply. + [JsonPropertyName("rules")] + public IList Rules { get => field ??= []; set; } + + /// Allowed values for the `PermissionsConfigureAdditionalContentExclusionPolicyScope` enumeration. + [JsonPropertyName("scope")] + public PermissionsConfigureAdditionalContentExclusionPolicyScope Scope { get; set; } } -/// Configured per-agent subagent overrides. -public sealed class UpdateSubagentSettingsRequestSubagents +/// If specified, replaces the session's path-permission policy. The runtime constructs the appropriate PathManager based on these inputs (rooted at the session's working directory). Omit to leave the current path policy unchanged. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class PermissionPathsConfig { - /// Per-agent settings keyed by subagent agent_type. - [JsonPropertyName("agents")] - public IDictionary? Agents { get; set; } + /// Additional directories to allow tool access to (in addition to the session's working directory). Conventional `.github/skills/` and `.github/agents/` definitions under them also join the session catalogs when their subsystem gates are enabled, so supplying a directory is a trust decision for configuration stored there. When `unrestricted` is true, these are still pre-populated on the UnrestrictedPathManager so they remain visible via getDirectories() (e.g. for @-mention completion). + [JsonPropertyName("additionalDirectories")] + public IList? AdditionalDirectories { get; set; } - /// Names of subagents the user has turned off; they cannot be dispatched. - [JsonPropertyName("disabledSubagents")] - public IList? DisabledSubagents { get; set; } + /// Whether to include the system temp directory in the allowed list (defaults to true). Ignored when `unrestricted` is true. + [JsonPropertyName("includeTempDirectory")] + public bool? IncludeTempDirectory { get; set; } - /// Maximum number of subagents that can run concurrently; applies to usage-based billing users only. - [JsonPropertyName("maxConcurrency")] - public int? MaxConcurrency { get; set; } + /// If true, the runtime allows access to all paths without prompting. Equivalent to constructing an UnrestrictedPathManager. + [JsonPropertyName("unrestricted")] + public bool? Unrestricted { get; set; } - /// Maximum subagent nesting depth; applies to usage-based billing users only. - [JsonPropertyName("maxDepth")] - public int? MaxDepth { get; set; } + /// Workspace root path (special-cased to be allowed even before the directory exists). Ignored when `unrestricted` is true. + [JsonPropertyName("workspacePath")] + public string? WorkspacePath { get; set; } } -/// Subagent settings to apply to the current session. +/// If specified, replaces the session's approved/denied permission rules. Omit to leave the current rules unchanged. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UpdateSubagentSettingsRequest +public sealed class PermissionRulesSet { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Rules that auto-approve matching requests. + [JsonPropertyName("approved")] + public IList Approved { get => field ??= []; set; } - /// Subagent settings to apply, or null to clear the live session override. - [JsonPropertyName("subagents")] - public UpdateSubagentSettingsRequestSubagents? Subagents { get; set; } + /// Rules that auto-deny matching requests. + [JsonPropertyName("denied")] + public IList Denied { get => field ??= []; set; } } -/// RPC data type for SessionCommandsList operations. +/// If specified, replaces the session's URL-permission policy. The runtime constructs a fresh DefaultUrlManager based on these inputs. Omit to leave the current URL policy unchanged. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionCommandsListRequest +public sealed class PermissionUrlsConfig { - /// Include runtime built-in commands. - [JsonPropertyName("includeBuiltins")] - public bool? IncludeBuiltins { get; set; } - - /// Include commands registered by protocol clients, including SDK clients and extensions. - [JsonPropertyName("includeClientCommands")] - public bool? IncludeClientCommands { get; set; } + /// Initial list of allowed URL/domain patterns. Patterns may include path components. Ignored when `unrestricted` is true. + [JsonPropertyName("initialAllowed")] + public IList? InitialAllowed { get; set; } - /// Include enabled user-invocable skills and commands. - [JsonPropertyName("includeSkills")] - public bool? IncludeSkills { get; set; } + /// If true, the runtime allows access to all URLs without prompting. Initial allow-list is ignored when this is true. + [JsonPropertyName("unrestricted")] + public bool? Unrestricted { get; set; } } -/// RPC data type for SessionCommandsListRequestWithSession operations. +/// Patch of permission policy fields to apply (omit a field to leave it unchanged). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionCommandsListRequestWithSession +internal sealed class PermissionsConfigureParams { - /// Include runtime built-in commands. - [JsonPropertyName("includeBuiltins")] - public bool? IncludeBuiltins { get; set; } + /// If specified, replaces the host-supplied GitHub Content Exclusion policies on the session (combined with natively-discovered policies when evaluating tool/file access). Omit to leave the current policies unchanged. + [JsonPropertyName("additionalContentExclusionPolicies")] + public IList? AdditionalContentExclusionPolicies { get; set; } - /// Include commands registered by protocol clients, including SDK clients and extensions. - [JsonPropertyName("includeClientCommands")] - public bool? IncludeClientCommands { get; set; } + /// If specified, sets whether path/URL read permission requests are auto-approved. Omit to leave the current value unchanged. + [JsonPropertyName("approveAllReadPermissionRequests")] + public bool? ApproveAllReadPermissionRequests { get; set; } - /// Include enabled user-invocable skills and commands. - [JsonPropertyName("includeSkills")] - public bool? IncludeSkills { get; set; } + /// If specified, sets whether tool permission requests are auto-approved without prompting. Omit to leave the current value unchanged. + [JsonPropertyName("approveAllToolPermissionRequests")] + public bool? ApproveAllToolPermissionRequests { get; set; } + + /// If specified, replaces the session's path-permission policy. The runtime constructs the appropriate PathManager based on these inputs (rooted at the session's working directory). Omit to leave the current path policy unchanged. + [JsonPropertyName("paths")] + public PermissionPathsConfig? Paths { get; set; } + + /// If specified, replaces the session's approved/denied permission rules. Omit to leave the current rules unchanged. + [JsonPropertyName("rules")] + public PermissionRulesSet? Rules { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// If specified, replaces the session's URL-permission policy. The runtime constructs a fresh DefaultUrlManager based on these inputs. Omit to leave the current URL policy unchanged. + [JsonPropertyName("urls")] + public PermissionUrlsConfig? Urls { get; set; } } -/// Result of invoking the slash command (text output, prompt to send to the agent, completion, or subcommand selection). +/// Indicates whether the permission decision was applied; false when the request was already resolved. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class PermissionRequestResult +{ + /// Whether the permission request was handled successfully. + [JsonPropertyName("success")] + public bool Success { get; set; } +} + +/// The client's response to the pending permission prompt. /// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( TypeDiscriminatorPropertyName = "kind", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(SlashCommandInvocationResultText), "text")] -[JsonDerivedType(typeof(SlashCommandInvocationResultAgentPrompt), "agent-prompt")] -[JsonDerivedType(typeof(SlashCommandInvocationResultCompleted), "completed")] -[JsonDerivedType(typeof(SlashCommandInvocationResultSelectSubcommand), "select-subcommand")] -[JsonDerivedType(typeof(SlashCommandInvocationResultAddTimelineEntry), "add-timeline-entry")] -[JsonDerivedType(typeof(SlashCommandInvocationResultShowDialog), "show-dialog")] -[JsonDerivedType(typeof(SlashCommandInvocationResultSetModel), "set-model")] -[JsonDerivedType(typeof(SlashCommandInvocationResultSetPlanModel), "set-plan-model")] -public partial class SlashCommandInvocationResult +[JsonDerivedType(typeof(PermissionDecisionApproveOnce), "approve-once")] +[JsonDerivedType(typeof(PermissionDecisionApproveForSession), "approve-for-session")] +[JsonDerivedType(typeof(PermissionDecisionApproveReadOnlyForSession), "approve-read-only-for-session")] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocation), "approve-for-location")] +[JsonDerivedType(typeof(PermissionDecisionApprovePermanently), "approve-permanently")] +[JsonDerivedType(typeof(PermissionDecisionReject), "reject")] +[JsonDerivedType(typeof(PermissionDecisionUserNotAvailable), "user-not-available")] +[JsonDerivedType(typeof(PermissionDecisionApproved), "approved")] +[JsonDerivedType(typeof(PermissionDecisionApprovedForSession), "approved-for-session")] +[JsonDerivedType(typeof(PermissionDecisionApprovedForLocation), "approved-for-location")] +[JsonDerivedType(typeof(PermissionDecisionCancelled), "cancelled")] +[JsonDerivedType(typeof(PermissionDecisionDeniedByRules), "denied-by-rules")] +[JsonDerivedType(typeof(PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser), "denied-no-approval-rule-and-could-not-request-from-user")] +[JsonDerivedType(typeof(PermissionDecisionDeniedInteractivelyByUser), "denied-interactively-by-user")] +[JsonDerivedType(typeof(PermissionDecisionDeniedByContentExclusionPolicy), "denied-by-content-exclusion-policy")] +[JsonDerivedType(typeof(PermissionDecisionDeniedByPermissionRequestHook), "denied-by-permission-request-hook")] +public partial class PermissionDecision { /// The type discriminator. [JsonPropertyName("kind")] @@ -22575,823 +24843,734 @@ public partial class SlashCommandInvocationResult } -/// Slash-command invocation result containing text output plus Markdown/ANSI rendering flags. -/// The text variant of . +/// Permission-decision request variant to approve only the current permission request. +/// The approve-once variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SlashCommandInvocationResultText : SlashCommandInvocationResult +public partial class PermissionDecisionApproveOnce : PermissionDecision { /// [JsonIgnore] - public override string Kind => "text"; + public override string Kind => "approve-once"; - /// Whether text contains Markdown. + /// True only when a host surfaced this request to a user who approved it. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("markdown")] - public bool? Markdown { get; set; } + [JsonPropertyName("approvedInteractively")] + public bool? ApprovedInteractively { get; set; } +} - /// Whether ANSI sequences should be preserved. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("preserveAnsi")] - public bool? PreserveAnsi { get; set; } +/// Session-scoped approval to remember (tool prompts only; omitted for path/url prompts). +/// Polymorphic base type discriminated by kind. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalCommands), "commands")] +[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalRead), "read")] +[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalWrite), "write")] +[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalMcp), "mcp")] +[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalMcpSampling), "mcp-sampling")] +[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalMemory), "memory")] +[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalCustomTool), "custom-tool")] +[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalExtensionManagement), "extension-management")] +[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalWorkflow), "workflow")] +[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess), "extension-permission-access")] +[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalExtensionEnvAccess), "extension-env-access")] +public partial class PermissionDecisionApproveForSessionApproval +{ + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; +} - /// True when the invocation mutated user runtime settings; consumers caching settings should refresh. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("runtimeSettingsChanged")] - public bool? RuntimeSettingsChanged { get; set; } - /// Present when the invocation changed the sandbox for this session only. Nothing was persisted, so consumers must mirror the change onto the live session rather than reloading settings, and must not treat it as a settings change. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("sandboxSessionChange")] - public SandboxSessionChange? SandboxSessionChange { get; set; } +/// Session-scoped approval details for specific command identifiers. +/// The commands variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PermissionDecisionApproveForSessionApprovalCommands : PermissionDecisionApproveForSessionApproval +{ + /// + [JsonIgnore] + public override string Kind => "commands"; - /// Text output for the client to render. - [JsonPropertyName("text")] - public required string Text { get; set; } + /// Command identifiers covered by this approval. + [JsonPropertyName("commandIdentifiers")] + public required IList CommandIdentifiers { get; set; } } -/// Slash-command invocation result that submits an agent prompt, with display prompt, optional mode, optional user-facing notice, and settings-change flag. -/// The agent-prompt variant of . +/// Session-scoped approval details for read-only filesystem operations. +/// The read variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SlashCommandInvocationResultAgentPrompt : SlashCommandInvocationResult +public partial class PermissionDecisionApproveForSessionApprovalRead : PermissionDecisionApproveForSessionApproval { /// [JsonIgnore] - public override string Kind => "agent-prompt"; - - /// Prompt text to display to the user. - [JsonPropertyName("displayPrompt")] - public required string DisplayPrompt { get; set; } - - /// Optional target session mode for the agent prompt. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("mode")] - public SessionMode? Mode { get; set; } - - /// Optional user-facing notice to show before the prompt is submitted. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("notice")] - public string? Notice { get; set; } - - /// Prompt to submit to the agent. - [JsonPropertyName("prompt")] - public required string Prompt { get; set; } - - /// True when the invocation mutated user runtime settings; consumers caching settings should refresh. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("runtimeSettingsChanged")] - public bool? RuntimeSettingsChanged { get; set; } + public override string Kind => "read"; } -/// Slash-command invocation result indicating completion, with optional message and settings-change flag. -/// The completed variant of . +/// Session-scoped approval details for filesystem write operations. +/// The write variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SlashCommandInvocationResultCompleted : SlashCommandInvocationResult +public partial class PermissionDecisionApproveForSessionApprovalWrite : PermissionDecisionApproveForSessionApproval { /// [JsonIgnore] - public override string Kind => "completed"; - - /// Optional user-facing message describing the completed command. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("message")] - public string? Message { get; set; } - - /// Optional target session mode applied without submitting an agent prompt. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("mode")] - public SessionMode? Mode { get; set; } - - /// True when the invocation mutated user runtime settings; consumers caching settings should refresh. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("runtimeSettingsChanged")] - public bool? RuntimeSettingsChanged { get; set; } + public override string Kind => "write"; } -/// Selectable slash-command subcommand option with name, description, and optional group label. +/// Session-scoped approval details for an MCP server tool, or all tools on the server when `toolName` is null. +/// The mcp variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SlashCommandSelectSubcommandOption +public partial class PermissionDecisionApproveForSessionApprovalMcp : PermissionDecisionApproveForSessionApproval { - /// Human-readable description of the subcommand. - [JsonPropertyName("description")] - public string Description { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "mcp"; - /// Optional group label for organizing options. - [JsonPropertyName("group")] - public string? Group { get; set; } + /// MCP server name. + [JsonPropertyName("serverName")] + public required string ServerName { get; set; } - /// Subcommand name to invoke. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// MCP tool name, or null to cover every tool on the server. + [JsonPropertyName("toolName")] + public string? ToolName { get; set; } } -/// Slash-command invocation result asking the client to present subcommand options for a parent command. -/// The select-subcommand variant of . +/// Session-scoped approval details for MCP sampling requests from a server. +/// The mcp-sampling variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SlashCommandInvocationResultSelectSubcommand : SlashCommandInvocationResult +public partial class PermissionDecisionApproveForSessionApprovalMcpSampling : PermissionDecisionApproveForSessionApproval { /// [JsonIgnore] - public override string Kind => "select-subcommand"; - - /// Parent command name that requires subcommand selection. - [JsonPropertyName("command")] - public required string Command { get; set; } - - /// Available subcommand options for the client to present. - [JsonPropertyName("options")] - public required IList Options { get; set; } - - /// True when the invocation mutated user runtime settings; consumers caching settings should refresh. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("runtimeSettingsChanged")] - public bool? RuntimeSettingsChanged { get; set; } + public override string Kind => "mcp-sampling"; - /// Human-readable title for the selection UI. - [JsonPropertyName("title")] - public required string Title { get; set; } + /// MCP server name. + [JsonPropertyName("serverName")] + public required string ServerName { get; set; } } -/// RPC data type for SlashCommandTimelineEntry operations. +/// Session-scoped approval details for writes to long-term memory. +/// The memory variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SlashCommandTimelineEntry +public partial class PermissionDecisionApproveForSessionApprovalMemory : PermissionDecisionApproveForSessionApproval { - /// What the user must do to recover, when the entry reports a failure the runtime knows an action for. The `text` never names a client affordance, so a client that offers one renders it from this value. - [JsonPropertyName("remediation")] - public RemediationAction? Remediation { get; set; } - - /// Text displayed for the timeline entry. - [JsonPropertyName("text")] - public string Text { get; set; } = string.Empty; - - /// Timeline entry presentation type. - [JsonPropertyName("type")] - public string Type { get; set; } = string.Empty; - - /// Optional URL associated with the timeline entry. - [JsonPropertyName("url")] - public string? Url { get; set; } + /// + [JsonIgnore] + public override string Kind => "memory"; } -/// The add-timeline-entry variant of . +/// Session-scoped approval details for a custom tool, keyed by tool name. +/// The custom-tool variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SlashCommandInvocationResultAddTimelineEntry : SlashCommandInvocationResult +public partial class PermissionDecisionApproveForSessionApprovalCustomTool : PermissionDecisionApproveForSessionApproval { /// [JsonIgnore] - public override string Kind => "add-timeline-entry"; - - /// Timeline entry the host should append. - [JsonPropertyName("entry")] - public required SlashCommandTimelineEntry Entry { get; set; } - - /// Optional text the host should prefill into the input editor. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("prefillInput")] - public string? PrefillInput { get; set; } + public override string Kind => "custom-tool"; - /// Whether command execution changed persisted runtime settings. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("runtimeSettingsChanged")] - public bool? RuntimeSettingsChanged { get; set; } + /// Custom tool name. + [JsonPropertyName("toolName")] + public required string ToolName { get; set; } } -/// RPC data type for SlashCommandModelPickerDialog operations. +/// Session-scoped approval details for extension-management operations, optionally narrowed by operation. +/// The extension-management variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SlashCommandModelPickerDialog +public partial class PermissionDecisionApproveForSessionApprovalExtensionManagement : PermissionDecisionApproveForSessionApproval { - /// Discriminator for a model-picker dialog. - [JsonPropertyName("kind")] - public string Kind { get; set; } = string.Empty; - - /// Model that should be enabled before it can be selected. - [JsonPropertyName("modelToEnable")] - public string? ModelToEnable { get; set; } - - /// Settings scope the picker should modify. - [JsonPropertyName("scope")] - public string? Scope { get; set; } + /// + [JsonIgnore] + public override string Kind => "extension-management"; - /// Model-selection target represented by the picker. - [JsonPropertyName("target")] - public string? Target { get; set; } + /// Optional operation identifier; when omitted, the approval covers all extension management operations. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("operation")] + public string? Operation { get; set; } } -/// The show-dialog variant of . +/// Session-scoped workflow approval, optionally narrowed by approval key. +/// The workflow variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SlashCommandInvocationResultShowDialog : SlashCommandInvocationResult +public partial class PermissionDecisionApproveForSessionApprovalWorkflow : PermissionDecisionApproveForSessionApproval { /// [JsonIgnore] - public override string Kind => "show-dialog"; - - /// Dialog the host should display. - [JsonPropertyName("dialog")] - public required SlashCommandModelPickerDialog Dialog { get; set; } + public override string Kind => "workflow"; - /// Whether command execution changed persisted runtime settings. + /// Optional workflow operation name or canonical approval key; when omitted, the approval covers all workflow operations. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("runtimeSettingsChanged")] - public bool? RuntimeSettingsChanged { get; set; } + [JsonPropertyName("approvalKey")] + public string? ApprovalKey { get; set; } } -/// User-settings snapshot to restore if the host cancels the model switch. -public sealed class SlashCommandInvocationResultSetModelRevertOnCancel +/// Session-scoped approval details for an extension's permission-gated capability access, keyed by extension name. +/// The extension-permission-access variant of . +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public partial class PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess : PermissionDecisionApproveForSessionApproval { + /// + [JsonIgnore] + public override string Kind => "extension-permission-access"; + + /// Extension name. + [JsonPropertyName("extensionName")] + public required string ExtensionName { get; set; } } -/// The set-model variant of . +/// Session-scoped approval details for an extension's access to sensitive environment variables, keyed by extension name and the exact set of variable names. +/// The extension-env-access variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SlashCommandInvocationResultSetModel : SlashCommandInvocationResult +public partial class PermissionDecisionApproveForSessionApprovalExtensionEnvAccess : PermissionDecisionApproveForSessionApproval { /// [JsonIgnore] - public override string Kind => "set-model"; - - /// Auto routing profile selected by the command, when the model is Auto. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("autoTier")] - public AutoTier? AutoTier { get; set; } - - /// Model selected by the command. - [JsonPropertyName("model")] - public required string Model { get; set; } - - /// Reasoning effort selected for the model. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("reasoningEffort")] - public string? ReasoningEffort { get; set; } - - /// Repository settings scope modified by the command. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("repoScope")] - public string? RepoScope { get; set; } - - /// User-settings snapshot to restore if the host cancels the model switch. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("revertOnCancel")] - public SlashCommandInvocationResultSetModelRevertOnCancel? RevertOnCancel { get; set; } - - /// Whether command execution changed persisted runtime settings. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("runtimeSettingsChanged")] - public bool? RuntimeSettingsChanged { get; set; } + public override string Kind => "extension-env-access"; - /// Settings scope modified by the command. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("scope")] - public string? Scope { get; set; } + /// Names of the sensitive environment variables this approval covers. Values are never persisted. + [JsonPropertyName("environmentVariables")] + public required IList EnvironmentVariables { get; set; } - /// User-facing warning produced while selecting the model. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("warning")] - public string? Warning { get; set; } + /// Extension name. + [JsonPropertyName("extensionName")] + public required string ExtensionName { get; set; } } -/// The set-plan-model variant of . +/// Permission-decision request variant to approve for the rest of the session, with optional tool approval or URL domain. +/// The approve-for-session variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SlashCommandInvocationResultSetPlanModel : SlashCommandInvocationResult +public partial class PermissionDecisionApproveForSession : PermissionDecision { /// [JsonIgnore] - public override string Kind => "set-plan-model"; - - /// User-facing confirmation message for the plan-model selection. - [JsonPropertyName("message")] - public required string Message { get; set; } + public override string Kind => "approve-for-session"; - /// Dedicated model selected for plan mode. + /// Session-scoped approval to remember (tool prompts only; omitted for path/url prompts). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("planModel")] - public string? PlanModel { get; set; } + [JsonPropertyName("approval")] + public PermissionDecisionApproveForSessionApproval? Approval { get; set; } - /// Whether command execution changed persisted runtime settings. + /// URL domain to approve for the rest of the session (URL prompts only). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("runtimeSettingsChanged")] - public bool? RuntimeSettingsChanged { get; set; } + [JsonPropertyName("domain")] + public string? Domain { get; set; } } -/// Slash command name and optional raw input string to invoke. +/// Approve file-tool read access to specific directories for this logical session, including continuation or resume. +/// The approve-read-only-for-session variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CommandsInvokeRequest +public partial class PermissionDecisionApproveReadOnlyForSession : PermissionDecision { - /// Raw input after the command name. - [JsonPropertyName("input")] - public string? Input { get; set; } - - /// Command name. Leading slashes are stripped and the name is matched case-insensitively. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - - /// Optional client surface that initiated the invocation. - [JsonPropertyName("origin")] - public CommandsInvocationOrigin? Origin { get; set; } + /// + [JsonIgnore] + public override string Kind => "approve-read-only-for-session"; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Canonical directories covered by the read-only grant. + [JsonPropertyName("directories")] + public required IList Directories { get; set; } } -/// Whether finalizing the invocation effect succeeded, and the failure reason when it did not. +/// Approval to persist for this location. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CommandsFinalizeInvocationEffectResult +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalCommands), "commands")] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalRead), "read")] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalWrite), "write")] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalMcp), "mcp")] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalMcpSampling), "mcp-sampling")] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalMemory), "memory")] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalCustomTool), "custom-tool")] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalExtensionManagement), "extension-management")] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalWorkflow), "workflow")] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess), "extension-permission-access")] +[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalExtensionEnvAccess), "extension-env-access")] +public partial class PermissionDecisionApproveForLocationApproval { - /// Failure reason when the invocation effect could not be finalized. - [JsonPropertyName("error")] - public string? Error { get; set; } - - /// Whether the pending invocation effect was finalized successfully. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// The slash-command result object that produced the pending effect, echoed back unchanged. -public sealed class CommandsFinalizeInvocationEffectRequestEffect -{ -} -/// The pending slash-command invocation effect to finalize, plus whether the host applied or cancelled it. +/// Location-scoped approval details for specific command identifiers. +/// The commands variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CommandsFinalizeInvocationEffectRequest +public partial class PermissionDecisionApproveForLocationApprovalCommands : PermissionDecisionApproveForLocationApproval { - /// The slash-command result object that produced the pending effect, echoed back unchanged. - [JsonPropertyName("effect")] - public CommandsFinalizeInvocationEffectRequestEffect Effect { get => field ??= new(); set; } - - /// Whether the host applied or cancelled the pending invocation effect. - [JsonPropertyName("outcome")] - public CommandsInvocationEffectOutcome Outcome { get; set; } - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// + [JsonIgnore] + public override string Kind => "commands"; -/// Indicates whether the pending client-handled command was completed successfully. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CommandsHandlePendingCommandResult -{ - /// Whether the command was handled successfully. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Command identifiers covered by this approval. + [JsonPropertyName("commandIdentifiers")] + public required IList CommandIdentifiers { get; set; } } -/// Pending command request ID and an optional error if the client handler failed. +/// Location-scoped approval details for read-only filesystem operations. +/// The read variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CommandsHandlePendingCommandRequest +public partial class PermissionDecisionApproveForLocationApprovalRead : PermissionDecisionApproveForLocationApproval { - /// Error message if the command handler failed. - [JsonPropertyName("error")] - public string? Error { get; set; } - - /// Request ID from the command invocation event. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "read"; } -/// Error message produced while executing the command, if any. +/// Location-scoped approval details for filesystem write operations. +/// The write variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ExecuteCommandResult +public partial class PermissionDecisionApproveForLocationApprovalWrite : PermissionDecisionApproveForLocationApproval { - /// Error message produced while executing the command, if any. Omitted when the handler succeeded. - [JsonPropertyName("error")] - public string? Error { get; set; } + /// + [JsonIgnore] + public override string Kind => "write"; } -/// Slash command name and argument string to execute synchronously. +/// Location-scoped approval details for an MCP server tool, or all tools on the server when `toolName` is null. +/// The mcp variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ExecuteCommandParams +public partial class PermissionDecisionApproveForLocationApprovalMcp : PermissionDecisionApproveForLocationApproval { - /// Argument string to pass to the command (empty string if none). - [JsonPropertyName("args")] - public string Args { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "mcp"; - /// Name of the slash command to invoke (without the leading '/'). - [JsonPropertyName("commandName")] - public string CommandName { get; set; } = string.Empty; + /// MCP server name. + [JsonPropertyName("serverName")] + public required string ServerName { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// MCP tool name, or null to cover every tool on the server. + [JsonPropertyName("toolName")] + public string? ToolName { get; set; } } -/// Indicates whether the command was accepted into the local execution queue. -/// Data type discriminated by queued. +/// Location-scoped approval details for MCP sampling requests from a server. +/// The mcp-sampling variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class EnqueueCommandResult +public partial class PermissionDecisionApproveForLocationApprovalMcpSampling : PermissionDecisionApproveForLocationApproval { - /// The boolean discriminator. - [JsonPropertyName("queued")] - public bool Queued { get; set; } + /// + [JsonIgnore] + public override string Kind => "mcp-sampling"; - /// Stable opaque ID of the queued command. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("queueId")] - public string? QueueId { get; set; } + /// MCP server name. + [JsonPropertyName("serverName")] + public required string ServerName { get; set; } } -/// Slash-prefixed command string to enqueue for FIFO processing. +/// Location-scoped approval details for writes to long-term memory. +/// The memory variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class EnqueueCommandParams +public partial class PermissionDecisionApproveForLocationApprovalMemory : PermissionDecisionApproveForLocationApproval { - /// Slash-prefixed command string to enqueue, e.g. '/compact' or '/model gpt-4'. Queued FIFO with any in-flight items; if the session is idle, processing kicks off immediately. - [JsonPropertyName("command")] - public string Command { get; set; } = string.Empty; - - /// Optional user-facing text for the queue row. The command string is shown when omitted. - [JsonPropertyName("displayText")] - public string? DisplayText { get; set; } - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "memory"; } -/// Indicates whether the queued-command response was matched to a pending request. +/// Location-scoped approval details for a custom tool, keyed by tool name. +/// The custom-tool variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CommandsRespondToQueuedCommandResult +public partial class PermissionDecisionApproveForLocationApprovalCustomTool : PermissionDecisionApproveForLocationApproval { - /// Whether a pending queued command with the given request ID was found and resolved. False when the request was already resolved, cancelled, or unknown. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// + [JsonIgnore] + public override string Kind => "custom-tool"; + + /// Custom tool name. + [JsonPropertyName("toolName")] + public required string ToolName { get; set; } } -/// Result of the queued command execution. -/// Data type discriminated by handled. +/// Location-scoped approval details for extension-management operations, optionally narrowed by operation. +/// The extension-management variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class QueuedCommandResult +public partial class PermissionDecisionApproveForLocationApprovalExtensionManagement : PermissionDecisionApproveForLocationApproval { - /// The boolean discriminator. - [JsonPropertyName("handled")] - public bool Handled { get; set; } + /// + [JsonIgnore] + public override string Kind => "extension-management"; - /// When true, the runtime will not process subsequent queued commands until a new request comes in. + /// Optional operation identifier; when omitted, the approval covers all extension management operations. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("stopProcessingQueue")] - public bool? StopProcessingQueue { get; set; } + [JsonPropertyName("operation")] + public string? Operation { get; set; } } -/// Queued-command request ID and the result indicating whether the host executed it (and whether to stop processing further queued commands). +/// Location-scoped workflow approval, optionally narrowed by approval key. +/// The workflow variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class CommandsRespondToQueuedCommandRequest +public partial class PermissionDecisionApproveForLocationApprovalWorkflow : PermissionDecisionApproveForLocationApproval { - /// Request ID from the `command.queued` event the host is responding to. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; - - /// Result of the queued command execution. - [JsonPropertyName("result")] - public QueuedCommandResult Result { get => field ??= new(); set; } + /// + [JsonIgnore] + public override string Kind => "workflow"; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Optional workflow operation name or canonical approval key; when omitted, the approval covers all workflow operations. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("approvalKey")] + public string? ApprovalKey { get; set; } } -/// Telemetry engagement ID for the session, when available. +/// Location-scoped approval details for an extension's permission-gated capability access, keyed by extension name. +/// The extension-permission-access variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionTelemetryEngagement +public partial class PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess : PermissionDecisionApproveForLocationApproval { - /// Current telemetry engagement ID, when available. - [JsonPropertyName("engagementId")] - public string? EngagementId { get; set; } -} + /// + [JsonIgnore] + public override string Kind => "extension-permission-access"; -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionTelemetryGetEngagementIdRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Extension name. + [JsonPropertyName("extensionName")] + public required string ExtensionName { get; set; } } -/// Feature override key/value pairs to attach to subsequent telemetry events from this session. +/// Location-scoped approval details for an extension's access to sensitive environment variables, keyed by extension name and the exact set of variable names. +/// The extension-env-access variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class TelemetrySetFeatureOverridesRequest +public partial class PermissionDecisionApproveForLocationApprovalExtensionEnvAccess : PermissionDecisionApproveForLocationApproval { - /// Override key/value pairs to attach to subsequent telemetry events from this session. Replaces any previously-set overrides. - [JsonPropertyName("features")] - public IDictionary Features { get => field ??= new Dictionary(); set; } + /// + [JsonIgnore] + public override string Kind => "extension-env-access"; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Names of the sensitive environment variables this approval covers. Values are never persisted. + [JsonPropertyName("environmentVariables")] + public required IList EnvironmentVariables { get; set; } + + /// Extension name. + [JsonPropertyName("extensionName")] + public required string ExtensionName { get; set; } } -/// Completed transient query. Ordered chunks and the terminal outcome are also delivered through `ui.ephemeral_query` session events while it runs. +/// Permission-decision request variant to approve and persist a permission for a project location, with approval details and location key. +/// The approve-for-location variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UIEphemeralQueryResult +public partial class PermissionDecisionApproveForLocation : PermissionDecision { - /// Answer returned by the model. - [JsonPropertyName("answer")] - public string Answer { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "approve-for-location"; + + /// Approval to persist for this location. + [JsonPropertyName("approval")] + public required PermissionDecisionApproveForLocationApproval Approval { get; set; } + + /// Location key (git root or cwd) to persist the approval to. + [JsonPropertyName("locationKey")] + public required string LocationKey { get; set; } } -/// Transient question to answer without adding it to conversation history. +/// Permission-decision request variant to permanently approve a URL domain across sessions. +/// The approve-permanently variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UIEphemeralQueryRequest +public partial class PermissionDecisionApprovePermanently : PermissionDecision { - /// Question to answer from the current conversation context. - [JsonPropertyName("question")] - public string Question { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "approve-permanently"; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// URL domain to approve permanently. + [JsonPropertyName("domain")] + public required string Domain { get; set; } } -/// The elicitation response (accept with form values, decline, or cancel). +/// Permission-decision request variant to reject a pending permission request, with optional feedback. +/// The reject variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UIElicitationResponse +public partial class PermissionDecisionReject : PermissionDecision { - /// MCP response metadata. - [JsonPropertyName("_meta")] - public IDictionary? Meta { get; set; } - - /// The user's response: accept (submitted), decline (rejected), or cancel (dismissed). - [JsonPropertyName("action")] - public UIElicitationResponseAction Action { get; set; } + /// + [JsonIgnore] + public override string Kind => "reject"; - /// The form values submitted by the user (present when action is 'accept'). - [JsonPropertyName("content")] - public IDictionary? Content { get; set; } + /// Optional feedback explaining the rejection. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("feedback")] + public string? Feedback { get; set; } } -/// JSON Schema describing the form fields to present to the user. +/// Permission-decision variant indicating no user was available to confirm the request. +/// The user-not-available variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UIElicitationSchema +public partial class PermissionDecisionUserNotAvailable : PermissionDecision { - /// Form field definitions, keyed by field name. - [JsonPropertyName("properties")] - public IDictionary Properties { get => field ??= new Dictionary(); set; } - - /// List of required field names. - [JsonPropertyName("required")] - public IList? Required { get; set; } - - /// Schema type indicator (always 'object'). - [JsonPropertyName("type")] - public string Type { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "user-not-available"; } -/// Metadata controlling an MCP task's lifetime. +/// Permission-decision variant indicating the request was approved. +/// The approved variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpTaskMetadata +public partial class PermissionDecisionApproved : PermissionDecision { - /// Task time-to-live. - [JsonPropertyName("ttl")] - public long? Ttl { get; set; } + /// + [JsonIgnore] + public override string Kind => "approved"; } -/// Prompt message and JSON schema describing the form fields to elicit from the user. +/// Permission-decision variant indicating approval was remembered for the session, with approval details. +/// The approved-for-session variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UIElicitationRequest +public partial class PermissionDecisionApprovedForSession : PermissionDecision { - /// MCP request metadata. - [JsonPropertyName("_meta")] - public IDictionary? Meta { get; set; } - - /// Message describing what information is needed from the user. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; - - /// Elicitation mode. Omitted and form are equivalent for structured elicitation. - [JsonPropertyName("mode")] - public McpElicitationFormMode? Mode { get; set; } - - /// JSON Schema describing the form fields to present to the user. - [JsonPropertyName("requestedSchema")] - public UIElicitationSchema RequestedSchema { get => field ??= new(); set; } - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "approved-for-session"; - /// MCP task metadata. - [JsonPropertyName("task")] - public McpTaskMetadata? Task { get; set; } + /// The approval to add as a session-scoped rule. + [JsonPropertyName("approval")] + public required UserToolSessionApproval Approval { get; set; } } -/// Indicates whether the elicitation response was accepted; false if it was already resolved by another client. +/// Permission-decision variant indicating approval was persisted for a project location, with approval details and location key. +/// The approved-for-location variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UIElicitationResult +public partial class PermissionDecisionApprovedForLocation : PermissionDecision { - /// Whether the response was accepted. False if the request was already resolved by another client. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// + [JsonIgnore] + public override string Kind => "approved-for-location"; + + /// The approval to persist for this location. + [JsonPropertyName("approval")] + public required UserToolSessionApproval Approval { get; set; } + + /// The location key (git root or cwd) to persist the approval to. + [JsonPropertyName("locationKey")] + public required string LocationKey { get; set; } } -/// Pending elicitation request ID and the user's response (accept/decline/cancel + form values). +/// Permission-decision variant indicating the request was cancelled before use, with an optional reason. +/// The cancelled variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UIHandlePendingElicitationRequest +public partial class PermissionDecisionCancelled : PermissionDecision { - /// The unique request ID from the elicitation.requested event. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; - - /// The elicitation response (accept with form values, decline, or cancel). - [JsonPropertyName("result")] - public UIElicitationResponse Result { get => field ??= new(); set; } + /// + [JsonIgnore] + public override string Kind => "cancelled"; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Optional explanation of why the request was cancelled. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("reason")] + public string? Reason { get; set; } } -/// Indicates whether the pending UI request was resolved by this call. +/// Permission-decision variant indicating explicit denial by permission rules, with the matching rules. +/// The denied-by-rules variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UIHandlePendingResult +public partial class PermissionDecisionDeniedByRules : PermissionDecision { - /// True if the request was still pending and was resolved by this call. False if the request ID was unknown, already resolved by another client (e.g. GitHub), expired, or otherwise no longer pending. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// + [JsonIgnore] + public override string Kind => "denied-by-rules"; + + /// Rules that denied the request. + [JsonPropertyName("rules")] + public required IList Rules { get; set; } } -/// User response for a pending user-input request, with answer text and whether it was typed freeform. +/// Permission-decision variant indicating no approval rule matched and user confirmation was unavailable. +/// The denied-no-approval-rule-and-could-not-request-from-user variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UIUserInputResponse +public partial class PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser : PermissionDecision { - /// The user's answer text. - [JsonPropertyName("answer")] - public string Answer { get; set; } = string.Empty; - - /// True if the user typed a freeform response, false if they selected a presented choice. Used by telemetry to differentiate between free text input and choice selection. - [JsonPropertyName("wasFreeform")] - public bool WasFreeform { get; set; } + /// + [JsonIgnore] + public override string Kind => "denied-no-approval-rule-and-could-not-request-from-user"; } -/// Request ID of a pending `user_input.requested` event and the user's response. +/// Permission-decision variant indicating the user denied an interactive prompt, with optional feedback and force-reject flag. +/// The denied-interactively-by-user variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UIHandlePendingUserInputRequest +public partial class PermissionDecisionDeniedInteractivelyByUser : PermissionDecision { - /// The unique request ID from the user_input.requested event. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "denied-interactively-by-user"; - /// User response for a pending user-input request, with answer text and whether it was typed freeform. - [JsonPropertyName("response")] - public UIUserInputResponse Response { get => field ??= new(); set; } + /// Optional feedback from the user explaining the denial. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("feedback")] + public string? Feedback { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether to force-reject the current agent turn. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("forceReject")] + public bool? ForceReject { get; set; } } -/// Optional sampling result payload. Omit to reject/cancel the sampling request without providing a result. +/// Permission-decision variant indicating denial by content-exclusion policy, with path and message. +/// The denied-by-content-exclusion-policy variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UIHandlePendingSamplingResponse +public partial class PermissionDecisionDeniedByContentExclusionPolicy : PermissionDecision { + /// + [JsonIgnore] + public override string Kind => "denied-by-content-exclusion-policy"; + + /// Human-readable explanation of why the path was excluded. + [JsonPropertyName("message")] + public required string Message { get; set; } + + /// File path that triggered the exclusion. + [JsonPropertyName("path")] + public required string Path { get; set; } } -/// Request ID of a pending `sampling.requested` event and an optional sampling result payload (omit to reject). +/// Permission-decision variant indicating denial by a permission request hook, with optional message and interrupt flag. +/// The denied-by-permission-request-hook variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UIHandlePendingSamplingRequest +public partial class PermissionDecisionDeniedByPermissionRequestHook : PermissionDecision { - /// The unique request ID from the sampling.requested event. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "denied-by-permission-request-hook"; - /// Optional sampling result payload. Omit to reject/cancel the sampling request without providing a result. - [JsonPropertyName("response")] - public UIHandlePendingSamplingResponse? Response { get; set; } + /// Whether to interrupt the current agent turn. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("interrupt")] + public bool? Interrupt { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Optional message from the hook explaining the denial. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("message")] + public string? Message { get; set; } } -/// Request ID of a pending `auto_mode_switch.requested` event and the user's response. +/// Pending permission request ID and the decision to apply (approve/reject and scope). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UIHandlePendingAutoModeSwitchRequest +internal sealed class PermissionDecisionRequest { - /// The unique request ID from the auto_mode_switch.requested event. + /// Optional informational context describing how and where this response was made. Omit it to preserve legacy behavior without attributing an origin. + [JsonPropertyName("decisionContext")] + public PermissionDecisionContext? DecisionContext { get; set; } + + /// Request ID of the pending permission request. [JsonPropertyName("requestId")] public string RequestId { get; set; } = string.Empty; - /// User's choice for auto-mode switching: yes (allow this turn), yes_always (allow + persist as setting), or no (decline). - [JsonPropertyName("response")] - public UIAutoModeSwitchResponse Response { get; set; } + /// The client's response to the pending permission prompt. + [JsonPropertyName("result")] + public PermissionDecision Result { get => field ??= new(); set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// The user's selected action for an exhausted session limit. +/// Pending permission prompt reconstructed from event history, with request ID and user-facing prompt details. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UISessionLimitsExhaustedResponse +public sealed class PendingPermissionRequest { - /// Action selected by the user. - [JsonPropertyName("action")] - public UISessionLimitsExhaustedResponseAction Action { get; set; } + /// Permission-recovery episode that authorized this request to surface for interactive attention. + [JsonPropertyName("recoveryEpisodeId")] + public string? RecoveryEpisodeId { get; set; } - /// AI Credits to add to the current max when action is 'add'. - [JsonPropertyName("additionalAiCredits")] - public double? AdditionalAiCredits { get; set; } + /// The user-facing permission prompt details (commands, write, read, mcp, url, memory, custom-tool, path, hook). + [JsonPropertyName("request")] + public PermissionPromptRequest Request { get; set; } = null!; - /// New absolute max AI Credits when action is 'set'. - [JsonPropertyName("maxAiCredits")] - public double? MaxAiCredits { get; set; } + /// Unique identifier for the pending permission request. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; } -/// Request ID of a pending `session_limits_exhausted.requested` event and the user's selected limit action. +/// List of pending permission requests reconstructed from event history. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UIHandlePendingSessionLimitsExhaustedRequest +public sealed class PendingPermissionRequestList { - /// The unique request ID from the session_limits_exhausted.requested event. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; - - /// The selected session-limit action. - [JsonPropertyName("response")] - public UISessionLimitsExhaustedResponse Response { get => field ??= new(); set; } + /// Pending permission prompts reconstructed from the session's event history. Equivalent to the set of `permission.requested` events that have not yet been followed by a matching `permission.completed` event. Used by clients (e.g. the CLI) to hydrate UI for prompts that were emitted before the client attached to the session. + [JsonPropertyName("items")] + public IList Items { get => field ??= []; set; } +} +/// No parameters; returns currently-pending permission requests for the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class PermissionsPendingRequestsRequest +{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// User response for a pending exit-plan-mode request, with approval state, selected action, auto-approve flag, and feedback. +/// Indicates whether the operation succeeded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UIExitPlanModeResponse +public sealed class PermissionsSetApproveAllResult { - /// Whether the plan was approved. - [JsonPropertyName("approved")] - public bool Approved { get; set; } - - /// Whether subsequent edits should be auto-approved without confirmation. - [JsonPropertyName("autoApproveEdits")] - public bool? AutoApproveEdits { get; set; } - - /// When true, the agent is instructed to end its turn without starting implementation so the client can restore the session model and auto-submit a fresh implementation turn on it. Set only when a distinct plan configuration (a different model, reasoning effort, or context tier) actually ran the planning turn. - [JsonPropertyName("deferImplementation")] - public bool? DeferImplementation { get; set; } - - /// Feedback from the user when they declined the plan or requested changes. - [JsonPropertyName("feedback")] - public string? Feedback { get; set; } - - /// The action the user selected. Defaults to 'autopilot' when autoApproveEdits is true, otherwise 'interactive'. - [JsonPropertyName("selectedAction")] - public UIExitPlanModeAction? SelectedAction { get; set; } + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Request ID of a pending `exit_plan_mode.requested` event and the user's response. +/// Allow-all toggle for tool permission requests, with an optional telemetry source. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UIHandlePendingExitPlanModeRequest +internal sealed class PermissionsSetApproveAllRequest { - /// The unique request ID from the exit_plan_mode.requested event. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; - - /// User response for a pending exit-plan-mode request, with approval state, selected action, auto-approve flag, and feedback. - [JsonPropertyName("response")] - public UIExitPlanModeResponse Response { get => field ??= new(); set; } + /// Whether to auto-approve all tool permission requests. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Optional source for allow-all telemetry. Defaults to `rpc` when omitted for SDK callers. + [JsonPropertyName("source")] + public PermissionsSetApproveAllSource? Source { get; set; } } -/// Register an in-process handler for `auto_mode_switch.requested` events. The caller still attaches the actual listener via the standard event-subscription mechanism; this registration solely tells the server bridge to skip its own dispatch (so a remote client doesn't race the in-process handler for the same requestId). +/// Indicates whether the requested permission mode was applied and reports the authoritative post-mutation mode. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UIRegisterDirectAutoModeSwitchHandlerResult +public sealed class PermissionsSetModeResult { - /// Opaque handle representing the registration. Pass this same handle to `unregisterDirectAutoModeSwitchHandler` when the in-process handler is no longer active. Multiple registrations are reference-counted; the server bridge will only dispatch auto-mode-switch requests when no handles are active. - [JsonPropertyName("handle")] - public string Handle { get; set; } = string.Empty; + /// Authoritative permission mode after the mutation. + [JsonPropertyName("mode")] + public PermissionMode Mode { get; set; } + + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Identifies the target session. +/// Permission mode to apply for the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionUiRegisterDirectAutoModeSwitchHandlerRequest +internal sealed class PermissionsSetModeRequest { + /// Optional judge model id for assisted mode. When omitted, the session resolves the provider default: `gpt-5.5` for CAPI sessions and the active session model for BYOK sessions. + [JsonPropertyName("assistedApprovalModel")] + public string? AssistedApprovalModel { get; set; } + + /// Permission mode to apply. + [JsonPropertyName("mode")] + public PermissionMode Mode { get; set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Optional source for permission-mode telemetry. `organization_targeting` is reserved for startup selection after the authenticated account matches an organization targeting policy; SDK callers default to `rpc` and cannot claim targeting provenance. + [JsonPropertyName("source")] + public PermissionModeSource? Source { get; set; } } -/// Indicates whether the handle was active and the registration count was decremented. +/// Current permission mode. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UIUnregisterDirectAutoModeSwitchHandlerResult +public sealed class PermissionsGetModeResult { - /// True if the handle was active and decremented the counter; false if the handle was unknown. - [JsonPropertyName("unregistered")] - public bool Unregistered { get; set; } + /// Current permission mode. + [JsonPropertyName("mode")] + public PermissionMode Mode { get; set; } } -/// Opaque handle previously returned by `registerDirectAutoModeSwitchHandler` to release. +/// No parameters. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class UIUnregisterDirectAutoModeSwitchHandlerRequest +internal sealed class PermissionsGetModeRequest { - /// Handle previously returned by `registerDirectAutoModeSwitchHandler`. - [JsonPropertyName("handle")] - public string Handle { get; set; } = string.Empty; - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; @@ -23399,427 +25578,313 @@ internal sealed class UIUnregisterDirectAutoModeSwitchHandlerRequest /// Indicates whether the operation succeeded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsConfigureResult +public sealed class PermissionsModifyRulesResult { /// Whether the operation succeeded. [JsonPropertyName("success")] public bool Success { get; set; } } -/// Source descriptor for a `session.permissions.configure` content-exclusion rule, with source name and type. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsConfigureAdditionalContentExclusionPolicyRuleSource -{ - /// Name of the policy source. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; - - /// Type of the policy source. - [JsonPropertyName("type")] - public string Type { get; set; } = string.Empty; -} - -/// Single content-exclusion rule supplied to `session.permissions.configure`, with paths, match conditions, and source. +/// Scope and add/remove instructions for modifying session- or location-scoped permission rules. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsConfigureAdditionalContentExclusionPolicyRule +internal sealed class PermissionsModifyRulesParams { - /// Conditions of which at least one must match. - [JsonPropertyName("ifAnyMatch")] - public IList? IfAnyMatch { get; set; } - - /// Conditions none of which may match. - [JsonPropertyName("ifNoneMatch")] - public IList? IfNoneMatch { get; set; } - - /// Path patterns covered by this rule. - [JsonPropertyName("paths")] - public IList Paths { get => field ??= []; set; } - - /// Source descriptor for a `session.permissions.configure` content-exclusion rule, with source name and type. - [JsonPropertyName("source")] - public PermissionsConfigureAdditionalContentExclusionPolicyRuleSource Source { get => field ??= new(); set; } -} + /// Rules to add to the scope. Applied before `remove`/`removeAll`. + [JsonPropertyName("add")] + public IList? Add { get; set; } -/// Content-exclusion policy supplied to `session.permissions.configure`, with rules, last-updated data, and scope. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsConfigureAdditionalContentExclusionPolicy -{ - /// Opaque policy update timestamp supplied by the host. - [JsonPropertyName("last_updated_at")] - public JsonElement LastUpdatedAt { get; set; } + /// Specific rules to remove from the scope. Ignored when `removeAll` is true. + [JsonPropertyName("remove")] + public IList? Remove { get; set; } - /// Content-exclusion rules to apply. - [JsonPropertyName("rules")] - public IList Rules { get => field ??= []; set; } + /// When true, removes every rule currently in the scope (after any `add` is applied). Useful for clearing the location scope wholesale. + [JsonPropertyName("removeAll")] + public bool? RemoveAll { get; set; } - /// Allowed values for the `PermissionsConfigureAdditionalContentExclusionPolicyScope` enumeration. + /// Whether the change applies to ephemeral session-scoped rules (cleared at session end) or to location-scoped rules persisted via the location-permissions config file. [JsonPropertyName("scope")] - public PermissionsConfigureAdditionalContentExclusionPolicyScope Scope { get; set; } + public PermissionsModifyRulesScope Scope { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// If specified, replaces the session's path-permission policy. The runtime constructs the appropriate PathManager based on these inputs (rooted at the session's working directory). Omit to leave the current path policy unchanged. +/// Indicates whether the operation succeeded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionPathsConfig +public sealed class PermissionsSetRequiredResult { - /// Additional directories to allow tool access to (in addition to the session's working directory). Conventional `.github/skills/` and `.github/agents/` definitions under them also join the session catalogs when their subsystem gates are enabled, so supplying a directory is a trust decision for configuration stored there. When `unrestricted` is true, these are still pre-populated on the UnrestrictedPathManager so they remain visible via getDirectories() (e.g. for @-mention completion). - [JsonPropertyName("additionalDirectories")] - public IList? AdditionalDirectories { get; set; } - - /// Whether to include the system temp directory in the allowed list (defaults to true). Ignored when `unrestricted` is true. - [JsonPropertyName("includeTempDirectory")] - public bool? IncludeTempDirectory { get; set; } - - /// If true, the runtime allows access to all paths without prompting. Equivalent to constructing an UnrestrictedPathManager. - [JsonPropertyName("unrestricted")] - public bool? Unrestricted { get; set; } - - /// Workspace root path (special-cased to be allowed even before the directory exists). Ignored when `unrestricted` is true. - [JsonPropertyName("workspacePath")] - public string? WorkspacePath { get; set; } + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// If specified, replaces the session's approved/denied permission rules. Omit to leave the current rules unchanged. +/// Toggles whether permission prompts should be bridged into session events for this client. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionRulesSet +internal sealed class PermissionsSetRequiredRequest { - /// Rules that auto-approve matching requests. - [JsonPropertyName("approved")] - public IList Approved { get => field ??= []; set; } + /// Whether the client wants `permission.requested` events bridged from the session-owned permission service. CLI clients that render prompt UI set this to `true` for as long as their listener is mounted; headless callers leave it unset (the default is `false`). + [JsonPropertyName("required")] + public bool Required { get; set; } - /// Rules that auto-deny matching requests. - [JsonPropertyName("denied")] - public IList Denied { get => field ??= []; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// If specified, replaces the session's URL-permission policy. The runtime constructs a fresh DefaultUrlManager based on these inputs. Omit to leave the current URL policy unchanged. +/// Indicates whether the operation succeeded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionUrlsConfig +public sealed class PermissionsResetSessionApprovalsResult { - /// Initial list of allowed URL/domain patterns. Patterns may include path components. Ignored when `unrestricted` is true. - [JsonPropertyName("initialAllowed")] - public IList? InitialAllowed { get; set; } - - /// If true, the runtime allows access to all URLs without prompting. Initial allow-list is ignored when this is true. - [JsonPropertyName("unrestricted")] - public bool? Unrestricted { get; set; } + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Patch of permission policy fields to apply (omit a field to leave it unchanged). +/// Clears session-scoped tool approvals and optionally clears location-scoped approvals and exact session-approved paths. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionsConfigureParams +internal sealed class PermissionsResetSessionApprovalsRequest { - /// If specified, replaces the host-supplied GitHub Content Exclusion policies on the session (combined with natively-discovered policies when evaluating tool/file access). Omit to leave the current policies unchanged. - [JsonPropertyName("additionalContentExclusionPolicies")] - public IList? AdditionalContentExclusionPolicies { get; set; } - - /// If specified, sets whether path/URL read permission requests are auto-approved. Omit to leave the current value unchanged. - [JsonPropertyName("approveAllReadPermissionRequests")] - public bool? ApproveAllReadPermissionRequests { get; set; } - - /// If specified, sets whether tool permission requests are auto-approved without prompting. Omit to leave the current value unchanged. - [JsonPropertyName("approveAllToolPermissionRequests")] - public bool? ApproveAllToolPermissionRequests { get; set; } - - /// If specified, replaces the session's path-permission policy. The runtime constructs the appropriate PathManager based on these inputs (rooted at the session's working directory). Omit to leave the current path policy unchanged. - [JsonPropertyName("paths")] - public PermissionPathsConfig? Paths { get; set; } - - /// If specified, replaces the session's approved/denied permission rules. Omit to leave the current rules unchanged. - [JsonPropertyName("rules")] - public PermissionRulesSet? Rules { get; set; } + /// Whether location-scoped approvals and exact session-approved paths are cleared too. Defaults to `true`. + [JsonPropertyName("includeLocation")] + public bool? IncludeLocation { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// If specified, replaces the session's URL-permission policy. The runtime constructs a fresh DefaultUrlManager based on these inputs. Omit to leave the current URL policy unchanged. - [JsonPropertyName("urls")] - public PermissionUrlsConfig? Urls { get; set; } } -/// Indicates whether the permission decision was applied; false when the request was already resolved. +/// Indicates whether the operation succeeded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionRequestResult +public sealed class PermissionsNotifyPromptShownResult { - /// Whether the permission request was handled successfully. + /// Whether the operation succeeded. [JsonPropertyName("success")] public bool Success { get; set; } } -/// The client's response to the pending permission prompt. -/// Polymorphic base type discriminated by kind. +/// Notification payload describing the permission prompt that the client just rendered. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(PermissionDecisionApproveOnce), "approve-once")] -[JsonDerivedType(typeof(PermissionDecisionApproveForSession), "approve-for-session")] -[JsonDerivedType(typeof(PermissionDecisionApproveReadOnlyForSession), "approve-read-only-for-session")] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocation), "approve-for-location")] -[JsonDerivedType(typeof(PermissionDecisionApprovePermanently), "approve-permanently")] -[JsonDerivedType(typeof(PermissionDecisionReject), "reject")] -[JsonDerivedType(typeof(PermissionDecisionUserNotAvailable), "user-not-available")] -[JsonDerivedType(typeof(PermissionDecisionApproved), "approved")] -[JsonDerivedType(typeof(PermissionDecisionApprovedForSession), "approved-for-session")] -[JsonDerivedType(typeof(PermissionDecisionApprovedForLocation), "approved-for-location")] -[JsonDerivedType(typeof(PermissionDecisionCancelled), "cancelled")] -[JsonDerivedType(typeof(PermissionDecisionDeniedByRules), "denied-by-rules")] -[JsonDerivedType(typeof(PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser), "denied-no-approval-rule-and-could-not-request-from-user")] -[JsonDerivedType(typeof(PermissionDecisionDeniedInteractivelyByUser), "denied-interactively-by-user")] -[JsonDerivedType(typeof(PermissionDecisionDeniedByContentExclusionPolicy), "denied-by-content-exclusion-policy")] -[JsonDerivedType(typeof(PermissionDecisionDeniedByPermissionRequestHook), "denied-by-permission-request-hook")] -public partial class PermissionDecision +internal sealed class PermissionPromptShownNotification { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Human-readable description of the prompt the user is being asked to approve. Used by the runtime to fire the registered `permission_prompt` notification hook (e.g. terminal bell, desktop notification). + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} -/// Permission-decision request variant to approve only the current permission request. -/// The approve-once variant of . +/// Snapshot of the session's recursive directory grants, exact session-approved paths, and primary working directory. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveOnce : PermissionDecision +public sealed class PermissionPathsList { - /// - [JsonIgnore] - public override string Kind => "approve-once"; + /// All directories currently allowed for tool access on this session. + [JsonPropertyName("directories")] + public IList Directories { get => field ??= []; set; } - /// True only when a host surfaced this request to a user who approved it. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("approvedInteractively")] - public bool? ApprovedInteractively { get; set; } + /// The primary working directory for this session. + [JsonPropertyName("primary")] + public string Primary { get; set; } = string.Empty; + + /// Exact paths approved for this session without recursively allowing their descendants. + [JsonPropertyName("sessionApprovedPaths")] + public IList? SessionApprovedPaths { get; set; } } -/// Session-scoped approval to remember (tool prompts only; omitted for path/url prompts). -/// Polymorphic base type discriminated by kind. +/// No parameters; returns the session's recursive directory grants and exact session-approved paths. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalCommands), "commands")] -[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalRead), "read")] -[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalWrite), "write")] -[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalMcp), "mcp")] -[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalMcpSampling), "mcp-sampling")] -[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalMemory), "memory")] -[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalCustomTool), "custom-tool")] -[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalExtensionManagement), "extension-management")] -[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalWorkflow), "workflow")] -[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess), "extension-permission-access")] -[JsonDerivedType(typeof(PermissionDecisionApproveForSessionApprovalExtensionEnvAccess), "extension-env-access")] -public partial class PermissionDecisionApproveForSessionApproval +internal sealed class PermissionsPathsListRequest { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } - -/// Session-scoped approval details for specific command identifiers. -/// The commands variant of . +/// Indicates whether the operation succeeded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSessionApprovalCommands : PermissionDecisionApproveForSessionApproval +public sealed class PermissionsPathsAddResult { - /// - [JsonIgnore] - public override string Kind => "commands"; - - /// Command identifiers covered by this approval. - [JsonPropertyName("commandIdentifiers")] - public required IList CommandIdentifiers { get; set; } + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Session-scoped approval details for read-only filesystem operations. -/// The read variant of . +/// Directory path to add to the session's allowed directories. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSessionApprovalRead : PermissionDecisionApproveForSessionApproval +internal sealed class PermissionPathsAddParams { - /// - [JsonIgnore] - public override string Kind => "read"; + /// Directory to add to the allow-list. The runtime resolves and validates the path before adding, then loads conventional `.github/skills/` and `.github/agents/` definitions under it when their subsystem gates are enabled. Adding the directory is therefore also a trust decision for configuration stored there. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Session-scoped approval details for filesystem write operations. -/// The write variant of . +/// Indicates whether the operation succeeded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSessionApprovalWrite : PermissionDecisionApproveForSessionApproval +public sealed class PermissionsPathsUpdatePrimaryResult { - /// - [JsonIgnore] - public override string Kind => "write"; + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Session-scoped approval details for an MCP server tool, or all tools on the server when `toolName` is null. -/// The mcp variant of . +/// Directory path to set as the session's new primary working directory. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSessionApprovalMcp : PermissionDecisionApproveForSessionApproval +internal sealed class PermissionPathsUpdatePrimaryParams { - /// - [JsonIgnore] - public override string Kind => "mcp"; - - /// MCP server name. - [JsonPropertyName("serverName")] - public required string ServerName { get; set; } + /// Directory to set as the new primary working directory for the session's permission policy. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// MCP tool name, or null to cover every tool on the server. - [JsonPropertyName("toolName")] - public string? ToolName { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Session-scoped approval details for MCP sampling requests from a server. -/// The mcp-sampling variant of . +/// Indicates whether the supplied path is within the session's allowed directories. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSessionApprovalMcpSampling : PermissionDecisionApproveForSessionApproval +public sealed class PermissionPathsAllowedCheckResult { - /// - [JsonIgnore] - public override string Kind => "mcp-sampling"; - - /// MCP server name. - [JsonPropertyName("serverName")] - public required string ServerName { get; set; } + /// Whether the path is within the session's allowed directories. + [JsonPropertyName("allowed")] + public bool Allowed { get; set; } } -/// Session-scoped approval details for writes to long-term memory. -/// The memory variant of . +/// Path to evaluate against the session's allowed directories. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSessionApprovalMemory : PermissionDecisionApproveForSessionApproval +internal sealed class PermissionPathsAllowedCheckParams { - /// - [JsonIgnore] - public override string Kind => "memory"; + /// Path to check against the session's allowed directories. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Session-scoped approval details for a custom tool, keyed by tool name. -/// The custom-tool variant of . +/// Indicates whether the supplied path is within the session's workspace directory. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSessionApprovalCustomTool : PermissionDecisionApproveForSessionApproval +public sealed class PermissionPathsWorkspaceCheckResult { - /// - [JsonIgnore] - public override string Kind => "custom-tool"; - - /// Custom tool name. - [JsonPropertyName("toolName")] - public required string ToolName { get; set; } + /// Whether the path is within the session workspace directory. + [JsonPropertyName("allowed")] + public bool Allowed { get; set; } } -/// Session-scoped approval details for extension-management operations, optionally narrowed by operation. -/// The extension-management variant of . +/// Path to evaluate against the session's workspace (primary) directory. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSessionApprovalExtensionManagement : PermissionDecisionApproveForSessionApproval +internal sealed class PermissionPathsWorkspaceCheckParams { - /// - [JsonIgnore] - public override string Kind => "extension-management"; + /// Path to check against the session workspace directory. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Optional operation identifier; when omitted, the approval covers all extension management operations. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("operation")] - public string? Operation { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Session-scoped workflow approval, optionally narrowed by approval key. -/// The workflow variant of . +/// Resolved location-permissions key and type. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSessionApprovalWorkflow : PermissionDecisionApproveForSessionApproval +public sealed class PermissionLocationResolveResult { - /// - [JsonIgnore] - public override string Kind => "workflow"; + /// Location key used in the location-permissions store. + [JsonPropertyName("locationKey")] + public string LocationKey { get; set; } = string.Empty; - /// Optional workflow operation name or canonical approval key; when omitted, the approval covers all workflow operations. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("approvalKey")] - public string? ApprovalKey { get; set; } + /// Whether the location is a git repo or directory. + [JsonPropertyName("locationType")] + public PermissionLocationType LocationType { get; set; } } -/// Session-scoped approval details for an extension's permission-gated capability access, keyed by extension name. -/// The extension-permission-access variant of . +/// Working directory to resolve into a location-permissions key. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess : PermissionDecisionApproveForSessionApproval +internal sealed class PermissionLocationResolveParams { - /// - [JsonIgnore] - public override string Kind => "extension-permission-access"; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// Extension name. - [JsonPropertyName("extensionName")] - public required string ExtensionName { get; set; } + /// Working directory whose permission location should be resolved. + [JsonPropertyName("workingDirectory")] + public string WorkingDirectory { get; set; } = string.Empty; } -/// Session-scoped approval details for an extension's access to sensitive environment variables, keyed by extension name and the exact set of variable names. -/// The extension-env-access variant of . +/// Summary of persisted location permissions applied to the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSessionApprovalExtensionEnvAccess : PermissionDecisionApproveForSessionApproval +public sealed class PermissionLocationApplyResult { - /// - [JsonIgnore] - public override string Kind => "extension-env-access"; + /// Number of persisted allowed directories added to the live path manager. + [JsonPropertyName("appliedDirectoryCount")] + public long AppliedDirectoryCount { get; set; } - /// Names of the sensitive environment variables this approval covers. Values are never persisted. - [JsonPropertyName("environmentVariables")] - public required IList EnvironmentVariables { get; set; } + /// Number of location-scoped rules added to the live permission service. + [JsonPropertyName("appliedRuleCount")] + public long AppliedRuleCount { get; set; } - /// Extension name. - [JsonPropertyName("extensionName")] - public required string ExtensionName { get; set; } + /// Location-scoped rules applied to the live permission service. + [JsonPropertyName("appliedRules")] + public IList AppliedRules { get => field ??= []; set; } + + /// Whether a different location was applied since the previous apply call. + [JsonPropertyName("changed")] + public bool Changed { get; set; } + + /// Location key used in the location-permissions store. + [JsonPropertyName("locationKey")] + public string LocationKey { get; set; } = string.Empty; + + /// Whether the location is a git repo or directory. + [JsonPropertyName("locationType")] + public PermissionLocationType LocationType { get; set; } } -/// Permission-decision request variant to approve for the rest of the session, with optional tool approval or URL domain. -/// The approve-for-session variant of . +/// Working directory to load persisted location permissions for. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForSession : PermissionDecision +internal sealed class PermissionLocationApplyParams { - /// - [JsonIgnore] - public override string Kind => "approve-for-session"; - - /// Session-scoped approval to remember (tool prompts only; omitted for path/url prompts). - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("approval")] - public PermissionDecisionApproveForSessionApproval? Approval { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// URL domain to approve for the rest of the session (URL prompts only). - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("domain")] - public string? Domain { get; set; } + /// Working directory whose persisted location permissions should be applied. + [JsonPropertyName("workingDirectory")] + public string WorkingDirectory { get; set; } = string.Empty; } -/// Approve file-tool read access to specific directories for this logical session, including continuation or resume. -/// The approve-read-only-for-session variant of . +/// Indicates whether the operation succeeded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveReadOnlyForSession : PermissionDecision +public sealed class PermissionsLocationsAddToolApprovalResult { - /// - [JsonIgnore] - public override string Kind => "approve-read-only-for-session"; - - /// Canonical directories covered by the read-only grant. - [JsonPropertyName("directories")] - public required IList Directories { get; set; } + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Approval to persist for this location. +/// Tool approval to persist and apply. /// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonPolymorphic( TypeDiscriminatorPropertyName = "kind", UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalCommands), "commands")] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalRead), "read")] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalWrite), "write")] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalMcp), "mcp")] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalMcpSampling), "mcp-sampling")] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalMemory), "memory")] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalCustomTool), "custom-tool")] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalExtensionManagement), "extension-management")] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalWorkflow), "workflow")] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess), "extension-permission-access")] -[JsonDerivedType(typeof(PermissionDecisionApproveForLocationApprovalExtensionEnvAccess), "extension-env-access")] -public partial class PermissionDecisionApproveForLocationApproval +[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsCommands), "commands")] +[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsRead), "read")] +[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsWrite), "write")] +[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsMcp), "mcp")] +[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsMcpSampling), "mcp-sampling")] +[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsMemory), "memory")] +[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsCustomTool), "custom-tool")] +[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsExtensionManagement), "extension-management")] +[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsWorkflow), "workflow")] +[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsExtensionPermissionAccess), "extension-permission-access")] +[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsExtensionEnvAccess), "extension-env-access")] +public partial class PermissionsLocationsAddToolApprovalDetails { /// The type discriminator. [JsonPropertyName("kind")] @@ -23827,10 +25892,10 @@ public partial class PermissionDecisionApproveForLocationApproval } -/// Location-scoped approval details for specific command identifiers. -/// The commands variant of . +/// Location-persisted tool approval details for specific command identifiers. +/// The commands variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocationApprovalCommands : PermissionDecisionApproveForLocationApproval +public partial class PermissionsLocationsAddToolApprovalDetailsCommands : PermissionsLocationsAddToolApprovalDetails { /// [JsonIgnore] @@ -23841,30 +25906,30 @@ public partial class PermissionDecisionApproveForLocationApprovalCommands : Perm public required IList CommandIdentifiers { get; set; } } -/// Location-scoped approval details for read-only filesystem operations. -/// The read variant of . +/// Location-persisted tool approval details for read-only filesystem operations. +/// The read variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocationApprovalRead : PermissionDecisionApproveForLocationApproval +public partial class PermissionsLocationsAddToolApprovalDetailsRead : PermissionsLocationsAddToolApprovalDetails { /// [JsonIgnore] public override string Kind => "read"; } -/// Location-scoped approval details for filesystem write operations. -/// The write variant of . +/// Location-persisted tool approval details for filesystem write operations. +/// The write variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocationApprovalWrite : PermissionDecisionApproveForLocationApproval +public partial class PermissionsLocationsAddToolApprovalDetailsWrite : PermissionsLocationsAddToolApprovalDetails { /// [JsonIgnore] public override string Kind => "write"; } -/// Location-scoped approval details for an MCP server tool, or all tools on the server when `toolName` is null. -/// The mcp variant of . +/// Location-persisted tool approval details for an MCP server tool, or all tools when `toolName` is null. +/// The mcp variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocationApprovalMcp : PermissionDecisionApproveForLocationApproval +public partial class PermissionsLocationsAddToolApprovalDetailsMcp : PermissionsLocationsAddToolApprovalDetails { /// [JsonIgnore] @@ -23879,10 +25944,10 @@ public partial class PermissionDecisionApproveForLocationApprovalMcp : Permissio public string? ToolName { get; set; } } -/// Location-scoped approval details for MCP sampling requests from a server. -/// The mcp-sampling variant of . +/// Location-persisted tool approval details for MCP sampling requests from a server. +/// The mcp-sampling variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocationApprovalMcpSampling : PermissionDecisionApproveForLocationApproval +public partial class PermissionsLocationsAddToolApprovalDetailsMcpSampling : PermissionsLocationsAddToolApprovalDetails { /// [JsonIgnore] @@ -23893,20 +25958,20 @@ public partial class PermissionDecisionApproveForLocationApprovalMcpSampling : P public required string ServerName { get; set; } } -/// Location-scoped approval details for writes to long-term memory. -/// The memory variant of . +/// Location-persisted tool approval details for writes to long-term memory. +/// The memory variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocationApprovalMemory : PermissionDecisionApproveForLocationApproval +public partial class PermissionsLocationsAddToolApprovalDetailsMemory : PermissionsLocationsAddToolApprovalDetails { /// [JsonIgnore] public override string Kind => "memory"; } -/// Location-scoped approval details for a custom tool, keyed by tool name. -/// The custom-tool variant of . +/// Location-persisted tool approval details for a custom tool, keyed by tool name. +/// The custom-tool variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocationApprovalCustomTool : PermissionDecisionApproveForLocationApproval +public partial class PermissionsLocationsAddToolApprovalDetailsCustomTool : PermissionsLocationsAddToolApprovalDetails { /// [JsonIgnore] @@ -23917,10 +25982,10 @@ public partial class PermissionDecisionApproveForLocationApprovalCustomTool : Pe public required string ToolName { get; set; } } -/// Location-scoped approval details for extension-management operations, optionally narrowed by operation. -/// The extension-management variant of . +/// Location-persisted tool approval details for extension-management operations, optionally narrowed by operation. +/// The extension-management variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocationApprovalExtensionManagement : PermissionDecisionApproveForLocationApproval +public partial class PermissionsLocationsAddToolApprovalDetailsExtensionManagement : PermissionsLocationsAddToolApprovalDetails { /// [JsonIgnore] @@ -23932,10 +25997,10 @@ public partial class PermissionDecisionApproveForLocationApprovalExtensionManage public string? Operation { get; set; } } -/// Location-scoped workflow approval, optionally narrowed by approval key. -/// The workflow variant of . +/// Location-persisted workflow approval, optionally narrowed by approval key. +/// The workflow variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocationApprovalWorkflow : PermissionDecisionApproveForLocationApproval +public partial class PermissionsLocationsAddToolApprovalDetailsWorkflow : PermissionsLocationsAddToolApprovalDetails { /// [JsonIgnore] @@ -23947,10 +26012,10 @@ public partial class PermissionDecisionApproveForLocationApprovalWorkflow : Perm public string? ApprovalKey { get; set; } } -/// Location-scoped approval details for an extension's permission-gated capability access, keyed by extension name. -/// The extension-permission-access variant of . +/// Location-persisted tool approval details for an extension's permission-gated capability access, keyed by extension name. +/// The extension-permission-access variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess : PermissionDecisionApproveForLocationApproval +public partial class PermissionsLocationsAddToolApprovalDetailsExtensionPermissionAccess : PermissionsLocationsAddToolApprovalDetails { /// [JsonIgnore] @@ -23961,10 +26026,10 @@ public partial class PermissionDecisionApproveForLocationApprovalExtensionPermis public required string ExtensionName { get; set; } } -/// Location-scoped approval details for an extension's access to sensitive environment variables, keyed by extension name and the exact set of variable names. -/// The extension-env-access variant of . +/// Location-persisted tool approval details for an extension's access to sensitive environment variables, keyed by extension name and the exact set of variable names. +/// The extension-env-access variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocationApprovalExtensionEnvAccess : PermissionDecisionApproveForLocationApproval +public partial class PermissionsLocationsAddToolApprovalDetailsExtensionEnvAccess : PermissionsLocationsAddToolApprovalDetails { /// [JsonIgnore] @@ -23979,4909 +26044,5332 @@ public partial class PermissionDecisionApproveForLocationApprovalExtensionEnvAcc public required string ExtensionName { get; set; } } -/// Permission-decision request variant to approve and persist a permission for a project location, with approval details and location key. -/// The approve-for-location variant of . +/// Location-scoped tool approval to persist. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproveForLocation : PermissionDecision +internal sealed class PermissionLocationAddToolApprovalParams { - /// - [JsonIgnore] - public override string Kind => "approve-for-location"; - - /// Approval to persist for this location. + /// Tool approval to persist and apply. [JsonPropertyName("approval")] - public required PermissionDecisionApproveForLocationApproval Approval { get; set; } + public PermissionsLocationsAddToolApprovalDetails Approval { get => field ??= new(); set; } /// Location key (git root or cwd) to persist the approval to. [JsonPropertyName("locationKey")] - public required string LocationKey { get; set; } + public string LocationKey { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Permission-decision request variant to permanently approve a URL domain across sessions. -/// The approve-permanently variant of . +/// Folder path to check for trust. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApprovePermanently : PermissionDecision +internal sealed class FolderTrustCheckParams { - /// - [JsonIgnore] - public override string Kind => "approve-permanently"; + /// Folder path to check. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// URL domain to approve permanently. - [JsonPropertyName("domain")] - public required string Domain { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Permission-decision request variant to reject a pending permission request, with optional feedback. -/// The reject variant of . +/// Indicates whether the operation succeeded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionReject : PermissionDecision +public sealed class PermissionsFolderTrustAddTrustedResult { - /// - [JsonIgnore] - public override string Kind => "reject"; - - /// Optional feedback explaining the rejection. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("feedback")] - public string? Feedback { get; set; } + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Permission-decision variant indicating no user was available to confirm the request. -/// The user-not-available variant of . +/// Folder path to add to trusted folders. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionUserNotAvailable : PermissionDecision +internal sealed class FolderTrustAddParams { - /// - [JsonIgnore] - public override string Kind => "user-not-available"; + /// Folder path to mark as trusted. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Permission-decision variant indicating the request was approved. -/// The approved variant of . +/// Indicates whether the operation succeeded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApproved : PermissionDecision +public sealed class PermissionsUrlsSetUnrestrictedModeResult { - /// - [JsonIgnore] - public override string Kind => "approved"; + /// Whether the operation succeeded. + [JsonPropertyName("success")] + public bool Success { get; set; } } -/// Permission-decision variant indicating approval was remembered for the session, with approval details. -/// The approved-for-session variant of . +/// Whether the URL-permission policy should run in unrestricted mode. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApprovedForSession : PermissionDecision +internal sealed class PermissionUrlsSetUnrestrictedModeParams { - /// - [JsonIgnore] - public override string Kind => "approved-for-session"; + /// Whether to allow access to all URLs without prompting. Toggles the runtime's URL-permission policy in place. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } - /// The approval to add as a session-scoped rule. - [JsonPropertyName("approval")] - public required UserToolSessionApproval Approval { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Permission-decision variant indicating approval was persisted for a project location, with approval details and location key. -/// The approved-for-location variant of . +/// The repository the remote session targets. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionApprovedForLocation : PermissionDecision +public sealed class MetadataSnapshotRemoteMetadataRepository { - /// - [JsonIgnore] - public override string Kind => "approved-for-location"; + /// The branch the remote session is operating on. + [JsonPropertyName("branch")] + public string Branch { get; set; } = string.Empty; - /// The approval to persist for this location. - [JsonPropertyName("approval")] - public required UserToolSessionApproval Approval { get; set; } + /// The GitHub repository name (without owner). + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; - /// The location key (git root or cwd) to persist the approval to. - [JsonPropertyName("locationKey")] - public required string LocationKey { get; set; } + /// The GitHub owner (user or organization) of the target repository. + [JsonPropertyName("owner")] + public string Owner { get; set; } = string.Empty; } -/// Permission-decision variant indicating the request was cancelled before use, with an optional reason. -/// The cancelled variant of . +/// Remote-session-specific metadata. Populated only when `isRemote` is true. Fields are immutable for the lifetime of the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionCancelled : PermissionDecision +public sealed class MetadataSnapshotRemoteMetadata { - /// - [JsonIgnore] - public override string Kind => "cancelled"; + /// The pull request number the remote session is associated with, if any. + [JsonPropertyName("pullRequestNumber")] + public long? PullRequestNumber { get; set; } - /// Optional explanation of why the request was cancelled. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("reason")] - public string? Reason { get; set; } -} + /// The repository the remote session targets. + [JsonPropertyName("repository")] + public MetadataSnapshotRemoteMetadataRepository Repository { get => field ??= new(); set; } -/// Permission-decision variant indicating explicit denial by permission rules, with the matching rules. -/// The denied-by-rules variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionDeniedByRules : PermissionDecision -{ - /// - [JsonIgnore] - public override string Kind => "denied-by-rules"; + /// The original resource identifier (task ID or PR node ID), preserved across event-replay reconstructions. Falls back to `sessionId` when absent. + [JsonPropertyName("resourceId")] + public string? ResourceId { get; set; } - /// Rules that denied the request. - [JsonPropertyName("rules")] - public required IList Rules { get; set; } + /// Whether the remote task originated from Copilot Coding Agent (cca) or a CLI `--remote` invocation. + [JsonPropertyName("taskType")] + public MetadataSnapshotRemoteMetadataTaskType? TaskType { get; set; } } -/// Permission-decision variant indicating no approval rule matched and user confirmation was unavailable. -/// The denied-no-approval-rule-and-could-not-request-from-user variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser : PermissionDecision +/// Public-facing projection of workspace metadata for SDK / TUI consumers. +public sealed class SessionMetadataSnapshotWorkspace { - /// - [JsonIgnore] - public override string Kind => "denied-no-approval-rule-and-could-not-request-from-user"; -} + /// Branch checked out at session start, if any. + [JsonPropertyName("branch")] + public string? Branch { get; set; } -/// Permission-decision variant indicating the user denied an interactive prompt, with optional feedback and force-reject flag. -/// The denied-interactively-by-user variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionDeniedInteractivelyByUser : PermissionDecision -{ - /// - [JsonIgnore] - public override string Kind => "denied-interactively-by-user"; + /// ISO 8601 timestamp when the workspace was created. + [JsonPropertyName("created_at")] + public DateTimeOffset? CreatedAt { get; set; } - /// Optional feedback from the user explaining the denial. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("feedback")] - public string? Feedback { get; set; } + /// Current working directory at session start. + [JsonPropertyName("cwd")] + public string? Cwd { get; set; } - /// Whether to force-reject the current agent turn. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("forceReject")] - public bool? ForceReject { get; set; } -} + /// Resolved git root for cwd, if any. + [JsonPropertyName("git_root")] + public string? GitRoot { get; set; } -/// Permission-decision variant indicating denial by content-exclusion policy, with path and message. -/// The denied-by-content-exclusion-policy variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionDeniedByContentExclusionPolicy : PermissionDecision -{ - /// - [JsonIgnore] - public override string Kind => "denied-by-content-exclusion-policy"; + /// Repository host type, if known. + [JsonPropertyName("host_type")] + public WorkspaceSummaryHostType? HostType { get; set; } - /// Human-readable explanation of why the path was excluded. - [JsonPropertyName("message")] - public required string Message { get; set; } + /// Workspace identifier (1:1 with sessionId). + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// File path that triggered the exclusion. - [JsonPropertyName("path")] - public required string Path { get; set; } -} + /// Display name for the session, if set. + [JsonPropertyName("name")] + public string? Name { get; set; } -/// Permission-decision variant indicating denial by a permission request hook, with optional message and interrupt flag. -/// The denied-by-permission-request-hook variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionDecisionDeniedByPermissionRequestHook : PermissionDecision -{ - /// - [JsonIgnore] - public override string Kind => "denied-by-permission-request-hook"; + /// Repository identifier in 'owner/repo' or 'org/project/repo' format, if any. + [JsonPropertyName("repository")] + public string? Repository { get; set; } - /// Whether to interrupt the current agent turn. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("interrupt")] - public bool? Interrupt { get; set; } + /// ISO 8601 timestamp when the workspace was last updated. + [JsonPropertyName("updated_at")] + public DateTimeOffset? UpdatedAt { get; set; } - /// Optional message from the hook explaining the denial. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("message")] - public string? Message { get; set; } + /// Whether the display name was explicitly set by the user. + [JsonPropertyName("user_named")] + public bool? UserNamed { get; set; } } -/// Pending permission request ID and the decision to apply (approve/reject and scope). +/// Point-in-time snapshot of slow-changing session identifier and state fields. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionDecisionRequest +public sealed class SessionMetadataSnapshot { - /// Optional informational context describing how and where this response was made. Omit it to preserve legacy behavior without attributing an origin. - [JsonPropertyName("decisionContext")] - public PermissionDecisionContext? DecisionContext { get; set; } + /// True when the session was detected to be in use by another process at construction time. Local consumers may surface a confirmation prompt before fully attaching. Always false for new sessions. + [JsonPropertyName("alreadyInUse")] + public bool AlreadyInUse { get; set; } + + /// Runtime client name associated with the session (telemetry identifier). + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } + + /// The current agent mode for this session (e.g., 'interactive', 'plan', 'autopilot'). + [JsonPropertyName("currentMode")] + public MetadataSnapshotCurrentMode CurrentMode { get; set; } + + /// Live indexed-search state for this session activation. Omitted by runtimes that do not expose indexed-search status; absence does not indicate enablement. + [JsonPropertyName("indexedSearch")] + public IndexedSearchState? IndexedSearch { get; set; } + + /// User-provided name supplied at session construction (via `--name`), if any. Immutable after construction. + [JsonPropertyName("initialName")] + public string? InitialName { get; set; } + + /// Whether this is a remote session (i.e., one whose runtime executes elsewhere and is steered through this process). + [JsonPropertyName("isRemote")] + public bool IsRemote { get; set; } + + /// ISO 8601 timestamp of when the session's persisted state was last modified on disk. For new sessions, equals startTime. For resumed sessions, reflects the previous modification time at construction. + [JsonPropertyName("modifiedTime")] + public DateTimeOffset ModifiedTime { get; set; } - /// Request ID of the pending permission request. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// Remote-session-specific metadata. Populated only when `isRemote` is true. Fields are immutable for the lifetime of the session. + [JsonPropertyName("remoteMetadata")] + public MetadataSnapshotRemoteMetadata? RemoteMetadata { get; set; } - /// The client's response to the pending permission prompt. - [JsonPropertyName("result")] - public PermissionDecision Result { get => field ??= new(); set; } + /// Currently selected model identifier, if any. + [JsonPropertyName("selectedModel")] + public string? SelectedModel { get; set; } - /// Target session identifier. + /// The unique identifier of the session. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; -} -/// Pending permission prompt reconstructed from event history, with request ID and user-facing prompt details. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PendingPermissionRequest -{ - /// Permission-recovery episode that authorized this request to surface for interactive attention. - [JsonPropertyName("recoveryEpisodeId")] - public string? RecoveryEpisodeId { get; set; } + /// Current session limits, or null when no limits are active. + [JsonPropertyName("sessionLimits")] + public SessionLimitsConfig? SessionLimits { get; set; } - /// The user-facing permission prompt details (commands, write, read, mcp, url, memory, custom-tool, path, hook). - [JsonPropertyName("request")] - public PermissionPromptRequest Request { get; set; } = null!; + /// ISO 8601 timestamp of when the session started. + [JsonPropertyName("startTime")] + public DateTimeOffset StartTime { get; set; } - /// Unique identifier for the pending permission request. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; -} + /// Short human-readable summary of the session, if known. Omitted when no summary has been generated. + [JsonPropertyName("summary")] + public string? Summary { get; set; } -/// List of pending permission requests reconstructed from event history. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PendingPermissionRequestList -{ - /// Pending permission prompts reconstructed from the session's event history. Equivalent to the set of `permission.requested` events that have not yet been followed by a matching `permission.completed` event. Used by clients (e.g. the CLI) to hydrate UI for prompts that were emitted before the client attached to the session. - [JsonPropertyName("items")] - public IList Items { get => field ??= []; set; } + /// Absolute path to the session's current working directory. + [JsonPropertyName("workingDirectory")] + public string WorkingDirectory { get; set; } = string.Empty; + + /// Public-facing workspace metadata for this session, or null if the session has no associated workspace. Excludes runtime-internal fields (GitHub IDs, summary count, internal flags). + [JsonPropertyName("workspace")] + public SessionMetadataSnapshotWorkspace? Workspace { get; set; } + + /// Absolute path to the session's workspace directory on disk, or null if the session has no associated workspace. + [JsonPropertyName("workspacePath")] + public string? WorkspacePath { get; set; } } -/// No parameters; returns currently-pending permission requests for the session. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionsPendingRequestsRequest +internal sealed class SessionMetadataSnapshotRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the operation succeeded. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsSetApproveAllResult +internal sealed class SessionMetadataGetClientMetadataRequest { - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Allow-all toggle for tool permission requests, with an optional telemetry source. +/// Atomic patch for client-owned session metadata. Operations apply in clear, remove, then set order. The resulting bag must satisfy the ClientMetadata entry and serialized-size limits. Local storage coordinates concurrent runtime processes; custom SessionFs providers must serialize writers that access the same session from multiple processes. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionsSetApproveAllRequest +internal sealed class MetadataUpdateClientMetadataRequest { - /// Whether to auto-approve all tool permission requests. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// Remove every existing client metadata entry before applying remove and set. Defaults to false. + [JsonPropertyName("clear")] + public bool? Clear { get; set; } + + /// Case-sensitive keys to remove. Missing keys are ignored. Each key must be non-empty, at most 256 UTF-8 bytes, and outside the reserved `copilot/` and `github/` namespaces. + [JsonPropertyName("remove")] + public IList? Remove { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - /// Optional source for allow-all telemetry. Defaults to `rpc` when omitted for SDK callers. - [JsonPropertyName("source")] - public PermissionsSetApproveAllSource? Source { get; set; } + /// String entries to add or replace. Set wins when a key also appears in remove. Each key must be non-empty, at most 256 UTF-8 bytes, and outside the reserved `copilot/` and `github/` namespaces. Each value may contain at most 16 KiB of UTF-8 data. + [JsonPropertyName("set")] + public IDictionary? Set { get; set; } } -/// Indicates whether the requested permission mode was applied and reports the authoritative post-mutation mode. +/// Indicates whether the local session is currently processing a turn or background continuation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsSetModeResult +public sealed class MetadataIsProcessingResult { - /// Authoritative permission mode after the mutation. - [JsonPropertyName("mode")] - public PermissionMode Mode { get; set; } - - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Whether the session is currently processing user/agent messages. False for non-local sessions (which don't run a local agentic loop). Reflects an in-flight turn or background continuation. + [JsonPropertyName("processing")] + public bool Processing { get; set; } } -/// Permission mode to apply for the session. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionsSetModeRequest +internal sealed class SessionMetadataIsProcessingRequest { - /// Optional judge model id for assisted mode. When omitted, the session resolves the provider default: `gpt-5.5` for CAPI sessions and the active session model for BYOK sessions. - [JsonPropertyName("assistedApprovalModel")] - public string? AssistedApprovalModel { get; set; } - - /// Permission mode to apply. - [JsonPropertyName("mode")] - public PermissionMode Mode { get; set; } - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// Optional source for permission-mode telemetry. `organization_targeting` is reserved for startup selection after the authenticated account matches an organization targeting policy; SDK callers default to `rpc` and cannot claim targeting provenance. - [JsonPropertyName("source")] - public PermissionModeSource? Source { get; set; } } -/// Current permission mode. +/// Current activity flags for the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsGetModeResult +public sealed class SessionActivity { - /// Current permission mode. - [JsonPropertyName("mode")] - public PermissionMode Mode { get; set; } + /// Whether an in-flight operation can currently be aborted. + [JsonPropertyName("abortable")] + public bool Abortable { get; set; } + + /// Whether the session currently has active work, including running turns or tasks. + [JsonPropertyName("hasActiveWork")] + public bool HasActiveWork { get; set; } } -/// No parameters. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionsGetModeRequest +internal sealed class SessionMetadataActivityRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the operation succeeded. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsModifyRulesResult +/// Token-usage breakdown for the session's current context window. +public sealed class MetadataContextInfoResultContextInfo { - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } -} + /// Output reservation overlapping the displayed prompt allowance plus tokens after the effective input budget's buffer-exhaustion blocking threshold (default 95%). + [JsonPropertyName("bufferTokens")] + public long BufferTokens { get; set; } -/// Scope and add/remove instructions for modifying session- or location-scoped permission rules. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionsModifyRulesParams -{ - /// Rules to add to the scope. Applied before `remove`/`removeAll`. - [JsonPropertyName("add")] - public IList? Add { get; set; } + /// Token count at which background compaction starts (configurable percentage of promptTokenLimit). + [JsonPropertyName("compactionThreshold")] + public long CompactionThreshold { get; set; } - /// Specific rules to remove from the scope. Ignored when `removeAll` is true. - [JsonPropertyName("remove")] - public IList? Remove { get; set; } + /// Tokens consumed by user/assistant/tool messages. + [JsonPropertyName("conversationTokens")] + public long ConversationTokens { get; set; } - /// When true, removes every rule currently in the scope (after any `add` is applied). Useful for clearing the location scope wholesale. - [JsonPropertyName("removeAll")] - public bool? RemoveAll { get; set; } + /// Provider-owned model display label, or the Auto routing label. Presentation only; modelName remains the tokenization identity. + [JsonPropertyName("displayModelName")] + public string? DisplayModelName { get; set; } - /// Whether the change applies to ephemeral session-scoped rules (cleared at session end) or to location-scoped rules persisted via the location-permissions config file. - [JsonPropertyName("scope")] - public PermissionsModifyRulesScope Scope { get; set; } + /// Advertised prompt allowance for the selected context tier, without adding output tokens. The denominator for context-usage displays. + [JsonPropertyName("limit")] + public long Limit { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Tokens consumed by MCP tool definitions (subset of toolDefinitionsTokens, excludes deferred tools). + [JsonPropertyName("mcpToolsTokens")] + public long McpToolsTokens { get; set; } -/// Indicates whether the operation succeeded. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsSetRequiredResult -{ - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } -} + /// The model used for token counting. + [JsonPropertyName("modelName")] + public string ModelName { get; set; } = string.Empty; -/// Toggles whether permission prompts should be bridged into session events for this client. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionsSetRequiredRequest -{ - /// Whether the client wants `permission.requested` events bridged from the session-owned permission service. CLI clients that render prompt UI set this to `true` for as long as their listener is mounted; headless callers leave it unset (the default is `false`). - [JsonPropertyName("required")] - public bool Required { get; set; } + /// Effective input budget: the selected tier's prompt allowance bounded by the combined context ceiling minus the requested output allowance. Uses DEFAULT_TOKEN_LIMIT when limits are unspecified. + [JsonPropertyName("promptTokenLimit")] + public long PromptTokenLimit { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Provider whose catalog supplies this context window. Omitted when provider identity is unavailable. + [JsonPropertyName("provider")] + public ModelProviderRef? Provider { get; set; } -/// Indicates whether the operation succeeded. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsResetSessionApprovalsResult -{ - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } -} + /// Tokens consumed by the system prompt. + [JsonPropertyName("systemTokens")] + public long SystemTokens { get; set; } -/// Clears session-scoped tool approvals and optionally clears location-scoped approvals and exact session-approved paths. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionsResetSessionApprovalsRequest -{ - /// Whether location-scoped approvals and exact session-approved paths are cleared too. Defaults to `true`. - [JsonPropertyName("includeLocation")] - public bool? IncludeLocation { get; set; } + /// Tokens consumed by tool definitions sent to the model (excludes deferred tools). + [JsonPropertyName("toolDefinitionsTokens")] + public long ToolDefinitionsTokens { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Sum of system, conversation and tool-definition tokens. + [JsonPropertyName("totalTokens")] + public long TotalTokens { get; set; } } -/// Indicates whether the operation succeeded. +/// Token breakdown for the session's current context window, or null if uninitialized. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsNotifyPromptShownResult +public sealed class MetadataContextInfoResult { - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Token breakdown for the current context window, or null if the session has not yet been initialized (no system prompt or tool metadata cached). + [JsonPropertyName("contextInfo")] + public MetadataContextInfoResultContextInfo? ContextInfo { get; set; } } -/// Notification payload describing the permission prompt that the client just rendered. +/// Model identifier and token limits used to compute the context-info breakdown. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionPromptShownNotification +internal sealed class MetadataContextInfoRequest { - /// Human-readable description of the prompt the user is being asked to approve. Used by the runtime to fire the registered `permission_prompt` notification hook (e.g. terminal bell, desktop notification). - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; + /// Requested output allowance to reserve against the combined context ceiling. Pass 0 to resolve the session's request cap, falling back to the model's advertised output limit. + [JsonPropertyName("outputTokenLimit")] + public long OutputTokenLimit { get; set; } + + /// Advertised prompt allowance. Pass 0 to resolve the selected model and context tier from the session. + [JsonPropertyName("promptTokenLimit")] + public long PromptTokenLimit { get; set; } + + /// Provider owning selectedModel. Omit to use the current provider for the current model, or deterministic legacy lookup for a different model. + [JsonPropertyName("providerId")] + public string? ProviderId { get; set; } + + /// Model identifier used for tokenization. Omit to use the session default. Used both for token counting and to compute display values. + [JsonPropertyName("selectedModel")] + public string? SelectedModel { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Snapshot of the session's recursive directory grants, exact session-approved paths, and primary working directory. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionPathsList +/// The six normalized `/context` header buckets, computed from the same tokenization as `entries` so the two never disagree. Convenience rollups: `freeSpace` and `buffer` describe window capacity rather than occupied context, so the values do not sum to `totalTokens`. +public sealed class MetadataContextAttributionResultContextAttributionCategories { - /// All directories currently allowed for tool access on this session. - [JsonPropertyName("directories")] - public IList Directories { get => field ??= []; set; } + /// Overlapping output reservation plus post-blocking-threshold buffer. + [JsonPropertyName("buffer")] + public long Buffer { get; set; } - /// The primary working directory for this session. - [JsonPropertyName("primary")] - public string Primary { get; set; } = string.Empty; + /// Custom-instructions tokens (0 when none are configured). + [JsonPropertyName("customInstructions")] + public long CustomInstructions { get; set; } - /// Exact paths approved for this session without recursively allowing their descendants. - [JsonPropertyName("sessionApprovedPaths")] - public IList? SessionApprovedPaths { get; set; } -} + /// Remaining unused window capacity (clamped at 0). + [JsonPropertyName("freeSpace")] + public long FreeSpace { get; set; } -/// No parameters; returns the session's recursive directory grants and exact session-approved paths. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionsPathsListRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// MCP tool-definition tokens. + [JsonPropertyName("mcpTools")] + public long McpTools { get; set; } -/// Indicates whether the operation succeeded. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsPathsAddResult -{ - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } -} + /// Conversation (user/assistant/tool) message tokens. + [JsonPropertyName("messages")] + public long Messages { get; set; } -/// Directory path to add to the session's allowed directories. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionPathsAddParams -{ - /// Directory to add to the allow-list. The runtime resolves and validates the path before adding, then loads conventional `.github/skills/` and `.github/agents/` definitions under it when their subsystem gates are enabled. Adding the directory is therefore also a trust decision for configuration stored there. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// System prompt tokens, excluding custom instructions. + [JsonPropertyName("systemPrompt")] + public long SystemPrompt { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Non-MCP tool-definition tokens. + [JsonPropertyName("systemTools")] + public long SystemTools { get; set; } } -/// Indicates whether the operation succeeded. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsPathsUpdatePrimaryResult +/// Successful compaction history for the session. +public sealed class MetadataContextAttributionResultContextAttributionCompactions { - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Number of successful compactions in this session. + [JsonPropertyName("count")] + public long Count { get; set; } } -/// Directory path to set as the session's new primary working directory. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionPathsUpdatePrimaryParams +/// RPC data type for MetadataContextAttributionResultContextAttributionEntry operations. +public sealed class MetadataContextAttributionResultContextAttributionEntry { - /// Directory to set as the new primary working directory for the session's permission policy. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Supplementary per-entry metadata (e.g. `messageCount`, `role`, `evictable`, `pluginSource`). Values are stringified; parse as needed and ignore unrecognized keys. + [JsonPropertyName("attributes")] + public IDictionary? Attributes { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Identifier for this entry, formed by joining its `kind` and source name (e.g. `tool:bash`, `skill:tmux`, `toolDefinition:bash`); unique within the snapshot. Use it to match the same entry across snapshots, to correlate with other APIs (skill/agent/MCP registries), and as the `parentId` target for nesting. Distinct from the human-facing `label`. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; -/// Indicates whether the supplied path is within the session's allowed directories. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionPathsAllowedCheckResult -{ - /// Whether the path is within the session's allowed directories. - [JsonPropertyName("allowed")] - public bool Allowed { get; set; } -} + /// Source category for this entry. Not a closed set — tolerate unknown values. Known values today: `skill`, `subagent`, `mcpServer`, `tool`, `system`, `toolDefinition`, `plugin`. + [JsonPropertyName("kind")] + public string Kind { get; set; } = string.Empty; -/// Path to evaluate against the session's allowed directories. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionPathsAllowedCheckParams -{ - /// Path to check against the session's allowed directories. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Human-readable display label, e.g. `bash` or `skill: tmux`. Presentation-only; may be localized/reformatted without notice — do not key off it. + [JsonPropertyName("label")] + public string Label { get; set; } = string.Empty; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Optional `id` of the parent entry: e.g. a `plugin` entry parenting its `skill`/`mcpServer` entries, or the `system` entry parenting `toolDefinition` entries. Omitted for top-level entries. + [JsonPropertyName("parentId")] + public string? ParentId { get; set; } -/// Indicates whether the supplied path is within the session's workspace directory. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionPathsWorkspaceCheckResult -{ - /// Whether the path is within the session workspace directory. - [JsonPropertyName("allowed")] - public bool Allowed { get; set; } + /// Token count currently in context attributable to this entry. + [JsonPropertyName("tokens")] + public long Tokens { get; set; } } -/// Path to evaluate against the session's workspace (primary) directory. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionPathsWorkspaceCheckParams +/// Per-source token attribution snapshot for the current context window. The heaviest individual messages are available separately via `metadata.getContextHeaviestMessages`. +public sealed class MetadataContextAttributionResultContextAttribution { - /// Path to check against the session workspace directory. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Output reservation overlapping the displayed prompt allowance plus the tokens past the effective input budget's buffer-exhaustion blocking threshold. Mirrors `SessionContextInfo.bufferTokens`. + [JsonPropertyName("bufferTokens")] + public long BufferTokens { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// The six normalized `/context` header buckets, computed from the same tokenization as `entries` so the two never disagree. Convenience rollups: `freeSpace` and `buffer` describe window capacity rather than occupied context, so the values do not sum to `totalTokens`. + [JsonPropertyName("categories")] + public MetadataContextAttributionResultContextAttributionCategories Categories { get => field ??= new(); set; } + + /// Successful compaction history for the session. + [JsonPropertyName("compactions")] + public MetadataContextAttributionResultContextAttributionCompactions Compactions { get => field ??= new(); set; } + + /// Token count at which background compaction starts. Mirrors `SessionContextInfo.compactionThreshold`. + [JsonPropertyName("compactionThreshold")] + public long CompactionThreshold { get; set; } + + /// Flat list of per-source attribution entries. Group by `kind` and render unrecognized kinds generically. Nesting and rollups are expressed via `parentId`. + [JsonPropertyName("entries")] + public IList Entries { get => field ??= []; set; } + + /// Advertised prompt allowance for the selected context tier: the denominator for context-usage displays and capacity for `categories.freeSpace` and `categories.buffer`. Mirrors `SessionContextInfo.limit`. + [JsonPropertyName("limit")] + public long Limit { get; set; } + + /// The concrete model id the entire breakdown was tokenized against (feeds the per-model token multiplier). Under `Auto` (Free/Student) this is the resolved model, not the literal `auto` sentinel, so totals are not undercounted. A single-model approximation of a potentially multi-model Auto session. + [JsonPropertyName("modelId")] + public string ModelId { get; set; } = string.Empty; + + /// How `modelId` was chosen. Not a closed set — tolerate unknown values. Known values today: `autoResolved` (the model Auto resolved to), `selected` (the user's explicitly selected model), `default` (a fallback before any model is known). + [JsonPropertyName("modelSource")] + public string ModelSource { get; set; } = string.Empty; + + /// Effective input budget after reserving requested output against the combined context ceiling. Mirrors `SessionContextInfo.promptTokenLimit`. + [JsonPropertyName("promptTokenLimit")] + public long PromptTokenLimit { get; set; } + + /// Total token count of the current context window the entries are measured against (system message + conversation messages + tool definitions — the same total reported by /context). Divide an entry's `tokens` by this to derive its share. + [JsonPropertyName("totalTokens")] + public long TotalTokens { get; set; } } -/// Resolved location-permissions key and type. +/// Per-source attribution breakdown for the session's current context window, or null if uninitialized. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionLocationResolveResult +public sealed class MetadataContextAttributionResult { - /// Location key used in the location-permissions store. - [JsonPropertyName("locationKey")] - public string LocationKey { get; set; } = string.Empty; - - /// Whether the location is a git repo or directory. - [JsonPropertyName("locationType")] - public PermissionLocationType LocationType { get; set; } + /// Per-source context-window attribution, or null if the session has not yet been initialized (no system prompt or tool metadata cached). + [JsonPropertyName("contextAttribution")] + public MetadataContextAttributionResultContextAttribution? ContextAttribution { get; set; } } -/// Working directory to resolve into a location-permissions key. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionLocationResolveParams +internal sealed class SessionMetadataGetContextAttributionRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// Working directory whose permission location should be resolved. - [JsonPropertyName("workingDirectory")] - public string WorkingDirectory { get; set; } = string.Empty; } -/// Summary of persisted location permissions applied to the session. +/// A single large message currently in context. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionLocationApplyResult +public sealed class ContextHeaviestMessage { - /// Number of persisted allowed directories added to the live path manager. - [JsonPropertyName("appliedDirectoryCount")] - public long AppliedDirectoryCount { get; set; } + /// Stable identifier for this message within the snapshot. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Number of location-scoped rules added to the live permission service. - [JsonPropertyName("appliedRuleCount")] - public long AppliedRuleCount { get; set; } + /// Human-readable source label, e.g. `tool: bash` or `skill: tmux`. Presentation-only. + [JsonPropertyName("label")] + public string Label { get; set; } = string.Empty; - /// Location-scoped rules applied to the live permission service. - [JsonPropertyName("appliedRules")] - public IList AppliedRules { get => field ??= []; set; } + /// Role of the chat message (`user`, `assistant`, or `tool`). + [JsonPropertyName("role")] + public string Role { get; set; } = string.Empty; - /// Whether a different location was applied since the previous apply call. - [JsonPropertyName("changed")] - public bool Changed { get; set; } + /// Token count currently in context for this individual message. + [JsonPropertyName("tokens")] + public long Tokens { get; set; } +} - /// Location key used in the location-permissions store. - [JsonPropertyName("locationKey")] - public string LocationKey { get; set; } = string.Empty; +/// The heaviest individual messages in the session's context window, most-expensive first. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class MetadataContextHeaviestMessagesResult +{ + /// Heaviest messages, most-expensive first. + [JsonPropertyName("messages")] + public IList Messages { get => field ??= []; set; } - /// Whether the location is a git repo or directory. - [JsonPropertyName("locationType")] - public PermissionLocationType LocationType { get; set; } + /// Total token count of the current context window, so callers can compute each message's share without a second call. + [JsonPropertyName("totalTokens")] + public long TotalTokens { get; set; } } -/// Working directory to load persisted location permissions for. +/// Parameters for the heaviest-messages query. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionLocationApplyParams +internal sealed class MetadataContextHeaviestMessagesRequest { + /// Maximum number of messages to return, most-expensive first. Omit for the server default. + [JsonPropertyName("limit")] + public long? Limit { get; set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// Working directory whose persisted location permissions should be applied. - [JsonPropertyName("workingDirectory")] - public string WorkingDirectory { get; set; } = string.Empty; -} - -/// Indicates whether the operation succeeded. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsLocationsAddToolApprovalResult -{ - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } } -/// Tool approval to persist and apply. -/// Polymorphic base type discriminated by kind. +/// Notify the session that its working directory context has changed. Emits a `session.context_changed` event so consumers (telemetry, OTel tracker, ACP, the timeline UI) can react. Use this when the host has detected a cwd/branch/repo change outside the session's normal lifecycle (e.g., after a shell command in interactive mode). For a local session, a report whose `cwd` diverges from the session's current working directory is ignored (the call still succeeds but records nothing and emits no event); move a local session's working directory via `metadata.setWorkingDirectory` instead. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsCommands), "commands")] -[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsRead), "read")] -[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsWrite), "write")] -[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsMcp), "mcp")] -[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsMcpSampling), "mcp-sampling")] -[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsMemory), "memory")] -[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsCustomTool), "custom-tool")] -[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsExtensionManagement), "extension-management")] -[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsWorkflow), "workflow")] -[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsExtensionPermissionAccess), "extension-permission-access")] -[JsonDerivedType(typeof(PermissionsLocationsAddToolApprovalDetailsExtensionEnvAccess), "extension-env-access")] -public partial class PermissionsLocationsAddToolApprovalDetails +public sealed class MetadataRecordContextChangeResult { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; } - -/// Location-persisted tool approval details for specific command identifiers. -/// The commands variant of . +/// Updated working-directory/git context to record on the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionsLocationsAddToolApprovalDetailsCommands : PermissionsLocationsAddToolApprovalDetails +internal sealed class MetadataRecordContextChangeRequest { - /// - [JsonIgnore] - public override string Kind => "commands"; + /// Updated working directory and git context. Emitted as the new payload of `session.context_changed`. + [JsonPropertyName("context")] + public SessionWorkingDirectoryContext Context { get => field ??= new(); set; } - /// Command identifiers covered by this approval. - [JsonPropertyName("commandIdentifiers")] - public required IList CommandIdentifiers { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Location-persisted tool approval details for read-only filesystem operations. -/// The read variant of . +/// Update the session's working directory. Used by the host when the user explicitly changes cwd (e.g., the `/cd` slash command). The host is responsible for any related side-effects (file index, etc.); it does NOT change the process working directory (a session's cwd is per-session, not process-global). For local sessions the runtime validates the target first (an absolute path that exists on disk) and re-bases the permission primary directory; a rejected validation fails the call before anything is mutated, persisted, or emitted. Location-scoped permission rules are then re-keyed to the new directory (best-effort). Remote sessions only record the path. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionsLocationsAddToolApprovalDetailsRead : PermissionsLocationsAddToolApprovalDetails +public sealed class MetadataSetWorkingDirectoryResult { - /// - [JsonIgnore] - public override string Kind => "read"; + /// Working directory after the update. + [JsonPropertyName("workingDirectory")] + public string WorkingDirectory { get; set; } = string.Empty; } -/// Location-persisted tool approval details for filesystem write operations. -/// The write variant of . +/// Absolute path to set as the session's new working directory. For local sessions the path must be absolute and exist on disk: it is validated before any session state changes, and a failing validation rejects the call with nothing mutated, persisted, or emitted. Remote sessions record the path as-is. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionsLocationsAddToolApprovalDetailsWrite : PermissionsLocationsAddToolApprovalDetails +internal sealed class MetadataSetWorkingDirectoryRequest { - /// - [JsonIgnore] - public override string Kind => "write"; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Absolute path to set as the session's working directory. The runtime updates the session's recorded cwd so subsequent operations (shell tools, file lookups, telemetry) anchor to it. + [JsonPropertyName("workingDirectory")] + public string WorkingDirectory { get; set; } = string.Empty; } -/// Location-persisted tool approval details for an MCP server tool, or all tools when `toolName` is null. -/// The mcp variant of . +/// Re-tokenize the session's existing messages against `modelId` and return the token totals. Useful for hosts that want an initial estimate of context usage on session resume, before the next agent turn fires `session.context_info_changed` events. Returns zeros for an empty session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionsLocationsAddToolApprovalDetailsMcp : PermissionsLocationsAddToolApprovalDetails +public sealed class MetadataRecomputeContextTokensResult { - /// - [JsonIgnore] - public override string Kind => "mcp"; + /// Tokens contributed by user/assistant/tool messages (excludes system/developer prompts). + [JsonPropertyName("messagesTokenCount")] + public long MessagesTokenCount { get; set; } - /// MCP server name. - [JsonPropertyName("serverName")] - public required string ServerName { get; set; } + /// Tokens contributed by system/developer prompt snapshots. + [JsonPropertyName("systemTokenCount")] + public long SystemTokenCount { get; set; } - /// MCP tool name, or null to cover every tool on the server. - [JsonPropertyName("toolName")] - public string? ToolName { get; set; } + /// Sum of tokens across chat-context and system-context messages currently held by the session. + [JsonPropertyName("totalTokens")] + public long TotalTokens { get; set; } } -/// Location-persisted tool approval details for MCP sampling requests from a server. -/// The mcp-sampling variant of . +/// Model identifier to use when re-tokenizing the session's existing messages. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionsLocationsAddToolApprovalDetailsMcpSampling : PermissionsLocationsAddToolApprovalDetails +internal sealed class MetadataRecomputeContextTokensRequest { - /// - [JsonIgnore] - public override string Kind => "mcp-sampling"; + /// Model identifier used for tokenization. The runtime token-counts both chat-context and system-context messages against this model. + [JsonPropertyName("modelId")] + public string ModelId { get; set; } = string.Empty; - /// MCP server name. - [JsonPropertyName("serverName")] - public required string ServerName { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Location-persisted tool approval details for writes to long-term memory. -/// The memory variant of . +/// Availability of built-in job tools surfaced to boundary consumers. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionsLocationsAddToolApprovalDetailsMemory : PermissionsLocationsAddToolApprovalDetails +public sealed class SessionSettingsBuiltInToolAvailabilitySnapshot { - /// - [JsonIgnore] - public override string Kind => "memory"; + /// Whether the create-pull-request tool is available. + [JsonPropertyName("createPullRequest")] + public bool? CreatePullRequest { get; set; } + + /// Whether the report-progress tool is available. + [JsonPropertyName("reportProgress")] + public bool? ReportProgress { get; set; } } -/// Location-persisted tool approval details for a custom tool, keyed by tool name. -/// The custom-tool variant of . +/// Redacted job settings for a session. The job nonce is excluded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionsLocationsAddToolApprovalDetailsCustomTool : PermissionsLocationsAddToolApprovalDetails +public sealed class SessionSettingsJobSnapshot { - /// - [JsonIgnore] - public override string Kind => "custom-tool"; + /// Availability of job-specific built-in tools. + [JsonPropertyName("builtInToolAvailability")] + public SessionSettingsBuiltInToolAvailabilitySnapshot? BuiltInToolAvailability { get; set; } - /// Custom tool name. - [JsonPropertyName("toolName")] - public required string ToolName { get; set; } + /// GitHub Actions event type for the job. + [JsonPropertyName("eventType")] + public string? EventType { get; set; } + + /// Whether this is the workflow's trigger job. + [JsonPropertyName("isTriggerJob")] + public bool? IsTriggerJob { get; set; } } -/// Location-persisted tool approval details for extension-management operations, optionally narrowed by operation. -/// The extension-management variant of . +/// Redacted model routing settings for a session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionsLocationsAddToolApprovalDetailsExtensionManagement : PermissionsLocationsAddToolApprovalDetails +public sealed class SessionSettingsModelSnapshot { - /// - [JsonIgnore] - public override string Kind => "extension-management"; + /// Agent service callback URL for job and progress updates. + [JsonPropertyName("callbackUrl")] + public string? CallbackUrl { get; set; } - /// Optional operation identifier; when omitted, the approval covers all extension management operations. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("operation")] - public string? Operation { get; set; } -} + /// Default reasoning effort for the selected model. + [JsonPropertyName("defaultReasoningEffort")] + public string? DefaultReasoningEffort { get; set; } -/// Location-persisted workflow approval, optionally narrowed by approval key. -/// The workflow variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionsLocationsAddToolApprovalDetailsWorkflow : PermissionsLocationsAddToolApprovalDetails -{ - /// - [JsonIgnore] - public override string Kind => "workflow"; + /// Agent job identifier for the session. + [JsonPropertyName("instanceId")] + public string? InstanceId { get; set; } - /// Optional workflow operation name or canonical approval key; when omitted, the approval covers all workflow operations. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("approvalKey")] - public string? ApprovalKey { get; set; } + /// Selected model identifier. + [JsonPropertyName("model")] + public string? Model { get; set; } } -/// Location-persisted tool approval details for an extension's permission-gated capability access, keyed by extension name. -/// The extension-permission-access variant of . +/// Online-evaluation settings safe to expose across the SDK boundary. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionsLocationsAddToolApprovalDetailsExtensionPermissionAccess : PermissionsLocationsAddToolApprovalDetails +public sealed class SessionSettingsOnlineEvaluationSnapshot { - /// - [JsonIgnore] - public override string Kind => "extension-permission-access"; + /// Whether online evaluation is disabled. + [JsonPropertyName("disableOnlineEvaluation")] + public bool? DisableOnlineEvaluation { get; set; } - /// Extension name. - [JsonPropertyName("extensionName")] - public required string ExtensionName { get; set; } + /// Whether online-evaluation output-file generation is enabled. + [JsonPropertyName("enableOnlineEvaluationOutputFile")] + public bool? EnableOnlineEvaluationOutputFile { get; set; } } -/// Location-persisted tool approval details for an extension's access to sensitive environment variables, keyed by extension name and the exact set of variable names. -/// The extension-env-access variant of . +/// Redacted repository and GitHub host settings for a session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class PermissionsLocationsAddToolApprovalDetailsExtensionEnvAccess : PermissionsLocationsAddToolApprovalDetails +public sealed class SessionSettingsRepoSnapshot { - /// - [JsonIgnore] - public override string Kind => "extension-env-access"; + /// Checked-out repository branch. + [JsonPropertyName("branch")] + public string? Branch { get; set; } - /// Names of the sensitive environment variables this approval covers. Values are never persisted. - [JsonPropertyName("environmentVariables")] - public required IList EnvironmentVariables { get; set; } + /// Checked-out commit SHA. + [JsonPropertyName("commit")] + public string? Commit { get; set; } - /// Extension name. - [JsonPropertyName("extensionName")] - public required string ExtensionName { get; set; } -} + /// GitHub server host name. + [JsonPropertyName("host")] + public string? Host { get; set; } -/// Location-scoped tool approval to persist. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionLocationAddToolApprovalParams -{ - /// Tool approval to persist and apply. - [JsonPropertyName("approval")] - public PermissionsLocationsAddToolApprovalDetails Approval { get => field ??= new(); set; } + /// Protocol used to access the GitHub host. + [JsonPropertyName("hostProtocol")] + public string? HostProtocol { get; set; } - /// Location key (git root or cwd) to persist the approval to. - [JsonPropertyName("locationKey")] - public string LocationKey { get; set; } = string.Empty; + /// GitHub repository database ID. + [JsonPropertyName("id")] + public double? Id { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Repository name. + [JsonPropertyName("name")] + public string? Name { get; set; } -/// Folder trust check result. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class FolderTrustCheckResult -{ - /// Whether the folder is trusted. - [JsonPropertyName("trusted")] - public bool Trusted { get; set; } + /// GitHub repository owner database ID. + [JsonPropertyName("ownerId")] + public double? OwnerId { get; set; } + + /// Repository owner login. + [JsonPropertyName("ownerName")] + public string? OwnerName { get; set; } + + /// Number of commits in the pull request. + [JsonPropertyName("prCommitCount")] + public double? PrCommitCount { get; set; } + + /// Whether the repository is writable. + [JsonPropertyName("readWrite")] + public bool? ReadWrite { get; set; } + + /// GitHub secret-scanning service URL. + [JsonPropertyName("secretScanningUrl")] + public string? SecretScanningUrl { get; set; } + + /// GitHub server base URL. + [JsonPropertyName("serverUrl")] + public string? ServerUrl { get; set; } } -/// Folder path to check for trust. +/// Redacted validation and memory-tool settings for a session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class FolderTrustCheckParams +public sealed class SessionSettingsValidationSnapshot { - /// Folder path to check. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Whether advisory validation is enabled. + [JsonPropertyName("advisoryEnabled")] + public bool? AdvisoryEnabled { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether CodeQL validation is enabled. + [JsonPropertyName("codeqlEnabled")] + public bool? CodeqlEnabled { get; set; } + + /// Whether code-review validation is enabled. + [JsonPropertyName("codeReviewEnabled")] + public bool? CodeReviewEnabled { get; set; } + + /// Model used for code-review validation. + [JsonPropertyName("codeReviewModel")] + public string? CodeReviewModel { get; set; } + + /// Dependabot validation timeout budget in seconds. + [JsonPropertyName("dependabotTimeout")] + public double? DependabotTimeout { get; set; } + + /// Whether the memory-store tool is enabled. + [JsonPropertyName("memoryStoreEnabled")] + public bool? MemoryStoreEnabled { get; set; } + + /// Whether the memory-vote tool is enabled. + [JsonPropertyName("memoryVoteEnabled")] + public bool? MemoryVoteEnabled { get; set; } + + /// Whether secret-scanning validation is enabled. + [JsonPropertyName("secretScanningEnabled")] + public bool? SecretScanningEnabled { get; set; } + + /// General validation timeout budget in seconds. + [JsonPropertyName("timeout")] + public double? Timeout { get; set; } } -/// Indicates whether the operation succeeded. +/// Redacted, serializable view of session runtime settings for SDK boundary consumers. Secrets and raw feature flags are intentionally excluded. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsFolderTrustAddTrustedResult +internal sealed class SessionSettingsSnapshot { - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Name of the SDK client that created the session. + [JsonPropertyName("clientName")] + public string? ClientName { get; set; } + + /// Redacted job settings. + [JsonPropertyName("job")] + public SessionSettingsJobSnapshot Job { get => field ??= new(); set; } + + /// Redacted model routing settings. + [JsonPropertyName("model")] + public SessionSettingsModelSnapshot Model { get => field ??= new(); set; } + + /// Online-evaluation settings safe for SDK consumers. + [JsonPropertyName("onlineEvaluation")] + public SessionSettingsOnlineEvaluationSnapshot OnlineEvaluation { get => field ??= new(); set; } + + /// Redacted repository and host settings. + [JsonPropertyName("repo")] + public SessionSettingsRepoSnapshot Repo { get => field ??= new(); set; } + + /// Session start time as Unix epoch milliseconds. + [JsonPropertyName("startTimeMs")] + public double? StartTimeMs { get; set; } + + /// Session timeout in milliseconds. + [JsonPropertyName("timeoutMs")] + public double? TimeoutMs { get; set; } + + /// Redacted validation and memory-tool settings. + [JsonPropertyName("validation")] + public SessionSettingsValidationSnapshot Validation { get => field ??= new(); set; } + + /// Agent runtime version selector copied from the session settings, such as `latest` or a runtime release identifier. + [JsonPropertyName("version")] + public string? Version { get; set; } } -/// Folder path to add to trusted folders. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class FolderTrustAddParams +internal sealed class SessionSettingsSnapshotRequest { - /// Folder path to mark as trusted. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the operation succeeded. +/// Result of evaluating a Rust-owned settings predicate. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class PermissionsUrlsSetUnrestrictedModeResult +internal sealed class SessionSettingsEvaluatePredicateResult { - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Whether the named settings predicate evaluated to enabled. + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } } -/// Whether the URL-permission policy should run in unrestricted mode. +/// Named Rust-owned settings predicate to evaluate for this session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class PermissionUrlsSetUnrestrictedModeParams +internal sealed class SessionSettingsEvaluatePredicateRequest { - /// Whether to allow access to all URLs without prompting. Toggles the runtime's URL-permission policy in place. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// Predicate name. The runtime owns the raw feature-flag names and composition logic. + [JsonPropertyName("name")] + public SessionSettingsPredicateName Name { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Tool name for tool-scoped predicates such as trivial-change handling. + [JsonPropertyName("toolName")] + public string? ToolName { get; set; } } -/// The repository the remote session targets. +/// Content-exclusion decision for one requested path. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MetadataSnapshotRemoteMetadataRepository +public sealed class ContentExclusionPathCheck { - /// The branch the remote session is operating on. - [JsonPropertyName("branch")] - public string Branch { get; set; } = string.Empty; - - /// The GitHub repository name (without owner). - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Whether the session's complete content-exclusion policy excludes the path. + [JsonPropertyName("excluded")] + public bool Excluded { get; set; } - /// The GitHub owner (user or organization) of the target repository. - [JsonPropertyName("owner")] - public string Owner { get; set; } = string.Empty; + /// The path supplied by the caller. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; } -/// Remote-session-specific metadata. Populated only when `isRemote` is true. Fields are immutable for the lifetime of the session. +/// Batch content-exclusion result. Callers must fail closed when policy evaluation is unavailable. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MetadataSnapshotRemoteMetadata +public sealed class ContentExclusionCheckPathsResult { - /// The pull request number the remote session is associated with, if any. - [JsonPropertyName("pullRequestNumber")] - public long? PullRequestNumber { get; set; } - - /// The repository the remote session targets. - [JsonPropertyName("repository")] - public MetadataSnapshotRemoteMetadataRepository Repository { get => field ??= new(); set; } - - /// The original resource identifier (task ID or PR node ID), preserved across event-replay reconstructions. Falls back to `sessionId` when absent. - [JsonPropertyName("resourceId")] - public string? ResourceId { get; set; } + /// Whether the session's policy service was available for the complete batch. When false, checks is empty and callers must treat every requested path as excluded. + [JsonPropertyName("available")] + public bool Available { get; set; } - /// Whether the remote task originated from Copilot Coding Agent (cca) or a CLI `--remote` invocation. - [JsonPropertyName("taskType")] - public MetadataSnapshotRemoteMetadataTaskType? TaskType { get; set; } + /// Per-path decisions in request order. Empty when available is false. + [JsonPropertyName("checks")] + public IList Checks { get => field ??= []; set; } } -/// Public-facing projection of workspace metadata for SDK / TUI consumers. -public sealed class SessionMetadataSnapshotWorkspace +/// Local file system absolute paths within the session working directory to check against its content-exclusion policy. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ContentExclusionCheckPathsRequest { - /// Branch checked out at session start, if any. - [JsonPropertyName("branch")] - public string? Branch { get; set; } - - /// ISO 8601 timestamp when the workspace was created. - [JsonPropertyName("created_at")] - public DateTimeOffset? CreatedAt { get; set; } - - /// Current working directory at session start. - [JsonPropertyName("cwd")] - public string? Cwd { get; set; } - - /// Resolved git root for cwd, if any. - [JsonPropertyName("git_root")] - public string? GitRoot { get; set; } - - /// Repository host type, if known. - [JsonPropertyName("host_type")] - public WorkspaceSummaryHostType? HostType { get; set; } - - /// Workspace identifier (1:1 with sessionId). - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - - /// Display name for the session, if set. - [JsonPropertyName("name")] - public string? Name { get; set; } - - /// Repository identifier in 'owner/repo' or 'org/project/repo' format, if any. - [JsonPropertyName("repository")] - public string? Repository { get; set; } - - /// ISO 8601 timestamp when the workspace was last updated. - [JsonPropertyName("updated_at")] - public DateTimeOffset? UpdatedAt { get; set; } + /// Local file system absolute paths within the session working directory to check. Results are returned in the same order, including duplicates. + [JsonPropertyName("paths")] + public IList Paths { get => field ??= []; set; } - /// Whether the display name was explicitly set by the user. - [JsonPropertyName("user_named")] - public bool? UserNamed { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Point-in-time snapshot of slow-changing session identifier and state fields. +/// Identifier of the spawned shell process, usable with shell.kill while the process is running. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionMetadataSnapshot +public sealed class ShellExecResult { - /// True when the session was detected to be in use by another process at construction time. Local consumers may surface a confirmation prompt before fully attaching. Always false for new sessions. - [JsonPropertyName("alreadyInUse")] - public bool AlreadyInUse { get; set; } - - /// Runtime client name associated with the session (telemetry identifier). - [JsonPropertyName("clientName")] - public string? ClientName { get; set; } - - /// The current agent mode for this session (e.g., 'interactive', 'plan', 'autopilot'). - [JsonPropertyName("currentMode")] - public MetadataSnapshotCurrentMode CurrentMode { get; set; } + /// Identifier usable with shell.kill while the process is running. + [JsonPropertyName("processId")] + public string ProcessId { get; set; } = string.Empty; +} - /// Live indexed-search state for this session activation. Omitted by runtimes that do not expose indexed-search status; absence does not indicate enablement. - [JsonPropertyName("indexedSearch")] - public IndexedSearchState? IndexedSearch { get; set; } +/// Shell command to run, with optional working directory and timeout in milliseconds. Spawn failures return an RPC error. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ShellExecRequest +{ + /// Shell command to execute. + [JsonPropertyName("command")] + public string Command { get; set; } = string.Empty; - /// User-provided name supplied at session construction (via `--name`), if any. Immutable after construction. - [JsonPropertyName("initialName")] - public string? InitialName { get; set; } + /// Working directory (defaults to session working directory). + [JsonPropertyName("cwd")] + public string? Cwd { get; set; } - /// Whether this is a remote session (i.e., one whose runtime executes elsewhere and is steered through this process). - [JsonPropertyName("isRemote")] - public bool IsRemote { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; - /// ISO 8601 timestamp of when the session's persisted state was last modified on disk. For new sessions, equals startTime. For resumed sessions, reflects the previous modification time at construction. - [JsonPropertyName("modifiedTime")] - public DateTimeOffset ModifiedTime { get; set; } + /// Timeout in milliseconds (default: 30000). + [JsonConverter(typeof(MillisecondsTimeSpanConverter))] + [JsonPropertyName("timeout")] + public TimeSpan? Timeout { get; set; } +} - /// Remote-session-specific metadata. Populated only when `isRemote` is true. Fields are immutable for the lifetime of the session. - [JsonPropertyName("remoteMetadata")] - public MetadataSnapshotRemoteMetadata? RemoteMetadata { get; set; } +/// Indicates whether the signal was delivered; false if the process was unknown or already exited. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ShellKillResult +{ + /// Whether the signal was sent successfully. + [JsonPropertyName("killed")] + public bool Killed { get; set; } +} - /// Currently selected model identifier, if any. - [JsonPropertyName("selectedModel")] - public string? SelectedModel { get; set; } +/// Identifier of a process previously returned by "shell.exec" and the signal to send. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ShellKillRequest +{ + /// Process identifier returned by shell.exec. + [JsonPropertyName("processId")] + public string ProcessId { get; set; } = string.Empty; - /// The unique identifier of the session. + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - /// Current session limits, or null when no limits are active. - [JsonPropertyName("sessionLimits")] - public SessionLimitsConfig? SessionLimits { get; set; } + /// Signal to send (default: SIGTERM). + [JsonPropertyName("signal")] + public ShellKillSignal? Signal { get; set; } +} - /// ISO 8601 timestamp of when the session started. - [JsonPropertyName("startTime")] - public DateTimeOffset StartTime { get; set; } +/// Result of a user-requested shell command. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class UserRequestedShellCommandResult +{ + /// Error output when the execution failed. + [JsonPropertyName("error")] + public string? Error { get; set; } - /// Short human-readable summary of the session, if known. Omitted when no summary has been generated. - [JsonPropertyName("summary")] - public string? Summary { get; set; } + /// Process exit code, when available. + [JsonPropertyName("exitCode")] + public long? ExitCode { get; set; } - /// Absolute path to the session's current working directory. - [JsonPropertyName("workingDirectory")] - public string WorkingDirectory { get; set; } = string.Empty; + /// Captured command output. + [JsonPropertyName("output")] + public string Output { get; set; } = string.Empty; - /// Public-facing workspace metadata for this session, or null if the session has no associated workspace. Excludes runtime-internal fields (GitHub IDs, summary count, internal flags). - [JsonPropertyName("workspace")] - public SessionMetadataSnapshotWorkspace? Workspace { get; set; } + /// Whether the command completed successfully. + [JsonPropertyName("success")] + public bool Success { get; set; } - /// Absolute path to the session's workspace directory on disk, or null if the session has no associated workspace. - [JsonPropertyName("workspacePath")] - public string? WorkspacePath { get; set; } + /// Tool call id emitted for the shell execution. + [JsonPropertyName("toolCallId")] + public string ToolCallId { get; set; } = string.Empty; } -/// Identifies the target session. +/// User-requested shell command and cancellation handle. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMetadataSnapshotRequest +internal sealed class ShellExecuteUserRequestedRequest { + /// Shell command to execute. + [JsonPropertyName("command")] + public string Command { get; set; } = string.Empty; + + /// Caller-provided cancellation handle for this execution. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Identifies the target session. +/// Cancellation result for a user-requested shell command. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMetadataGetClientMetadataRequest +public sealed class CancelUserRequestedShellCommandResult +{ + /// Whether an in-flight execution was found and signalled to cancel. + [JsonPropertyName("cancelled")] + public bool Cancelled { get; set; } +} + +/// User-requested shell execution cancellation handle. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class ShellCancelUserRequestedRequest { + /// Request ID previously passed to executeUserRequested. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Atomic patch for client-owned session metadata. Operations apply in clear, remove, then set order. The resulting bag must satisfy the ClientMetadata entry and serialized-size limits. Local storage coordinates concurrent runtime processes; custom SessionFs providers must serialize writers that access the same session from multiple processes. +/// Post-compaction context window usage breakdown. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class MetadataUpdateClientMetadataRequest +public sealed class HistoryCompactContextWindow { - /// Remove every existing client metadata entry before applying remove and set. Defaults to false. - [JsonPropertyName("clear")] - public bool? Clear { get; set; } + /// Token count from non-system messages (user, assistant, tool). + [JsonPropertyName("conversationTokens")] + public long? ConversationTokens { get; set; } - /// Case-sensitive keys to remove. Missing keys are ignored. Each key must be non-empty, at most 256 UTF-8 bytes, and outside the reserved `copilot/` and `github/` namespaces. - [JsonPropertyName("remove")] - public IList? Remove { get; set; } + /// Current total tokens in the context window (system + conversation + tool definitions). + [JsonPropertyName("currentTokens")] + public long CurrentTokens { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Current number of messages in the conversation. + [JsonPropertyName("messagesLength")] + public long MessagesLength { get; set; } - /// String entries to add or replace. Set wins when a key also appears in remove. Each key must be non-empty, at most 256 UTF-8 bytes, and outside the reserved `copilot/` and `github/` namespaces. Each value may contain at most 16 KiB of UTF-8 data. - [JsonPropertyName("set")] - public IDictionary? Set { get; set; } + /// Token count from system message(s). + [JsonPropertyName("systemTokens")] + public long? SystemTokens { get; set; } + + /// Maximum token count for the model's context window. + [JsonPropertyName("tokenLimit")] + public long TokenLimit { get; set; } + + /// Token count from tool definitions. + [JsonPropertyName("toolDefinitionsTokens")] + public long? ToolDefinitionsTokens { get; set; } } -/// Indicates whether the local session is currently processing a turn or background continuation. +/// Compaction outcome with the number of tokens and messages removed, summary text, and the resulting context window breakdown. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MetadataIsProcessingResult +public sealed class HistoryCompactResult { - /// Whether the session is currently processing user/agent messages. False for non-local sessions (which don't run a local agentic loop). Reflects an in-flight turn or background continuation. - [JsonPropertyName("processing")] - public bool Processing { get; set; } + /// Post-compaction context window usage breakdown. + [JsonPropertyName("contextWindow")] + public HistoryCompactContextWindow? ContextWindow { get; set; } + + /// Number of messages removed during compaction. + [JsonPropertyName("messagesRemoved")] + public long MessagesRemoved { get; set; } + + /// Whether compaction completed successfully. + [JsonPropertyName("success")] + public bool Success { get; set; } + + /// Summary text produced by compaction. Omitted when compaction did not produce a summary (e.g. failure path). + [JsonPropertyName("summaryContent")] + public string? SummaryContent { get; set; } + + /// Number of tokens freed by compaction. + [JsonPropertyName("tokensRemoved")] + public long TokensRemoved { get; set; } } -/// Identifies the target session. +/// RPC data type for SessionHistoryCompact operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMetadataIsProcessingRequest +public sealed class SessionHistoryCompactRequest +{ + /// Optional user-provided instructions to focus the compaction summary. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(4000)] + [JsonPropertyName("customInstructions")] + public string? CustomInstructions { get; set; } + + /// Context window token limit this compaction is targeting, recorded as the `tokenLimit` on the persisted `session.compaction_start` / `session.compaction_complete` events. Set it when the compaction targets a window other than the compacting model's own, e.g. switching to a model with a smaller context window: the compaction still runs on the current model, so the limit that motivated it would otherwise be lost. When absent, the events record the compacting model's own resolved limit. Attribution metadata only - it does not change how much the compaction removes. + [JsonPropertyName("tokenLimit")] + public long? TokenLimit { get; set; } + + /// What initiated this compaction request, recorded as the `trigger` on the persisted `session.compaction_start` / `session.compaction_complete` events. When absent, the compaction is persisted without trigger attribution (initiator unknown). + [JsonPropertyName("trigger")] + public SessionHistoryCompactRequestTrigger? Trigger { get; set; } +} + +/// RPC data type for SessionHistoryCompactRequestWithSession operations. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionHistoryCompactRequestWithSession { + /// Optional user-provided instructions to focus the compaction summary. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(4000)] + [JsonPropertyName("customInstructions")] + public string? CustomInstructions { get; set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Context window token limit this compaction is targeting, recorded as the `tokenLimit` on the persisted `session.compaction_start` / `session.compaction_complete` events. Set it when the compaction targets a window other than the compacting model's own, e.g. switching to a model with a smaller context window: the compaction still runs on the current model, so the limit that motivated it would otherwise be lost. When absent, the events record the compacting model's own resolved limit. Attribution metadata only - it does not change how much the compaction removes. + [JsonPropertyName("tokenLimit")] + public long? TokenLimit { get; set; } + + /// What initiated this compaction request, recorded as the `trigger` on the persisted `session.compaction_start` / `session.compaction_complete` events. When absent, the compaction is persisted without trigger attribution (initiator unknown). + [JsonPropertyName("trigger")] + public SessionHistoryCompactRequestTrigger? Trigger { get; set; } } -/// Current activity flags for the session. +/// Number of events that were removed by the truncation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionActivity +public sealed class HistoryTruncateResult { - /// Whether an in-flight operation can currently be aborted. - [JsonPropertyName("abortable")] - public bool Abortable { get; set; } + /// Failure detail when checkpointCleanupFailed is true. + [JsonPropertyName("checkpointCleanupError")] + public string? CheckpointCleanupError { get; set; } - /// Whether the session currently has active work, including running turns or tasks. - [JsonPropertyName("hasActiveWork")] - public bool HasActiveWork { get; set; } + /// True when conversation truncation succeeded but post-truncation workspace checkpoint cleanup failed. History is already truncated; callers may still prune snapshots but should report a checkpoint-cleanup rather than a truncation failure. + [JsonPropertyName("checkpointCleanupFailed")] + public bool? CheckpointCleanupFailed { get; set; } + + /// Number of events that were removed. + [JsonPropertyName("eventsRemoved")] + public long EventsRemoved { get; set; } } -/// Identifies the target session. +/// Identifier of the event to truncate to; this event and all later events are removed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMetadataActivityRequest +internal sealed class HistoryTruncateRequest { + /// Event ID to truncate to. This event and all events after it are removed from the session. + [JsonPropertyName("eventId")] + public string EventId { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Token-usage breakdown for the session's current context window. -public sealed class MetadataContextInfoResultContextInfo +/// A root user turn that the session can rewind to. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class HistoryRewindPoint { - /// Output reservation overlapping the displayed prompt allowance plus tokens after the effective input budget's buffer-exhaustion blocking threshold (default 95%). - [JsonPropertyName("bufferTokens")] - public long BufferTokens { get; set; } + /// Whether at least one file in this turn or a later turn can be restored. + [JsonPropertyName("canRestoreFiles")] + public bool CanRestoreFiles { get; set; } - /// Token count at which background compaction starts (configurable percentage of promptTokenLimit). - [JsonPropertyName("compactionThreshold")] - public long CompactionThreshold { get; set; } + /// ID of the user.message event that begins the discarded suffix. + [JsonPropertyName("eventId")] + public string EventId { get; set; } = string.Empty; - /// Tokens consumed by user/assistant/tool messages. - [JsonPropertyName("conversationTokens")] - public long ConversationTokens { get; set; } + /// Number of unique files in this turn and all later turns that have captured changes. + [JsonPropertyName("fileCount")] + public long FileCount { get; set; } - /// Provider-owned model display label, or the Auto routing label. Presentation only; modelName remains the tokenization identity. - [JsonPropertyName("displayModelName")] - public string? DisplayModelName { get; set; } + /// Whether this turn was an automatically injected autopilot continuation. + [JsonPropertyName("isAutopilotContinuation")] + public bool IsAutopilotContinuation { get; set; } - /// Advertised prompt allowance for the selected context tier, without adding output tokens. The denominator for context-usage displays. - [JsonPropertyName("limit")] - public long Limit { get; set; } + /// Lines added by this turn's captured file changes. + [JsonPropertyName("linesAdded")] + public long LinesAdded { get; set; } - /// Tokens consumed by MCP tool definitions (subset of toolDefinitionsTokens, excludes deferred tools). - [JsonPropertyName("mcpToolsTokens")] - public long McpToolsTokens { get; set; } + /// Lines removed by this turn's captured file changes. + [JsonPropertyName("linesRemoved")] + public long LinesRemoved { get; set; } - /// The model used for token counting. - [JsonPropertyName("modelName")] - public string ModelName { get; set; } = string.Empty; + /// ISO timestamp of the user turn. + [JsonPropertyName("timestamp")] + public string Timestamp { get; set; } = string.Empty; - /// Effective input budget: the selected tier's prompt allowance bounded by the combined context ceiling minus the requested output allowance. Uses DEFAULT_TOKEN_LIMIT when limits are unspecified. - [JsonPropertyName("promptTokenLimit")] - public long PromptTokenLimit { get; set; } + /// Whether this turn itself captured any file changes. + [JsonPropertyName("turnChangedFiles")] + public bool TurnChangedFiles { get; set; } - /// Provider whose catalog supplies this context window. Omitted when provider identity is unavailable. - [JsonPropertyName("provider")] - public ModelProviderRef? Provider { get; set; } + /// User-visible message text for the turn. + [JsonPropertyName("userMessage")] + public string UserMessage { get; set; } = string.Empty; +} - /// Tokens consumed by the system prompt. - [JsonPropertyName("systemTokens")] - public long SystemTokens { get; set; } +/// Rewind points and file-change-tracking availability for the session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class HistoryListRewindPointsResult +{ + /// Whether this session captured file changes from its first turn. + [JsonPropertyName("fileChangeTrackingEnabled")] + public bool FileChangeTrackingEnabled { get; set; } - /// Tokens consumed by tool definitions sent to the model (excludes deferred tools). - [JsonPropertyName("toolDefinitionsTokens")] - public long ToolDefinitionsTokens { get; set; } + /// Root user turns in chronological order. Empty when `unavailableReason` is set. + [JsonPropertyName("points")] + public IList Points { get => field ??= []; set; } - /// Sum of system, conversation and tool-definition tokens. - [JsonPropertyName("totalTokens")] - public long TotalTokens { get; set; } + /// Why the listed points could not be produced, when applicable; the points list is empty whenever it is set. `unsupported-remote-session` is permanent for the session and comes with `fileChangeTrackingEnabled: false`. `session-busy` is transient and only ever reported by a session that *is* tracking (`fileChangeTrackingEnabled: true`), because the file-change captures cannot be read while work that may still mutate them is in flight; the same request succeeds once the session settles, so a client that wants points should retry rather than treat it as a failure. It is never `file-change-tracking-disabled`: an untracked local session still lists conversation-only points and reports that through `fileChangeTrackingEnabled: false`. + [JsonPropertyName("unavailableReason")] + public HistoryRewindUnavailableReason? UnavailableReason { get; set; } } -/// Token breakdown for the session's current context window, or null if uninitialized. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MetadataContextInfoResult +internal sealed class SessionHistoryListRewindPointsRequest { - /// Token breakdown for the current context window, or null if the session has not yet been initialized (no system prompt or tool metadata cached). - [JsonPropertyName("contextInfo")] - public MetadataContextInfoResultContextInfo? ContextInfo { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Model identifier and token limits used to compute the context-info breakdown. +/// A file that a conversation-and-files rewind would restore. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class MetadataContextInfoRequest +public sealed class HistoryRewindFilePreview { - /// Requested output allowance to reserve against the combined context ceiling. Pass 0 to resolve the session's request cap, falling back to the model's advertised output limit. - [JsonPropertyName("outputTokenLimit")] - public long OutputTokenLimit { get; set; } - - /// Advertised prompt allowance. Pass 0 to resolve the selected model and context tier from the session. - [JsonPropertyName("promptTokenLimit")] - public long PromptTokenLimit { get; set; } + /// Aggregate change made across the discarded turns. + [JsonPropertyName("changeType")] + public HistoryRewindChangeType ChangeType { get; set; } - /// Provider owning selectedModel. Omit to use the current provider for the current model, or deterministic legacy lookup for a different model. - [JsonPropertyName("providerId")] - public string? ProviderId { get; set; } + /// Lines added across the discarded turns. + [JsonPropertyName("linesAdded")] + public long LinesAdded { get; set; } - /// Model identifier used for tokenization. Omit to use the session default. Used both for token counting and to compute display values. - [JsonPropertyName("selectedModel")] - public string? SelectedModel { get; set; } + /// Lines removed across the discarded turns. + [JsonPropertyName("linesRemoved")] + public long LinesRemoved { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Absolute path of the captured file. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; } -/// The six normalized `/context` header buckets, computed from the same tokenization as `entries` so the two never disagree. Convenience rollups: `freeSpace` and `buffer` describe window capacity rather than occupied context, so the values do not sum to `totalTokens`. -public sealed class MetadataContextAttributionResultContextAttributionCategories +/// Files and aggregate changes for a prospective rewind. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class HistoryPreviewRewindResult { - /// Overlapping output reservation plus post-blocking-threshold buffer. - [JsonPropertyName("buffer")] - public long Buffer { get; set; } - - /// Custom-instructions tokens (0 when none are configured). - [JsonPropertyName("customInstructions")] - public long CustomInstructions { get; set; } + /// Whether file restore is available for this session. This is authoritative: switch on it and read `reason` only when it is false. + [JsonPropertyName("available")] + public bool Available { get; set; } - /// Remaining unused window capacity (clamped at 0). - [JsonPropertyName("freeSpace")] - public long FreeSpace { get; set; } + /// Number of unique files in the preview. + [JsonPropertyName("fileCount")] + public long FileCount { get; set; } - /// MCP tool-definition tokens. - [JsonPropertyName("mcpTools")] - public long McpTools { get; set; } + /// Files ordered by path. + [JsonPropertyName("files")] + public IList Files { get => field ??= []; set; } - /// Conversation (user/assistant/tool) message tokens. - [JsonPropertyName("messages")] - public long Messages { get; set; } + /// Why file restore is unavailable, when applicable. Populated only when `available` is false and never set when `available` is true. + [JsonPropertyName("reason")] + public HistoryRewindUnavailableReason? Reason { get; set; } +} - /// System prompt tokens, excluding custom instructions. - [JsonPropertyName("systemPrompt")] - public long SystemPrompt { get; set; } +/// Event boundary to preview for conversation-and-files rewind. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class HistoryPreviewRewindRequest +{ + /// ID of the user.message event that begins the discarded suffix. + [JsonPropertyName("eventId")] + public string EventId { get; set; } = string.Empty; - /// Non-MCP tool-definition tokens. - [JsonPropertyName("systemTools")] - public long SystemTools { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Successful compaction history for the session. -public sealed class MetadataContextAttributionResultContextAttributionCompactions +/// A captured file that rewind intentionally left unchanged. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class HistorySkippedFileRestore { - /// Number of successful compactions in this session. - [JsonPropertyName("count")] - public long Count { get; set; } + /// Absolute path of the skipped file. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// Reason the file was not restored. + [JsonPropertyName("reason")] + public HistoryFileRestoreSkipReason Reason { get; set; } } -/// RPC data type for MetadataContextAttributionResultContextAttributionEntry operations. -public sealed class MetadataContextAttributionResultContextAttributionEntry +/// Structured outcome of a rewind request. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class HistoryRewindResult { - /// Supplementary per-entry metadata (e.g. `messageCount`, `role`, `evictable`, `pluginSource`). Values are stringified; parse as needed and ignore unrecognized keys. - [JsonPropertyName("attributes")] - public IDictionary? Attributes { get; set; } - - /// Identifier for this entry, formed by joining its `kind` and source name (e.g. `tool:bash`, `skill:tmux`, `toolDefinition:bash`); unique within the snapshot. Use it to match the same entry across snapshots, to correlate with other APIs (skill/agent/MCP registries), and as the `parentId` target for nesting. Distinct from the human-facing `label`. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Failure detail. Set only for the failure and partial-failure outcomes (`files-rolled-back`, `rollback-incomplete`, `truncation-failed`, `checkpoint-cleanup-failed`, `snapshot-prune-failed`); omitted for `success` and for the unavailable outcomes (`session-busy`, `file-change-tracking-disabled`, `unsupported-remote-session`). + [JsonPropertyName("error")] + public string? Error { get; set; } - /// Source category for this entry. Not a closed set — tolerate unknown values. Known values today: `skill`, `subagent`, `mcpServer`, `tool`, `system`, `toolDefinition`, `plugin`. - [JsonPropertyName("kind")] - public string Kind { get; set; } = string.Empty; + /// Number of persisted events removed by conversation truncation. Present only when truncation succeeded (outcomes `success`, `checkpoint-cleanup-failed`, and `snapshot-prune-failed`); omitted for every unavailable outcome (`session-busy`, `file-change-tracking-disabled`, `unsupported-remote-session`) and for `truncation-failed`, `files-rolled-back`, and `rollback-incomplete`. + [JsonPropertyName("eventsRemoved")] + public long? EventsRemoved { get; set; } - /// Human-readable display label, e.g. `bash` or `skill: tmux`. Presentation-only; may be localized/reformatted without notice — do not key off it. - [JsonPropertyName("label")] - public string Label { get; set; } = string.Empty; + /// Overall rewind outcome. This discriminates the result: it governs which of the remaining fields are populated, so consumers must switch on it before reading `eventsRemoved`, `restoredFiles`, `skippedFiles`, or `error`. See each field for the outcomes that populate it. + [JsonPropertyName("outcome")] + public HistoryRewindOutcome Outcome { get; set; } - /// Optional `id` of the parent entry: e.g. a `plugin` entry parenting its `skill`/`mcpServer` entries, or the `system` entry parenting `toolDefinition` entries. Omitted for top-level entries. - [JsonPropertyName("parentId")] - public string? ParentId { get; set; } + /// Absolute paths restored to their captured preimages. Always empty for conversation-only rewinds and for the unavailable outcomes (`session-busy`, `file-change-tracking-disabled`, `unsupported-remote-session`); only conversation-and-files outcomes that reached the file-restore stage populate it. + [JsonPropertyName("restoredFiles")] + public IList RestoredFiles { get => field ??= []; set; } - /// Token count currently in context attributable to this entry. - [JsonPropertyName("tokens")] - public long Tokens { get; set; } + /// Captured files intentionally left unchanged. Always empty for conversation-only rewinds and for the unavailable outcomes (`session-busy`, `file-change-tracking-disabled`, `unsupported-remote-session`); only conversation-and-files outcomes that reached the file-restore stage populate it. + [JsonPropertyName("skippedFiles")] + public IList SkippedFiles { get => field ??= []; set; } } -/// Per-source token attribution snapshot for the current context window. The heaviest individual messages are available separately via `metadata.getContextHeaviestMessages`. -public sealed class MetadataContextAttributionResultContextAttribution +/// Boundary and mode for rewinding session history. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class HistoryRewindRequest { - /// Output reservation overlapping the displayed prompt allowance plus the tokens past the effective input budget's buffer-exhaustion blocking threshold. Mirrors `SessionContextInfo.bufferTokens`. - [JsonPropertyName("bufferTokens")] - public long BufferTokens { get; set; } - - /// The six normalized `/context` header buckets, computed from the same tokenization as `entries` so the two never disagree. Convenience rollups: `freeSpace` and `buffer` describe window capacity rather than occupied context, so the values do not sum to `totalTokens`. - [JsonPropertyName("categories")] - public MetadataContextAttributionResultContextAttributionCategories Categories { get => field ??= new(); set; } + /// ID of the user.message event that begins the discarded suffix. + [JsonPropertyName("eventId")] + public string EventId { get; set; } = string.Empty; - /// Successful compaction history for the session. - [JsonPropertyName("compactions")] - public MetadataContextAttributionResultContextAttributionCompactions Compactions { get => field ??= new(); set; } + /// Whether to rewind only conversation history or also restore captured files. + [JsonPropertyName("mode")] + public HistoryRewindMode Mode { get; set; } - /// Token count at which background compaction starts. Mirrors `SessionContextInfo.compactionThreshold`. - [JsonPropertyName("compactionThreshold")] - public long CompactionThreshold { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Flat list of per-source attribution entries. Group by `kind` and render unrecognized kinds generically. Nesting and rollups are expressed via `parentId`. - [JsonPropertyName("entries")] - public IList Entries { get => field ??= []; set; } +/// Indicates whether an in-progress background compaction was cancelled. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class HistoryCancelBackgroundCompactionResult +{ + /// Whether an in-progress background compaction was cancelled. False when no compaction was running, when the session is remote, or when the underlying processor was unavailable. + [JsonPropertyName("cancelled")] + public bool Cancelled { get; set; } +} - /// Advertised prompt allowance for the selected context tier: the denominator for context-usage displays and capacity for `categories.freeSpace` and `categories.buffer`. Mirrors `SessionContextInfo.limit`. - [JsonPropertyName("limit")] - public long Limit { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionHistoryCancelBackgroundCompactionRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// The concrete model id the entire breakdown was tokenized against (feeds the per-model token multiplier). Under `Auto` (Free/Student) this is the resolved model, not the literal `auto` sentinel, so totals are not undercounted. A single-model approximation of a potentially multi-model Auto session. - [JsonPropertyName("modelId")] - public string ModelId { get; set; } = string.Empty; +/// Indicates whether an in-progress manual compaction was aborted. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class HistoryAbortManualCompactionResult +{ + /// Whether an in-progress manual compaction was aborted. False when no manual compaction was running, when its abort controller was already aborted, or when the session is remote. + [JsonPropertyName("aborted")] + public bool Aborted { get; set; } +} - /// How `modelId` was chosen. Not a closed set — tolerate unknown values. Known values today: `autoResolved` (the model Auto resolved to), `selected` (the user's explicitly selected model), `default` (a fallback before any model is known). - [JsonPropertyName("modelSource")] - public string ModelSource { get; set; } = string.Empty; +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionHistoryAbortManualCompactionRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Effective input budget after reserving requested output against the combined context ceiling. Mirrors `SessionContextInfo.promptTokenLimit`. - [JsonPropertyName("promptTokenLimit")] - public long PromptTokenLimit { get; set; } +/// Markdown summary of the conversation context (empty when not available). +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class HistorySummarizeForHandoffResult +{ + /// Markdown summary of the conversation context produced by an LLM. Empty string when there are no messages or when the session does not support local summarization. + [JsonPropertyName("summary")] + public string Summary { get; set; } = string.Empty; +} - /// Total token count of the current context window the entries are measured against (system message + conversation messages + tool definitions — the same total reported by /context). Divide an entry's `tokens` by this to derive its share. - [JsonPropertyName("totalTokens")] - public long TotalTokens { get; set; } +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionHistorySummarizeForHandoffRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Per-source attribution breakdown for the session's current context window, or null if uninitialized. +/// What a successful clear removed. A clear that could not be applied rejects instead of reporting a count. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MetadataContextAttributionResult +public sealed class HistoryClearContextResult { - /// Per-source context-window attribution, or null if the session has not yet been initialized (no system prompt or tool metadata cached). - [JsonPropertyName("contextAttribution")] - public MetadataContextAttributionResultContextAttribution? ContextAttribution { get; set; } + /// Number of non-system, non-developer messages that were removed from the conversation. Zero only when the window already held no conversation. + [JsonPropertyName("messagesCleared")] + public long MessagesCleared { get; set; } } -/// Identifies the target session. +/// Parameters for clearing the conversation and seeding the window that replaces it. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionMetadataGetContextAttributionRequest +internal sealed class HistoryClearContextRequest { + /// First user message of the fresh context window. Required: a cleared window holding only system and developer messages is not a conversation a model can answer, so every clear seeds the window it creates. Delivered by the enclosing turn driver once the agentic loop exits, which is why the call must be made from inside a tool handler. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// A single large message currently in context. +/// User-facing pending queue entry, with kind and display text for a queued message, slash command, or model change. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ContextHeaviestMessage +public sealed class QueuePendingItems { - /// Stable identifier for this message within the snapshot. + /// Agent mode stored on this queued entry, as stamped when it was enqueued. Items without an explicit mode report interactive. This is not necessarily the mode that will constrain the turn: a plan or autopilot session applies its own write gate, continuation loop and permission posture to every drained item regardless of the mode stored here. + [JsonPropertyName("agentMode")] + public SendAgentMode AgentMode { get; set; } + + /// Human-readable text to display for this queue entry in the UI. + [JsonPropertyName("displayText")] + public string DisplayText { get; set; } = string.Empty; + + /// Stable opaque id for the canonical queued item. Batch rows share one id. [JsonPropertyName("id")] public string Id { get; set; } = string.Empty; - /// Human-readable source label, e.g. `tool: bash` or `skill: tmux`. Presentation-only. - [JsonPropertyName("label")] - public string Label { get; set; } = string.Empty; + /// Whether this item is a queued user message or a queued slash command / model change. + [JsonPropertyName("kind")] + public QueuePendingItemsKind Kind { get; set; } - /// Role of the chat message (`user`, `assistant`, or `tool`). - [JsonPropertyName("role")] - public string Role { get; set; } = string.Empty; + /// Stable identity of the queued user message. Present for message rows and absent for slash commands and model changes. + [JsonPropertyName("messageId")] + public string? MessageId { get; set; } - /// Token count currently in context for this individual message. - [JsonPropertyName("tokens")] - public long Tokens { get; set; } + /// Optional source tag associated with this pending queue entry. This is an open string, not authenticated authorship. In particular, `user` does not prove that a person typed the message. If the source is absent or unrecognized, consumers must not infer human or agent authorship and should handle the entry neutrally. Consumers should tolerate future source values. + [JsonPropertyName("source")] + public string? Source { get; set; } } -/// The heaviest individual messages in the session's context window, most-expensive first. +/// Snapshot of the session's pending queued items and immediate-steering messages. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MetadataContextHeaviestMessagesResult +public sealed class QueuePendingItemsResult { - /// Heaviest messages, most-expensive first. - [JsonPropertyName("messages")] - public IList Messages { get => field ??= []; set; } + /// How many leading entries of `steeringMessages` have already been folded into the running turn (and so have an emitted `user.message`), as opposed to still waiting for one. Absent for hosts that do not distinguish the two. + [JsonPropertyName("inFlightSteeringCount")] + public long? InFlightSteeringCount { get; set; } - /// Total token count of the current context window, so callers can compute each message's share without a second call. - [JsonPropertyName("totalTokens")] - public long TotalTokens { get; set; } + /// Pending queued items in submission order. Includes user messages, queued slash commands, and queued model changes; omits internal system items. + [JsonPropertyName("items")] + public IList Items { get => field ??= []; set; } + + /// Display text for messages currently in the immediate steering queue (interjections sent during a running turn). + [JsonPropertyName("steeringMessages")] + public IList SteeringMessages { get => field ??= []; set; } + + /// ID of the running turn's user message while the model has not answered it, so `withdrawMessage` can still take it back once nothing sent after it is pending. A message leaves `items` when its turn starts, before its `user.message` is recorded; this tells that message apart from one that was removed. Absent when no turn prompt can be taken back. + [JsonPropertyName("withdrawableTurnMessageId")] + public string? WithdrawableTurnMessageId { get; set; } } -/// Parameters for the heaviest-messages query. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class MetadataContextHeaviestMessagesRequest +internal sealed class SessionQueuePendingItemsRequest { - /// Maximum number of messages to return, most-expensive first. Omit for the server default. - [JsonPropertyName("limit")] - public long? Limit { get; set; } - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Notify the session that its working directory context has changed. Emits a `session.context_changed` event so consumers (telemetry, OTel tracker, ACP, the timeline UI) can react. Use this when the host has detected a cwd/branch/repo change outside the session's normal lifecycle (e.g., after a shell command in interactive mode). For a local session, a report whose `cwd` diverges from the session's current working directory is ignored (the call still succeeds but records nothing and emits no event); move a local session's working directory via `metadata.setWorkingDirectory` instead. +/// Internal snapshot of native queue state for local session orchestration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MetadataRecordContextChangeResult +internal sealed class QueueSnapshotResult { + /// Queue item identifier of a model switch that has been dequeued but not yet applied. + [JsonPropertyName("inFlightModelChangeId")] + public string? InFlightModelChangeId { get; set; } + + /// Insertion orders for queued items, aligned with `items`. + [JsonPropertyName("itemOrders")] + public IList? ItemOrders { get; set; } + + /// User-facing pending items in FIFO order. + [JsonPropertyName("items")] + public IList Items { get => field ??= []; set; } + + /// Insertion orders for immediate steering messages, aligned with `steeringMessages`. + [JsonPropertyName("steeringMessageOrders")] + public IList? SteeringMessageOrders { get; set; } + + /// Immediate steering messages waiting for an active turn. + [JsonPropertyName("steeringMessages")] + public IList SteeringMessages { get => field ??= []; set; } } -/// Updated working-directory/git context to record on the session. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class MetadataRecordContextChangeRequest +internal sealed class SessionQueueSnapshotRequest { - /// Updated working directory and git context. Emitted as the new payload of `session.context_changed`. - [JsonPropertyName("context")] - public SessionWorkingDirectoryContext Context { get => field ??= new(); set; } - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Update the session's working directory. Used by the host when the user explicitly changes cwd (e.g., the `/cd` slash command). The host is responsible for any related side-effects (file index, etc.); it does NOT change the process working directory (a session's cwd is per-session, not process-global). For local sessions the runtime validates the target first (an absolute path that exists on disk) and re-bases the permission primary directory; a rejected validation fails the call before anything is mutated, persisted, or emitted. Location-scoped permission rules are then re-keyed to the new directory (best-effort). Remote sessions only record the path. +/// Result of moving a queued item. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MetadataSetWorkingDirectoryResult +public sealed class QueueMoveItemResult { - /// Working directory after the update. - [JsonPropertyName("workingDirectory")] - public string WorkingDirectory { get; set; } = string.Empty; + /// True when the item changed position; false when it was already at the requested position. + [JsonPropertyName("changed")] + public bool Changed { get; set; } } -/// Absolute path to set as the session's new working directory. For local sessions the path must be absolute and exist on disk: it is validated before any session state changes, and a failing validation rejects the call with nothing mutated, persisted, or emitted. Remote sessions record the path as-is. +/// Parameters for moving a queued item by stable id. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class MetadataSetWorkingDirectoryRequest +internal sealed class QueueMoveItemRequest { + /// Stable opaque queued-item id. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - /// Absolute path to set as the session's working directory. The runtime updates the session's recorded cwd so subsequent operations (shell tools, file lookups, telemetry) anchor to it. - [JsonPropertyName("workingDirectory")] - public string WorkingDirectory { get; set; } = string.Empty; + /// Zero-based target position in the public visible queue. Values outside the queue clamp to an end. + [JsonPropertyName("toPosition")] + public long ToPosition { get; set; } } -/// Re-tokenize the session's existing messages against `modelId` and return the token totals. Useful for hosts that want an initial estimate of context usage on session resume, before the next agent turn fires `session.context_info_changed` events. Returns zeros for an empty session. +/// Result of inserting a queued message. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class MetadataRecomputeContextTokensResult +public sealed class QueueInsertAtResult { - /// Tokens contributed by user/assistant/tool messages (excludes system/developer prompts). - [JsonPropertyName("messagesTokenCount")] - public long MessagesTokenCount { get; set; } + /// Fresh stable opaque id assigned to the inserted item. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; +} - /// Tokens contributed by system/developer prompt snapshots. - [JsonPropertyName("systemTokenCount")] - public long SystemTokenCount { get; set; } +/// Serializable message fields accepted by queue.insertAt. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class QueueInsertMessage +{ + /// Optional explicit agent mode. When omitted, the session's current mode is assigned. + [JsonPropertyName("agentMode")] + public SendAgentMode? AgentMode { get; set; } - /// Sum of tokens across chat-context and system-context messages currently held by the session. - [JsonPropertyName("totalTokens")] - public long TotalTokens { get; set; } + /// Optional attachments for the message. + [JsonPropertyName("attachments")] + public IList? Attachments { get; set; } + + /// Whether the message is billable. + [JsonPropertyName("billable")] + public bool? Billable { get; set; } + + /// Accepted for internal SendOptions compatibility but ignored; delivery is derived from current session activity. + [JsonPropertyName("delivery")] + public string? Delivery { get; set; } + + /// Optional user-facing display text. + [JsonPropertyName("displayPrompt")] + public string? DisplayPrompt { get; set; } + + /// Accepted for SendOptions compatibility but ignored; inserted items always use queued delivery semantics. + [JsonPropertyName("mode")] + public SendMode? Mode { get; set; } + + /// Accepted for SendOptions compatibility but ignored; the requested public position controls placement. + [JsonPropertyName("prepend")] + public bool? Prepend { get; set; } + + /// The user message text. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; + + /// Per-turn request headers. + [JsonPropertyName("requestHeaders")] + public IDictionary? RequestHeaders { get; set; } + + /// Required tool name for the turn, when any. + [JsonPropertyName("requiredTool")] + public string? RequiredTool { get; set; } + + /// Optional provenance source. `system` is rejected: it would hide the inserted row from `pendingItems` and make it unaddressable while still executing, so inserted items must stay visible. + [JsonPropertyName("source")] + public string? Source { get; set; } + + /// Accepted for SendOptions compatibility but ignored; insertion scheduling is controlled by the queue drain state. + [JsonPropertyName("wait")] + public bool? Wait { get; set; } } -/// Model identifier to use when re-tokenizing the session's existing messages. +/// Parameters for inserting a queued message at a public visible position. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class MetadataRecomputeContextTokensRequest +internal sealed class QueueInsertAtRequest { - /// Model identifier used for tokenization. The runtime token-counts both chat-context and system-context messages against this model. - [JsonPropertyName("modelId")] - public string ModelId { get; set; } = string.Empty; + /// Queued message contents and delivery metadata. + [JsonPropertyName("message")] + public QueueInsertMessage Message { get => field ??= new(); set; } + + /// Zero-based position in the public visible queue. Values outside the queue clamp to an end. + [JsonPropertyName("position")] + public long Position { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Availability of built-in job tools surfaced to boundary consumers. +/// Result of removing a queued item. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionSettingsBuiltInToolAvailabilitySnapshot +public sealed class QueueRemoveAtResult { - /// Whether the create-pull-request tool is available. - [JsonPropertyName("createPullRequest")] - public bool? CreatePullRequest { get; set; } - - /// Whether the report-progress tool is available. - [JsonPropertyName("reportProgress")] - public bool? ReportProgress { get; set; } + /// True when the addressed item was removed. + [JsonPropertyName("removed")] + public bool Removed { get; set; } } -/// Redacted job settings for a session. The job nonce is excluded. +/// Parameters for removing a queued item by stable id. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionSettingsJobSnapshot +internal sealed class QueueRemoveAtRequest { - /// Availability of job-specific built-in tools. - [JsonPropertyName("builtInToolAvailability")] - public SessionSettingsBuiltInToolAvailabilitySnapshot? BuiltInToolAvailability { get; set; } + /// Stable opaque ID of the queued item to remove. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// GitHub Actions event type for the job. - [JsonPropertyName("eventType")] - public string? EventType { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Whether this is the workflow's trigger job. - [JsonPropertyName("isTriggerJob")] - public bool? IsTriggerJob { get; set; } +/// Result of editing a queued message. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class QueueUpdateTextResult +{ + /// True when the stored text changed. + [JsonPropertyName("updated")] + public bool Updated { get; set; } } -/// Redacted model routing settings for a session. +/// Parameters for editing a single queued message. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionSettingsModelSnapshot +internal sealed class QueueUpdateTextRequest { - /// Agent service callback URL for job and progress updates. - [JsonPropertyName("callbackUrl")] - public string? CallbackUrl { get; set; } + /// Optional replacement prompt displayed to the user. + [JsonPropertyName("displayPrompt")] + public string? DisplayPrompt { get; set; } - /// Default reasoning effort for the selected model. - [JsonPropertyName("defaultReasoningEffort")] - public string? DefaultReasoningEffort { get; set; } + /// Stable opaque ID of the queued item to edit. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Agent job identifier for the session. - [JsonPropertyName("instanceId")] - public string? InstanceId { get; set; } + /// Replacement prompt sent to the model. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; - /// Selected model identifier. - [JsonPropertyName("model")] - public string? Model { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Online-evaluation settings safe to expose across the SDK boundary. +/// Result of withdrawing a user message. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionSettingsOnlineEvaluationSnapshot +public sealed class QueueWithdrawMessageResult { - /// Whether online evaluation is disabled. - [JsonPropertyName("disableOnlineEvaluation")] - public bool? DisableOnlineEvaluation { get; set; } + /// True when the running turn was interrupted to withdraw the message. With removed false, the turn was interrupted but its events could not be removed, for example because the model answered first, so the message stays in the interrupted turn. + [JsonPropertyName("interrupted")] + public bool Interrupted { get; set; } - /// Whether online-evaluation output-file generation is enabled. - [JsonPropertyName("enableOnlineEvaluationOutputFile")] - public bool? EnableOnlineEvaluationOutputFile { get; set; } + /// True when the message left the queue or, for a running turn, history. + [JsonPropertyName("removed")] + public bool Removed { get; set; } } -/// Redacted repository and GitHub host settings for a session. +/// Conditional withdrawal of a single user message, from its queue or from the running turn it started. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionSettingsRepoSnapshot +internal sealed class QueueWithdrawMessageRequest { - /// Checked-out repository branch. - [JsonPropertyName("branch")] - public string? Branch { get; set; } - - /// Checked-out commit SHA. - [JsonPropertyName("commit")] - public string? Commit { get; set; } - - /// GitHub server host name. - [JsonPropertyName("host")] - public string? Host { get; set; } + /// The prompt originally sent. A message edited since submission is not withdrawn, so an obsolete draft cannot replace the edit. + [JsonPropertyName("expectedPrompt")] + public string ExpectedPrompt { get; set; } = string.Empty; - /// Protocol used to access the GitHub host. - [JsonPropertyName("hostProtocol")] - public string? HostProtocol { get; set; } + /// Message identity returned by send, not the queue item id. Batch messages are not eligible. + [JsonPropertyName("messageId")] + public string MessageId { get; set; } = string.Empty; - /// GitHub repository database ID. - [JsonPropertyName("id")] - public double? Id { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Repository name. - [JsonPropertyName("name")] - public string? Name { get; set; } +/// Append to one pending steering message without changing its identity or delivery position. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class QueueAppendSteeringRequest +{ + /// Mode captured at submission. Only steering messages in the same mode may be combined. + [JsonPropertyName("agentMode")] + public SendAgentMode AgentMode { get; set; } - /// GitHub repository owner database ID. - [JsonPropertyName("ownerId")] - public double? OwnerId { get; set; } + /// Attachments to add after the message's existing attachments. An empty list preserves the existing attachments. + [JsonPropertyName("attachments")] + public IList Attachments { get => field ??= []; set; } - /// Repository owner login. - [JsonPropertyName("ownerName")] - public string? OwnerName { get; set; } + /// Display text to append to the existing preview after a blank line. + [JsonPropertyName("displayPrompt")] + public string DisplayPrompt { get; set; } = string.Empty; - /// Number of commits in the pull request. - [JsonPropertyName("prCommitCount")] - public double? PrCommitCount { get; set; } + /// Expected current prompt, including any previous appends. The runtime applies plan-mode normalization before comparing and refuses a changed message. + [JsonPropertyName("expectedPrompt")] + public string ExpectedPrompt { get; set; } = string.Empty; - /// Whether the repository is writable. - [JsonPropertyName("readWrite")] - public bool? ReadWrite { get; set; } + /// Message identity returned by send, not the queue item id. Only unclaimed user steering messages are eligible. + [JsonPropertyName("messageId")] + public string MessageId { get; set; } = string.Empty; - /// GitHub secret-scanning service URL. - [JsonPropertyName("secretScanningUrl")] - public string? SecretScanningUrl { get; set; } + /// Text to append after a blank line. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; - /// GitHub server base URL. - [JsonPropertyName("serverUrl")] - public string? ServerUrl { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Redacted validation and memory-tool settings for a session. +/// Result of duplicating a queued item. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionSettingsValidationSnapshot +public sealed class QueueDuplicateAtResult { - /// Whether advisory validation is enabled. - [JsonPropertyName("advisoryEnabled")] - public bool? AdvisoryEnabled { get; set; } + /// Fresh stable opaque id assigned to the duplicate. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; +} - /// Whether CodeQL validation is enabled. - [JsonPropertyName("codeqlEnabled")] - public bool? CodeqlEnabled { get; set; } +/// Parameters for duplicating a queued item. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class QueueDuplicateAtRequest +{ + /// Stable opaque ID of the queued item to duplicate. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Whether code-review validation is enabled. - [JsonPropertyName("codeReviewEnabled")] - public bool? CodeReviewEnabled { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Model used for code-review validation. - [JsonPropertyName("codeReviewModel")] - public string? CodeReviewModel { get; set; } +/// Parameters for acquiring or releasing the queued-lane drain pause. Acquisition is exclusive and non-idempotent: `paused: true` against an already-paused session fails with `queue_already_paused`. The pause is never released automatically — it is not tied to the caller's lifetime, so a client that exits without sending `paused: false` leaves the lane frozen. Release is unowned: `paused: false` clears the pause for any caller, including one that never acquired it. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class QueueSetDrainPausedRequest +{ + /// Whether queued-lane draining should be paused. + [JsonPropertyName("paused")] + public bool Paused { get; set; } - /// Dependabot validation timeout budget in seconds. - [JsonPropertyName("dependabotTimeout")] - public double? DependabotTimeout { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Whether the memory-store tool is enabled. - [JsonPropertyName("memoryStoreEnabled")] - public bool? MemoryStoreEnabled { get; set; } +/// Result of trying to steer a queued message into a live turn. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class QueueSendNowResult +{ + /// True when the item was accepted into the steering lane; false when no main turn was live. + [JsonPropertyName("steered")] + public bool Steered { get; set; } +} - /// Whether the memory-vote tool is enabled. - [JsonPropertyName("memoryVoteEnabled")] - public bool? MemoryVoteEnabled { get; set; } +/// Parameters for steering a queued message into a live turn. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class QueueSendNowRequest +{ + /// Stable opaque ID of the queued item to steer into the live turn. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; - /// Whether secret-scanning validation is enabled. - [JsonPropertyName("secretScanningEnabled")] - public bool? SecretScanningEnabled { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// General validation timeout budget in seconds. - [JsonPropertyName("timeout")] - public double? Timeout { get; set; } +/// Whether the native queue has pending work. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class QueueHasPendingResult +{ + /// True when queued or immediate native work is pending. + [JsonPropertyName("hasPending")] + public bool HasPending { get; set; } } -/// Redacted, serializable view of session runtime settings for SDK boundary consumers. Secrets and raw feature flags are intentionally excluded. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSettingsSnapshot +internal sealed class SessionQueueHasPendingRequest { - /// Name of the SDK client that created the session. - [JsonPropertyName("clientName")] - public string? ClientName { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Redacted job settings. - [JsonPropertyName("job")] - public SessionSettingsJobSnapshot Job { get => field ??= new(); set; } +/// Whether a deferred-idle drain should run. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class QueueBeginDeferredIdleDrainResult +{ + /// True when the host should run finishDeferredIdleDrain asynchronously. + [JsonPropertyName("shouldDrain")] + public bool ShouldDrain { get; set; } +} - /// Redacted model routing settings. - [JsonPropertyName("model")] - public SessionSettingsModelSnapshot Model { get => field ??= new(); set; } +/// Inputs for starting a deferred-idle drain. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class QueueBeginDeferredIdleDrainRequest +{ + /// Whether the host still has active background work. + [JsonPropertyName("activeBackgroundWork")] + public bool ActiveBackgroundWork { get; set; } - /// Online-evaluation settings safe for SDK consumers. - [JsonPropertyName("onlineEvaluation")] - public SessionSettingsOnlineEvaluationSnapshot OnlineEvaluation { get => field ??= new(); set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Redacted repository and host settings. - [JsonPropertyName("repo")] - public SessionSettingsRepoSnapshot Repo { get => field ??= new(); set; } +/// Action selected by the native deferred-idle drain. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class QueueFinishDeferredIdleDrainResult +{ + /// Whether the deferred idle was caused by an aborted foreground turn. + [JsonPropertyName("aborted")] + public bool Aborted { get; set; } - /// Session start time as Unix epoch milliseconds. - [JsonPropertyName("startTimeMs")] - public double? StartTimeMs { get; set; } + /// One of none, processQueue, or emitSessionIdle. + [JsonPropertyName("action")] + public string Action { get; set; } = string.Empty; +} - /// Session timeout in milliseconds. - [JsonPropertyName("timeoutMs")] - public double? TimeoutMs { get; set; } +/// Inputs for completing a deferred-idle drain. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class QueueFinishDeferredIdleDrainRequest +{ + /// Whether the host still has active background work. + [JsonPropertyName("activeBackgroundWork")] + public bool ActiveBackgroundWork { get; set; } - /// Redacted validation and memory-tool settings. - [JsonPropertyName("validation")] - public SessionSettingsValidationSnapshot Validation { get => field ??= new(); set; } + /// Whether native queued work remains. + [JsonPropertyName("hasPending")] + public bool HasPending { get; set; } - /// Agent runtime version selector copied from the session settings, such as `latest` or a runtime release identifier. - [JsonPropertyName("version")] - public string? Version { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Identifies the target session. +/// Inputs for marking session.idle deferred in native state. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSettingsSnapshotRequest +internal sealed class QueueDeferSessionIdleRequest { + /// Whether the deferred idle was caused by an aborted foreground turn. + [JsonPropertyName("aborted")] + public bool Aborted { get; set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Result of evaluating a Rust-owned settings predicate. +/// Indicates whether a user-facing pending item was removed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSettingsEvaluatePredicateResult +public sealed class QueueRemoveMostRecentResult { - /// Whether the named settings predicate evaluated to enabled. - [JsonPropertyName("enabled")] - public bool Enabled { get; set; } + /// True if a user-facing pending item was removed (LIFO across both queues); false when no removable items remained. + [JsonPropertyName("removed")] + public bool Removed { get; set; } } -/// Named Rust-owned settings predicate to evaluate for this session. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionSettingsEvaluatePredicateRequest +internal sealed class SessionQueueRemoveMostRecentRequest { - /// Predicate name. The runtime owns the raw feature-flag names and composition logic. - [JsonPropertyName("name")] - public SessionSettingsPredicateName Name { get; set; } - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// Tool name for tool-scoped predicates such as trivial-change handling. - [JsonPropertyName("toolName")] - public string? ToolName { get; set; } } -/// Content-exclusion decision for one requested path. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ContentExclusionPathCheck +internal sealed class SessionQueueClearRequest { - /// Whether the session's complete content-exclusion policy excludes the path. - [JsonPropertyName("excluded")] - public bool Excluded { get; set; } - - /// The path supplied by the caller. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Batch content-exclusion result. Callers must fail closed when policy evaluation is unavailable. +/// Internal filter for consuming queued system notifications. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ContentExclusionCheckPathsResult +internal sealed class QueueConsumeSystemNotificationsRequest { - /// Whether the session's policy service was available for the complete batch. When false, checks is empty and callers must treat every requested path as excluded. - [JsonPropertyName("available")] - public bool Available { get; set; } + /// Opaque runtime-owned filter object. + [JsonPropertyName("filter")] + public JsonElement Filter { get; set; } - /// Per-path decisions in request order. Empty when available is false. - [JsonPropertyName("checks")] - public IList Checks { get => field ??= []; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Local file system absolute paths within the session working directory to check against its content-exclusion policy. +/// Result of enqueueing the resume-pending wake item. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ContentExclusionCheckPathsRequest +internal sealed class QueueEnqueueResumePendingResult { - /// Local file system absolute paths within the session working directory to check. Results are returned in the same order, including duplicates. - [JsonPropertyName("paths")] - public IList Paths { get => field ??= []; set; } + /// True when a wake item was newly queued. + [JsonPropertyName("queued")] + public bool Queued { get; set; } +} +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionQueueEnqueueResumePendingRequest +{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Identifier of the spawned shell process, usable with shell.kill while the process is running. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ShellExecResult +internal sealed class SessionQueueProcessRequest { - /// Identifier usable with shell.kill while the process is running. - [JsonPropertyName("processId")] - public string ProcessId { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Shell command to run, with optional working directory and timeout in milliseconds. Spawn failures return an RPC error. +/// Cursor, batch size, and optional long-poll/filter parameters for reading session events. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ShellExecRequest +internal sealed class EventLogReadRequest { - /// Shell command to execute. - [JsonPropertyName("command")] - public string Command { get; set; } = string.Empty; + /// Optional non-empty list of subagent identifiers. When provided, only events owned by one of these agents are returned; ownership recognizes the event envelope's agentId plus legacy data.agentId and data.parentToolCallId markers. This filter takes precedence over agentScope. + [JsonPropertyName("agentIds")] + public IList? AgentIds { get; set; } - /// Working directory (defaults to session working directory). - [JsonPropertyName("cwd")] - public string? Cwd { get; set; } + /// Agent-scope filter: 'primary' returns only main-agent events plus events whose type starts with 'subagent.' (matching the typed-subscription default behavior); 'all' returns events from all agents (matching wildcard-subscription behavior). Default is 'all' to preserve wildcard semantics for catch-up callers. + [JsonPropertyName("agentScope")] + public EventsAgentScope? AgentScope { get; set; } + + /// Opaque cursor returned by a previous read. Omit on the first call to start from the beginning of the session's persisted history. + [JsonPropertyName("cursor")] + public string? Cursor { get; set; } + + /// Direction to page through the session's persisted event history. 'forward' (default) pages from the cursor toward newer events (or from the start of history when no cursor is given). 'backward' enables tail-first reads: with no cursor it returns the NEWEST `max` events, and the returned cursor pages toward OLDER events on subsequent backward reads. Events within a returned batch are always in chronological (oldest-to-newest) order, even for a backward read. Backward reads cover PERSISTED history only; ephemeral events are never returned by a backward read. `direction` selects the INITIAL read only: the returned cursor is self-describing, so a continuation read pages in the cursor's own direction regardless of the `direction` passed alongside it — a forward cursor always pages forward and a backward cursor always pages backward. Pass the direction that matches the cursor to avoid confusion. + [JsonPropertyName("direction")] + public EventsReadDirection? Direction { get; set; } + + /// When false, skip ephemeral events entirely and return only durable (persisted) events. History-backfill callers that discard ephemerals anyway should set this so the read is bounded by the durable log length instead of racing the ephemeral ring on a busy session. Defaults to true (ephemerals are interleaved with durable events in creation order). Ignored by backward reads, which always cover persisted history only. + [JsonPropertyName("includeEphemeral")] + public bool? IncludeEphemeral { get; set; } + + /// Maximum number of events to return in this batch (1–1000, default 200). + [JsonPropertyName("max")] + public long? Max { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - /// Timeout in milliseconds (default: 30000). + /// Either '*' to receive all event types, or a non-empty list of event types to receive. + [JsonPropertyName("types")] + public JsonElement? Types { get; set; } + + /// Milliseconds to wait for new events when the cursor is at the tail of history. 0 (default) returns immediately even if no events are available. Capped at 30000ms. Ephemeral events that arrive during the wait are delivered in this batch but are NOT replayable on a subsequent read (use a non-zero waitMs in your next call to capture future ephemerals as they happen). This applies to forward reads only: a backward read always returns immediately and ignores `waitMs`, because backward paging covers persisted history only while new events append at the tail (the opposite end from a backward page), so no blocking or ephemeral delivery can occur. [JsonConverter(typeof(MillisecondsTimeSpanConverter))] - [JsonPropertyName("timeout")] - public TimeSpan? Timeout { get; set; } + [JsonPropertyName("waitMs")] + public TimeSpan? Wait { get; set; } } -/// Indicates whether the signal was delivered; false if the process was unknown or already exited. +/// Snapshot of the current tail cursor without returning any events. Use this when a consumer wants to subscribe to live events going forward without first paginating through the entire persisted history (which would happen if `read` were called without a cursor on a long-lived session). [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ShellKillResult +public sealed class EventLogTailResult { - /// Whether the signal was sent successfully. - [JsonPropertyName("killed")] - public bool Killed { get; set; } + /// Opaque cursor pointing at the current tail of the session's persisted-events history. Pass back to `read` to receive only events that arrive AFTER this snapshot. When the session has no events, this returns the same sentinel as an unset cursor (i.e. equivalent to omitting the cursor on a first read). + [JsonPropertyName("cursor")] + public string Cursor { get; set; } = string.Empty; } -/// Identifier of a process previously returned by "shell.exec" and the signal to send. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ShellKillRequest +internal sealed class SessionEventLogTailRequest { - /// Process identifier returned by shell.exec. - [JsonPropertyName("processId")] - public string ProcessId { get; set; } = string.Empty; - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - - /// Signal to send (default: SIGTERM). - [JsonPropertyName("signal")] - public ShellKillSignal? Signal { get; set; } } -/// Result of a user-requested shell command. +/// Opaque handle representing an event-type interest registration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class UserRequestedShellCommandResult +public sealed class RegisterEventInterestResult { - /// Error output when the execution failed. - [JsonPropertyName("error")] - public string? Error { get; set; } + /// Opaque handle for this registration. Pass to releaseInterest to release. Each call to registerInterest produces a fresh handle, even when the same eventType is registered multiple times. + [JsonPropertyName("handle")] + public string Handle { get; set; } = string.Empty; +} - /// Process exit code, when available. - [JsonPropertyName("exitCode")] - public long? ExitCode { get; set; } +/// Event type to register consumer interest for, used by runtime gating logic. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class RegisterEventInterestParams +{ + /// The event type the consumer wants the runtime to treat as 'observed' for behavior-switching gating. Some runtime code paths inspect whether any consumer is interested in a specific event type and choose a different implementation accordingly (e.g. `mcp.oauth_required`: when interest is registered the runtime delegates interactive OAuth token acquisition to the consumer via `mcp.oauth_required` events; when no interest is registered the runtime still attempts non-interactive reconnect from cached or refreshable tokens, and only marks the server `needs-auth` if usable credentials are unavailable — it does not open a browser or start interactive OAuth without a consumer). SDK clients that long-poll events do NOT automatically appear as listeners to these gating checks — they must explicitly call `registerInterest` for each event type they want the runtime to count as having a consumer. Multiple registrations for the same event type from the same or different consumers are tracked independently and must each be released. See: `mcp.oauth_required`, `sampling.requested`, `auto_mode_switch.requested`, `session_limits_exhausted.requested`, `user_input.requested`, `elicitation.requested`, `command.queued`, `exit_plan_mode.requested`. + [JsonPropertyName("eventType")] + public string EventType { get; set; } = string.Empty; - /// Captured command output. - [JsonPropertyName("output")] - public string Output { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Whether the command completed successfully. +/// Indicates whether the operation succeeded. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class EventLogReleaseInterestResult +{ + /// Whether the operation succeeded. [JsonPropertyName("success")] public bool Success { get; set; } - - /// Tool call id emitted for the shell execution. - [JsonPropertyName("toolCallId")] - public string ToolCallId { get; set; } = string.Empty; } -/// User-requested shell command and cancellation handle. +/// Opaque handle previously returned by `registerInterest` to release. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ShellExecuteUserRequestedRequest +internal sealed class ReleaseEventInterestParams { - /// Shell command to execute. - [JsonPropertyName("command")] - public string Command { get; set; } = string.Empty; - - /// Caller-provided cancellation handle for this execution. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// Handle returned by a previous `registerInterest` call. Idempotent: releasing an unknown or already-released handle is a no-op (returns success). When the last outstanding handle for an event type is released, the runtime reverts to its 'no consumer' code path for that event type. + [JsonPropertyName("handle")] + public string Handle { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Cancellation result for a user-requested shell command. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CancelUserRequestedShellCommandResult +internal sealed class SessionUsageGetMetricsRequest { - /// Whether an in-flight execution was found and signalled to cancel. - [JsonPropertyName("cancelled")] - public bool Cancelled { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// User-requested shell execution cancellation handle. +/// Internal absolute code-change totals reported by the owning host. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ShellCancelUserRequestedRequest +internal sealed class SessionUsageSetCodeChangesRequest { - /// Request ID previously passed to executeUserRequested. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// Absolute changed-file count; omission preserves the previous count. + [JsonPropertyName("filesCount")] + public double? FilesCount { get; set; } + + /// Absolute added-line total, replacing the previous reading. + [JsonPropertyName("linesAdded")] + public double LinesAdded { get; set; } + + /// Absolute removed-line total, replacing the previous reading. + [JsonPropertyName("linesRemoved")] + public double LinesRemoved { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Post-compaction context window usage breakdown. +/// Existing delegation guidance for an account without delegation access. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistoryCompactContextWindow +public sealed class SessionQuotaDelegateWarning { - /// Token count from non-system messages (user, assistant, tool). - [JsonPropertyName("conversationTokens")] - public long? ConversationTokens { get; set; } + /// User-facing guidance. + [JsonPropertyName("text")] + public string Text { get; set; } = string.Empty; - /// Current total tokens in the context window (system + conversation + tool definitions). - [JsonPropertyName("currentTokens")] - public long CurrentTokens { get; set; } + /// Link to upgrade the account. + [JsonPropertyName("url")] + public string Url { get; set; } = string.Empty; +} - /// Current number of messages in the conversation. - [JsonPropertyName("messagesLength")] - public long MessagesLength { get; set; } +/// Session quota snapshot, preserving the incumbent numeric units and reset metadata. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionQuotaSnapshot +{ + /// Entitled quantity in this quota's units. + [JsonPropertyName("entitlementRequests")] + public double EntitlementRequests { get; set; } - /// Token count from system message(s). - [JsonPropertyName("systemTokens")] - public long? SystemTokens { get; set; } + /// Whether the provider reports available quota. + [JsonPropertyName("hasQuota")] + public bool? HasQuota { get; set; } - /// Maximum token count for the model's context window. - [JsonPropertyName("tokenLimit")] - public long TokenLimit { get; set; } + /// Whether the entitlement is unlimited. + [JsonPropertyName("isUnlimitedEntitlement")] + public bool IsUnlimitedEntitlement { get; set; } - /// Token count from tool definitions. - [JsonPropertyName("toolDefinitionsTokens")] - public long? ToolDefinitionsTokens { get; set; } -} + /// Additional usage in this quota's units. + [JsonPropertyName("overage")] + public double Overage { get; set; } -/// Compaction outcome with the number of tokens and messages removed, summary text, and the resulting context window breakdown. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistoryCompactResult -{ - /// Post-compaction context window usage breakdown. - [JsonPropertyName("contextWindow")] - public HistoryCompactContextWindow? ContextWindow { get; set; } + /// Whether additional usage is allowed after quota exhaustion. + [JsonPropertyName("overageAllowedWithExhaustedQuota")] + public bool OverageAllowedWithExhaustedQuota { get; set; } - /// Number of messages removed during compaction. - [JsonPropertyName("messagesRemoved")] - public long MessagesRemoved { get; set; } + /// Additional-usage budget cap, when provided. + [JsonPropertyName("overageEntitlement")] + public double? OverageEntitlement { get; set; } - /// Whether compaction completed successfully. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Percentage of the entitlement remaining. + [JsonPropertyName("remainingPercentage")] + public double RemainingPercentage { get; set; } - /// Summary text produced by compaction. Omitted when compaction did not produce a summary (e.g. failure path). - [JsonPropertyName("summaryContent")] - public string? SummaryContent { get; set; } + /// Quota reset time in milliseconds since the Unix epoch, when known. + [JsonPropertyName("resetDateEpochMs")] + public double? ResetDateEpochMs { get; set; } - /// Number of tokens freed by compaction. - [JsonPropertyName("tokensRemoved")] - public long TokensRemoved { get; set; } -} + /// Whether the reset time is estimated. + [JsonPropertyName("resetDateEstimated")] + public bool? ResetDateEstimated { get; set; } -/// RPC data type for SessionHistoryCompact operations. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionHistoryCompactRequest -{ - /// Optional user-provided instructions to focus the compaction summary. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(4000)] - [JsonPropertyName("customInstructions")] - public string? CustomInstructions { get; set; } + /// Whether this quota uses token-based billing. + [JsonPropertyName("tokenBasedBilling")] + public bool? TokenBasedBilling { get; set; } - /// Context window token limit this compaction is targeting, recorded as the `tokenLimit` on the persisted `session.compaction_start` / `session.compaction_complete` events. Set it when the compaction targets a window other than the compacting model's own, e.g. switching to a model with a smaller context window: the compaction still runs on the current model, so the limit that motivated it would otherwise be lost. When absent, the events record the compacting model's own resolved limit. Attribution metadata only - it does not change how much the compaction removes. - [JsonPropertyName("tokenLimit")] - public long? TokenLimit { get; set; } + /// Whether usage is allowed after quota exhaustion. + [JsonPropertyName("usageAllowedWithExhaustedQuota")] + public bool UsageAllowedWithExhaustedQuota { get; set; } - /// What initiated this compaction request, recorded as the `trigger` on the persisted `session.compaction_start` / `session.compaction_complete` events. When absent, the compaction is persisted without trigger attribution (initiator unknown). - [JsonPropertyName("trigger")] - public SessionHistoryCompactRequestTrigger? Trigger { get; set; } + /// Consumed quantity in this quota's units. + [JsonPropertyName("usedRequests")] + public double UsedRequests { get; set; } } -/// RPC data type for SessionHistoryCompactRequestWithSession operations. +/// The incumbent session-owned quota and account projection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionHistoryCompactRequestWithSession +public sealed class SessionQuotaGetResult { - /// Optional user-provided instructions to focus the compaction summary. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MaxLength(4000)] - [JsonPropertyName("customInstructions")] - public string? CustomInstructions { get; set; } + /// Whether the account can sign up for Copilot Free. + [JsonPropertyName("canSignupForCopilotFree")] + public bool CanSignupForCopilotFree { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether the account can delegate tasks to GitHub. + [JsonPropertyName("delegateAvailable")] + public bool DelegateAvailable { get; set; } - /// Context window token limit this compaction is targeting, recorded as the `tokenLimit` on the persisted `session.compaction_start` / `session.compaction_complete` events. Set it when the compaction targets a window other than the compacting model's own, e.g. switching to a model with a smaller context window: the compaction still runs on the current model, so the limit that motivated it would otherwise be lost. When absent, the events record the compacting model's own resolved limit. Attribution metadata only - it does not change how much the compaction removes. - [JsonPropertyName("tokenLimit")] - public long? TokenLimit { get; set; } + /// Existing delegation warning for a free account. + [JsonPropertyName("delegateWarning")] + public SessionQuotaDelegateWarning? DelegateWarning { get; set; } - /// What initiated this compaction request, recorded as the `trigger` on the persisted `session.compaction_start` / `session.compaction_complete` events. When absent, the compaction is persisted without trigger attribution (initiator unknown). - [JsonPropertyName("trigger")] - public SessionHistoryCompactRequestTrigger? Trigger { get; set; } -} + /// Whether dynamic workflows are enabled for the active account. + [JsonPropertyName("dynamicWorkflowsEnabled")] + public bool DynamicWorkflowsEnabled { get; set; } -/// Number of events that were removed by the truncation. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistoryTruncateResult -{ - /// Failure detail when checkpointCleanupFailed is true. - [JsonPropertyName("checkpointCleanupError")] - public string? CheckpointCleanupError { get; set; } + /// Whether dynamic workflows are visible under the session's feature flags. + [JsonPropertyName("dynamicWorkflowsUiVisible")] + public bool DynamicWorkflowsUiVisible { get; set; } - /// True when conversation truncation succeeded but post-truncation workspace checkpoint cleanup failed. History is already truncated; callers may still prune snapshots but should report a checkpoint-cleanup rather than a truncation failure. - [JsonPropertyName("checkpointCleanupFailed")] - public bool? CheckpointCleanupFailed { get; set; } + /// Whether the account uses the free limited Copilot plan. + [JsonPropertyName("isFreeUser")] + public bool IsFreeUser { get; set; } + + /// Whether the account uses token-based billing. + [JsonPropertyName("isTbbUser")] + public bool IsTbbUser { get; set; } + + /// Whether model cost columns should be shown. + [JsonPropertyName("modelCostColumnVisible")] + public bool ModelCostColumnVisible { get; set; } + + /// Resolved Copilot plan tier. + [JsonPropertyName("planTier")] + public SessionQuotaPlanTier PlanTier { get; set; } + + /// Whether premium-request costs are billable. + [JsonPropertyName("premiumRequestsBillable")] + public bool PremiumRequestsBillable { get; set; } + + /// Provider-owned account quota state, including snapshots without numeric balances. + [JsonPropertyName("providerQuotas")] + public IList? ProviderQuotas { get; set; } + + /// Known quota snapshots, keyed by the provider's quota type. + [JsonPropertyName("snapshots")] + public IDictionary Snapshots { get => field ??= new Dictionary(); set; } - /// Number of events that were removed. - [JsonPropertyName("eventsRemoved")] - public long EventsRemoved { get; set; } + /// Upgrade link for a free account. + [JsonPropertyName("upgradeUrl")] + public string? UpgradeUrl { get; set; } } -/// Identifier of the event to truncate to; this event and all later events are removed. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HistoryTruncateRequest +internal sealed class SessionQuotaGetRequest { - /// Event ID to truncate to. This event and all events after it are removed from the session. - [JsonPropertyName("eventId")] - public string EventId { get; set; } = string.Empty; - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// A root user turn that the session can rewind to. +/// The incumbent session-owned quota and account projection. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistoryRewindPoint +public sealed class SessionQuotaRefreshResult { - /// Whether at least one file in this turn or a later turn can be restored. - [JsonPropertyName("canRestoreFiles")] - public bool CanRestoreFiles { get; set; } + /// Whether the account can sign up for Copilot Free. + [JsonPropertyName("canSignupForCopilotFree")] + public bool CanSignupForCopilotFree { get; set; } - /// ID of the user.message event that begins the discarded suffix. - [JsonPropertyName("eventId")] - public string EventId { get; set; } = string.Empty; + /// Whether the account can delegate tasks to GitHub. + [JsonPropertyName("delegateAvailable")] + public bool DelegateAvailable { get; set; } - /// Number of unique files in this turn and all later turns that have captured changes. - [JsonPropertyName("fileCount")] - public long FileCount { get; set; } + /// Existing delegation warning for a free account. + [JsonPropertyName("delegateWarning")] + public SessionQuotaDelegateWarning? DelegateWarning { get; set; } - /// Whether this turn was an automatically injected autopilot continuation. - [JsonPropertyName("isAutopilotContinuation")] - public bool IsAutopilotContinuation { get; set; } + /// Whether dynamic workflows are enabled for the active account. + [JsonPropertyName("dynamicWorkflowsEnabled")] + public bool DynamicWorkflowsEnabled { get; set; } - /// Lines added by this turn's captured file changes. - [JsonPropertyName("linesAdded")] - public long LinesAdded { get; set; } + /// Whether dynamic workflows are visible under the session's feature flags. + [JsonPropertyName("dynamicWorkflowsUiVisible")] + public bool DynamicWorkflowsUiVisible { get; set; } - /// Lines removed by this turn's captured file changes. - [JsonPropertyName("linesRemoved")] - public long LinesRemoved { get; set; } + /// Whether the account uses the free limited Copilot plan. + [JsonPropertyName("isFreeUser")] + public bool IsFreeUser { get; set; } - /// ISO timestamp of the user turn. - [JsonPropertyName("timestamp")] - public string Timestamp { get; set; } = string.Empty; + /// Whether the account uses token-based billing. + [JsonPropertyName("isTbbUser")] + public bool IsTbbUser { get; set; } - /// Whether this turn itself captured any file changes. - [JsonPropertyName("turnChangedFiles")] - public bool TurnChangedFiles { get; set; } + /// Whether model cost columns should be shown. + [JsonPropertyName("modelCostColumnVisible")] + public bool ModelCostColumnVisible { get; set; } - /// User-visible message text for the turn. - [JsonPropertyName("userMessage")] - public string UserMessage { get; set; } = string.Empty; -} + /// Resolved Copilot plan tier. + [JsonPropertyName("planTier")] + public SessionQuotaPlanTier PlanTier { get; set; } -/// Rewind points and file-change-tracking availability for the session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistoryListRewindPointsResult -{ - /// Whether this session captured file changes from its first turn. - [JsonPropertyName("fileChangeTrackingEnabled")] - public bool FileChangeTrackingEnabled { get; set; } + /// Whether premium-request costs are billable. + [JsonPropertyName("premiumRequestsBillable")] + public bool PremiumRequestsBillable { get; set; } - /// Root user turns in chronological order. Empty when `unavailableReason` is set. - [JsonPropertyName("points")] - public IList Points { get => field ??= []; set; } + /// Provider-owned account quota state, including snapshots without numeric balances. + [JsonPropertyName("providerQuotas")] + public IList? ProviderQuotas { get; set; } - /// Why the listed points could not be produced, when applicable; the points list is empty whenever it is set. `unsupported-remote-session` is permanent for the session and comes with `fileChangeTrackingEnabled: false`. `session-busy` is transient and only ever reported by a session that *is* tracking (`fileChangeTrackingEnabled: true`), because the file-change captures cannot be read while work that may still mutate them is in flight; the same request succeeds once the session settles, so a client that wants points should retry rather than treat it as a failure. It is never `file-change-tracking-disabled`: an untracked local session still lists conversation-only points and reports that through `fileChangeTrackingEnabled: false`. - [JsonPropertyName("unavailableReason")] - public HistoryRewindUnavailableReason? UnavailableReason { get; set; } + /// Known quota snapshots, keyed by the provider's quota type. + [JsonPropertyName("snapshots")] + public IDictionary Snapshots { get => field ??= new Dictionary(); set; } + + /// Upgrade link for a free account. + [JsonPropertyName("upgradeUrl")] + public string? UpgradeUrl { get; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionHistoryListRewindPointsRequest +internal sealed class SessionQuotaRefreshRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// A file that a conversation-and-files rewind would restore. +/// A pending session quota warning, consumed once by takeWarnings. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistoryRewindFilePreview +public sealed class QuotaWarningProjection { - /// Aggregate change made across the discarded turns. - [JsonPropertyName("changeType")] - public HistoryRewindChangeType ChangeType { get; set; } - - /// Lines added across the discarded turns. - [JsonPropertyName("linesAdded")] - public long LinesAdded { get; set; } + /// User-facing warning text. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; - /// Lines removed across the discarded turns. - [JsonPropertyName("linesRemoved")] - public long LinesRemoved { get; set; } + /// Related account or upgrade link. + [JsonPropertyName("url")] + public string? Url { get; set; } - /// Absolute path of the captured file. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Existing warning category. + [JsonPropertyName("warningType")] + public string WarningType { get; set; } = string.Empty; } -/// Files and aggregate changes for a prospective rewind. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistoryPreviewRewindResult +internal sealed class SessionQuotaTakeWarningsRequest { - /// Whether file restore is available for this session. This is authoritative: switch on it and read `reason` only when it is false. - [JsonPropertyName("available")] - public bool Available { get; set; } - - /// Number of unique files in the preview. - [JsonPropertyName("fileCount")] - public long FileCount { get; set; } - - /// Files ordered by path. - [JsonPropertyName("files")] - public IList Files { get => field ??= []; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Why file restore is unavailable, when applicable. Populated only when `available` is false and never set when `available` is true. - [JsonPropertyName("reason")] - public HistoryRewindUnavailableReason? Reason { get; set; } +/// Prediction result. Available results include prediction details; unavailable results include an explicit reason. +/// Polymorphic base type discriminated by kind. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(SessionLimitPredictionResultAvailable), "available")] +[JsonDerivedType(typeof(SessionLimitPredictionResultUnavailable), "unavailable")] +public partial class SessionLimitPredictionResult +{ + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Event boundary to preview for conversation-and-files rewind. + +/// Baseline data provenance for a prediction. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HistoryPreviewRewindRequest +public sealed class SessionLimitPredictionBaselineData { - /// ID of the user.message event that begins the discarded suffix. - [JsonPropertyName("eventId")] - public string EventId { get; set; } = string.Empty; + /// End of the baseline data slice. + [JsonPropertyName("windowEnd")] + public string WindowEnd { get; set; } = string.Empty; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Start of the baseline data slice. + [JsonPropertyName("windowStart")] + public string WindowStart { get; set; } = string.Empty; } -/// A captured file that rewind intentionally left unchanged. +/// Semantic usage tier and its AI-credit cap. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistorySkippedFileRestore +public sealed class SessionLimitPredictionTierOption { - /// Absolute path of the skipped file. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// AI-credit cap for this tier. + [JsonPropertyName("cap")] + public double Cap { get; set; } - /// Reason the file was not restored. - [JsonPropertyName("reason")] - public HistoryFileRestoreSkipReason Reason { get; set; } + /// Semantic usage tier. + [JsonPropertyName("tier")] + public SessionLimitPredictionTier Tier { get; set; } } -/// Structured outcome of a rewind request. +/// Explainable AI-credit session-limit prediction. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistoryRewindResult +public sealed class SessionLimitPredictionDetails { - /// Failure detail. Set only for the failure and partial-failure outcomes (`files-rolled-back`, `rollback-incomplete`, `truncation-failed`, `checkpoint-cleanup-failed`, `snapshot-prune-failed`); omitted for `success` and for the unavailable outcomes (`session-busy`, `file-change-tracking-disabled`, `unsupported-remote-session`). - [JsonPropertyName("error")] - public string? Error { get; set; } + /// Baseline data provenance. + [JsonPropertyName("baselineData")] + public SessionLimitPredictionBaselineData BaselineData { get => field ??= new(); set; } - /// Number of persisted events removed by conversation truncation. Present only when truncation succeeded (outcomes `success`, `checkpoint-cleanup-failed`, and `snapshot-prune-failed`); omitted for every unavailable outcome (`session-busy`, `file-change-tracking-disabled`, `unsupported-remote-session`) and for `truncation-failed`, `files-rolled-back`, and `rollback-incomplete`. - [JsonPropertyName("eventsRemoved")] - public long? EventsRemoved { get; set; } + /// Client population used for the prediction. + [JsonPropertyName("clientType")] + public SessionLimitPredictionClientType ClientType { get; set; } - /// Overall rewind outcome. This discriminates the result: it governs which of the remaining fields are populated, so consumers must switch on it before reading `eventsRemoved`, `restoredFiles`, `skippedFiles`, or `error`. See each field for the outcomes that populate it. - [JsonPropertyName("outcome")] - public HistoryRewindOutcome Outcome { get; set; } + /// Resolved model family when known. + [JsonPropertyName("family")] + public string? Family { get; set; } - /// Absolute paths restored to their captured preimages. Always empty for conversation-only rewinds and for the unavailable outcomes (`session-busy`, `file-change-tracking-disabled`, `unsupported-remote-session`); only conversation-and-files outcomes that reached the file-restore stage populate it. - [JsonPropertyName("restoredFiles")] - public IList RestoredFiles { get => field ??= []; set; } + /// Model identifier used for lookup. + [JsonPropertyName("modelId")] + public string ModelId { get; set; } = string.Empty; - /// Captured files intentionally left unchanged. Always empty for conversation-only rewinds and for the unavailable outcomes (`session-busy`, `file-change-tracking-disabled`, `unsupported-remote-session`); only conversation-and-files outcomes that reached the file-restore stage populate it. - [JsonPropertyName("skippedFiles")] - public IList SkippedFiles { get => field ??= []; set; } -} + /// Recommended maximum AI credits for this session. + [JsonPropertyName("recommendedCap")] + public double RecommendedCap { get; set; } -/// Boundary and mode for rewinding session history. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HistoryRewindRequest -{ - /// ID of the user.message event that begins the discarded suffix. - [JsonPropertyName("eventId")] - public string EventId { get; set; } = string.Empty; + /// Tier chosen as the recommended cap. + [JsonPropertyName("recommendedTier")] + public SessionLimitPredictionTier RecommendedTier { get; set; } - /// Whether to rewind only conversation history or also restore captured files. - [JsonPropertyName("mode")] - public HistoryRewindMode Mode { get; set; } + /// Baseline fallback level used to create the prediction. + [JsonPropertyName("source")] + public SessionLimitPredictionSource Source { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Key matched at the source level, such as a model id, family id, or `global`. + [JsonPropertyName("sourceKey")] + public string SourceKey { get; set; } = string.Empty; + + /// Ordered usage tiers and their AI-credit caps. + [JsonPropertyName("tiers")] + public IList Tiers { get => field ??= []; set; } } -/// Indicates whether an in-progress background compaction was cancelled. +/// The available variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistoryCancelBackgroundCompactionResult +public partial class SessionLimitPredictionResultAvailable : SessionLimitPredictionResult { - /// Whether an in-progress background compaction was cancelled. False when no compaction was running, when the session is remote, or when the underlying processor was unavailable. - [JsonPropertyName("cancelled")] - public bool Cancelled { get; set; } + /// + [JsonIgnore] + public override string Kind => "available"; + + /// Predicted session limit details. + [JsonPropertyName("prediction")] + public required SessionLimitPredictionDetails Prediction { get; set; } } -/// Identifies the target session. +/// The unavailable variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionHistoryCancelBackgroundCompactionRequest +public partial class SessionLimitPredictionResultUnavailable : SessionLimitPredictionResult { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "unavailable"; + + /// Reason no prediction is available. + [JsonPropertyName("reason")] + public required SessionLimitPredictionUnavailableReason Reason { get; set; } } -/// Indicates whether an in-progress manual compaction was aborted. +/// RPC data type for SessionLimitPredictionPredict operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistoryAbortManualCompactionResult +public sealed class SessionLimitPredictionPredictRequest { - /// Whether an in-progress manual compaction was aborted. False when no manual compaction was running, when its abort controller was already aborted, or when the session is remote. - [JsonPropertyName("aborted")] - public bool Aborted { get; set; } + /// Client type to size for. Defaults to `cli-interactive`. + [JsonPropertyName("clientType")] + public SessionLimitPredictionClientType? ClientType { get; set; } + + /// Optional model identifier override. If omitted, the session's current model is used. + [JsonPropertyName("modelId")] + public string? ModelId { get; set; } } -/// Identifies the target session. +/// RPC data type for SessionLimitPredictionPredictRequestWithSession operations. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionHistoryAbortManualCompactionRequest +internal sealed class SessionLimitPredictionPredictRequestWithSession { + /// Client type to size for. Defaults to `cli-interactive`. + [JsonPropertyName("clientType")] + public SessionLimitPredictionClientType? ClientType { get; set; } + + /// Optional model identifier override. If omitted, the session's current model is used. + [JsonPropertyName("modelId")] + public string? ModelId { get; set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Markdown summary of the conversation context (empty when not available). +/// GitHub URL for the session and a flag indicating whether remote steering is enabled. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistorySummarizeForHandoffResult +public sealed class RemoteEnableResult { - /// Markdown summary of the conversation context produced by an LLM. Empty string when there are no messages or when the session does not support local summarization. - [JsonPropertyName("summary")] - public string Summary { get; set; } = string.Empty; + /// Whether remote steering is enabled. + [JsonPropertyName("remoteSteerable")] + public bool RemoteSteerable { get; set; } + + /// GitHub frontend URL for this session. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("url")] + public string? Url { get; set; } } -/// Identifies the target session. +/// Optional remote session mode ("off", "export", or "on"); defaults to enabling both export and remote steering. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionHistorySummarizeForHandoffRequest +internal sealed class RemoteEnableRequest { + /// Per-session remote mode. "off" disables remote, "export" exports session events to GitHub without enabling remote steering, "on" enables both export and remote steering. + [JsonPropertyName("mode")] + public RemoteSessionMode? Mode { get; set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// What a successful clear removed. A clear that could not be applied rejects instead of reporting a count. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HistoryClearContextResult -{ - /// Number of non-system, non-developer messages that were removed from the conversation. Zero only when the window already held no conversation. - [JsonPropertyName("messagesCleared")] - public long MessagesCleared { get; set; } -} - -/// Parameters for clearing the conversation and seeding the window that replaces it. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class HistoryClearContextRequest +internal sealed class SessionRemoteDisableRequest { - /// First user message of the fresh context window. Required: a cleared window holding only system and developer messages is not a conversation a model can answer, so every clear seeds the window it creates. Delivered by the enclosing turn driver once the agentic loop exits, which is why the call must be made from inside a tool handler. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// User-facing pending queue entry, with kind and display text for a queued message, slash command, or model change. +/// Persist a steerability change as a `session.remote_steerable_changed` event. Used by the host (CLI / SDK consumer) when it has just finished enabling or disabling steering on a remote exporter that the runtime does not directly own. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QueuePendingItems +public sealed class RemoteNotifySteerableChangedResult { - /// Agent mode stored on this queued entry, as stamped when it was enqueued. Items without an explicit mode report interactive. This is not necessarily the mode that will constrain the turn: a plan or autopilot session applies its own write gate, continuation loop and permission posture to every drained item regardless of the mode stored here. - [JsonPropertyName("agentMode")] - public SendAgentMode AgentMode { get; set; } - - /// Human-readable text to display for this queue entry in the UI. - [JsonPropertyName("displayText")] - public string DisplayText { get; set; } = string.Empty; - - /// Stable opaque id for the canonical queued item. Batch rows share one id. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - - /// Whether this item is a queued user message or a queued slash command / model change. - [JsonPropertyName("kind")] - public QueuePendingItemsKind Kind { get; set; } - - /// Stable identity of the queued user message. Present for message rows and absent for slash commands and model changes. - [JsonPropertyName("messageId")] - public string? MessageId { get; set; } - - /// Optional source tag associated with this pending queue entry. This is an open string, not authenticated authorship. In particular, `user` does not prove that a person typed the message. If the source is absent or unrecognized, consumers must not infer human or agent authorship and should handle the entry neutrally. Consumers should tolerate future source values. - [JsonPropertyName("source")] - public string? Source { get; set; } } -/// Snapshot of the session's pending queued items and immediate-steering messages. +/// New remote-steerability state to persist as a `session.remote_steerable_changed` event. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QueuePendingItemsResult +internal sealed class RemoteNotifySteerableChangedRequest { - /// How many leading entries of `steeringMessages` have already been folded into the running turn (and so have an emitted `user.message`), as opposed to still waiting for one. Absent for hosts that do not distinguish the two. - [JsonPropertyName("inFlightSteeringCount")] - public long? InFlightSteeringCount { get; set; } - - /// Pending queued items in submission order. Includes user messages, queued slash commands, and queued model changes; omits internal system items. - [JsonPropertyName("items")] - public IList Items { get => field ??= []; set; } - - /// Display text for messages currently in the immediate steering queue (interjections sent during a running turn). - [JsonPropertyName("steeringMessages")] - public IList SteeringMessages { get => field ??= []; set; } - - /// ID of the running turn's user message while the model has not answered it, so `withdrawMessage` can still take it back once nothing sent after it is pending. A message leaves `items` when its turn starts, before its `user.message` is recorded; this tells that message apart from one that was removed. Absent when no turn prompt can be taken back. - [JsonPropertyName("withdrawableTurnMessageId")] - public string? WithdrawableTurnMessageId { get; set; } -} + /// Whether the session now supports remote steering via GitHub. The runtime persists this as a `session.remote_steerable_changed` event so resume/replay sees the up-to-date capability. + [JsonPropertyName("remoteSteerable")] + public bool RemoteSteerable { get; set; } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionQueuePendingItemsRequest -{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Internal snapshot of native queue state for local session orchestration. +/// Current sharing status and shareable GitHub URL for a session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueSnapshotResult +public sealed class VisibilityGetResult { - /// Queue item identifier of a model switch that has been dequeued but not yet applied. - [JsonPropertyName("inFlightModelChangeId")] - public string? InFlightModelChangeId { get; set; } - - /// Insertion orders for queued items, aligned with `items`. - [JsonPropertyName("itemOrders")] - public IList? ItemOrders { get; set; } - - /// User-facing pending items in FIFO order. - [JsonPropertyName("items")] - public IList Items { get => field ??= []; set; } + /// Shareable GitHub URL for the session. Present when the session is synced and the URL can be resolved. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("shareUrl")] + public string? ShareUrl { get; set; } - /// Insertion orders for immediate steering messages, aligned with `steeringMessages`. - [JsonPropertyName("steeringMessageOrders")] - public IList? SteeringMessageOrders { get; set; } + /// Current sharing status. Absent when the session is not synced or the status could not be retrieved (e.g. the user is not authenticated). + [JsonPropertyName("status")] + public SessionVisibilityStatus? Status { get; set; } - /// Immediate steering messages waiting for an active turn. - [JsonPropertyName("steeringMessages")] - public IList SteeringMessages { get => field ??= []; set; } + /// Whether the session has been synced to Mission Control (i.e. has a GitHub task). When false, the session cannot be shared and `status`/`shareUrl` are absent. + [JsonPropertyName("synced")] + public bool Synced { get; set; } } /// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionQueueSnapshotRequest +internal sealed class SessionVisibilityGetRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Result of moving a queued item. +/// Effective sharing status and shareable GitHub URL after updating session visibility. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QueueMoveItemResult +public sealed class VisibilitySetResult { - /// True when the item changed position; false when it was already at the requested position. - [JsonPropertyName("changed")] - public bool Changed { get; set; } + /// Shareable GitHub URL for the session. Present when the session is synced and the URL can be resolved. + [Url] + [StringSyntax(StringSyntaxAttribute.Uri)] + [JsonPropertyName("shareUrl")] + public string? ShareUrl { get; set; } + + /// Effective sharing status after the update. May differ from the requested status for task types that are already visible to repository readers by default. Absent when the update could not be applied (e.g. the session is not synced or the user is not authenticated). + [JsonPropertyName("status")] + public SessionVisibilityStatus? Status { get; set; } + + /// Whether the session has been synced to Mission Control (i.e. has a GitHub task). When false, the visibility change could not be applied and `status`/`shareUrl` are absent. + [JsonPropertyName("synced")] + public bool Synced { get; set; } } -/// Parameters for moving a queued item by stable id. +/// Desired sharing status for the session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueMoveItemRequest +internal sealed class VisibilitySetRequest { - /// Stable opaque queued-item id. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; - /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; - /// Zero-based target position in the public visible queue. Values outside the queue clamp to an end. - [JsonPropertyName("toPosition")] - public long ToPosition { get; set; } -} - -/// Result of inserting a queued message. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QueueInsertAtResult -{ - /// Fresh stable opaque id assigned to the inserted item. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Sharing status to apply. "repo" makes the session visible to repository readers; "unshared" restricts it to the creator and collaborators. + [JsonPropertyName("status")] + public SessionVisibilityStatus Status { get; set; } } -/// Serializable message fields accepted by queue.insertAt. +/// Scheduled prompt entry with ID, timing (`intervalMs`, `cron`, or `at`), prompt text, recurrence, and next run time. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QueueInsertMessage +public sealed class ScheduleEntry { - /// Optional explicit agent mode. When omitted, the session's current mode is assigned. - [JsonPropertyName("agentMode")] - public SendAgentMode? AgentMode { get; set; } - - /// Optional attachments for the message. - [JsonPropertyName("attachments")] - public IList? Attachments { get; set; } - - /// Whether the message is billable. - [JsonPropertyName("billable")] - public bool? Billable { get; set; } + /// Absolute fire time (epoch milliseconds) for a one-shot calendar schedule. + [JsonPropertyName("at")] + public long? At { get; set; } - /// Accepted for internal SendOptions compatibility but ignored; delivery is derived from current session activity. - [JsonPropertyName("delivery")] - public string? Delivery { get; set; } + /// 5-field cron expression for a recurring calendar schedule, evaluated in `tz`. + [JsonPropertyName("cron")] + public string? Cron { get; set; } - /// Optional user-facing display text. + /// Display-only label for the prompt as shown in the UI (e.g. `/skill-name` for a skill-invocation schedule). The actual enqueued prompt is `prompt`. [JsonPropertyName("displayPrompt")] public string? DisplayPrompt { get; set; } - /// Accepted for SendOptions compatibility but ignored; inserted items always use queued delivery semantics. - [JsonPropertyName("mode")] - public SendMode? Mode { get; set; } + /// Sequential id assigned by the runtime within the session. Stable across resumes (rebuilt from the event log). + [JsonPropertyName("id")] + public long Id { get; set; } + + /// Interval between scheduled ticks, in milliseconds (relative-interval schedules). + [JsonConverter(typeof(MillisecondsTimeSpanConverter))] + [JsonPropertyName("intervalMs")] + public TimeSpan? Interval { get; set; } - /// Accepted for SendOptions compatibility but ignored; the requested public position controls placement. - [JsonPropertyName("prepend")] - public bool? Prepend { get; set; } + /// ISO 8601 timestamp when the next tick is scheduled to fire. + [JsonPropertyName("nextRunAt")] + public DateTimeOffset NextRunAt { get; set; } - /// The user message text. + /// Prompt text that gets enqueued on every tick. [JsonPropertyName("prompt")] public string Prompt { get; set; } = string.Empty; - /// Per-turn request headers. - [JsonPropertyName("requestHeaders")] - public IDictionary? RequestHeaders { get; set; } - - /// Required tool name for the turn, when any. - [JsonPropertyName("requiredTool")] - public string? RequiredTool { get; set; } + /// Whether the schedule re-arms after each tick (`/every`) or fires once (`/after`). + [JsonPropertyName("recurring")] + public bool Recurring { get; set; } - /// Optional provenance source. `system` is rejected: it would hide the inserted row from `pendingItems` and make it unaddressable while still executing, so inserted items must stay visible. - [JsonPropertyName("source")] - public string? Source { get; set; } + /// True for a self-paced (`dynamic`) schedule: no fixed cadence; the model arms each next run via the `manage_schedule` `wakeup` action. `nextRunAt` is model-controlled. + [JsonPropertyName("selfPaced")] + public bool? SelfPaced { get; set; } - /// Accepted for SendOptions compatibility but ignored; insertion scheduling is controlled by the queue drain state. - [JsonPropertyName("wait")] - public bool? Wait { get; set; } + /// IANA timezone the `cron` expression is evaluated in. + [JsonPropertyName("tz")] + public string? Tz { get; set; } } -/// Parameters for inserting a queued message at a public visible position. +/// Snapshot of the currently active recurring prompts for this session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueInsertAtRequest +public sealed class ScheduleList { - /// Queued message contents and delivery metadata. - [JsonPropertyName("message")] - public QueueInsertMessage Message { get => field ??= new(); set; } - - /// Zero-based position in the public visible queue. Values outside the queue clamp to an end. - [JsonPropertyName("position")] - public long Position { get; set; } + /// Active scheduled prompts, ordered by id. + [JsonPropertyName("entries")] + public IList Entries { get => field ??= []; set; } +} +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionScheduleListRequest +{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Result of removing a queued item. +/// Identifies the target session. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QueueRemoveAtResult +internal sealed class SessionScheduleHydrateRequest { - /// True when the addressed item was removed. - [JsonPropertyName("removed")] - public bool Removed { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Parameters for removing a queued item by stable id. +/// Whether the session currently has an active self-paced schedule. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueRemoveAtRequest +internal sealed class ScheduleHasSelfPacedResult { - /// Stable opaque ID of the queued item to remove. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// True when at least one active schedule is self-paced. + [JsonPropertyName("hasSelfPaced")] + public bool HasSelfPaced { get; set; } +} +/// Identifies the target session. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +internal sealed class SessionScheduleHasSelfPacedRequest +{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Result of editing a queued message. +/// Result of registering or re-arming a scheduled prompt. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QueueUpdateTextResult +internal sealed class ScheduleAddResult { - /// True when the stored text changed. - [JsonPropertyName("updated")] - public bool Updated { get; set; } + /// The registered or updated schedule entry. + [JsonPropertyName("entry")] + public ScheduleEntry? Entry { get; set; } + + /// User-facing validation error, when registration failed. + [JsonPropertyName("error")] + public string? Error { get; set; } } -/// Parameters for editing a single queued message. +/// Register a relative-interval scheduled prompt. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueUpdateTextRequest +internal sealed class ScheduleAddRequest { - /// Optional replacement prompt displayed to the user. + /// Optional display-only prompt label. [JsonPropertyName("displayPrompt")] public string? DisplayPrompt { get; set; } - /// Stable opaque ID of the queued item to edit. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Human-readable interval such as `30s`, `5m`, or `2h`. + [JsonPropertyName("interval")] + public string Interval { get; set; } = string.Empty; - /// Replacement prompt sent to the model. + /// Prompt text to enqueue when the schedule fires. [JsonPropertyName("prompt")] public string Prompt { get; set; } = string.Empty; + /// Whether the schedule should re-arm after each tick. Defaults to true. + [JsonPropertyName("recurring")] + public bool? Recurring { get; set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Result of withdrawing a user message. +/// Register a cron scheduled prompt. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QueueWithdrawMessageResult +internal sealed class ScheduleAddCronRequest { - /// True when the running turn was interrupted to withdraw the message. With removed false, the turn was interrupted but its events could not be removed, for example because the model answered first, so the message stays in the interrupted turn. - [JsonPropertyName("interrupted")] - public bool Interrupted { get; set; } + /// 5-field cron expression. + [JsonPropertyName("cron")] + public string Cron { get; set; } = string.Empty; - /// True when the message left the queue or, for a running turn, history. - [JsonPropertyName("removed")] - public bool Removed { get; set; } -} + /// Optional display-only prompt label. + [JsonPropertyName("displayPrompt")] + public string? DisplayPrompt { get; set; } -/// Conditional withdrawal of a single user message, from its queue or from the running turn it started. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueWithdrawMessageRequest -{ - /// The prompt originally sent. A message edited since submission is not withdrawn, so an obsolete draft cannot replace the edit. - [JsonPropertyName("expectedPrompt")] - public string ExpectedPrompt { get; set; } = string.Empty; + /// Prompt text to enqueue when the schedule fires. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; - /// Message identity returned by send, not the queue item id. Batch messages are not eligible. - [JsonPropertyName("messageId")] - public string MessageId { get; set; } = string.Empty; + /// Whether the schedule should re-arm after each tick. Defaults to true. + [JsonPropertyName("recurring")] + public bool? Recurring { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// IANA timezone for evaluating the cron expression. + [JsonPropertyName("tz")] + public string? Tz { get; set; } } -/// Append to one pending steering message without changing its identity or delivery position. +/// Register an absolute-time scheduled prompt. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueAppendSteeringRequest +internal sealed class ScheduleAddAtRequest { - /// Mode captured at submission. Only steering messages in the same mode may be combined. - [JsonPropertyName("agentMode")] - public SendAgentMode AgentMode { get; set; } - - /// Attachments to add after the message's existing attachments. An empty list preserves the existing attachments. - [JsonPropertyName("attachments")] - public IList Attachments { get => field ??= []; set; } + /// Epoch milliseconds when the prompt should fire. + [JsonPropertyName("at")] + public long At { get; set; } - /// Display text to append to the existing preview after a blank line. + /// Optional display-only prompt label. [JsonPropertyName("displayPrompt")] - public string DisplayPrompt { get; set; } = string.Empty; - - /// Expected current prompt, including any previous appends. The runtime applies plan-mode normalization before comparing and refuses a changed message. - [JsonPropertyName("expectedPrompt")] - public string ExpectedPrompt { get; set; } = string.Empty; - - /// Message identity returned by send, not the queue item id. Only unclaimed user steering messages are eligible. - [JsonPropertyName("messageId")] - public string MessageId { get; set; } = string.Empty; + public string? DisplayPrompt { get; set; } - /// Text to append after a blank line. + /// Prompt text to enqueue when the schedule fires. [JsonPropertyName("prompt")] public string Prompt { get; set; } = string.Empty; + /// Whether the schedule should re-arm after each tick. Defaults to false. + [JsonPropertyName("recurring")] + public bool? Recurring { get; set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Result of duplicating a queued item. +/// Register a self-paced scheduled prompt. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QueueDuplicateAtResult +internal sealed class ScheduleAddSelfPacedRequest { - /// Fresh stable opaque id assigned to the duplicate. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; -} + /// Optional display-only prompt label. + [JsonPropertyName("displayPrompt")] + public string? DisplayPrompt { get; set; } -/// Parameters for duplicating a queued item. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueDuplicateAtRequest -{ - /// Stable opaque ID of the queued item to duplicate. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Prompt text to enqueue when the schedule fires. + [JsonPropertyName("prompt")] + public string Prompt { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Parameters for acquiring or releasing the queued-lane drain pause. Acquisition is exclusive and non-idempotent: `paused: true` against an already-paused session fails with `queue_already_paused`. The pause is never released automatically — it is not tied to the caller's lifetime, so a client that exits without sending `paused: false` leaves the lane frozen. Release is unowned: `paused: false` clears the pause for any caller, including one that never acquired it. +/// Re-arm a self-paced scheduled prompt. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueSetDrainPausedRequest +internal sealed class ScheduleRearmSelfPacedRequest { - /// Whether queued-lane draining should be paused. - [JsonPropertyName("paused")] - public bool Paused { get; set; } + /// Epoch milliseconds when the prompt should next fire. + [JsonPropertyName("at")] + public long At { get; set; } + + /// Id of the self-paced scheduled prompt. + [JsonPropertyName("id")] + public long Id { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Result of trying to steer a queued message into a live turn. +/// Remove a scheduled prompt by id. The result entry is omitted if the id was unknown. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QueueSendNowResult +public sealed class ScheduleStopResult { - /// True when the item was accepted into the steering lane; false when no main turn was live. - [JsonPropertyName("steered")] - public bool Steered { get; set; } + /// The removed entry, or omitted if no entry matched. + [JsonPropertyName("entry")] + public ScheduleEntry? Entry { get; set; } } -/// Parameters for steering a queued message into a live turn. +/// Identifier of the scheduled prompt to remove. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueSendNowRequest +internal sealed class ScheduleStopRequest { - /// Stable opaque ID of the queued item to steer into the live turn. + /// Id of the scheduled prompt to remove. [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + public long Id { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Whether the native queue has pending work. +/// A bearer token supplied by the SDK client for a BYOK provider. The runtime sets it as `Authorization: Bearer <token>` on the outbound request and does no caching; the SDK consumer owns token caching and refresh. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueHasPendingResult +public sealed class ProviderTokenAcquireResult { - /// True when queued or immediate native work is pending. - [JsonPropertyName("hasPending")] - public bool HasPending { get; set; } + /// The bearer token value (without the `Bearer ` prefix). + [JsonPropertyName("token")] + public string Token { get; set; } = string.Empty; } -/// Identifies the target session. +/// Asks the SDK client to acquire a bearer token for a BYOK provider whose config set `hasBearerTokenProvider: true`. Issued by the runtime before each outbound model request; the runtime does no caching, so this is sent once per request. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionQueueHasPendingRequest +public sealed class ProviderTokenAcquireRequest { + /// Name of the BYOK provider needing a token. For the legacy whole-session provider this is the implicit provider name; for named providers it is the configured provider name. + [JsonPropertyName("providerName")] + public string ProviderName { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Whether a deferred-idle drain should run. +/// Result returned by an extension workflow closure. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueBeginDeferredIdleDrainResult +public sealed class WorkflowExecuteResult { - /// True when the host should run finishDeferredIdleDrain asynchronously. - [JsonPropertyName("shouldDrain")] - public bool ShouldDrain { get; set; } + /// Workflow result value. + [JsonPropertyName("result")] + public JsonElement? Result { get; set; } } -/// Inputs for starting a deferred-idle drain. +/// Parameters sent to the owning extension to execute a workflow closure. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueBeginDeferredIdleDrainRequest +public sealed class WorkflowExecuteRequest { - /// Whether the host still has active background work. - [JsonPropertyName("activeBackgroundWork")] - public bool ActiveBackgroundWork { get; set; } + /// Workflow input value. + [JsonPropertyName("args")] + public JsonElement Args { get; set; } + + /// Opaque token identifying this workflow execution attempt. + [JsonPropertyName("executionToken")] + public string ExecutionToken { get; set; } = string.Empty; + + /// Registered workflow name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Action selected by the native deferred-idle drain. +/// Parameters for cooperatively aborting a workflow body. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueFinishDeferredIdleDrainResult +public sealed class WorkflowAbortRequest { - /// Whether the deferred idle was caused by an aborted foreground turn. - [JsonPropertyName("aborted")] - public bool Aborted { get; set; } + /// Opaque token identifying the execution attempt to abort. + [JsonPropertyName("executionToken")] + public string ExecutionToken { get; set; } = string.Empty; - /// One of none, processQueue, or emitSessionIdle. - [JsonPropertyName("action")] - public string Action { get; set; } = string.Empty; + /// Workflow run identifier. + [JsonPropertyName("runId")] + public string RunId { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Inputs for completing a deferred-idle drain. +/// Whether the client authoritatively confirmed its external work stopped. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueFinishDeferredIdleDrainRequest +public sealed class ClientTaskCancelResult { - /// Whether the host still has active background work. - [JsonPropertyName("activeBackgroundWork")] - public bool ActiveBackgroundWork { get; set; } + /// True only when the owner confirms that external work stopped before responding. + [JsonPropertyName("cancelled")] + public bool Cancelled { get; set; } +} - /// Whether native queued work remains. - [JsonPropertyName("hasPending")] - public bool HasPending { get; set; } +/// Runtime-to-owner cancellation request for a client-owned task. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ClientTaskCancelRequest +{ + /// Opaque identifier shared by coalesced cancellation callers. + [JsonPropertyName("cancellationId")] + public string CancellationId { get; set; } = string.Empty; - /// Target session identifier. + /// Owner-scoped task key included for correlation. + [JsonPropertyName("clientTaskId")] + public string ClientTaskId { get; set; } = string.Empty; + + /// Canonical runtime-generated task identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + /// Reason the runtime requests cancellation. + [JsonPropertyName("reason")] + public ClientTaskCancelReason Reason { get; set; } + + /// Session that owns the client task. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Inputs for marking session.idle deferred in native state. +/// Describes a filesystem error. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueDeferSessionIdleRequest +public sealed class SessionFsError { - /// Whether the deferred idle was caused by an aborted foreground turn. - [JsonPropertyName("aborted")] - public bool Aborted { get; set; } + /// Error classification. + [JsonPropertyName("code")] + public SessionFsErrorCode Code { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Free-form detail about the error, for logging/diagnostics. + [JsonPropertyName("message")] + public string? Message { get; set; } + + /// For failed writeFile requests only: true if the provider changed the target before failing. Omit when unknown or unchanged. + [JsonPropertyName("writeChanged")] + public bool? WriteChanged { get; set; } } -/// Indicates whether a user-facing pending item was removed. +/// File content as a UTF-8 string, or a filesystem error if the read failed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QueueRemoveMostRecentResult +public sealed class SessionFsReadFileResult { - /// True if a user-facing pending item was removed (LIFO across both queues); false when no removable items remained. - [JsonPropertyName("removed")] - public bool Removed { get; set; } + /// File content as UTF-8 string. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; + + /// Describes a filesystem error. + [JsonPropertyName("error")] + public SessionFsError? Error { get; set; } } -/// Identifies the target session. +/// Path of the file to read from the client-provided session filesystem. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionQueueRemoveMostRecentRequest +public sealed class SessionFsReadFileRequest { + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Identifies the target session. +/// File bytes as standard base64, or a filesystem error if the read failed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionQueueClearRequest +public sealed class SessionFsReadFileBytesResult { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Exact file bytes encoded as standard base64. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; + + /// Describes a filesystem error. + [JsonPropertyName("error")] + public SessionFsError? Error { get; set; } } -/// Internal filter for consuming queued system notifications. +/// Path of the binary file to read from the client-provided session filesystem. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueConsumeSystemNotificationsRequest +public sealed class SessionFsReadFileBytesRequest { - /// Opaque runtime-owned filter object. - [JsonPropertyName("filter")] - public JsonElement Filter { get; set; } + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Result of enqueueing the resume-pending wake item. +/// File path, content to write, and optional mode for the client-provided session filesystem. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class QueueEnqueueResumePendingResult +public sealed class SessionFsWriteFileRequest { - /// True when a wake item was newly queued. - [JsonPropertyName("queued")] - public bool Queued { get; set; } + /// Content to write. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; + + /// Optional POSIX-style mode for newly created files. + [JsonPropertyName("mode")] + public long? Mode { get; set; } + + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Identifies the target session. +/// File path, standard-base64-encoded bytes to write, and optional mode for the client-provided session filesystem. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionQueueEnqueueResumePendingRequest +public sealed class SessionFsWriteFileBytesRequest { + /// Exact file bytes encoded as standard base64. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; + + /// Optional POSIX-style mode for newly created files. + [JsonPropertyName("mode")] + public long? Mode { get; set; } + + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Identifies the target session. +/// File path, content to append, and optional mode for the client-provided session filesystem. Implementations create parent directories as needed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionQueueProcessRequest +public sealed class SessionFsAppendFileRequest { + /// Content to append. + [JsonPropertyName("content")] + public string Content { get; set; } = string.Empty; + + /// Optional POSIX-style mode for newly created files. + [JsonPropertyName("mode")] + public long? Mode { get; set; } + + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Cursor, batch size, and optional long-poll/filter parameters for reading session events. +/// Indicates whether the requested path exists in the client-provided session filesystem. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class EventLogReadRequest +public sealed class SessionFsExistsResult { - /// Optional non-empty list of subagent identifiers. When provided, only events owned by one of these agents are returned; ownership recognizes the event envelope's agentId plus legacy data.agentId and data.parentToolCallId markers. This filter takes precedence over agentScope. - [JsonPropertyName("agentIds")] - public IList? AgentIds { get; set; } + /// Whether the path exists. + [JsonPropertyName("exists")] + public bool Exists { get; set; } +} - /// Agent-scope filter: 'primary' returns only main-agent events plus events whose type starts with 'subagent.' (matching the typed-subscription default behavior); 'all' returns events from all agents (matching wildcard-subscription behavior). Default is 'all' to preserve wildcard semantics for catch-up callers. - [JsonPropertyName("agentScope")] - public EventsAgentScope? AgentScope { get; set; } +/// Path to test for existence in the client-provided session filesystem. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionFsExistsRequest +{ + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Opaque cursor returned by a previous read. Omit on the first call to start from the beginning of the session's persisted history. - [JsonPropertyName("cursor")] - public string? Cursor { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} - /// Direction to page through the session's persisted event history. 'forward' (default) pages from the cursor toward newer events (or from the start of history when no cursor is given). 'backward' enables tail-first reads: with no cursor it returns the NEWEST `max` events, and the returned cursor pages toward OLDER events on subsequent backward reads. Events within a returned batch are always in chronological (oldest-to-newest) order, even for a backward read. Backward reads cover PERSISTED history only; ephemeral events are never returned by a backward read. `direction` selects the INITIAL read only: the returned cursor is self-describing, so a continuation read pages in the cursor's own direction regardless of the `direction` passed alongside it — a forward cursor always pages forward and a backward cursor always pages backward. Pass the direction that matches the cursor to avoid confusion. - [JsonPropertyName("direction")] - public EventsReadDirection? Direction { get; set; } +/// Filesystem metadata for the requested path, or a filesystem error if the stat failed. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionFsStatResult +{ + /// ISO 8601 timestamp of creation. + [JsonPropertyName("birthtime")] + public DateTimeOffset Birthtime { get; set; } - /// When false, skip ephemeral events entirely and return only durable (persisted) events. History-backfill callers that discard ephemerals anyway should set this so the read is bounded by the durable log length instead of racing the ephemeral ring on a busy session. Defaults to true (ephemerals are interleaved with durable events in creation order). Ignored by backward reads, which always cover persisted history only. - [JsonPropertyName("includeEphemeral")] - public bool? IncludeEphemeral { get; set; } + /// Describes a filesystem error. + [JsonPropertyName("error")] + public SessionFsError? Error { get; set; } - /// Maximum number of events to return in this batch (1–1000, default 200). - [JsonPropertyName("max")] - public long? Max { get; set; } + /// Whether the path is a directory. + [JsonPropertyName("isDirectory")] + public bool IsDirectory { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Whether the path is a file. + [JsonPropertyName("isFile")] + public bool IsFile { get; set; } - /// Either '*' to receive all event types, or a non-empty list of event types to receive. - [JsonPropertyName("types")] - public JsonElement? Types { get; set; } + /// ISO 8601 timestamp of last modification. + [JsonPropertyName("mtime")] + public DateTimeOffset Mtime { get; set; } - /// Milliseconds to wait for new events when the cursor is at the tail of history. 0 (default) returns immediately even if no events are available. Capped at 30000ms. Ephemeral events that arrive during the wait are delivered in this batch but are NOT replayable on a subsequent read (use a non-zero waitMs in your next call to capture future ephemerals as they happen). This applies to forward reads only: a backward read always returns immediately and ignores `waitMs`, because backward paging covers persisted history only while new events append at the tail (the opposite end from a backward page), so no blocking or ephemeral delivery can occur. - [JsonConverter(typeof(MillisecondsTimeSpanConverter))] - [JsonPropertyName("waitMs")] - public TimeSpan? Wait { get; set; } + /// File size in bytes. + [JsonPropertyName("size")] + public long Size { get; set; } } -/// Snapshot of the current tail cursor without returning any events. Use this when a consumer wants to subscribe to live events going forward without first paginating through the entire persisted history (which would happen if `read` were called without a cursor on a long-lived session). +/// Path whose metadata should be returned from the client-provided session filesystem. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class EventLogTailResult +public sealed class SessionFsStatRequest { - /// Opaque cursor pointing at the current tail of the session's persisted-events history. Pass back to `read` to receive only events that arrive AFTER this snapshot. When the session has no events, this returns the same sentinel as an unset cursor (i.e. equivalent to omitting the cursor on a first read). - [JsonPropertyName("cursor")] - public string Cursor { get; set; } = string.Empty; + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// Identifies the target session. +/// Directory path to create in the client-provided session filesystem, with options for recursive creation and POSIX mode. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionEventLogTailRequest +public sealed class SessionFsMkdirRequest { + /// Optional POSIX-style mode for newly created directories. + [JsonPropertyName("mode")] + public long? Mode { get; set; } + + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + /// Create parent directories as needed. + [JsonPropertyName("recursive")] + public bool? Recursive { get; set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Opaque handle representing an event-type interest registration. +/// Names of entries in the requested directory, or a filesystem error if the read failed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class RegisterEventInterestResult +public sealed class SessionFsReaddirResult { - /// Opaque handle for this registration. Pass to releaseInterest to release. Each call to registerInterest produces a fresh handle, even when the same eventType is registered multiple times. - [JsonPropertyName("handle")] - public string Handle { get; set; } = string.Empty; + /// Entry names in the directory. + [JsonPropertyName("entries")] + public IList Entries { get => field ??= []; set; } + + /// Describes a filesystem error. + [JsonPropertyName("error")] + public SessionFsError? Error { get; set; } } -/// Event type to register consumer interest for, used by runtime gating logic. +/// Directory path whose entries should be listed from the client-provided session filesystem. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class RegisterEventInterestParams +public sealed class SessionFsReaddirRequest { - /// The event type the consumer wants the runtime to treat as 'observed' for behavior-switching gating. Some runtime code paths inspect whether any consumer is interested in a specific event type and choose a different implementation accordingly (e.g. `mcp.oauth_required`: when interest is registered the runtime delegates interactive OAuth token acquisition to the consumer via `mcp.oauth_required` events; when no interest is registered the runtime still attempts non-interactive reconnect from cached or refreshable tokens, and only marks the server `needs-auth` if usable credentials are unavailable — it does not open a browser or start interactive OAuth without a consumer). SDK clients that long-poll events do NOT automatically appear as listeners to these gating checks — they must explicitly call `registerInterest` for each event type they want the runtime to count as having a consumer. Multiple registrations for the same event type from the same or different consumers are tracked independently and must each be released. See: `mcp.oauth_required`, `sampling.requested`, `auto_mode_switch.requested`, `session_limits_exhausted.requested`, `user_input.requested`, `elicitation.requested`, `command.queued`, `exit_plan_mode.requested`. - [JsonPropertyName("eventType")] - public string EventType { get; set; } = string.Empty; + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Indicates whether the operation succeeded. +/// Directory entry returned by session filesystem `readdirWithTypes`, with name and entry type. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class EventLogReleaseInterestResult +public sealed class SessionFsReaddirWithTypesEntry { - /// Whether the operation succeeded. - [JsonPropertyName("success")] - public bool Success { get; set; } + /// Entry name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Entry type. + [JsonPropertyName("type")] + public SessionFsReaddirWithTypesEntryType Type { get; set; } } -/// Opaque handle previously returned by `registerInterest` to release. +/// Entries in the requested directory paired with file/directory type information, or a filesystem error if the read failed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ReleaseEventInterestParams +public sealed class SessionFsReaddirWithTypesResult { - /// Handle returned by a previous `registerInterest` call. Idempotent: releasing an unknown or already-released handle is a no-op (returns success). When the last outstanding handle for an event type is released, the runtime reverts to its 'no consumer' code path for that event type. - [JsonPropertyName("handle")] - public string Handle { get; set; } = string.Empty; + /// Directory entries with type information. + [JsonPropertyName("entries")] + public IList Entries { get => field ??= []; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Describes a filesystem error. + [JsonPropertyName("error")] + public SessionFsError? Error { get; set; } } -/// Identifies the target session. +/// Directory path whose entries (with type information) should be listed from the client-provided session filesystem. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionUsageGetMetricsRequest +public sealed class SessionFsReaddirWithTypesRequest { + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Internal absolute code-change totals reported by the owning host. +/// Path to remove from the client-provided session filesystem, with options for recursive removal and force. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionUsageSetCodeChangesRequest +public sealed class SessionFsRmRequest { - /// Absolute changed-file count; omission preserves the previous count. - [JsonPropertyName("filesCount")] - public double? FilesCount { get; set; } + /// Ignore errors if the path does not exist. + [JsonPropertyName("force")] + public bool? Force { get; set; } - /// Absolute added-line total, replacing the previous reading. - [JsonPropertyName("linesAdded")] - public double LinesAdded { get; set; } + /// Path using SessionFs conventions. + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; - /// Absolute removed-line total, replacing the previous reading. - [JsonPropertyName("linesRemoved")] - public double LinesRemoved { get; set; } + /// Remove directories and their contents recursively. + [JsonPropertyName("recursive")] + public bool? Recursive { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Existing delegation guidance for an account without delegation access. +/// Source and destination paths for renaming or moving an entry in the client-provided session filesystem. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionQuotaDelegateWarning +public sealed class SessionFsRenameRequest { - /// User-facing guidance. - [JsonPropertyName("text")] - public string Text { get; set; } = string.Empty; + /// Destination path using SessionFs conventions. + [JsonPropertyName("dest")] + public string Dest { get; set; } = string.Empty; - /// Link to upgrade the account. - [JsonPropertyName("url")] - public string Url { get; set; } = string.Empty; + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// Source path using SessionFs conventions. + [JsonPropertyName("src")] + public string Src { get; set; } = string.Empty; } -/// Session quota snapshot, preserving the incumbent numeric units and reset metadata. +/// Query results including rows, columns, and rows affected, or a filesystem error if execution failed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionQuotaSnapshot +public sealed class SessionFsSqliteQueryResult { - /// Entitled quantity in this quota's units. - [JsonPropertyName("entitlementRequests")] - public double EntitlementRequests { get; set; } - - /// Whether the provider reports available quota. - [JsonPropertyName("hasQuota")] - public bool? HasQuota { get; set; } - - /// Whether the entitlement is unlimited. - [JsonPropertyName("isUnlimitedEntitlement")] - public bool IsUnlimitedEntitlement { get; set; } - - /// Additional usage in this quota's units. - [JsonPropertyName("overage")] - public double Overage { get; set; } - - /// Whether additional usage is allowed after quota exhaustion. - [JsonPropertyName("overageAllowedWithExhaustedQuota")] - public bool OverageAllowedWithExhaustedQuota { get; set; } - - /// Additional-usage budget cap, when provided. - [JsonPropertyName("overageEntitlement")] - public double? OverageEntitlement { get; set; } - - /// Percentage of the entitlement remaining. - [JsonPropertyName("remainingPercentage")] - public double RemainingPercentage { get; set; } - - /// Quota reset time in milliseconds since the Unix epoch, when known. - [JsonPropertyName("resetDateEpochMs")] - public double? ResetDateEpochMs { get; set; } + /// Column names from the result set. + [JsonPropertyName("columns")] + public IList Columns { get => field ??= []; set; } - /// Whether the reset time is estimated. - [JsonPropertyName("resetDateEstimated")] - public bool? ResetDateEstimated { get; set; } + /// Describes a filesystem error. + [JsonPropertyName("error")] + public SessionFsError? Error { get; set; } - /// Whether this quota uses token-based billing. - [JsonPropertyName("tokenBasedBilling")] - public bool? TokenBasedBilling { get; set; } + /// SQLite last_insert_rowid() value for INSERT. + [JsonPropertyName("lastInsertRowid")] + public long? LastInsertRowid { get; set; } - /// Whether usage is allowed after quota exhaustion. - [JsonPropertyName("usageAllowedWithExhaustedQuota")] - public bool UsageAllowedWithExhaustedQuota { get; set; } + /// For SELECT: array of row objects. For others: empty array. + [JsonPropertyName("rows")] + public IList> Rows { get => field ??= []; set; } - /// Consumed quantity in this quota's units. - [JsonPropertyName("usedRequests")] - public double UsedRequests { get; set; } + /// Number of rows affected (for INSERT/UPDATE/DELETE). + [JsonPropertyName("rowsAffected")] + public long RowsAffected { get; set; } } -/// The incumbent session-owned quota and account projection. +/// SQL query, query type, and optional bind parameters for executing a SQLite query against the per-session database. The provider applies its SQLite busy timeout for every call. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionQuotaGetResult +public sealed class SessionFsSqliteQueryRequest { - /// Whether the account can sign up for Copilot Free. - [JsonPropertyName("canSignupForCopilotFree")] - public bool CanSignupForCopilotFree { get; set; } - - /// Whether the account can delegate tasks to GitHub. - [JsonPropertyName("delegateAvailable")] - public bool DelegateAvailable { get; set; } - - /// Existing delegation warning for a free account. - [JsonPropertyName("delegateWarning")] - public SessionQuotaDelegateWarning? DelegateWarning { get; set; } - - /// Whether dynamic workflows are enabled for the active account. - [JsonPropertyName("dynamicWorkflowsEnabled")] - public bool DynamicWorkflowsEnabled { get; set; } - - /// Whether dynamic workflows are visible under the session's feature flags. - [JsonPropertyName("dynamicWorkflowsUiVisible")] - public bool DynamicWorkflowsUiVisible { get; set; } - - /// Whether the account uses the free limited Copilot plan. - [JsonPropertyName("isFreeUser")] - public bool IsFreeUser { get; set; } - - /// Whether the account uses token-based billing. - [JsonPropertyName("isTbbUser")] - public bool IsTbbUser { get; set; } - - /// Whether model cost columns should be shown. - [JsonPropertyName("modelCostColumnVisible")] - public bool ModelCostColumnVisible { get; set; } - - /// Resolved Copilot plan tier. - [JsonPropertyName("planTier")] - public SessionQuotaPlanTier PlanTier { get; set; } - - /// Whether premium-request costs are billable. - [JsonPropertyName("premiumRequestsBillable")] - public bool PremiumRequestsBillable { get; set; } - - /// Provider-owned account quota state, including snapshots without numeric balances. - [JsonPropertyName("providerQuotas")] - public IList? ProviderQuotas { get; set; } + /// Optional named bind parameters. + [JsonPropertyName("params")] + public IDictionary? Params { get; set; } - /// Known quota snapshots, keyed by the provider's quota type. - [JsonPropertyName("snapshots")] - public IDictionary Snapshots { get => field ??= new Dictionary(); set; } + /// SQL query to execute. + [JsonPropertyName("query")] + public string Query { get; set; } = string.Empty; - /// Upgrade link for a free account. - [JsonPropertyName("upgradeUrl")] - public string? UpgradeUrl { get; set; } -} + /// How to execute the query: 'exec' for DDL/multi-statement (no results), 'query' for SELECT (returns rows), 'run' for INSERT/UPDATE/DELETE (returns rowsAffected). + [JsonPropertyName("queryType")] + public SessionFsSqliteQueryType QueryType { get; set; } -/// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionQuotaGetRequest -{ /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// The incumbent session-owned quota and account projection. +/// Classified SQLite transaction failure. busyOrLocked guarantees rollback; postCommitAmbiguous must never be retried. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionQuotaRefreshResult +public sealed class SessionFsSqliteTransactionError { - /// Whether the account can sign up for Copilot Free. - [JsonPropertyName("canSignupForCopilotFree")] - public bool CanSignupForCopilotFree { get; set; } - - /// Whether the account can delegate tasks to GitHub. - [JsonPropertyName("delegateAvailable")] - public bool DelegateAvailable { get; set; } - - /// Existing delegation warning for a free account. - [JsonPropertyName("delegateWarning")] - public SessionQuotaDelegateWarning? DelegateWarning { get; set; } - - /// Whether dynamic workflows are enabled for the active account. - [JsonPropertyName("dynamicWorkflowsEnabled")] - public bool DynamicWorkflowsEnabled { get; set; } - - /// Whether dynamic workflows are visible under the session's feature flags. - [JsonPropertyName("dynamicWorkflowsUiVisible")] - public bool DynamicWorkflowsUiVisible { get; set; } - - /// Whether the account uses the free limited Copilot plan. - [JsonPropertyName("isFreeUser")] - public bool IsFreeUser { get; set; } - - /// Whether the account uses token-based billing. - [JsonPropertyName("isTbbUser")] - public bool IsTbbUser { get; set; } + /// Machine-readable classification of the transaction failure. + [JsonPropertyName("errorClass")] + public SessionFsSqliteTransactionErrorClass ErrorClass { get; set; } - /// Whether model cost columns should be shown. - [JsonPropertyName("modelCostColumnVisible")] - public bool ModelCostColumnVisible { get; set; } + /// Human-readable transaction failure message. + [JsonPropertyName("message")] + public string Message { get; set; } = string.Empty; +} - /// Resolved Copilot plan tier. - [JsonPropertyName("planTier")] - public SessionQuotaPlanTier PlanTier { get; set; } +/// Per-statement results, or a classified transaction error. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionFsSqliteTransactionResult +{ + /// Classified transaction failure, when execution did not succeed. + [JsonPropertyName("error")] + public SessionFsSqliteTransactionError? Error { get; set; } - /// Whether premium-request costs are billable. - [JsonPropertyName("premiumRequestsBillable")] - public bool PremiumRequestsBillable { get; set; } + /// Per-statement query results in input order. + [JsonPropertyName("results")] + public IList Results { get => field ??= []; set; } +} - /// Provider-owned account quota state, including snapshots without numeric balances. - [JsonPropertyName("providerQuotas")] - public IList? ProviderQuotas { get; set; } +/// One statement in an atomic SQLite transaction. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class SessionFsSqliteTransactionStatement +{ + /// Optional named bind parameters. + [JsonPropertyName("params")] + public IDictionary? Params { get; set; } - /// Known quota snapshots, keyed by the provider's quota type. - [JsonPropertyName("snapshots")] - public IDictionary Snapshots { get => field ??= new Dictionary(); set; } + /// SQL statement to execute. + [JsonPropertyName("query")] + public string Query { get; set; } = string.Empty; - /// Upgrade link for a free account. - [JsonPropertyName("upgradeUrl")] - public string? UpgradeUrl { get; set; } + /// How to execute the statement. + [JsonPropertyName("queryType")] + public SessionFsSqliteQueryType QueryType { get; set; } } -/// Identifies the target session. +/// Statements to execute atomically. Providers apply busy handling for every call. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionQuotaRefreshRequest +public sealed class SessionFsSqliteTransactionRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; + + /// Ordered SQL statements to execute in one transaction. + [JsonPropertyName("statements")] + public IList Statements { get => field ??= []; set; } } -/// A pending session quota warning, consumed once by takeWarnings. +/// Indicates whether the per-session SQLite database already exists. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class QuotaWarningProjection +public sealed class SessionFsSqliteExistsResult { - /// User-facing warning text. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; - - /// Related account or upgrade link. - [JsonPropertyName("url")] - public string? Url { get; set; } - - /// Existing warning category. - [JsonPropertyName("warningType")] - public string WarningType { get; set; } = string.Empty; + /// Whether the session database already exists. + [JsonPropertyName("exists")] + public bool Exists { get; set; } } /// Identifies the target session. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionQuotaTakeWarningsRequest +public sealed class SessionFsSqliteExistsRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// Prediction result. Available results include prediction details; unavailable results include an explicit reason. -/// Polymorphic base type discriminated by kind. +/// Canvas open result returned by the provider. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(SessionLimitPredictionResultAvailable), "available")] -[JsonDerivedType(typeof(SessionLimitPredictionResultUnavailable), "unavailable")] -public partial class SessionLimitPredictionResult +public sealed class CanvasProviderOpenResult { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + /// Provider-supplied status text. + [JsonPropertyName("status")] + public string? Status { get; set; } + /// Provider-supplied title. + [JsonPropertyName("title")] + public string? Title { get; set; } -/// Baseline data provenance for a prediction. + /// URL for web-rendered canvases. + [JsonPropertyName("url")] + public string? Url { get; set; } +} + +/// Host capabilities. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionLimitPredictionBaselineData +public sealed class CanvasHostContextCapabilities { - /// End of the baseline data slice. - [JsonPropertyName("windowEnd")] - public string WindowEnd { get; set; } = string.Empty; - - /// Start of the baseline data slice. - [JsonPropertyName("windowStart")] - public string WindowStart { get; set; } = string.Empty; + /// Whether canvas rendering is supported. + [JsonPropertyName("canvases")] + public bool? Canvases { get; set; } } -/// Semantic usage tier and its AI-credit cap. +/// Host context supplied by the runtime. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionLimitPredictionTierOption +public sealed class CanvasHostContext { - /// AI-credit cap for this tier. - [JsonPropertyName("cap")] - public double Cap { get; set; } - - /// Semantic usage tier. - [JsonPropertyName("tier")] - public SessionLimitPredictionTier Tier { get; set; } + /// Host capabilities. + [JsonPropertyName("capabilities")] + public CanvasHostContextCapabilities? Capabilities { get; set; } } -/// Explainable AI-credit session-limit prediction. +/// Session context supplied by the runtime. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionLimitPredictionDetails +public sealed class CanvasSessionContext { - /// Baseline data provenance. - [JsonPropertyName("baselineData")] - public SessionLimitPredictionBaselineData BaselineData { get => field ??= new(); set; } - - /// Client population used for the prediction. - [JsonPropertyName("clientType")] - public SessionLimitPredictionClientType ClientType { get; set; } - - /// Resolved model family when known. - [JsonPropertyName("family")] - public string? Family { get; set; } - - /// Model identifier used for lookup. - [JsonPropertyName("modelId")] - public string ModelId { get; set; } = string.Empty; + /// Active session working directory, when known. + [JsonPropertyName("workingDirectory")] + public string? WorkingDirectory { get; set; } +} - /// Recommended maximum AI credits for this session. - [JsonPropertyName("recommendedCap")] - public double RecommendedCap { get; set; } +/// Canvas open parameters sent to the provider. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class CanvasProviderOpenRequest +{ + /// Provider-local canvas identifier. + [JsonPropertyName("canvasId")] + public string CanvasId { get; set; } = string.Empty; - /// Tier chosen as the recommended cap. - [JsonPropertyName("recommendedTier")] - public SessionLimitPredictionTier RecommendedTier { get; set; } + /// Owning provider identifier. + [JsonPropertyName("extensionId")] + public string ExtensionId { get; set; } = string.Empty; - /// Baseline fallback level used to create the prediction. - [JsonPropertyName("source")] - public SessionLimitPredictionSource Source { get; set; } + /// Host context supplied by the runtime. + [JsonPropertyName("host")] + public CanvasHostContext? Host { get; set; } - /// Key matched at the source level, such as a model id, family id, or `global`. - [JsonPropertyName("sourceKey")] - public string SourceKey { get; set; } = string.Empty; + /// Canvas open input. + [JsonPropertyName("input")] + public JsonElement? Input { get; set; } - /// Ordered usage tiers and their AI-credit caps. - [JsonPropertyName("tiers")] - public IList Tiers { get => field ??= []; set; } -} + /// Stable caller-supplied canvas instance identifier. + [JsonPropertyName("instanceId")] + public string InstanceId { get; set; } = string.Empty; -/// The available variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SessionLimitPredictionResultAvailable : SessionLimitPredictionResult -{ - /// - [JsonIgnore] - public override string Kind => "available"; + /// Session context supplied by the runtime. + [JsonPropertyName("session")] + public CanvasSessionContext? Session { get; set; } - /// Predicted session limit details. - [JsonPropertyName("prediction")] - public required SessionLimitPredictionDetails Prediction { get; set; } + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// The unavailable variant of . +/// Canvas close parameters sent to the provider. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class SessionLimitPredictionResultUnavailable : SessionLimitPredictionResult +public sealed class CanvasProviderCloseRequest { - /// - [JsonIgnore] - public override string Kind => "unavailable"; + /// Provider-local canvas identifier. + [JsonPropertyName("canvasId")] + public string CanvasId { get; set; } = string.Empty; - /// Reason no prediction is available. - [JsonPropertyName("reason")] - public required SessionLimitPredictionUnavailableReason Reason { get; set; } -} + /// Owning provider identifier. + [JsonPropertyName("extensionId")] + public string ExtensionId { get; set; } = string.Empty; -/// RPC data type for SessionLimitPredictionPredict operations. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionLimitPredictionPredictRequest -{ - /// Client type to size for. Defaults to `cli-interactive`. - [JsonPropertyName("clientType")] - public SessionLimitPredictionClientType? ClientType { get; set; } + /// Host context supplied by the runtime. + [JsonPropertyName("host")] + public CanvasHostContext? Host { get; set; } - /// Optional model identifier override. If omitted, the session's current model is used. - [JsonPropertyName("modelId")] - public string? ModelId { get; set; } + /// Canvas instance identifier. + [JsonPropertyName("instanceId")] + public string InstanceId { get; set; } = string.Empty; + + /// Session context supplied by the runtime. + [JsonPropertyName("session")] + public CanvasSessionContext? Session { get; set; } + + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; } -/// RPC data type for SessionLimitPredictionPredictRequestWithSession operations. +/// Canvas action invocation parameters sent to the provider. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionLimitPredictionPredictRequestWithSession +public sealed class CanvasProviderInvokeActionRequest { - /// Client type to size for. Defaults to `cli-interactive`. - [JsonPropertyName("clientType")] - public SessionLimitPredictionClientType? ClientType { get; set; } + /// Action name to invoke. + [JsonPropertyName("actionName")] + public string ActionName { get; set; } = string.Empty; - /// Optional model identifier override. If omitted, the session's current model is used. - [JsonPropertyName("modelId")] - public string? ModelId { get; set; } + /// Provider-local canvas identifier. + [JsonPropertyName("canvasId")] + public string CanvasId { get; set; } = string.Empty; + + /// Owning provider identifier. + [JsonPropertyName("extensionId")] + public string ExtensionId { get; set; } = string.Empty; + + /// Host context supplied by the runtime. + [JsonPropertyName("host")] + public CanvasHostContext? Host { get; set; } + + /// Action input. + [JsonPropertyName("input")] + public JsonElement? Input { get; set; } + + /// Canvas instance identifier. + [JsonPropertyName("instanceId")] + public string InstanceId { get; set; } = string.Empty; + + /// Session context supplied by the runtime. + [JsonPropertyName("session")] + public CanvasSessionContext? Session { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// GitHub URL for the session and a flag indicating whether remote steering is enabled. +/// Reports a supervised listener's hosting-task termination and cleanup outcome. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class RemoteEnableResult +public sealed class HostExitedRequest { - /// Whether remote steering is enabled. - [JsonPropertyName("remoteSteerable")] - public bool RemoteSteerable { get; set; } + /// Explicit startup or teardown failure, when present. + [JsonPropertyName("error")] + public string? Error { get; set; } - /// GitHub frontend URL for this session. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("url")] - public string? Url { get; set; } + /// Process exit status when available; absent for in-process listener tasks. + [JsonPropertyName("exitCode")] + public long? ExitCode { get; set; } + + /// Listener UUID. + [JsonPropertyName("hostId")] + public string HostId { get; set; } = string.Empty; + + /// Cause of termination. + [JsonPropertyName("reason")] + public HostExitReason Reason { get; set; } } -/// Optional remote session mode ("off", "export", or "on"); defaults to enabling both export and remote steering. +/// Opaque integrator-owned process launch profile for one extension entrypoint. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class RemoteEnableRequest +public sealed class ExtensionLaunchProfile { - /// Per-session remote mode. "off" disables remote, "export" exports session events to GitHub without enabling remote steering, "on" enables both export and remote steering. - [JsonPropertyName("mode")] - public RemoteSessionMode? Mode { get; set; } + /// Opaque integrator-defined arguments passed to the executable. The runtime does not append the extension entrypoint. + [JsonPropertyName("args")] + public IList Args { get => field ??= []; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Opaque integrator-defined environment variables. Runtime-owned COPILOT_SDK_PATH, SESSION_ID, and COPILOT_EXTENSION_PARENT_PID values take precedence. + [JsonPropertyName("env")] + public IDictionary Env { get => field ??= new Dictionary(); set; } + + /// Executable used to launch the extension entrypoint. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [JsonPropertyName("executable")] + public string Executable { get; set; } = string.Empty; } -/// Identifies the target session. +/// The launch profile for a supported entrypoint. Omit launch when the provider does not support the entrypoint. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionRemoteDisableRequest +public sealed class ExtensionLaunchProviderResolveResult { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Opaque launch profile, omitted when this provider does not support the entrypoint. + [JsonPropertyName("launch")] + public ExtensionLaunchProfile? Launch { get; set; } } -/// Persist a steerability change as a `session.remote_steerable_changed` event. Used by the host (CLI / SDK consumer) when it has just finished enabling or disabling steering on a remote exporter that the runtime does not directly own. +/// A discovered extension entrypoint that the registered integrator may classify and resolve to an opaque launch profile. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class RemoteNotifySteerableChangedResult +public sealed class ExtensionLaunchProviderResolveRequest { + /// Source-qualified extension identifier. + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + /// Absolute path to the discovered extension entrypoint. + [JsonPropertyName("modulePath")] + public string ModulePath { get; set; } = string.Empty; + + /// Human-readable extension name. + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// Discovery source for the extension entrypoint. + [JsonPropertyName("source")] + public ExtensionSource Source { get; set; } } -/// New remote-steerability state to persist as a `session.remote_steerable_changed` event. +/// Acknowledgement. Returning successfully simply means the SDK accepted the start frame; it does not imply the request will succeed. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class RemoteNotifySteerableChangedRequest +public sealed class LlmInferenceHttpRequestStartResult { - /// Whether the session now supports remote steering via GitHub. The runtime persists this as a `session.remote_steerable_changed` event so resume/replay sees the up-to-date capability. - [JsonPropertyName("remoteSteerable")] - public bool RemoteSteerable { get; set; } - - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; } -/// Current sharing status and shareable GitHub URL for a session. +/// The head of an outbound model-layer HTTP request. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class VisibilityGetResult +public sealed class LlmInferenceHttpRequestStartRequest { - /// Shareable GitHub URL for the session. Present when the session is synced and the URL can be resolved. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("shareUrl")] - public string? ShareUrl { get; set; } + /// Stable identity of the agent trajectory that issued this request. Present when the request originates from an agent turn; absent for requests outside any agent context. This is the same identity used by lifecycle and bridged session events and remains constant across turns and retries. + [JsonPropertyName("agentId")] + public string? AgentId { get; set; } - /// Current sharing status. Absent when the session is not synced or the status could not be retrieved (e.g. the user is not authenticated). - [JsonPropertyName("status")] - public SessionVisibilityStatus? Status { get; set; } + /// Identity of the agent invocation (one agentic loop) that issued this request. It remains fixed across physical retries within the invocation and is distinct from the stable trajectory `agentId`. A caller-supplied invocation id always takes precedence (this covers auxiliary calls that have no model call id). Otherwise, first-party CAPI requests fall back to the runtime's agent task id — the same value the runtime emits as the `X-Agent-Task-Id` header — while custom-provider requests fall back to the model call id. + [JsonPropertyName("agentInvocationId")] + public string? AgentInvocationId { get; set; } - /// Whether the session has been synced to Mission Control (i.e. has a GitHub task). When false, the session cannot be shared and `status`/`shareUrl` are absent. - [JsonPropertyName("synced")] - public bool Synced { get; set; } + /// HTTP request headers, preserving multiple values per name. + [JsonPropertyName("headers")] + public IDictionary> Headers { get => field ??= new Dictionary>(); set; } + + /// Coarse classification of the interaction that produced this request. Open string for forward-compatibility; known values include `conversation-agent`, `conversation-subagent`, `conversation-sampling`, `conversation-background`, `conversation-compaction`, and `conversation-user`. Absent when the runtime did not classify the request. Comes from the runtime's per-request agent context independently of transport; on the CAPI transport the runtime derives the upstream `X-Interaction-Type` header from this same context. + [JsonPropertyName("interactionType")] + public string? InteractionType { get; set; } + + /// HTTP method, e.g. GET, POST. + [JsonPropertyName("method")] + public string Method { get; set; } = string.Empty; + + /// Stable identity of the immediate parent trajectory. Present for child trajectories such as subagents and conversation-sampling requests; absent for root-agent and non-agent requests. + [JsonPropertyName("parentAgentId")] + public string? ParentAgentId { get; set; } + + /// Opaque runtime-minted id, unique per in-flight request. The SDK uses this to correlate httpRequestChunk frames and to address its httpResponseStart / httpResponseChunk replies back to the runtime. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; + + /// Id of the runtime session that triggered this request, when one is in scope. Absent for requests issued outside any session (e.g. startup model-catalog or capability resolution). This is a payload field — not a dispatch key — because the client-global API is registered process-wide rather than per session. + [JsonPropertyName("sessionId")] + public string? SessionId { get; set; } + + /// Transport the runtime would otherwise use for this request. `http` (the default when absent) covers plain HTTP and SSE responses; `websocket` indicates a full-duplex message channel where each body chunk maps to one WebSocket message and the `binary` flag distinguishes text from binary frames. The SDK consumer uses this to decide whether to service the request with an HTTP client or a WebSocket client. It is the one piece of request metadata the consumer cannot reliably infer from the URL or headers alone. + [JsonPropertyName("transport")] + public LlmInferenceHttpRequestStartTransport? Transport { get; set; } + + /// Absolute request URL. + [JsonPropertyName("url")] + public string Url { get; set; } = string.Empty; } -/// Identifies the target session. +/// Acknowledgement. The SDK is free to ignore the ack and treat chunk delivery as fire-and-forget. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionVisibilityGetRequest +public sealed class LlmInferenceHttpRequestChunkResult { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; } -/// Effective sharing status and shareable GitHub URL after updating session visibility. +/// A request body chunk or cancellation signal. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class VisibilitySetResult +public sealed class LlmInferenceHttpRequestChunkRequest { - /// Shareable GitHub URL for the session. Present when the session is synced and the URL can be resolved. - [Url] - [StringSyntax(StringSyntaxAttribute.Uri)] - [JsonPropertyName("shareUrl")] - public string? ShareUrl { get; set; } + /// Identity of the agent invocation (one agentic loop) this body chunk belongs to, matching the `agentInvocationId` semantics on httpRequestStart. Carried per chunk so a persistent transport can attribute successive turns correctly: when a WebSocket connection is reused across turns, the httpRequestStart identity reflects only the turn that opened the connection, so each later turn stamps its own invocation id here. Absent when the runtime has no invocation context for the request, or on the plain-HTTP transport where every request has its own httpRequestStart. + [JsonPropertyName("agentInvocationId")] + public string? AgentInvocationId { get; set; } - /// Effective sharing status after the update. May differ from the requested status for task types that are already visible to repository readers by default. Absent when the update could not be applied (e.g. the session is not synced or the user is not authenticated). - [JsonPropertyName("status")] - public SessionVisibilityStatus? Status { get; set; } + /// When true, `data` is base64-encoded bytes. When absent or false, `data` is UTF-8 text. + [JsonPropertyName("binary")] + public bool? Binary { get; set; } - /// Whether the session has been synced to Mission Control (i.e. has a GitHub task). When false, the visibility change could not be applied and `status`/`shareUrl` are absent. - [JsonPropertyName("synced")] - public bool Synced { get; set; } + /// When true, the runtime is cancelling the in-flight request (e.g. upstream consumer aborted). `data` is ignored. Implies end-of-request. + [JsonPropertyName("cancel")] + public bool? Cancel { get; set; } + + /// Optional human-readable reason for the cancellation, propagated for logging. + [JsonPropertyName("cancelReason")] + public string? CancelReason { get; set; } + + /// Body byte range. UTF-8 text when `binary` is absent or false; base64-encoded bytes when `binary` is true. May be empty. + [JsonPropertyName("data")] + public string Data { get; set; } = string.Empty; + + /// When true, this is the final body chunk for the request. The SDK may rely on having received an end-marked chunk before treating the request body as complete. + [JsonPropertyName("end")] + public bool? End { get; set; } + + /// Matches the requestId from the originating httpRequestStart frame. + [JsonPropertyName("requestId")] + public string RequestId { get; set; } = string.Empty; } -/// Desired sharing status for the session. +/// Client environment metadata describing the process that produced a telemetry event. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class VisibilitySetRequest +public sealed class GitHubTelemetryClientInfo { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Copilot CLI version string. + [JsonPropertyName("cli_version")] + public string CliVersion { get; set; } = string.Empty; - /// Sharing status to apply. "repo" makes the session visible to repository readers; "unshared" restricts it to the creator and collaborators. - [JsonPropertyName("status")] - public SessionVisibilityStatus Status { get; set; } + /// Name of the client application. + [JsonPropertyName("client_name")] + public string? ClientName { get; set; } + + /// Type of client. + [JsonPropertyName("client_type")] + public string? ClientType { get; set; } + + /// Copilot subscription plan, when known. + [JsonPropertyName("copilot_plan")] + public string? CopilotPlan { get; set; } + + /// Number of logical CPU cores on the host. + [JsonPropertyName("cpu_count")] + public long? CpuCount { get; set; } + + /// Distinct CPU model names for the host, comma-separated. + [JsonPropertyName("cpu_model")] + public string? CpuModel { get; set; } + + /// Stable machine identifier for the device. + [JsonPropertyName("dev_device_id")] + public string? DevDeviceId { get; set; } + + /// Whether the user is a GitHub/Microsoft staff member. + [JsonPropertyName("is_staff")] + public bool? IsStaff { get; set; } + + /// Node.js runtime version string. + [JsonPropertyName("node_version")] + public string NodeVersion { get; set; } = string.Empty; + + /// Operating system architecture (e.g. arm64, x64). + [JsonPropertyName("os_arch")] + public string OsArch { get; set; } = string.Empty; + + /// Operating system platform (e.g. darwin, linux, win32). + [JsonPropertyName("os_platform")] + public string OsPlatform { get; set; } = string.Empty; + + /// Operating system version string. + [JsonPropertyName("os_version")] + public string OsVersion { get; set; } = string.Empty; } -/// Scheduled prompt entry with ID, timing (`intervalMs`, `cron`, or `at`), prompt text, recurrence, and next run time. +/// A single telemetry event in the runtime's native GitHub-shaped telemetry format, forwarded verbatim to opted-in hosts. The `restricted` flag on the enclosing GitHubTelemetryNotification distinguishes standard from restricted events; the payload shape is identical for both. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ScheduleEntry +public sealed class GitHubTelemetryEvent { - /// Absolute fire time (epoch milliseconds) for a one-shot calendar schedule. - [JsonPropertyName("at")] - public long? At { get; set; } + /// Client environment metadata. + [JsonPropertyName("client")] + public GitHubTelemetryClientInfo? Client { get; set; } - /// 5-field cron expression for a recurring calendar schedule, evaluated in `tz`. - [JsonPropertyName("cron")] - public string? Cron { get; set; } + /// Copilot tracking ID for user-level attribution. + [JsonPropertyName("copilot_tracking_id")] + public string? CopilotTrackingId { get; set; } - /// Display-only label for the prompt as shown in the UI (e.g. `/skill-name` for a skill-invocation schedule). The actual enqueued prompt is `prompt`. - [JsonPropertyName("displayPrompt")] - public string? DisplayPrompt { get; set; } + /// Timestamp when the event was created (ISO 8601 format). + [JsonPropertyName("created_at")] + public string? CreatedAt { get; set; } - /// Sequential id assigned by the runtime within the session. Stable across resumes (rebuilt from the event log). - [JsonPropertyName("id")] - public long Id { get; set; } + /// Experiment assignment context. + [JsonPropertyName("exp_assignment_context")] + public string? ExpAssignmentContext { get; set; } - /// Interval between scheduled ticks, in milliseconds (relative-interval schedules). - [JsonConverter(typeof(MillisecondsTimeSpanConverter))] - [JsonPropertyName("intervalMs")] - public TimeSpan? Interval { get; set; } + /// Feature flags enabled for this session, as a map from flag to value. + [JsonPropertyName("features")] + public IDictionary? Features { get; set; } - /// ISO 8601 timestamp when the next tick is scheduled to fire. - [JsonPropertyName("nextRunAt")] - public DateTimeOffset NextRunAt { get; set; } + /// Event type/kind (e.g. get_completion_with_tools_turn, tool_call_executed). + [JsonPropertyName("kind")] + public string Kind { get; set; } = string.Empty; - /// Prompt text that gets enqueued on every tick. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; + /// Numeric metrics as a map from key to value. + [JsonPropertyName("metrics")] + public IDictionary Metrics { get => field ??= new Dictionary(); set; } - /// Whether the schedule re-arms after each tick (`/every`) or fires once (`/after`). - [JsonPropertyName("recurring")] - public bool Recurring { get; set; } + /// Reference to the model call that produced this event. + [JsonPropertyName("model_call_id")] + public string? ModelCallId { get; set; } - /// True for a self-paced (`dynamic`) schedule: no fixed cadence; the model arms each next run via the `manage_schedule` `wakeup` action. `nextRunAt` is model-controlled. - [JsonPropertyName("selfPaced")] - public bool? SelfPaced { get; set; } + /// String-valued properties as a map from key to value. + [JsonPropertyName("properties")] + public IDictionary Properties { get => field ??= new Dictionary(); set; } - /// IANA timezone the `cron` expression is evaluated in. - [JsonPropertyName("tz")] - public string? Tz { get; set; } + /// Session identifier the event belongs to. + [JsonPropertyName("session_id")] + public string? SessionId { get; set; } } -/// Snapshot of the currently active recurring prompts for this session. +/// Payload for a `gitHubTelemetry.event` notification: a single GitHub telemetry event the runtime forwards to a host connection that opted into telemetry forwarding during the `server.connect` handshake. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ScheduleList +public sealed class GitHubTelemetryNotification { - /// Active scheduled prompts, ordered by id. - [JsonPropertyName("entries")] - public IList Entries { get => field ??= []; set; } + /// The telemetry event, in the runtime's native GitHub-shaped telemetry format. + [JsonPropertyName("event")] + public GitHubTelemetryEvent Event { get => field ??= new(); set; } + + /// Whether this is a restricted telemetry event (cli.restricted_telemetry). Hosts must route restricted events to first-party Microsoft stores only. + [JsonPropertyName("restricted")] + public bool Restricted { get; set; } + + /// Session the telemetry event belongs to, when it is session-scoped. Omitted for sessionless events (for example, `server.sendTelemetry` calls with no session id), which are still forwarded to opted-in connections. + [JsonPropertyName("sessionId")] + public string? SessionId { get; set; } } -/// Identifies the target session. +/// SDK host response to a GitHub credential request. +/// Polymorphic base type discriminated by kind. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionScheduleListRequest +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "kind", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(GitHubTokenAcquireResultToken), "token")] +[JsonDerivedType(typeof(GitHubTokenAcquireResultCancelled), "cancelled")] +public partial class GitHubTokenAcquireResult { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// The type discriminator. + [JsonPropertyName("kind")] + public virtual string Kind { get; set; } = string.Empty; } -/// Identifies the target session. + +/// The token variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionScheduleHydrateRequest +public partial class GitHubTokenAcquireResultToken : GitHubTokenAcquireResult { - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Kind => "token"; + + /// GitHub access token acquired by the SDK host. + [JsonPropertyName("accessToken")] + public required string AccessToken { get; set; } + + /// Remaining token lifetime in seconds when callback execution completes. It must exceed the one-hour preflight refresh threshold. + [JsonPropertyName("expiresIn")] + public required long ExpiresIn { get; set; } + + /// OAuth token type. Defaults to bearer when omitted. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("tokenType")] + public string? TokenType { get; set; } } -/// Whether the session currently has an active self-paced schedule. +/// The cancelled variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ScheduleHasSelfPacedResult +public partial class GitHubTokenAcquireResultCancelled : GitHubTokenAcquireResult { - /// True when at least one active schedule is self-paced. - [JsonPropertyName("hasSelfPaced")] - public bool HasSelfPaced { get; set; } + /// + [JsonIgnore] + public override string Kind => "cancelled"; } -/// Identifies the target session. +/// Asks the SDK client to acquire a GitHub access token from an opaque callback registration. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class SessionScheduleHasSelfPacedRequest +public sealed class GitHubTokenAcquireRequest { - /// Target session identifier. + /// Effective GitHub host for which the callback must return a token. + [JsonPropertyName("host")] + public string Host { get; set; } = string.Empty; + + /// Why the runtime is requesting a GitHub credential. + [JsonPropertyName("reason")] + public GitHubTokenAcquireReason Reason { get; set; } + + /// Opaque identifier generated by the SDK for this callback registration. + [JsonPropertyName("registrationId")] + public string RegistrationId { get; set; } = string.Empty; + + /// Session receiving the token. Absent only before a cloud session has been assigned its id. [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + public string? SessionId { get; set; } } -/// Result of registering or re-arming a scheduled prompt. +/// A response is meaningful only on the connection and request that issued its challenge. +public sealed class InstallationsConfirmResult +{ + /// Exact challenge from the request. + [JsonPropertyName("confirmationId")] + public string ConfirmationId { get; set; } = string.Empty; + + /// Fresh explicit user decision. There is no default. + [JsonPropertyName("decision")] + public InstallationDecision Decision { get; set; } + + /// Exact review commitment from the request. + [JsonPropertyName("reviewFingerprint")] + public string ReviewFingerprint { get; set; } = string.Empty; +} + +/// Only resource kinds with an implemented installation engine have a review variant. +/// Polymorphic base type discriminated by resource. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "resource", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(InstallationReviewMcp), "mcp")] +[JsonDerivedType(typeof(InstallationReviewSkill), "skill")] +public partial class InstallationReview +{ + /// The type discriminator. + [JsonPropertyName("resource")] + public virtual string Resource { get; set; } = string.Empty; +} + + +/// Safe MCP review fields. No raw card, retrieval URL, plan handle or secret value. +/// Polymorphic base type discriminated by action. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ScheduleAddResult +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "action", + UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] +[JsonDerivedType(typeof(McpInstallationReviewInstall), "install")] +[JsonDerivedType(typeof(McpInstallationReviewUninstall), "uninstall")] +public partial class McpInstallationReview { - /// The registered or updated schedule entry. - [JsonPropertyName("entry")] - public ScheduleEntry? Entry { get; set; } - - /// User-facing validation error, when registration failed. - [JsonPropertyName("error")] - public string? Error { get; set; } + /// The type discriminator. + [JsonPropertyName("action")] + public virtual string Action { get; set; } = string.Empty; } -/// Register a relative-interval scheduled prompt. + +/// +/// Final remote configuration, not a template. The producer refuses external-value +/// expansion before presenting this review. Receipt-owned secrets appear only as +/// `${installation-secret:<id>}` references whose `<id>` matches a reviewed +/// `${secret:<id>}` placeholder; values are never included. +/// [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ScheduleAddRequest +public sealed class McpInstallationRemoteConfiguration { - /// Optional display-only prompt label. - [JsonPropertyName("displayPrompt")] - public string? DisplayPrompt { get; set; } - - /// Human-readable interval such as `30s`, `5m`, or `2h`. - [JsonPropertyName("interval")] - public string Interval { get; set; } = string.Empty; + /// + /// Configured headers, excluding separately authorised OAuth tokens. Values may + /// contain owned secret references, never secret values. + /// + [JsonPropertyName("headers")] + public IDictionary Headers { get => field ??= new Dictionary(); set; } - /// Prompt text to enqueue when the schedule fires. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; + /// Configured tool selection, not permission to invoke those tools. + [JsonPropertyName("tools")] + public IList Tools { get => field ??= []; set; } - /// Whether the schedule should re-arm after each tick. Defaults to true. - [JsonPropertyName("recurring")] - public bool? Recurring { get; set; } + /// Transport in the effective persisted remote configuration. + [JsonPropertyName("transport")] + public McpPlanRemoteTransport Transport { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Exact resolved endpoint, without templates or secret placeholders. + [JsonPropertyName("url")] + public string Url { get; set; } = string.Empty; } -/// Register a cron scheduled prompt. +/// The install variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ScheduleAddCronRequest +public partial class McpInstallationReviewInstall : McpInstallationReview { - /// 5-field cron expression. - [JsonPropertyName("cron")] - public string Cron { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Action => "install"; - /// Optional display-only prompt label. - [JsonPropertyName("displayPrompt")] - public string? DisplayPrompt { get; set; } + /// Catalogue identity retained from the bound candidate when available. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("catalogue")] + public InstallationCatalogueIdentity? Catalogue { get; set; } - /// Prompt text to enqueue when the schedule fires. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; + /// Original catalogue trust metadata, not a verification claim. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("catalogueTrust")] + public CatalogTrustSnapshot? CatalogueTrust { get; set; } - /// Whether the schedule should re-arm after each tick. Defaults to true. - [JsonPropertyName("recurring")] - public bool? Recurring { get; set; } + /// The configuration change for the selected alternative only. + [JsonPropertyName("configurationChange")] + public required McpPlanConfigurationChange ConfigurationChange { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + /// Complete effective remote configuration for final installation review. + /// Earlier private selection reviews and package choices omit this field. + /// The owned remote resource requires it before issuing confirmation. + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("effectiveConfiguration")] + public McpInstallationRemoteConfiguration? EffectiveConfiguration { get; set; } - /// IANA timezone for evaluating the cron expression. - [JsonPropertyName("tz")] - public string? Tz { get; set; } -} + /// Identity from the retained plan, not caller display text. + [JsonPropertyName("identity")] + public required McpPlanResourceIdentity Identity { get; set; } -/// Register an absolute-time scheduled prompt. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ScheduleAddAtRequest -{ - /// Epoch milliseconds when the prompt should fire. - [JsonPropertyName("at")] - public long At { get; set; } + /// Non-secret values supplied for this selected alternative. + [JsonPropertyName("inputs")] + public required IList Inputs { get; set; } - /// Optional display-only prompt label. - [JsonPropertyName("displayPrompt")] - public string? DisplayPrompt { get; set; } + /// Policy decision bound to this plan. + [JsonPropertyName("policy")] + public required McpPlanPolicyResult Policy { get; set; } - /// Prompt text to enqueue when the schedule fires. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; + /// Original source identity and content commitment. + [JsonPropertyName("provenance")] + public required McpPlanProvenance Provenance { get; set; } - /// Whether the schedule should re-arm after each tick. Defaults to false. - [JsonPropertyName("recurring")] - public bool? Recurring { get; set; } + /// Explicit reviewed backend selection; no backend is accessed when no secrets are supplied. + [JsonPropertyName("secretStorage")] + public required McpInstallationSecretStorage SecretStorage { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Only the selected alternative is applied. + [JsonPropertyName("selectedChoice")] + public required McpPlanTransportChoice SelectedChoice { get; set; } + + /// Exact reviewed placeholders supplied separately. Never secret values. + [JsonPropertyName("suppliedSecrets")] + public required IList SuppliedSecrets { get; set; } + + /// Exact reviewed user-scope destination. + [JsonPropertyName("target")] + public required McpPlanTarget Target { get; set; } } -/// Register a self-paced scheduled prompt. +/// The uninstall variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ScheduleAddSelfPacedRequest +public partial class McpInstallationReviewUninstall : McpInstallationReview { - /// Optional display-only prompt label. - [JsonPropertyName("displayPrompt")] - public string? DisplayPrompt { get; set; } + /// + [JsonIgnore] + public override string Action => "uninstall"; - /// Prompt text to enqueue when the schedule fires. - [JsonPropertyName("prompt")] - public string Prompt { get; set; } = string.Empty; + /// Identity from the installed receipt. + [JsonPropertyName("identity")] + public required McpPlanResourceIdentity Identity { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Receipt-owned installation being removed. + [JsonPropertyName("installationId")] + public required string InstallationId { get; set; } -/// Re-arm a self-paced scheduled prompt. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ScheduleRearmSelfPacedRequest -{ - /// Epoch milliseconds when the prompt should next fire. - [JsonPropertyName("at")] - public long At { get; set; } + /// Exact planner-owned secret slots to remove, excluding shared OAuth grants. + [JsonPropertyName("ownedSecretCount")] + public required long OwnedSecretCount { get; set; } - /// Id of the self-paced scheduled prompt. - [JsonPropertyName("id")] - public long Id { get; set; } + /// Current removal policy, independent of permission to activate the server. + [JsonPropertyName("policy")] + public required McpPlanPolicyResult Policy { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Shared profile authentication is deliberately retained, not pending cleanup. + [JsonPropertyName("preservesSharedAuthentication")] + public required bool PreservesSharedAuthentication { get; set; } -/// Remove a scheduled prompt by id. The result entry is omitted if the id was unknown. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ScheduleStopResult -{ - /// The removed entry, or omitted if no entry matched. - [JsonPropertyName("entry")] - public ScheduleEntry? Entry { get; set; } -} + /// Source identity and content commitment retained by the installed receipt. + [JsonPropertyName("provenance")] + public required McpPlanProvenance Provenance { get; set; } -/// Identifier of the scheduled prompt to remove. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -internal sealed class ScheduleStopRequest -{ - /// Id of the scheduled prompt to remove. - [JsonPropertyName("id")] - public long Id { get; set; } + /// Whether uninstall restores a protected pre-install configuration. + [JsonPropertyName("restoresPreviousConfiguration")] + public required bool RestoresPreviousConfiguration { get; set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Exact destination, checked for intervening changes before mutation. + [JsonPropertyName("target")] + public required McpPlanTarget Target { get; set; } } -/// A bearer token supplied by the SDK client for a BYOK provider. The runtime sets it as `Authorization: Bearer <token>` on the outbound request and does no caching; the SDK consumer owns token caching and refresh. +/// The mcp variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProviderTokenAcquireResult +public partial class InstallationReviewMcp : InstallationReview { - /// The bearer token value (without the `Bearer ` prefix). - [JsonPropertyName("token")] - public string Token { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Resource => "mcp"; + + /// The exact MCP action and its reviewed changes. + [JsonPropertyName("review")] + public required McpInstallationReview Review { get; set; } } -/// Asks the SDK client to acquire a bearer token for a BYOK provider whose config set `hasBearerTokenProvider: true`. Issued by the runtime before each outbound model request; the runtime does no caching, so this is sent once per request. +/// The skill variant of . [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ProviderTokenAcquireRequest +public partial class InstallationReviewSkill : InstallationReview { - /// Name of the BYOK provider needing a token. For the legacy whole-session provider this is the implicit provider name; for named providers it is the configured provider name. - [JsonPropertyName("providerName")] - public string ProviderName { get; set; } = string.Empty; + /// + [JsonIgnore] + public override string Resource => "skill"; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// The exact verified Skill action and its reviewed files. + [JsonPropertyName("review")] + public required SkillInstallationReview Review { get; set; } } -/// Result returned by an extension workflow closure. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowExecuteResult +/// One connection-owned, expiring request for a trusted host's explicit user decision. +public sealed class InstallationsConfirmRequest { - /// Workflow result value. - [JsonPropertyName("result")] - public JsonElement? Result { get; set; } -} + /// Opaque one-use challenge. Return unchanged; never log or persist. + [JsonPropertyName("confirmationId")] + public string ConfirmationId { get; set; } = string.Empty; -/// Parameters sent to the owning extension to execute a workflow closure. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowExecuteRequest -{ - /// Workflow input value. - [JsonPropertyName("args")] - public JsonElement Args { get; set; } + /// Original plan expiry as an ISO 8601 timestamp. Confirmation never extends it. + [JsonPropertyName("expiresAt")] + public string ExpiresAt { get; set; } = string.Empty; - /// Opaque token identifying this workflow execution attempt. - [JsonPropertyName("executionToken")] - public string ExecutionToken { get; set; } = string.Empty; + /// Random identifier of this installation operation, not a plan handle. + [JsonPropertyName("operationId")] + public string OperationId { get; set; } = string.Empty; - /// Registered workflow name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// + /// Original engine-resolved selector for a bound operation, never a dispatch default. + /// Bound MCP confirmation always includes it; correlate it with the original pending action. + /// + [JsonPropertyName("policySessionId")] + public string? PolicySessionId { get; set; } - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// Resource-specific review to present before collecting the user's decision. + [JsonPropertyName("review")] + public InstallationReview Review { get => field ??= new(); set; } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Opaque commitment to the exact review and inputs. Return unchanged; never log. + [JsonPropertyName("reviewFingerprint")] + public string ReviewFingerprint { get; set; } = string.Empty; } -/// Parameters for cooperatively aborting a workflow body. +/// Closed set of public task kinds a connection can negotiate. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class WorkflowAbortRequest +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct TaskKind : IEquatable { - /// Opaque token identifying the execution attempt to abort. - [JsonPropertyName("executionToken")] - public string ExecutionToken { get; set; } = string.Empty; + private readonly string? _value; - /// Workflow run identifier. - [JsonPropertyName("runId")] - public string RunId { get; set; } = string.Empty; + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public TaskKind(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; -/// Whether the client authoritatively confirmed its external work stopped. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ClientTaskCancelResult -{ - /// True only when the owner confirms that external work stopped before responding. - [JsonPropertyName("cancelled")] - public bool Cancelled { get; set; } -} + /// Runtime-owned background agent task. + public static TaskKind Agent { get; } = new("agent"); -/// Runtime-to-owner cancellation request for a client-owned task. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ClientTaskCancelRequest -{ - /// Opaque identifier shared by coalesced cancellation callers. - [JsonPropertyName("cancellationId")] - public string CancellationId { get; set; } = string.Empty; + /// Runtime-owned shell task. + public static TaskKind Shell { get; } = new("shell"); - /// Owner-scoped task key included for correlation. - [JsonPropertyName("clientTaskId")] - public string ClientTaskId { get; set; } = string.Empty; + /// Client-owned externally executed task. + public static TaskKind Client { get; } = new("client"); - /// Canonical runtime-generated task identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(TaskKind left, TaskKind right) => left.Equals(right); - /// Reason the runtime requests cancellation. - [JsonPropertyName("reason")] - public ClientTaskCancelReason Reason { get; set; } + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(TaskKind left, TaskKind right) => !(left == right); - /// Session that owns the client task. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// + public override bool Equals(object? obj) => obj is TaskKind other && Equals(other); -/// Describes a filesystem error. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsError -{ - /// Error classification. - [JsonPropertyName("code")] - public SessionFsErrorCode Code { get; set; } + /// + public bool Equals(TaskKind other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - /// Free-form detail about the error, for logging/diagnostics. - [JsonPropertyName("message")] - public string? Message { get; set; } + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - /// For failed writeFile requests only: true if the provider changed the target before failing. Omit when unknown or unchanged. - [JsonPropertyName("writeChanged")] - public bool? WriteChanged { get; set; } -} + /// + public override string ToString() => Value; -/// File content as a UTF-8 string, or a filesystem error if the read failed. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsReadFileResult -{ - /// File content as UTF-8 string. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override TaskKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } - /// Describes a filesystem error. - [JsonPropertyName("error")] - public SessionFsError? Error { get; set; } + /// + public override void Write(Utf8JsonWriter writer, TaskKind value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(TaskKind)); + } + } } -/// Path of the file to read from the client-provided session filesystem. + +/// State of the persistent certificate authority of the sandbox credential proxy. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsReadFileRequest +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct SandboxProxyCaState : IEquatable { - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + private readonly string? _value; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public SandboxProxyCaState(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } -/// File bytes as standard base64, or a filesystem error if the read failed. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsReadFileBytesResult -{ - /// Exact file bytes encoded as standard base64. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Describes a filesystem error. - [JsonPropertyName("error")] - public SessionFsError? Error { get; set; } + /// This platform has no supported OS trust store. The proxy uses a per-process certificate bundle. + public static SandboxProxyCaState Unsupported { get; } = new("unsupported"); + + /// OS trust does not include the certificate authority, or none is stored. + public static SandboxProxyCaState NotInstalled { get; } = new("notInstalled"); + + /// OS trust includes the stored certificate authority. + public static SandboxProxyCaState Installed { get; } = new("installed"); + + /// The runtime could not read the certificate authority or the OS trust store. + public static SandboxProxyCaState Error { get; } = new("error"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SandboxProxyCaState left, SandboxProxyCaState right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SandboxProxyCaState left, SandboxProxyCaState right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is SandboxProxyCaState other && Equals(other); + + /// + public bool Equals(SandboxProxyCaState other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override SandboxProxyCaState Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, SandboxProxyCaState value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SandboxProxyCaState)); + } + } } -/// Path of the binary file to read from the client-provided session filesystem. + +/// What the one-time staff update-channel migration did. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsReadFileBytesRequest +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct StaffUpdateChannelMigrationStatus : IEquatable { - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public StaffUpdateChannelMigrationStatus(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// The account is not a staff account, so the migration does not apply and nothing was recorded. + public static StaffUpdateChannelMigrationStatus Ineligible { get; } = new("ineligible"); -/// File path, content to write, and optional mode for the client-provided session filesystem. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsWriteFileRequest -{ - /// Content to write. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// The migration already ran within the cutoff window; the stored completion timestamp is returned unchanged. + public static StaffUpdateChannelMigrationStatus Current { get; } = new("current"); - /// Optional POSIX-style mode for newly created files. - [JsonPropertyName("mode")] - public long? Mode { get; set; } + /// The persisted update channel was changed to stable. Only this outcome requires the host to reload its configuration. + public static StaffUpdateChannelMigrationStatus Migrated { get; } = new("migrated"); - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// The persisted channel was already stable, so nothing changed, but the migration is now recorded as done. + public static StaffUpdateChannelMigrationStatus Completed { get; } = new("completed"); - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// The account is on the experimental channel, which the migration deliberately leaves alone, and the migration is recorded as done. + public static StaffUpdateChannelMigrationStatus ExcludedExperimental { get; } = new("excluded-experimental"); -/// File path, standard-base64-encoded bytes to write, and optional mode for the client-provided session filesystem. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsWriteFileBytesRequest -{ - /// Exact file bytes encoded as standard base64. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(StaffUpdateChannelMigrationStatus left, StaffUpdateChannelMigrationStatus right) => left.Equals(right); - /// Optional POSIX-style mode for newly created files. - [JsonPropertyName("mode")] - public long? Mode { get; set; } + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(StaffUpdateChannelMigrationStatus left, StaffUpdateChannelMigrationStatus right) => !(left == right); - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// + public override bool Equals(object? obj) => obj is StaffUpdateChannelMigrationStatus other && Equals(other); - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// + public bool Equals(StaffUpdateChannelMigrationStatus other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); -/// File path, content to append, and optional mode for the client-provided session filesystem. Implementations create parent directories as needed. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsAppendFileRequest -{ - /// Content to append. - [JsonPropertyName("content")] - public string Content { get; set; } = string.Empty; + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - /// Optional POSIX-style mode for newly created files. - [JsonPropertyName("mode")] - public long? Mode { get; set; } + /// + public override string ToString() => Value; - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override StaffUpdateChannelMigrationStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + public override void Write(Utf8JsonWriter writer, StaffUpdateChannelMigrationStatus value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(StaffUpdateChannelMigrationStatus)); + } + } } -/// Indicates whether the requested path exists in the client-provided session filesystem. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsExistsResult -{ - /// Whether the path exists. - [JsonPropertyName("exists")] - public bool Exists { get; set; } -} -/// Path to test for existence in the client-provided session filesystem. +/// What the one-time staff log-level migration did. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsExistsRequest +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct StaffLogLevelMigrationStatus : IEquatable { - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + private readonly string? _value; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public StaffLogLevelMigrationStatus(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } -/// Filesystem metadata for the requested path, or a filesystem error if the stat failed. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsStatResult -{ - /// ISO 8601 timestamp of creation. - [JsonPropertyName("birthtime")] - public DateTimeOffset Birthtime { get; set; } + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Describes a filesystem error. - [JsonPropertyName("error")] - public SessionFsError? Error { get; set; } + /// The account is not a staff account, so the migration does not apply and nothing was recorded. + public static StaffLogLevelMigrationStatus Ineligible { get; } = new("ineligible"); - /// Whether the path is a directory. - [JsonPropertyName("isDirectory")] - public bool IsDirectory { get; set; } + /// The migration already ran; the stored completion timestamp is returned unchanged. + public static StaffLogLevelMigrationStatus Current { get; } = new("current"); - /// Whether the path is a file. - [JsonPropertyName("isFile")] - public bool IsFile { get; set; } + /// The migration ran now. The persisted settings may have changed, so the host should adopt the returned settings when they are present. + public static StaffLogLevelMigrationStatus Refreshed { get; } = new("refreshed"); - /// ISO 8601 timestamp of last modification. - [JsonPropertyName("mtime")] - public DateTimeOffset Mtime { get; set; } + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(StaffLogLevelMigrationStatus left, StaffLogLevelMigrationStatus right) => left.Equals(right); - /// File size in bytes. - [JsonPropertyName("size")] - public long Size { get; set; } -} + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(StaffLogLevelMigrationStatus left, StaffLogLevelMigrationStatus right) => !(left == right); -/// Path whose metadata should be returned from the client-provided session filesystem. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsStatRequest -{ - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// + public override bool Equals(object? obj) => obj is StaffLogLevelMigrationStatus other && Equals(other); - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// + public bool Equals(StaffLogLevelMigrationStatus other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); -/// Directory path to create in the client-provided session filesystem, with options for recursive creation and POSIX mode. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsMkdirRequest -{ - /// Optional POSIX-style mode for newly created directories. - [JsonPropertyName("mode")] - public long? Mode { get; set; } + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// + public override string ToString() => Value; - /// Create parent directories as needed. - [JsonPropertyName("recursive")] - public bool? Recursive { get; set; } + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override StaffLogLevelMigrationStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + public override void Write(Utf8JsonWriter writer, StaffLogLevelMigrationStatus value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(StaffLogLevelMigrationStatus)); + } + } } -/// Names of entries in the requested directory, or a filesystem error if the read failed. + +/// What the one-time obsolete-settings cleanup did to the document. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsReaddirResult +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct UserSettingsMigrateObsoleteOnDiskStatus : IEquatable { - /// Entry names in the directory. - [JsonPropertyName("entries")] - public IList Entries { get => field ??= []; set; } + private readonly string? _value; - /// Describes a filesystem error. - [JsonPropertyName("error")] - public SessionFsError? Error { get; set; } -} + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public UserSettingsMigrateObsoleteOnDiskStatus(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } -/// Directory path whose entries should be listed from the client-provided session filesystem. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsReaddirRequest -{ - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// No settings document exists, so there was nothing to clean. + public static UserSettingsMigrateObsoleteOnDiskStatus Missing { get; } = new("missing"); -/// Directory entry returned by session filesystem `readdirWithTypes`, with name and entry type. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsReaddirWithTypesEntry -{ - /// Entry name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// The document could not be parsed, so it was left untouched rather than rewritten from a partial read. + public static UserSettingsMigrateObsoleteOnDiskStatus Invalid { get; } = new("invalid"); - /// Entry type. - [JsonPropertyName("type")] - public SessionFsReaddirWithTypesEntryType Type { get; set; } -} + /// The document parsed and held nothing obsolete, so nothing was written. + public static UserSettingsMigrateObsoleteOnDiskStatus Unchanged { get; } = new("unchanged"); -/// Entries in the requested directory paired with file/directory type information, or a filesystem error if the read failed. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsReaddirWithTypesResult -{ - /// Directory entries with type information. - [JsonPropertyName("entries")] - public IList Entries { get => field ??= []; set; } + /// Obsolete keys were removed and the document was rewritten. + public static UserSettingsMigrateObsoleteOnDiskStatus Changed { get; } = new("changed"); - /// Describes a filesystem error. - [JsonPropertyName("error")] - public SessionFsError? Error { get; set; } -} + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(UserSettingsMigrateObsoleteOnDiskStatus left, UserSettingsMigrateObsoleteOnDiskStatus right) => left.Equals(right); -/// Directory path whose entries (with type information) should be listed from the client-provided session filesystem. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsReaddirWithTypesRequest -{ - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(UserSettingsMigrateObsoleteOnDiskStatus left, UserSettingsMigrateObsoleteOnDiskStatus right) => !(left == right); - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// + public override bool Equals(object? obj) => obj is UserSettingsMigrateObsoleteOnDiskStatus other && Equals(other); -/// Path to remove from the client-provided session filesystem, with options for recursive removal and force. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsRmRequest -{ - /// Ignore errors if the path does not exist. - [JsonPropertyName("force")] - public bool? Force { get; set; } + /// + public bool Equals(UserSettingsMigrateObsoleteOnDiskStatus other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - /// Path using SessionFs conventions. - [JsonPropertyName("path")] - public string Path { get; set; } = string.Empty; + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - /// Remove directories and their contents recursively. - [JsonPropertyName("recursive")] - public bool? Recursive { get; set; } + /// + public override string ToString() => Value; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override UserSettingsMigrateObsoleteOnDiskStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, UserSettingsMigrateObsoleteOnDiskStatus value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(UserSettingsMigrateObsoleteOnDiskStatus)); + } + } } -/// Source and destination paths for renaming or moving an entry in the client-provided session filesystem. + +/// Whether one atomic settings edit changed a file. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsRenameRequest +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct SettingsEditStatus : IEquatable { - /// Destination path using SessionFs conventions. - [JsonPropertyName("dest")] - public string Dest { get; set; } = string.Empty; + private readonly string? _value; - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public SettingsEditStatus(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } - /// Source path using SessionFs conventions. - [JsonPropertyName("src")] - public string Src { get; set; } = string.Empty; -} + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; -/// Query results including rows, columns, and rows affected, or a filesystem error if execution failed. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsSqliteQueryResult -{ - /// Column names from the result set. - [JsonPropertyName("columns")] - public IList Columns { get => field ??= []; set; } + /// The edit changed the setting and was stored. + public static SettingsEditStatus Changed { get; } = new("changed"); - /// Describes a filesystem error. - [JsonPropertyName("error")] - public SessionFsError? Error { get; set; } + /// The setting already had the requested state. + public static SettingsEditStatus Unchanged { get; } = new("unchanged"); - /// SQLite last_insert_rowid() value for INSERT. - [JsonPropertyName("lastInsertRowid")] - public long? LastInsertRowid { get; set; } + /// The existing settings file could not be edited safely; nothing was written. + public static SettingsEditStatus Invalid { get; } = new("invalid"); - /// For SELECT: array of row objects. For others: empty array. - [JsonPropertyName("rows")] - public IList> Rows { get => field ??= []; set; } + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SettingsEditStatus left, SettingsEditStatus right) => left.Equals(right); - /// Number of rows affected (for INSERT/UPDATE/DELETE). - [JsonPropertyName("rowsAffected")] - public long RowsAffected { get; set; } -} + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SettingsEditStatus left, SettingsEditStatus right) => !(left == right); -/// SQL query, query type, and optional bind parameters for executing a SQLite query against the per-session database. The provider applies its SQLite busy timeout for every call. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsSqliteQueryRequest -{ - /// Optional named bind parameters. - [JsonPropertyName("params")] - public IDictionary? Params { get; set; } + /// + public override bool Equals(object? obj) => obj is SettingsEditStatus other && Equals(other); - /// SQL query to execute. - [JsonPropertyName("query")] - public string Query { get; set; } = string.Empty; + /// + public bool Equals(SettingsEditStatus other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - /// How to execute the query: 'exec' for DDL/multi-statement (no results), 'query' for SELECT (returns rows), 'run' for INSERT/UPDATE/DELETE (returns rowsAffected). - [JsonPropertyName("queryType")] - public SessionFsSqliteQueryType QueryType { get; set; } + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// + public override string ToString() => Value; -/// Classified SQLite transaction failure. busyOrLocked guarantees rollback; postCommitAmbiguous must never be retried. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsSqliteTransactionError -{ - /// Machine-readable classification of the transaction failure. - [JsonPropertyName("errorClass")] - public SessionFsSqliteTransactionErrorClass ErrorClass { get; set; } + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override SettingsEditStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } - /// Human-readable transaction failure message. - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; + /// + public override void Write(Utf8JsonWriter writer, SettingsEditStatus value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SettingsEditStatus)); + } + } } -/// Per-statement results, or a classified transaction error. + +/// One atomic settings mutation. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsSqliteTransactionResult +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct SettingsEditOperation : IEquatable { - /// Classified transaction failure, when execution did not succeed. - [JsonPropertyName("error")] - public SessionFsSqliteTransactionError? Error { get; set; } + private readonly string? _value; - /// Per-statement query results in input order. - [JsonPropertyName("results")] - public IList Results { get => field ??= []; set; } -} + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public SettingsEditOperation(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } -/// One statement in an atomic SQLite transaction. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsSqliteTransactionStatement -{ - /// Optional named bind parameters. - [JsonPropertyName("params")] - public IDictionary? Params { get; set; } + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// SQL statement to execute. - [JsonPropertyName("query")] - public string Query { get; set; } = string.Empty; + /// Set one scalar value. + public static SettingsEditOperation Set { get; } = new("set"); - /// How to execute the statement. - [JsonPropertyName("queryType")] - public SessionFsSqliteQueryType QueryType { get; set; } -} + /// Add one string to a list, unless present. + public static SettingsEditOperation AddItem { get; } = new("add-item"); -/// Statements to execute atomically. Providers apply busy handling for every call. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsSqliteTransactionRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// Remove one string from a list, unless absent. + public static SettingsEditOperation RemoveItem { get; } = new("remove-item"); - /// Ordered SQL statements to execute in one transaction. - [JsonPropertyName("statements")] - public IList Statements { get => field ??= []; set; } -} + /// Remove the setting without supplying a value. + public static SettingsEditOperation Remove { get; } = new("remove"); -/// Indicates whether the per-session SQLite database already exists. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class SessionFsSqliteExistsResult -{ - /// Whether the session database already exists. - [JsonPropertyName("exists")] - public bool Exists { get; set; } -} + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SettingsEditOperation left, SettingsEditOperation right) => left.Equals(right); -/// Identifies the target session. -public sealed class SessionFsSqliteExistsRequest -{ - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SettingsEditOperation left, SettingsEditOperation right) => !(left == right); -/// Canvas open result returned by the provider. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CanvasProviderOpenResult -{ - /// Provider-supplied status text. - [JsonPropertyName("status")] - public string? Status { get; set; } + /// + public override bool Equals(object? obj) => obj is SettingsEditOperation other && Equals(other); - /// Provider-supplied title. - [JsonPropertyName("title")] - public string? Title { get; set; } + /// + public bool Equals(SettingsEditOperation other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - /// URL for web-rendered canvases. - [JsonPropertyName("url")] - public string? Url { get; set; } -} + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); -/// Host capabilities. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CanvasHostContextCapabilities -{ - /// Whether canvas rendering is supported. - [JsonPropertyName("canvases")] - public bool? Canvases { get; set; } -} + /// + public override string ToString() => Value; -/// Host context supplied by the runtime. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CanvasHostContext -{ - /// Host capabilities. - [JsonPropertyName("capabilities")] - public CanvasHostContextCapabilities? Capabilities { get; set; } -} + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override SettingsEditOperation Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } -/// Session context supplied by the runtime. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CanvasSessionContext -{ - /// Active session working directory, when known. - [JsonPropertyName("workingDirectory")] - public string? WorkingDirectory { get; set; } + /// + public override void Write(Utf8JsonWriter writer, SettingsEditOperation value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SettingsEditOperation)); + } + } } -/// Canvas open parameters sent to the provider. + +/// Which repository settings file to edit. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CanvasProviderOpenRequest -{ - /// Provider-local canvas identifier. - [JsonPropertyName("canvasId")] - public string CanvasId { get; set; } = string.Empty; +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct RepoSettingsEditScope : IEquatable +{ + private readonly string? _value; - /// Owning provider identifier. - [JsonPropertyName("extensionId")] - public string ExtensionId { get; set; } = string.Empty; + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public RepoSettingsEditScope(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } - /// Host context supplied by the runtime. - [JsonPropertyName("host")] - public CanvasHostContext? Host { get; set; } + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Canvas open input. - [JsonPropertyName("input")] - public JsonElement? Input { get; set; } + /// The shared repository settings file. + public static RepoSettingsEditScope Repo { get; } = new("repo"); - /// Stable caller-supplied canvas instance identifier. - [JsonPropertyName("instanceId")] - public string InstanceId { get; set; } = string.Empty; + /// The local repository settings file. + public static RepoSettingsEditScope Local { get; } = new("local"); - /// Session context supplied by the runtime. - [JsonPropertyName("session")] - public CanvasSessionContext? Session { get; set; } + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(RepoSettingsEditScope left, RepoSettingsEditScope right) => left.Equals(right); - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(RepoSettingsEditScope left, RepoSettingsEditScope right) => !(left == right); -/// Canvas close parameters sent to the provider. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CanvasProviderCloseRequest -{ - /// Provider-local canvas identifier. - [JsonPropertyName("canvasId")] - public string CanvasId { get; set; } = string.Empty; + /// + public override bool Equals(object? obj) => obj is RepoSettingsEditScope other && Equals(other); - /// Owning provider identifier. - [JsonPropertyName("extensionId")] - public string ExtensionId { get; set; } = string.Empty; + /// + public bool Equals(RepoSettingsEditScope other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - /// Host context supplied by the runtime. - [JsonPropertyName("host")] - public CanvasHostContext? Host { get; set; } + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - /// Canvas instance identifier. - [JsonPropertyName("instanceId")] - public string InstanceId { get; set; } = string.Empty; + /// + public override string ToString() => Value; - /// Session context supplied by the runtime. - [JsonPropertyName("session")] - public CanvasSessionContext? Session { get; set; } + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override RepoSettingsEditScope Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; + /// + public override void Write(Utf8JsonWriter writer, RepoSettingsEditScope value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(RepoSettingsEditScope)); + } + } } -/// Canvas action invocation parameters sent to the provider. + +/// The population a feature flag is declared for, before overrides. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class CanvasProviderInvokeActionRequest +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct FeatureFlagAvailability : IEquatable { - /// Action name to invoke. - [JsonPropertyName("actionName")] - public string ActionName { get; set; } = string.Empty; + private readonly string? _value; - /// Provider-local canvas identifier. - [JsonPropertyName("canvasId")] - public string CanvasId { get; set; } = string.Empty; + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public FeatureFlagAvailability(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } - /// Owning provider identifier. - [JsonPropertyName("extensionId")] - public string ExtensionId { get; set; } = string.Empty; + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Host context supplied by the runtime. - [JsonPropertyName("host")] - public CanvasHostContext? Host { get; set; } + /// Enabled for everyone, before any override. + public static FeatureFlagAvailability On { get; } = new("on"); - /// Action input. - [JsonPropertyName("input")] - public JsonElement? Input { get; set; } + /// Enabled only for accounts on the owning team. + public static FeatureFlagAvailability Team { get; } = new("team"); - /// Canvas instance identifier. - [JsonPropertyName("instanceId")] - public string InstanceId { get; set; } = string.Empty; + /// Enabled only for staff accounts that have also opted into experimental features. + public static FeatureFlagAvailability StaffAndExperimental { get; } = new("staff-and-experimental"); - /// Session context supplied by the runtime. - [JsonPropertyName("session")] - public CanvasSessionContext? Session { get; set; } + /// Enabled for staff accounts and for accounts that opted into experimental features. + public static FeatureFlagAvailability StaffOrExperimental { get; } = new("staff-or-experimental"); - /// Target session identifier. - [JsonPropertyName("sessionId")] - public string SessionId { get; set; } = string.Empty; -} + /// Enabled for any staff account, GitHub or Microsoft. + public static FeatureFlagAvailability Staff { get; } = new("staff"); -/// Reports a supervised listener's hosting-task termination and cleanup outcome. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class HostExitedRequest -{ - /// Explicit startup or teardown failure, when present. - [JsonPropertyName("error")] - public string? Error { get; set; } + /// Enabled for GitHub staff accounts only. + public static FeatureFlagAvailability StaffGitHub { get; } = new("staff-github"); - /// Process exit status when available; absent for in-process listener tasks. - [JsonPropertyName("exitCode")] - public long? ExitCode { get; set; } + /// Enabled for Microsoft staff accounts only. + public static FeatureFlagAvailability StaffMicrosoft { get; } = new("staff-microsoft"); - /// Listener UUID. - [JsonPropertyName("hostId")] - public string HostId { get; set; } = string.Empty; + /// Enabled only for accounts that opted into experimental features. + public static FeatureFlagAvailability Experimental { get; } = new("experimental"); - /// Cause of termination. - [JsonPropertyName("reason")] - public HostExitReason Reason { get; set; } -} + /// Disabled for everyone, before any override. + public static FeatureFlagAvailability Off { get; } = new("off"); -/// Opaque integrator-owned process launch profile for one extension entrypoint. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ExtensionLaunchProfile -{ - /// Opaque integrator-defined arguments passed to the executable. The runtime does not append the extension entrypoint. - [JsonPropertyName("args")] - public IList Args { get => field ??= []; set; } + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(FeatureFlagAvailability left, FeatureFlagAvailability right) => left.Equals(right); - /// Opaque integrator-defined environment variables. Runtime-owned COPILOT_SDK_PATH, SESSION_ID, and COPILOT_EXTENSION_PARENT_PID values take precedence. - [JsonPropertyName("env")] - public IDictionary Env { get => field ??= new Dictionary(); set; } + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(FeatureFlagAvailability left, FeatureFlagAvailability right) => !(left == right); - /// Executable used to launch the extension entrypoint. - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] - [MinLength(1)] - [JsonPropertyName("executable")] - public string Executable { get; set; } = string.Empty; -} + /// + public override bool Equals(object? obj) => obj is FeatureFlagAvailability other && Equals(other); -/// The launch profile for a supported entrypoint. Omit launch when the provider does not support the entrypoint. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ExtensionLaunchProviderResolveResult -{ - /// Opaque launch profile, omitted when this provider does not support the entrypoint. - [JsonPropertyName("launch")] - public ExtensionLaunchProfile? Launch { get; set; } -} + /// + public bool Equals(FeatureFlagAvailability other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); -/// A discovered extension entrypoint that the registered integrator may classify and resolve to an opaque launch profile. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ExtensionLaunchProviderResolveRequest -{ - /// Source-qualified extension identifier. - [JsonPropertyName("id")] - public string Id { get; set; } = string.Empty; + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - /// Absolute path to the discovered extension entrypoint. - [JsonPropertyName("modulePath")] - public string ModulePath { get; set; } = string.Empty; + /// + public override string ToString() => Value; - /// Human-readable extension name. - [JsonPropertyName("name")] - public string Name { get; set; } = string.Empty; + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override FeatureFlagAvailability Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } - /// Discovery source for the extension entrypoint. - [JsonPropertyName("source")] - public ExtensionSource Source { get; set; } + /// + public override void Write(Utf8JsonWriter writer, FeatureFlagAvailability value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(FeatureFlagAvailability)); + } + } } -/// Acknowledgement. Returning successfully simply means the SDK accepted the start frame; it does not imply the request will succeed. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class LlmInferenceHttpRequestStartResult -{ -} -/// The head of an outbound model-layer HTTP request. +/// Which layer disabled bypass-permissions mode. The layer matters because only a server-delivered disable is pinned to an account and can later be lifted by signing in elsewhere. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class LlmInferenceHttpRequestStartRequest +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ManagedSettingsBypassDisableSource : IEquatable { - /// Stable identity of the agent trajectory that issued this request. Present when the request originates from an agent turn; absent for requests outside any agent context. This is the same identity used by lifecycle and bridged session events and remains constant across turns and retries. - [JsonPropertyName("agentId")] - public string? AgentId { get; set; } + private readonly string? _value; - /// Identity of the agent invocation (one agentic loop) that issued this request. It remains fixed across physical retries within the invocation and is distinct from the stable trajectory `agentId`. A caller-supplied invocation id always takes precedence (this covers auxiliary calls that have no model call id). Otherwise, first-party CAPI requests fall back to the runtime's agent task id — the same value the runtime emits as the `X-Agent-Task-Id` header — while custom-provider requests fall back to the model call id. - [JsonPropertyName("agentInvocationId")] - public string? AgentInvocationId { get; set; } + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ManagedSettingsBypassDisableSource(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } - /// HTTP request headers, preserving multiple values per name. - [JsonPropertyName("headers")] - public IDictionary> Headers { get => field ??= new Dictionary>(); set; } + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Coarse classification of the interaction that produced this request. Open string for forward-compatibility; known values include `conversation-agent`, `conversation-subagent`, `conversation-sampling`, `conversation-background`, `conversation-compaction`, and `conversation-user`. Absent when the runtime did not classify the request. Comes from the runtime's per-request agent context independently of transport; on the CAPI transport the runtime derives the upstream `X-Interaction-Type` header from this same context. - [JsonPropertyName("interactionType")] - public string? InteractionType { get; set; } + /// The user turned bypass mode off themselves. + public static ManagedSettingsBypassDisableSource User { get; } = new("user"); - /// HTTP method, e.g. GET, POST. - [JsonPropertyName("method")] - public string Method { get; set; } = string.Empty; + /// The account's server-delivered org policy disabled it. Pinned to the account named by `currentManagedIdentity`. + public static ManagedSettingsBypassDisableSource Managed { get; } = new("managed"); - /// Stable identity of the immediate parent trajectory. Present for child trajectories such as subagents and conversation-sampling requests; absent for root-agent and non-agent requests. - [JsonPropertyName("parentAgentId")] - public string? ParentAgentId { get; set; } + /// The device/MDM layer disabled it. Outranks the account, so no server answer lifts it. + public static ManagedSettingsBypassDisableSource Mdm { get; } = new("mdm"); - /// Opaque runtime-minted id, unique per in-flight request. The SDK uses this to correlate httpRequestChunk frames and to address its httpResponseStart / httpResponseChunk replies back to the runtime. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedSettingsBypassDisableSource left, ManagedSettingsBypassDisableSource right) => left.Equals(right); - /// Id of the runtime session that triggered this request, when one is in scope. Absent for requests issued outside any session (e.g. startup model-catalog or capability resolution). This is a payload field — not a dispatch key — because the client-global API is registered process-wide rather than per session. - [JsonPropertyName("sessionId")] - public string? SessionId { get; set; } + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedSettingsBypassDisableSource left, ManagedSettingsBypassDisableSource right) => !(left == right); - /// Transport the runtime would otherwise use for this request. `http` (the default when absent) covers plain HTTP and SSE responses; `websocket` indicates a full-duplex message channel where each body chunk maps to one WebSocket message and the `binary` flag distinguishes text from binary frames. The SDK consumer uses this to decide whether to service the request with an HTTP client or a WebSocket client. It is the one piece of request metadata the consumer cannot reliably infer from the URL or headers alone. - [JsonPropertyName("transport")] - public LlmInferenceHttpRequestStartTransport? Transport { get; set; } + /// + public override bool Equals(object? obj) => obj is ManagedSettingsBypassDisableSource other && Equals(other); - /// Absolute request URL. - [JsonPropertyName("url")] - public string Url { get; set; } = string.Empty; -} + /// + public bool Equals(ManagedSettingsBypassDisableSource other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); -/// Acknowledgement. The SDK is free to ignore the ack and treat chunk delivery as fire-and-forget. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class LlmInferenceHttpRequestChunkResult -{ + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ManagedSettingsBypassDisableSource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ManagedSettingsBypassDisableSource value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedSettingsBypassDisableSource)); + } + } } -/// A request body chunk or cancellation signal. + +/// What the managed-policy resolution said about bypass-permissions mode. `unknown` is a third answer rather than a missing one, and the caller must send it explicitly when it has no verdict. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class LlmInferenceHttpRequestChunkRequest +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ManagedSettingsBypassPolicyResolution : IEquatable { - /// Identity of the agent invocation (one agentic loop) this body chunk belongs to, matching the `agentInvocationId` semantics on httpRequestStart. Carried per chunk so a persistent transport can attribute successive turns correctly: when a WebSocket connection is reused across turns, the httpRequestStart identity reflects only the turn that opened the connection, so each later turn stamps its own invocation id here. Absent when the runtime has no invocation context for the request, or on the plain-HTTP transport where every request has its own httpRequestStart. - [JsonPropertyName("agentInvocationId")] - public string? AgentInvocationId { get; set; } + private readonly string? _value; - /// When true, `data` is base64-encoded bytes. When absent or false, `data` is UTF-8 text. - [JsonPropertyName("binary")] - public bool? Binary { get; set; } + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ManagedSettingsBypassPolicyResolution(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } - /// When true, the runtime is cancelling the in-flight request (e.g. upstream consumer aborted). `data` is ignored. Implies end-of-request. - [JsonPropertyName("cancel")] - public bool? Cancel { get; set; } + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Optional human-readable reason for the cancellation, propagated for logging. - [JsonPropertyName("cancelReason")] - public string? CancelReason { get; set; } + /// The policy resolved and does not disable bypass mode. + public static ManagedSettingsBypassPolicyResolution Allowed { get; } = new("allowed"); - /// Body byte range. UTF-8 text when `binary` is absent or false; base64-encoded bytes when `binary` is true. May be empty. - [JsonPropertyName("data")] - public string Data { get; set; } = string.Empty; + /// The policy resolved and disables bypass mode. + public static ManagedSettingsBypassPolicyResolution Disabled { get; } = new("disabled"); - /// When true, this is the final body chunk for the request. The SDK may rely on having received an end-marked chunk before treating the request body as complete. - [JsonPropertyName("end")] - public bool? End { get; set; } + /// No verdict: the fetch failed, or the service declared a policy this build may not enforce. Whatever is in force is preserved, because reverting to permissive on an unreadable policy would widen access. + public static ManagedSettingsBypassPolicyResolution Unknown { get; } = new("unknown"); - /// Matches the requestId from the originating httpRequestStart frame. - [JsonPropertyName("requestId")] - public string RequestId { get; set; } = string.Empty; + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedSettingsBypassPolicyResolution left, ManagedSettingsBypassPolicyResolution right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedSettingsBypassPolicyResolution left, ManagedSettingsBypassPolicyResolution right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ManagedSettingsBypassPolicyResolution other && Equals(other); + + /// + public bool Equals(ManagedSettingsBypassPolicyResolution other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ManagedSettingsBypassPolicyResolution Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ManagedSettingsBypassPolicyResolution value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedSettingsBypassPolicyResolution)); + } + } } -/// Client environment metadata describing the process that produced a telemetry event. + +/// Severity of a diagnostic emitted while ingesting managed settings. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class GitHubTelemetryClientInfo +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ManagedSettingsLogLevel : IEquatable { - /// Copilot CLI version string. - [JsonPropertyName("cli_version")] - public string CliVersion { get; set; } = string.Empty; + private readonly string? _value; - /// Name of the client application. - [JsonPropertyName("client_name")] - public string? ClientName { get; set; } + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ManagedSettingsLogLevel(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } - /// Type of client. - [JsonPropertyName("client_type")] - public string? ClientType { get; set; } + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Copilot subscription plan, when known. - [JsonPropertyName("copilot_plan")] - public string? CopilotPlan { get; set; } + /// Detail useful only when diagnosing an ingestion. + public static ManagedSettingsLogLevel Debug { get; } = new("debug"); - /// Number of logical CPU cores on the host. - [JsonPropertyName("cpu_count")] - public long? CpuCount { get; set; } + /// Ordinary progress worth surfacing under a verbose flag. + public static ManagedSettingsLogLevel Info { get; } = new("info"); - /// Distinct CPU model names for the host, comma-separated. - [JsonPropertyName("cpu_model")] - public string? CpuModel { get; set; } + /// A condition the operator should see but which did not stop the ingestion. + public static ManagedSettingsLogLevel Warning { get; } = new("warning"); - /// Stable machine identifier for the device. - [JsonPropertyName("dev_device_id")] - public string? DevDeviceId { get; set; } + /// A failure that changed the outcome of the ingestion. + public static ManagedSettingsLogLevel Error { get; } = new("error"); - /// Whether the user is a GitHub/Microsoft staff member. - [JsonPropertyName("is_staff")] - public bool? IsStaff { get; set; } + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedSettingsLogLevel left, ManagedSettingsLogLevel right) => left.Equals(right); - /// Node.js runtime version string. - [JsonPropertyName("node_version")] - public string NodeVersion { get; set; } = string.Empty; + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedSettingsLogLevel left, ManagedSettingsLogLevel right) => !(left == right); - /// Operating system architecture (e.g. arm64, x64). - [JsonPropertyName("os_arch")] - public string OsArch { get; set; } = string.Empty; + /// + public override bool Equals(object? obj) => obj is ManagedSettingsLogLevel other && Equals(other); - /// Operating system platform (e.g. darwin, linux, win32). - [JsonPropertyName("os_platform")] - public string OsPlatform { get; set; } = string.Empty; + /// + public bool Equals(ManagedSettingsLogLevel other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - /// Operating system version string. - [JsonPropertyName("os_version")] - public string OsVersion { get; set; } = string.Empty; + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ManagedSettingsLogLevel Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ManagedSettingsLogLevel value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedSettingsLogLevel)); + } + } } -/// A single telemetry event in the runtime's native GitHub-shaped telemetry format, forwarded verbatim to opted-in hosts. The `restricted` flag on the enclosing GitHubTelemetryNotification distinguishes standard from restricted events; the payload shape is identical for both. + +/// Which channel registered the policy helper that produced a helper layer. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class GitHubTelemetryEvent +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ManagedSettingsPolicyHelperAuthority : IEquatable { - /// Client environment metadata. - [JsonPropertyName("client")] - public GitHubTelemetryClientInfo? Client { get; set; } + private readonly string? _value; - /// Copilot tracking ID for user-level attribution. - [JsonPropertyName("copilot_tracking_id")] - public string? CopilotTrackingId { get; set; } + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ManagedSettingsPolicyHelperAuthority(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } - /// Timestamp when the event was created (ISO 8601 format). - [JsonPropertyName("created_at")] - public string? CreatedAt { get; set; } + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Experiment assignment context. - [JsonPropertyName("exp_assignment_context")] - public string? ExpAssignmentContext { get; set; } + /// The helper was registered by the device (MDM or managed file) layer. + public static ManagedSettingsPolicyHelperAuthority Device { get; } = new("device"); - /// Feature flags enabled for this session, as a map from flag to value. - [JsonPropertyName("features")] - public IDictionary? Features { get; set; } + /// The helper was registered by the account's server-delivered policy. + public static ManagedSettingsPolicyHelperAuthority Server { get; } = new("server"); - /// Event type/kind (e.g. get_completion_with_tools_turn, tool_call_executed). - [JsonPropertyName("kind")] - public string Kind { get; set; } = string.Empty; + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedSettingsPolicyHelperAuthority left, ManagedSettingsPolicyHelperAuthority right) => left.Equals(right); - /// Numeric metrics as a map from key to value. - [JsonPropertyName("metrics")] - public IDictionary Metrics { get => field ??= new Dictionary(); set; } + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedSettingsPolicyHelperAuthority left, ManagedSettingsPolicyHelperAuthority right) => !(left == right); - /// Reference to the model call that produced this event. - [JsonPropertyName("model_call_id")] - public string? ModelCallId { get; set; } + /// + public override bool Equals(object? obj) => obj is ManagedSettingsPolicyHelperAuthority other && Equals(other); - /// String-valued properties as a map from key to value. - [JsonPropertyName("properties")] - public IDictionary Properties { get => field ??= new Dictionary(); set; } + /// + public bool Equals(ManagedSettingsPolicyHelperAuthority other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - /// Session identifier the event belongs to. - [JsonPropertyName("session_id")] - public string? SessionId { get; set; } -} + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); -/// Payload for a `gitHubTelemetry.event` notification: a single GitHub telemetry event the runtime forwards to a host connection that opted into telemetry forwarding during the `server.connect` handshake. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class GitHubTelemetryNotification -{ - /// The telemetry event, in the runtime's native GitHub-shaped telemetry format. - [JsonPropertyName("event")] - public GitHubTelemetryEvent Event { get => field ??= new(); set; } + /// + public override string ToString() => Value; - /// Whether this is a restricted telemetry event (cli.restricted_telemetry). Hosts must route restricted events to first-party Microsoft stores only. - [JsonPropertyName("restricted")] - public bool Restricted { get; set; } + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ManagedSettingsPolicyHelperAuthority Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } - /// Session the telemetry event belongs to, when it is session-scoped. Omitted for sessionless events (for example, `server.sendTelemetry` calls with no session id), which are still forwarded to opted-in connections. - [JsonPropertyName("sessionId")] - public string? SessionId { get; set; } + /// + public override void Write(Utf8JsonWriter writer, ManagedSettingsPolicyHelperAuthority value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedSettingsPolicyHelperAuthority)); + } + } } -/// SDK host response to a GitHub credential request. -/// Polymorphic base type discriminated by kind. + +/// How the server layer of an ingestion was resolved. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "kind", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(GitHubTokenAcquireResultToken), "token")] -[JsonDerivedType(typeof(GitHubTokenAcquireResultCancelled), "cancelled")] -public partial class GitHubTokenAcquireResult +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ManagedSettingsServerPolicyResolution : IEquatable { - /// The type discriminator. - [JsonPropertyName("kind")] - public virtual string Kind { get; set; } = string.Empty; -} + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ManagedSettingsServerPolicyResolution(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; -/// The token variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class GitHubTokenAcquireResultToken : GitHubTokenAcquireResult -{ - /// - [JsonIgnore] - public override string Kind => "token"; + /// A live fetch succeeded. + public static ManagedSettingsServerPolicyResolution Live { get; } = new("live"); + + /// A recent cached entry was served without a live fetch. + public static ManagedSettingsServerPolicyResolution FreshCache { get; } = new("freshCache"); + + /// No cached policy or confirmed no-policy result exists. + public static ManagedSettingsServerPolicyResolution CacheMiss { get; } = new("cacheMiss"); + + /// A live fetch failed and a cached entry was served in its place. + public static ManagedSettingsServerPolicyResolution FallbackCache { get; } = new("fallbackCache"); + + /// No policy could be resolved and the host proceeds unmanaged. + public static ManagedSettingsServerPolicyResolution FailOpen { get; } = new("failOpen"); + + /// No policy could be resolved and the host applies the fail-closed gates. + public static ManagedSettingsServerPolicyResolution FailClosed { get; } = new("failClosed"); + + /// No fetch was attempted because no usable token was available. + public static ManagedSettingsServerPolicyResolution SkippedNoToken { get; } = new("skippedNoToken"); - /// GitHub access token acquired by the SDK host. - [JsonPropertyName("accessToken")] - public required string AccessToken { get; set; } + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedSettingsServerPolicyResolution left, ManagedSettingsServerPolicyResolution right) => left.Equals(right); - /// Remaining token lifetime in seconds when callback execution completes. It must exceed the one-hour preflight refresh threshold. - [JsonPropertyName("expiresIn")] - public required long ExpiresIn { get; set; } + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedSettingsServerPolicyResolution left, ManagedSettingsServerPolicyResolution right) => !(left == right); - /// OAuth token type. Defaults to bearer when omitted. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("tokenType")] - public string? TokenType { get; set; } -} + /// + public override bool Equals(object? obj) => obj is ManagedSettingsServerPolicyResolution other && Equals(other); -/// The cancelled variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class GitHubTokenAcquireResultCancelled : GitHubTokenAcquireResult -{ /// - [JsonIgnore] - public override string Kind => "cancelled"; -} + public bool Equals(ManagedSettingsServerPolicyResolution other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); -/// Asks the SDK client to acquire a GitHub access token from an opaque callback registration. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class GitHubTokenAcquireRequest -{ - /// Effective GitHub host for which the callback must return a token. - [JsonPropertyName("host")] - public string Host { get; set; } = string.Empty; + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - /// Why the runtime is requesting a GitHub credential. - [JsonPropertyName("reason")] - public GitHubTokenAcquireReason Reason { get; set; } + /// + public override string ToString() => Value; - /// Opaque identifier generated by the SDK for this callback registration. - [JsonPropertyName("registrationId")] - public string RegistrationId { get; set; } = string.Empty; + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ManagedSettingsServerPolicyResolution Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } - /// Session receiving the token. Absent only before a cloud session has been assigned its id. - [JsonPropertyName("sessionId")] - public string? SessionId { get; set; } + /// + public override void Write(Utf8JsonWriter writer, ManagedSettingsServerPolicyResolution value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedSettingsServerPolicyResolution)); + } + } } -/// A response is meaningful only on the connection and request that issued its challenge. -public sealed class InstallationsConfirmResult + +/// The operation that requires a policy-helper response. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ManagedSettingsPolicyHelperReason : IEquatable { - /// Exact challenge from the request. - [JsonPropertyName("confirmationId")] - public string ConfirmationId { get; set; } = string.Empty; + private readonly string? _value; - /// Fresh explicit user decision. There is no default. - [JsonPropertyName("decision")] - public InstallationDecision Decision { get; set; } + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ManagedSettingsPolicyHelperReason(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } - /// Exact review commitment from the request. - [JsonPropertyName("reviewFingerprint")] - public string ReviewFingerprint { get; set; } = string.Empty; -} + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; -/// Only resource kinds with an implemented installation engine have a review variant. -/// Polymorphic base type discriminated by resource. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "resource", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(InstallationReviewMcp), "mcp")] -[JsonDerivedType(typeof(InstallationReviewSkill), "skill")] -public partial class InstallationReview -{ - /// The type discriminator. - [JsonPropertyName("resource")] - public virtual string Resource { get; set; } = string.Empty; -} + /// Resolve policy for session startup. + public static ManagedSettingsPolicyHelperReason SessionStart { get; } = new("sessionStart"); + /// Resolve policy before plugin activation. + public static ManagedSettingsPolicyHelperReason PluginActivation { get; } = new("pluginActivation"); -/// Safe MCP review fields. No raw card, retrieval URL, plan handle or secret value. -/// Polymorphic base type discriminated by action. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonPolymorphic( - TypeDiscriminatorPropertyName = "action", - UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)] -[JsonDerivedType(typeof(McpInstallationReviewInstall), "install")] -[JsonDerivedType(typeof(McpInstallationReviewUninstall), "uninstall")] -public partial class McpInstallationReview -{ - /// The type discriminator. - [JsonPropertyName("action")] - public virtual string Action { get; set; } = string.Empty; -} + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedSettingsPolicyHelperReason left, ManagedSettingsPolicyHelperReason right) => left.Equals(right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedSettingsPolicyHelperReason left, ManagedSettingsPolicyHelperReason right) => !(left == right); -/// -/// Final remote configuration, not a template. The producer refuses external-value -/// expansion before presenting this review. Receipt-owned secrets appear only as -/// `${installation-secret:<id>}` references whose `<id>` matches a reviewed -/// `${secret:<id>}` placeholder; values are never included. -/// -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class McpInstallationRemoteConfiguration -{ - /// - /// Configured headers, excluding separately authorised OAuth tokens. Values may - /// contain owned secret references, never secret values. - /// - [JsonPropertyName("headers")] - public IDictionary Headers { get => field ??= new Dictionary(); set; } + /// + public override bool Equals(object? obj) => obj is ManagedSettingsPolicyHelperReason other && Equals(other); - /// Configured tool selection, not permission to invoke those tools. - [JsonPropertyName("tools")] - public IList Tools { get => field ??= []; set; } + /// + public bool Equals(ManagedSettingsPolicyHelperReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - /// Transport in the effective persisted remote configuration. - [JsonPropertyName("transport")] - public McpPlanRemoteTransport Transport { get; set; } + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - /// Exact resolved endpoint, without templates or secret placeholders. - [JsonPropertyName("url")] - public string Url { get; set; } = string.Empty; + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ManagedSettingsPolicyHelperReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ManagedSettingsPolicyHelperReason value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedSettingsPolicyHelperReason)); + } + } } -/// The install variant of . + +/// How an ingestion may use the on-disk server-policy cache. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationReviewInstall : McpInstallationReview +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ManagedSettingsServerPolicyCacheMode : IEquatable { - /// - [JsonIgnore] - public override string Action => "install"; + private readonly string? _value; - /// Catalogue identity retained from the bound candidate when available. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("catalogue")] - public InstallationCatalogueIdentity? Catalogue { get; set; } + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ManagedSettingsServerPolicyCacheMode(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } - /// Original catalogue trust metadata, not a verification claim. - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("catalogueTrust")] - public CatalogTrustSnapshot? CatalogueTrust { get; set; } + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// The configuration change for the selected alternative only. - [JsonPropertyName("configurationChange")] - public required McpPlanConfigurationChange ConfigurationChange { get; set; } + /// Serve a recent cache entry before a live fetch. + public static ManagedSettingsServerPolicyCacheMode PreferFresh { get; } = new("preferFresh"); - /// - /// Complete effective remote configuration for final installation review. - /// Earlier private selection reviews and package choices omit this field. - /// The owned remote resource requires it before issuing confirmation. - /// - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonPropertyName("effectiveConfiguration")] - public McpInstallationRemoteConfiguration? EffectiveConfiguration { get; set; } + /// Read cached policy without a network request. + public static ManagedSettingsServerPolicyCacheMode CacheOnly { get; } = new("cacheOnly"); - /// Identity from the retained plan, not caller display text. - [JsonPropertyName("identity")] - public required McpPlanResourceIdentity Identity { get; set; } + /// Serve a cached entry only as a fallback after a failed live fetch. + public static ManagedSettingsServerPolicyCacheMode FallbackOnly { get; } = new("fallbackOnly"); - /// Non-secret values supplied for this selected alternative. - [JsonPropertyName("inputs")] - public required IList Inputs { get; set; } + /// Ignore the cache entirely and rely on the live fetch alone. + public static ManagedSettingsServerPolicyCacheMode Disabled { get; } = new("disabled"); - /// Policy decision bound to this plan. - [JsonPropertyName("policy")] - public required McpPlanPolicyResult Policy { get; set; } + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedSettingsServerPolicyCacheMode left, ManagedSettingsServerPolicyCacheMode right) => left.Equals(right); - /// Original source identity and content commitment. - [JsonPropertyName("provenance")] - public required McpPlanProvenance Provenance { get; set; } + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedSettingsServerPolicyCacheMode left, ManagedSettingsServerPolicyCacheMode right) => !(left == right); - /// Explicit reviewed backend selection; no backend is accessed when no secrets are supplied. - [JsonPropertyName("secretStorage")] - public required McpInstallationSecretStorage SecretStorage { get; set; } + /// + public override bool Equals(object? obj) => obj is ManagedSettingsServerPolicyCacheMode other && Equals(other); - /// Only the selected alternative is applied. - [JsonPropertyName("selectedChoice")] - public required McpPlanTransportChoice SelectedChoice { get; set; } + /// + public bool Equals(ManagedSettingsServerPolicyCacheMode other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - /// Exact reviewed placeholders supplied separately. Never secret values. - [JsonPropertyName("suppliedSecrets")] - public required IList SuppliedSecrets { get; set; } + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - /// Exact reviewed user-scope destination. - [JsonPropertyName("target")] - public required McpPlanTarget Target { get; set; } + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ManagedSettingsServerPolicyCacheMode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ManagedSettingsServerPolicyCacheMode value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedSettingsServerPolicyCacheMode)); + } + } } -/// The uninstall variant of . + +/// Severity of a managed-settings validation finding. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class McpInstallationReviewUninstall : McpInstallationReview +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ManagedSettingsDiagnosticSeverity : IEquatable { - /// - [JsonIgnore] - public override string Action => "uninstall"; + private readonly string? _value; - /// Identity from the installed receipt. - [JsonPropertyName("identity")] - public required McpPlanResourceIdentity Identity { get; set; } + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ManagedSettingsDiagnosticSeverity(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } - /// Receipt-owned installation being removed. - [JsonPropertyName("installationId")] - public required string InstallationId { get; set; } + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Exact planner-owned secret slots to remove, excluding shared OAuth grants. - [JsonPropertyName("ownedSecretCount")] - public required long OwnedSecretCount { get; set; } + /// The runtime rejects the document. + public static ManagedSettingsDiagnosticSeverity Error { get; } = new("error"); - /// Current removal policy, independent of permission to activate the server. - [JsonPropertyName("policy")] - public required McpPlanPolicyResult Policy { get; set; } + /// The runtime accepts the document but ignores the flagged content. + public static ManagedSettingsDiagnosticSeverity Warning { get; } = new("warning"); - /// Shared profile authentication is deliberately retained, not pending cleanup. - [JsonPropertyName("preservesSharedAuthentication")] - public required bool PreservesSharedAuthentication { get; set; } + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedSettingsDiagnosticSeverity left, ManagedSettingsDiagnosticSeverity right) => left.Equals(right); - /// Source identity and content commitment retained by the installed receipt. - [JsonPropertyName("provenance")] - public required McpPlanProvenance Provenance { get; set; } + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedSettingsDiagnosticSeverity left, ManagedSettingsDiagnosticSeverity right) => !(left == right); - /// Whether uninstall restores a protected pre-install configuration. - [JsonPropertyName("restoresPreviousConfiguration")] - public required bool RestoresPreviousConfiguration { get; set; } + /// + public override bool Equals(object? obj) => obj is ManagedSettingsDiagnosticSeverity other && Equals(other); - /// Exact destination, checked for intervening changes before mutation. - [JsonPropertyName("target")] - public required McpPlanTarget Target { get; set; } -} + /// + public bool Equals(ManagedSettingsDiagnosticSeverity other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); -/// The mcp variant of . -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class InstallationReviewMcp : InstallationReview -{ /// - [JsonIgnore] - public override string Resource => "mcp"; + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - /// The exact MCP action and its reviewed changes. - [JsonPropertyName("review")] - public required McpInstallationReview Review { get; set; } + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ManagedSettingsDiagnosticSeverity Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ManagedSettingsDiagnosticSeverity value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedSettingsDiagnosticSeverity)); + } + } } -/// The skill variant of . + +/// A channel accepted by managedSettings.compose. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public partial class InstallationReviewSkill : InstallationReview +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ManagedSettingsChannel : IEquatable { - /// - [JsonIgnore] - public override string Resource => "skill"; + private readonly string? _value; - /// The exact verified Skill action and its reviewed files. - [JsonPropertyName("review")] - public required SkillInstallationReview Review { get; set; } -} + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ManagedSettingsChannel(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } -/// One connection-owned, expiring request for a trusted host's explicit user decision. -public sealed class InstallationsConfirmRequest -{ - /// Opaque one-use challenge. Return unchanged; never log or persist. - [JsonPropertyName("confirmationId")] - public string ConfirmationId { get; set; } = string.Empty; + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; - /// Original plan expiry as an ISO 8601 timestamp. Confirmation never extends it. - [JsonPropertyName("expiresAt")] - public string ExpiresAt { get; set; } = string.Empty; + /// Device policy, the strongest channel. + public static ManagedSettingsChannel Device { get; } = new("device"); - /// Random identifier of this installation operation, not a plan handle. - [JsonPropertyName("operationId")] - public string OperationId { get; set; } = string.Empty; + /// Account or organization policy. + public static ManagedSettingsChannel Server { get; } = new("server"); - /// - /// Original engine-resolved selector for a bound operation, never a dispatch default. - /// Bound MCP confirmation always includes it; correlate it with the original pending action. - /// - [JsonPropertyName("policySessionId")] - public string? PolicySessionId { get; set; } + /// Session-local helper output, the weakest channel. + public static ManagedSettingsChannel PolicyHelper { get; } = new("policyHelper"); - /// Resource-specific review to present before collecting the user's decision. - [JsonPropertyName("review")] - public InstallationReview Review { get => field ??= new(); set; } + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedSettingsChannel left, ManagedSettingsChannel right) => left.Equals(right); - /// Opaque commitment to the exact review and inputs. Return unchanged; never log. - [JsonPropertyName("reviewFingerprint")] - public string ReviewFingerprint { get; set; } = string.Empty; + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedSettingsChannel left, ManagedSettingsChannel right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ManagedSettingsChannel other && Equals(other); + + /// + public bool Equals(ManagedSettingsChannel other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ManagedSettingsChannel Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ManagedSettingsChannel value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedSettingsChannel)); + } + } } -/// Closed set of public task kinds a connection can negotiate. + +/// Managed-policy verdict only: deny blocks the URL, ask requires approval, allow approves under managed policy, and unmanaged leaves the normal consumer permission flow in effect. No verdict bypasses other security controls. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct TaskKind : IEquatable +public readonly struct ManagedPermissionVerdict : IEquatable { private readonly string? _value; - /// Initializes a new instance of the struct. - /// The value to associate with this . + /// Initializes a new instance of the struct. + /// The value to associate with this . [JsonConstructor] - public TaskKind(string value) + public ManagedPermissionVerdict(string value) { ArgumentException.ThrowIfNullOrWhiteSpace(value); _value = value; } - /// Gets the value associated with this . + /// Gets the value associated with this . public string Value => _value ?? string.Empty; - /// Runtime-owned background agent task. - public static TaskKind Agent { get; } = new("agent"); + /// Managed policy prohibits the operation; do not offer approval. + public static ManagedPermissionVerdict Deny { get; } = new("deny"); - /// Runtime-owned shell task. - public static TaskKind Shell { get; } = new("shell"); + /// Managed policy requires the consumer to obtain approval. + public static ManagedPermissionVerdict Ask { get; } = new("ask"); - /// Client-owned externally executed task. - public static TaskKind Client { get; } = new("client"); + /// Managed policy allows the operation, subject to other security controls. + public static ManagedPermissionVerdict Allow { get; } = new("allow"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(TaskKind left, TaskKind right) => left.Equals(right); + /// Managed policy does not decide the operation; use the consumer's normal permission flow. + public static ManagedPermissionVerdict Unmanaged { get; } = new("unmanaged"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(TaskKind left, TaskKind right) => !(left == right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ManagedPermissionVerdict left, ManagedPermissionVerdict right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ManagedPermissionVerdict left, ManagedPermissionVerdict right) => !(left == right); /// - public override bool Equals(object? obj) => obj is TaskKind other && Equals(other); + public override bool Equals(object? obj) => obj is ManagedPermissionVerdict other && Equals(other); /// - public bool Equals(TaskKind other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(ManagedPermissionVerdict other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -28889,20 +31377,20 @@ public TaskKind(string value) /// public override string ToString() => Value; - /// Provides a for serializing instances. + /// Provides a for serializing instances. [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + public sealed class Converter : JsonConverter { /// - public override TaskKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override ManagedPermissionVerdict Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, TaskKind value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, ManagedPermissionVerdict value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(TaskKind)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedPermissionVerdict)); } } } @@ -29427,75 +31915,6 @@ public override void Write(Utf8JsonWriter writer, ModelPolicyState value, JsonSe } -/// State of the persistent certificate authority of the sandbox credential proxy. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct SandboxProxyCaState : IEquatable -{ - private readonly string? _value; - - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public SandboxProxyCaState(string value) - { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; - } - - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// This platform has no supported OS trust store. The proxy uses a per-process certificate bundle. - public static SandboxProxyCaState Unsupported { get; } = new("unsupported"); - - /// OS trust does not include the certificate authority, or none is stored. - public static SandboxProxyCaState NotInstalled { get; } = new("notInstalled"); - - /// OS trust includes the stored certificate authority. - public static SandboxProxyCaState Installed { get; } = new("installed"); - - /// The runtime could not read the certificate authority or the OS trust store. - public static SandboxProxyCaState Error { get; } = new("error"); - - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SandboxProxyCaState left, SandboxProxyCaState right) => left.Equals(right); - - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SandboxProxyCaState left, SandboxProxyCaState right) => !(left == right); - - /// - public override bool Equals(object? obj) => obj is SandboxProxyCaState other && Equals(other); - - /// - public bool Equals(SandboxProxyCaState other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - - /// - public override string ToString() => Value; - - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter - { - /// - public override SandboxProxyCaState Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } - - /// - public override void Write(Utf8JsonWriter writer, SandboxProxyCaState value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SandboxProxyCaState)); - } - } -} - - /// Authentication type. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] @@ -33639,225 +36058,6 @@ public override void Write(Utf8JsonWriter writer, SlashCommandKind value, JsonSe } -/// Whether one atomic settings edit changed a file. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct SettingsEditStatus : IEquatable -{ - private readonly string? _value; - - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public SettingsEditStatus(string value) - { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; - } - - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// The edit changed the setting and was stored. - public static SettingsEditStatus Changed { get; } = new("changed"); - - /// The setting already had the requested state. - public static SettingsEditStatus Unchanged { get; } = new("unchanged"); - - /// The existing settings file could not be edited safely; nothing was written. - public static SettingsEditStatus Invalid { get; } = new("invalid"); - - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SettingsEditStatus left, SettingsEditStatus right) => left.Equals(right); - - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SettingsEditStatus left, SettingsEditStatus right) => !(left == right); - - /// - public override bool Equals(object? obj) => obj is SettingsEditStatus other && Equals(other); - - /// - public bool Equals(SettingsEditStatus other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - - /// - public override string ToString() => Value; - - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter - { - /// - public override SettingsEditStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } - - /// - public override void Write(Utf8JsonWriter writer, SettingsEditStatus value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SettingsEditStatus)); - } - } -} - - -/// One atomic settings mutation. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct SettingsEditOperation : IEquatable -{ - private readonly string? _value; - - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public SettingsEditOperation(string value) - { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; - } - - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// Set one scalar value. - public static SettingsEditOperation Set { get; } = new("set"); - - /// Add one string to a list, unless present. - public static SettingsEditOperation AddItem { get; } = new("add-item"); - - /// Remove one string from a list, unless absent. - public static SettingsEditOperation RemoveItem { get; } = new("remove-item"); - - /// Remove the setting without supplying a value. - public static SettingsEditOperation Remove { get; } = new("remove"); - - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SettingsEditOperation left, SettingsEditOperation right) => left.Equals(right); - - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SettingsEditOperation left, SettingsEditOperation right) => !(left == right); - - /// - public override bool Equals(object? obj) => obj is SettingsEditOperation other && Equals(other); - - /// - public bool Equals(SettingsEditOperation other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - - /// - public override string ToString() => Value; - - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter - { - /// - public override SettingsEditOperation Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } - - /// - public override void Write(Utf8JsonWriter writer, SettingsEditOperation value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SettingsEditOperation)); - } - } -} - - -/// The population a feature flag is declared for, before overrides. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct FeatureFlagAvailability : IEquatable -{ - private readonly string? _value; - - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public FeatureFlagAvailability(string value) - { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; - } - - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// Enabled for everyone, before any override. - public static FeatureFlagAvailability On { get; } = new("on"); - - /// Enabled only for accounts on the owning team. - public static FeatureFlagAvailability Team { get; } = new("team"); - - /// Enabled only for staff accounts that have also opted into experimental features. - public static FeatureFlagAvailability StaffAndExperimental { get; } = new("staff-and-experimental"); - - /// Enabled for staff accounts and for accounts that opted into experimental features. - public static FeatureFlagAvailability StaffOrExperimental { get; } = new("staff-or-experimental"); - - /// Enabled for any staff account, GitHub or Microsoft. - public static FeatureFlagAvailability Staff { get; } = new("staff"); - - /// Enabled for GitHub staff accounts only. - public static FeatureFlagAvailability StaffGitHub { get; } = new("staff-github"); - - /// Enabled for Microsoft staff accounts only. - public static FeatureFlagAvailability StaffMicrosoft { get; } = new("staff-microsoft"); - - /// Enabled only for accounts that opted into experimental features. - public static FeatureFlagAvailability Experimental { get; } = new("experimental"); - - /// Disabled for everyone, before any override. - public static FeatureFlagAvailability Off { get; } = new("off"); - - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(FeatureFlagAvailability left, FeatureFlagAvailability right) => left.Equals(right); - - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(FeatureFlagAvailability left, FeatureFlagAvailability right) => !(left == right); - - /// - public override bool Equals(object? obj) => obj is FeatureFlagAvailability other && Equals(other); - - /// - public bool Equals(FeatureFlagAvailability other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - - /// - public override string ToString() => Value; - - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter - { - /// - public override FeatureFlagAvailability Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } - - /// - public override void Write(Utf8JsonWriter writer, FeatureFlagAvailability value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(FeatureFlagAvailability)); - } - } -} - - /// Hosting platform type of the repository. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] @@ -33921,204 +36121,6 @@ public override void Write(Utf8JsonWriter writer, SessionWorkingDirectoryContext } -/// Severity of a managed-settings validation finding. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct ManagedSettingsDiagnosticSeverity : IEquatable -{ - private readonly string? _value; - - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public ManagedSettingsDiagnosticSeverity(string value) - { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; - } - - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// The runtime rejects the document. - public static ManagedSettingsDiagnosticSeverity Error { get; } = new("error"); - - /// The runtime accepts the document but ignores the flagged content. - public static ManagedSettingsDiagnosticSeverity Warning { get; } = new("warning"); - - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ManagedSettingsDiagnosticSeverity left, ManagedSettingsDiagnosticSeverity right) => left.Equals(right); - - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ManagedSettingsDiagnosticSeverity left, ManagedSettingsDiagnosticSeverity right) => !(left == right); - - /// - public override bool Equals(object? obj) => obj is ManagedSettingsDiagnosticSeverity other && Equals(other); - - /// - public bool Equals(ManagedSettingsDiagnosticSeverity other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - - /// - public override string ToString() => Value; - - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter - { - /// - public override ManagedSettingsDiagnosticSeverity Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } - - /// - public override void Write(Utf8JsonWriter writer, ManagedSettingsDiagnosticSeverity value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedSettingsDiagnosticSeverity)); - } - } -} - - -/// A channel accepted by managedSettings.compose. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct ManagedSettingsChannel : IEquatable -{ - private readonly string? _value; - - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public ManagedSettingsChannel(string value) - { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; - } - - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// Device policy, the strongest channel. - public static ManagedSettingsChannel Device { get; } = new("device"); - - /// Account or organization policy. - public static ManagedSettingsChannel Server { get; } = new("server"); - - /// Session-local helper output, the weakest channel. - public static ManagedSettingsChannel PolicyHelper { get; } = new("policyHelper"); - - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ManagedSettingsChannel left, ManagedSettingsChannel right) => left.Equals(right); - - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ManagedSettingsChannel left, ManagedSettingsChannel right) => !(left == right); - - /// - public override bool Equals(object? obj) => obj is ManagedSettingsChannel other && Equals(other); - - /// - public bool Equals(ManagedSettingsChannel other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - - /// - public override string ToString() => Value; - - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter - { - /// - public override ManagedSettingsChannel Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } - - /// - public override void Write(Utf8JsonWriter writer, ManagedSettingsChannel value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedSettingsChannel)); - } - } -} - - -/// Managed-policy verdict only: deny blocks the URL, ask requires approval, allow approves under managed policy, and unmanaged leaves the normal consumer permission flow in effect. No verdict bypasses other security controls. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct ManagedPermissionVerdict : IEquatable -{ - private readonly string? _value; - - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public ManagedPermissionVerdict(string value) - { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; - } - - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// Managed policy prohibits the operation; do not offer approval. - public static ManagedPermissionVerdict Deny { get; } = new("deny"); - - /// Managed policy requires the consumer to obtain approval. - public static ManagedPermissionVerdict Ask { get; } = new("ask"); - - /// Managed policy allows the operation, subject to other security controls. - public static ManagedPermissionVerdict Allow { get; } = new("allow"); - - /// Managed policy does not decide the operation; use the consumer's normal permission flow. - public static ManagedPermissionVerdict Unmanaged { get; } = new("unmanaged"); - - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ManagedPermissionVerdict left, ManagedPermissionVerdict right) => left.Equals(right); - - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ManagedPermissionVerdict left, ManagedPermissionVerdict right) => !(left == right); - - /// - public override bool Equals(object? obj) => obj is ManagedPermissionVerdict other && Equals(other); - - /// - public bool Equals(ManagedPermissionVerdict other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - - /// - public override string ToString() => Value; - - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter - { - /// - public override ManagedPermissionVerdict Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } - - /// - public override void Write(Utf8JsonWriter writer, ManagedPermissionVerdict value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ManagedPermissionVerdict)); - } - } -} - - /// Path conventions used by this filesystem. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] @@ -43951,32 +45953,485 @@ public override void Write(Utf8JsonWriter writer, RemoteSessionMode value, JsonS /// Initializes a new instance of the struct. /// The value to associate with this . [JsonConstructor] - public SessionVisibilityStatus(string value) + public SessionVisibilityStatus(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// The session is visible to repository readers. + public static SessionVisibilityStatus Repo { get; } = new("repo"); + + /// The session is restricted to its creator and collaborators. + public static SessionVisibilityStatus Unshared { get; } = new("unshared"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SessionVisibilityStatus left, SessionVisibilityStatus right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SessionVisibilityStatus left, SessionVisibilityStatus right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is SessionVisibilityStatus other && Equals(other); + + /// + public bool Equals(SessionVisibilityStatus other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override SessionVisibilityStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, SessionVisibilityStatus value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionVisibilityStatus)); + } + } +} + + +/// Why the runtime requests client-task cancellation. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct ClientTaskCancelReason : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public ClientTaskCancelReason(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// A caller requested task cancellation. + public static ClientTaskCancelReason CancelRequested { get; } = new("cancel_requested"); + + /// The session is shutting down. + public static ClientTaskCancelReason SessionShutdown { get; } = new("session_shutdown"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(ClientTaskCancelReason left, ClientTaskCancelReason right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(ClientTaskCancelReason left, ClientTaskCancelReason right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is ClientTaskCancelReason other && Equals(other); + + /// + public bool Equals(ClientTaskCancelReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override ClientTaskCancelReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, ClientTaskCancelReason value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ClientTaskCancelReason)); + } + } +} + + +/// Error classification. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct SessionFsErrorCode : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public SessionFsErrorCode(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// The requested path does not exist. + public static SessionFsErrorCode ENOENT { get; } = new("ENOENT"); + + /// The filesystem operation failed for an unspecified reason. + public static SessionFsErrorCode UNKNOWN { get; } = new("UNKNOWN"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SessionFsErrorCode left, SessionFsErrorCode right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SessionFsErrorCode left, SessionFsErrorCode right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is SessionFsErrorCode other && Equals(other); + + /// + public bool Equals(SessionFsErrorCode other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override SessionFsErrorCode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, SessionFsErrorCode value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionFsErrorCode)); + } + } +} + + +/// Entry type. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct SessionFsReaddirWithTypesEntryType : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public SessionFsReaddirWithTypesEntryType(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// The entry is a file. + public static SessionFsReaddirWithTypesEntryType File { get; } = new("file"); + + /// The entry is a directory. + public static SessionFsReaddirWithTypesEntryType Directory { get; } = new("directory"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SessionFsReaddirWithTypesEntryType left, SessionFsReaddirWithTypesEntryType right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SessionFsReaddirWithTypesEntryType left, SessionFsReaddirWithTypesEntryType right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is SessionFsReaddirWithTypesEntryType other && Equals(other); + + /// + public bool Equals(SessionFsReaddirWithTypesEntryType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override SessionFsReaddirWithTypesEntryType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, SessionFsReaddirWithTypesEntryType value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionFsReaddirWithTypesEntryType)); + } + } +} + + +/// How to execute the query: 'exec' for DDL/multi-statement (no results), 'query' for SELECT (returns rows), 'run' for INSERT/UPDATE/DELETE (returns rowsAffected). +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct SessionFsSqliteQueryType : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public SessionFsSqliteQueryType(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// Execute DDL or multi-statement SQL without returning rows. + public static SessionFsSqliteQueryType Exec { get; } = new("exec"); + + /// Execute a SELECT-style query and return rows. + public static SessionFsSqliteQueryType Query { get; } = new("query"); + + /// Execute INSERT, UPDATE, or DELETE SQL and return affected-row metadata. + public static SessionFsSqliteQueryType Run { get; } = new("run"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SessionFsSqliteQueryType left, SessionFsSqliteQueryType right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SessionFsSqliteQueryType left, SessionFsSqliteQueryType right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is SessionFsSqliteQueryType other && Equals(other); + + /// + public bool Equals(SessionFsSqliteQueryType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override SessionFsSqliteQueryType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, SessionFsSqliteQueryType value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionFsSqliteQueryType)); + } + } +} + + +/// SQLite transaction failure classification. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct SessionFsSqliteTransactionErrorClass : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public SessionFsSqliteTransactionErrorClass(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// SQLite reported BUSY or LOCKED before commit; the transaction was rolled back and may be retried. + public static SessionFsSqliteTransactionErrorClass BusyOrLocked { get; } = new("busyOrLocked"); + + /// The statement, database, or provider failed definitively and must not be retried automatically. + public static SessionFsSqliteTransactionErrorClass Fatal { get; } = new("fatal"); + + /// The transport failed after the provider may have committed; retrying could duplicate effects. + public static SessionFsSqliteTransactionErrorClass PostCommitAmbiguous { get; } = new("postCommitAmbiguous"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(SessionFsSqliteTransactionErrorClass left, SessionFsSqliteTransactionErrorClass right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(SessionFsSqliteTransactionErrorClass left, SessionFsSqliteTransactionErrorClass right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is SessionFsSqliteTransactionErrorClass other && Equals(other); + + /// + public bool Equals(SessionFsSqliteTransactionErrorClass other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override SessionFsSqliteTransactionErrorClass Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, SessionFsSqliteTransactionErrorClass value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionFsSqliteTransactionErrorClass)); + } + } +} + + +/// Defines the allowed values. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct HostExitReason : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public HostExitReason(string value) + { + ArgumentException.ThrowIfNullOrWhiteSpace(value); + _value = value; + } + + /// Gets the value associated with this . + public string Value => _value ?? string.Empty; + + /// The owner requested disposal. + public static HostExitReason Disposed { get; } = new("disposed"); + + /// The hosting task or its SDK transport exited; this does not mean the runtime process exited. + public static HostExitReason Exited { get; } = new("exited"); + + /// The owning SDK connection disconnected. + public static HostExitReason OwnerDisconnected { get; } = new("ownerDisconnected"); + + /// The runtime is shutting down. + public static HostExitReason RuntimeShutdown { get; } = new("runtimeShutdown"); + + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(HostExitReason left, HostExitReason right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(HostExitReason left, HostExitReason right) => !(left == right); + + /// + public override bool Equals(object? obj) => obj is HostExitReason other && Equals(other); + + /// + public bool Equals(HostExitReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + + /// + public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + + /// + public override string ToString() => Value; + + /// Provides a for serializing instances. + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class Converter : JsonConverter + { + /// + public override HostExitReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); + } + + /// + public override void Write(Utf8JsonWriter writer, HostExitReason value, JsonSerializerOptions options) + { + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(HostExitReason)); + } + } +} + + +/// Transport the runtime would otherwise use for this request. `http` (the default when absent) covers plain HTTP and SSE responses; `websocket` indicates a full-duplex message channel where each body chunk maps to one WebSocket message and the `binary` flag distinguishes text from binary frames. The SDK consumer uses this to decide whether to service the request with an HTTP client or a WebSocket client. It is the one piece of request metadata the consumer cannot reliably infer from the URL or headers alone. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +[JsonConverter(typeof(Converter))] +[DebuggerDisplay("{Value,nq}")] +public readonly struct LlmInferenceHttpRequestStartTransport : IEquatable +{ + private readonly string? _value; + + /// Initializes a new instance of the struct. + /// The value to associate with this . + [JsonConstructor] + public LlmInferenceHttpRequestStartTransport(string value) { ArgumentException.ThrowIfNullOrWhiteSpace(value); _value = value; } - /// Gets the value associated with this . + /// Gets the value associated with this . public string Value => _value ?? string.Empty; - /// The session is visible to repository readers. - public static SessionVisibilityStatus Repo { get; } = new("repo"); + /// Plain HTTP or SSE response. Each body chunk is an opaque byte range; the response is a status line, headers, and a (possibly streamed) body. + public static LlmInferenceHttpRequestStartTransport Http { get; } = new("http"); - /// The session is restricted to its creator and collaborators. - public static SessionVisibilityStatus Unshared { get; } = new("unshared"); + /// Full-duplex WebSocket channel. Each body chunk maps to exactly one WebSocket message and the `binary` flag distinguishes text from binary frames; request and response chunks flow concurrently. + public static LlmInferenceHttpRequestStartTransport Websocket { get; } = new("websocket"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SessionVisibilityStatus left, SessionVisibilityStatus right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(LlmInferenceHttpRequestStartTransport left, LlmInferenceHttpRequestStartTransport right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SessionVisibilityStatus left, SessionVisibilityStatus right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(LlmInferenceHttpRequestStartTransport left, LlmInferenceHttpRequestStartTransport right) => !(left == right); /// - public override bool Equals(object? obj) => obj is SessionVisibilityStatus other && Equals(other); + public override bool Equals(object? obj) => obj is LlmInferenceHttpRequestStartTransport other && Equals(other); /// - public bool Equals(SessionVisibilityStatus other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(LlmInferenceHttpRequestStartTransport other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -43984,62 +46439,62 @@ public SessionVisibilityStatus(string value) /// public override string ToString() => Value; - /// Provides a for serializing instances. + /// Provides a for serializing instances. [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + public sealed class Converter : JsonConverter { /// - public override SessionVisibilityStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override LlmInferenceHttpRequestStartTransport Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, SessionVisibilityStatus value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, LlmInferenceHttpRequestStartTransport value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionVisibilityStatus)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(LlmInferenceHttpRequestStartTransport)); } } } -/// Why the runtime requests client-task cancellation. +/// Why the runtime is requesting a GitHub credential. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct ClientTaskCancelReason : IEquatable +public readonly struct GitHubTokenAcquireReason : IEquatable { private readonly string? _value; - /// Initializes a new instance of the struct. - /// The value to associate with this . + /// Initializes a new instance of the struct. + /// The value to associate with this . [JsonConstructor] - public ClientTaskCancelReason(string value) + public GitHubTokenAcquireReason(string value) { ArgumentException.ThrowIfNullOrWhiteSpace(value); _value = value; } - /// Gets the value associated with this . + /// Gets the value associated with this . public string Value => _value ?? string.Empty; - /// A caller requested task cancellation. - public static ClientTaskCancelReason CancelRequested { get; } = new("cancel_requested"); + /// The runtime is acquiring the registration's first credential. + public static GitHubTokenAcquireReason Initial { get; } = new("initial"); - /// The session is shutting down. - public static ClientTaskCancelReason SessionShutdown { get; } = new("session_shutdown"); + /// The runtime is replacing a credential that is approaching expiry. + public static GitHubTokenAcquireReason Refresh { get; } = new("refresh"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ClientTaskCancelReason left, ClientTaskCancelReason right) => left.Equals(right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(GitHubTokenAcquireReason left, GitHubTokenAcquireReason right) => left.Equals(right); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ClientTaskCancelReason left, ClientTaskCancelReason right) => !(left == right); + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(GitHubTokenAcquireReason left, GitHubTokenAcquireReason right) => !(left == right); /// - public override bool Equals(object? obj) => obj is ClientTaskCancelReason other && Equals(other); + public override bool Equals(object? obj) => obj is GitHubTokenAcquireReason other && Equals(other); /// - public bool Equals(ClientTaskCancelReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(GitHubTokenAcquireReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -44047,62 +46502,65 @@ public ClientTaskCancelReason(string value) /// public override string ToString() => Value; - /// Provides a for serializing instances. + /// Provides a for serializing instances. [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + public sealed class Converter : JsonConverter { /// - public override ClientTaskCancelReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override GitHubTokenAcquireReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, ClientTaskCancelReason value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, GitHubTokenAcquireReason value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ClientTaskCancelReason)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(GitHubTokenAcquireReason)); } } } -/// Error classification. +/// Explicit user decisions, never inferred from a permission grant or model response. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] [DebuggerDisplay("{Value,nq}")] -public readonly struct SessionFsErrorCode : IEquatable +public readonly struct InstallationDecision : IEquatable { private readonly string? _value; - /// Initializes a new instance of the struct. - /// The value to associate with this . + /// Initializes a new instance of the struct. + /// The value to associate with this . [JsonConstructor] - public SessionFsErrorCode(string value) + public InstallationDecision(string value) { ArgumentException.ThrowIfNullOrWhiteSpace(value); _value = value; } - /// Gets the value associated with this . + /// Gets the value associated with this . public string Value => _value ?? string.Empty; - /// The requested path does not exist. - public static SessionFsErrorCode ENOENT { get; } = new("ENOENT"); + /// The user explicitly approved the exact review on this request. + public static InstallationDecision Confirm { get; } = new("confirm"); - /// The filesystem operation failed for an unspecified reason. - public static SessionFsErrorCode UNKNOWN { get; } = new("UNKNOWN"); + /// The user declined the reviewed operation. + public static InstallationDecision Decline { get; } = new("decline"); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SessionFsErrorCode left, SessionFsErrorCode right) => left.Equals(right); + /// The user cancelled the pending decision without granting consent. + public static InstallationDecision Cancel { get; } = new("cancel"); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SessionFsErrorCode left, SessionFsErrorCode right) => !(left == right); + /// Returns a value indicating whether two instances are equivalent. + public static bool operator ==(InstallationDecision left, InstallationDecision right) => left.Equals(right); + + /// Returns a value indicating whether two instances are not equivalent. + public static bool operator !=(InstallationDecision left, InstallationDecision right) => !(left == right); /// - public override bool Equals(object? obj) => obj is SessionFsErrorCode other && Equals(other); + public override bool Equals(object? obj) => obj is InstallationDecision other && Equals(other); /// - public bool Equals(SessionFsErrorCode other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + public bool Equals(InstallationDecision other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); /// public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); @@ -44110,703 +46568,1436 @@ public SessionFsErrorCode(string value) /// public override string ToString() => Value; - /// Provides a for serializing instances. + /// Provides a for serializing instances. [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + public sealed class Converter : JsonConverter { /// - public override SessionFsErrorCode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override InstallationDecision Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); } /// - public override void Write(Utf8JsonWriter writer, SessionFsErrorCode value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, InstallationDecision value, JsonSerializerOptions options) { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionFsErrorCode)); + GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(InstallationDecision)); } } } -/// Entry type. +/// Provides server-scoped RPC methods (no session required). +public sealed class ServerRpc +{ + private readonly JsonRpc _rpc; + + internal ServerRpc(JsonRpc rpc) + { + _rpc = rpc; + } + + /// Checks server responsiveness and returns protocol information. + /// Optional message to echo back. + /// The to monitor for cancellation requests. The default is . + /// Server liveness response, including the echoed message, current server timestamp, and protocol version. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + public async Task PingAsync(string? message = null, CancellationToken cancellationToken = default) + { + var request = new PingRequest { Message = message }; + return await CopilotClient.InvokeRpcAsync(_rpc, "ping", [request], cancellationToken); + } + + /// Performs the SDK server connection handshake and validates the optional connection token. Marked internal because this is JSON-RPC transport plumbing invoked automatically by an SDK client's own `connect()` wrapper, not a user-facing method. Stays internal as long as the SDK client owns the handshake; would only become public if the SDK ever exposed the raw schema surface to consumers without a connection wrapper. + /// Opt this connection in to GitHub telemetry forwarding for its lifetime. When set, the runtime forwards this host's telemetry across all its sessions, its sessionless events, and explicitly process-wide events over the `gitHubTelemetry.event` notification. Connections intentionally sharing one server receive that server's events; independently embedded runtime hosts do not receive each other's host-owned events. Regular events are also written to the runtime's normal GitHub/CTS path (dual-write); host-only compatibility events are forward-only and intentionally skip that path. Intended for first-party hosts that re-emit the events into their own telemetry stores. Both unrestricted and restricted events are forwarded, each tagged with a `restricted` discriminator; a backstop drops restricted events when restricted telemetry is disabled — using the process-global gate for ordinary events and an explicit session-scoped decision for host-only events. + /// Identity of the integrating host. Optional; omit it to keep the default attribution. + /// Task kinds this connection can decode when observing session tasks. Omit to retain agent and shell compatibility. + /// Connection token; required when the server was started with COPILOT_CONNECTION_TOKEN. + /// The to monitor for cancellation requests. The default is . + /// Handshake result reporting the server's protocol version and package version on success. + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + internal async Task ConnectAsync(bool? enableGitHubTelemetryForwarding = null, ConnectClientInfo? clientInfo = null, IList? supportedTaskKinds = null, string? token = null, CancellationToken cancellationToken = default) + { + var request = new ConnectRequest { EnableGitHubTelemetryForwarding = enableGitHubTelemetryForwarding, ClientInfo = clientInfo, SupportedTaskKinds = supportedTaskKinds, Token = token }; + return await CopilotClient.InvokeRpcAsync(_rpc, "connect", [request], cancellationToken); + } + + /// Registers the calling SDK client as the per-entrypoint extension launch provider. Call before creating any sessions. When omitted, the runtime uses its built-in extension launcher. + /// The to monitor for cancellation requests. The default is . + [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] + public async Task RegisterExtensionLaunchProviderAsync(CancellationToken cancellationToken = default) + { + await CopilotClient.InvokeRpcAsync(_rpc, "registerExtensionLaunchProvider", [], cancellationToken); + } + + /// Sandbox APIs. + public ServerSandboxApi Sandbox => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Persistence APIs. + public ServerPersistenceApi Persistence => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// User APIs. + public ServerUserApi User => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Repo APIs. + public ServerRepoApi Repo => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// FeatureFlags APIs. + public ServerFeatureFlagsApi FeatureFlags => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Permissions APIs. + public ServerPermissionsApi Permissions => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// ManagedSettings APIs. + public ServerManagedSettingsApi ManagedSettings => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Environments APIs. + public ServerEnvironmentsApi Environments => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Host APIs. + public ServerHostApi Host => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Hooks APIs. + public ServerHooksApi Hooks => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Models APIs. + public ServerModelsApi Models => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Tools APIs. + public ServerToolsApi Tools => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Account APIs. + public ServerAccountApi Account => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Secrets APIs. + public ServerSecretsApi Secrets => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Mcp APIs. + public ServerMcpApi Mcp => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Extensions APIs. + public ServerExtensionsApi Extensions => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Instructions APIs. + public ServerInstructionsApi Instructions => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Skills APIs. + public ServerSkillsApi Skills => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Catalog APIs. + public ServerCatalogApi Catalog => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Plugins APIs. + public ServerPluginsApi Plugins => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Agents APIs. + public ServerAgentsApi Agents => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// GlobalState APIs. + public ServerGlobalStateApi GlobalState => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Commands APIs. + public ServerCommandsApi Commands => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// GitHubRepository APIs. + public ServerGitHubRepositoryApi GitHubRepository => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// GitHubOwners APIs. + public ServerGitHubOwnersApi GitHubOwners => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Git APIs. + public ServerGitApi Git => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Runtime APIs. + public ServerRuntimeApi Runtime => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// SessionFs APIs. + public ServerSessionFsApi SessionFs => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// LlmInference APIs. + public ServerLlmInferenceApi LlmInference => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Sessions APIs. + public ServerSessionsApi Sessions => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// AgentRegistry APIs. + public ServerAgentRegistryApi AgentRegistry => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Connectors APIs. + public ServerConnectorsApi Connectors => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; +} + +/// Provides server-scoped Sandbox APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct SessionFsReaddirWithTypesEntryType : IEquatable +public sealed class ServerSandboxApi { - private readonly string? _value; + private readonly JsonRpc _rpc; - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public SessionFsReaddirWithTypesEntryType(string value) + internal ServerSandboxApi(JsonRpc rpc) { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; + _rpc = rpc; } - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; + /// Raises a user's sandbox settings to an administrator's managed sandbox floor and returns the result a session should actually run under. The floor can only tighten: an enterprise force-on is reflected even when the user's own `enabled` is false, and a user cannot lower a setting the floor raised. The result is normalized through the declared sandbox shape, so a key reorder or an undeclared passthrough key is not mistaken for a policy change by callers that diff two results. A host must call this rather than merge the two layers itself, because reimplementing the direction of the fold is what turns an administrator's floor into a suggestion. + /// The user's own `sandbox` settings slice. Omitted when the user has configured none, which still yields the managed floor rather than a disabled sandbox. + /// The effective managed `sandbox` slice acting as a floor. Omitted when no administrator policy applies, in which case the user's own settings stand unchanged. + /// The to monitor for cancellation requests. The default is . + /// The user's sandbox settings raised to the managed floor. + internal async Task ResolveFlooredConfigAsync(object? userSandbox = null, object? managedSandbox = null, CancellationToken cancellationToken = default) + { + var request = new SandboxResolveFlooredConfigParams { UserSandbox = CopilotClient.ToJsonElementForWire(userSandbox), ManagedSandbox = CopilotClient.ToJsonElementForWire(managedSandbox) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.resolveFlooredConfig", [request], cancellationToken); + } - /// The entry is a file. - public static SessionFsReaddirWithTypesEntryType File { get; } = new("file"); + /// Builds the effective filesystem policy one `@`-file picker checks its suggestions against, so Git discovery and grant canonicalization run once for the picker's lifetime instead of on every debounced keystroke. Returns no policy when the sandbox is absent or disabled, which the paired filter reads as "keep every candidate". A host must pair this with `sandbox.filterPickerCandidates` rather than resolve a grant list itself, because the picker's grants are narrower than a file tool's — the same path a built-in tool may read can be one the picker must not offer. + /// The session's working directory. Git discovery and grant canonicalization are resolved against it. + /// The session's resolved `sandbox` slice. Omitted, or disabled, yields no policy and every candidate is kept. + /// The to monitor for cancellation requests. The default is . + /// The prepared file-picker policy, or none when the sandbox is disabled. + internal async Task PreparePickerPolicyAsync(string cwd, object? sandbox = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(cwd); - /// The entry is a directory. - public static SessionFsReaddirWithTypesEntryType Directory { get; } = new("directory"); + var request = new SandboxPreparePickerPolicyParams { Cwd = cwd, Sandbox = CopilotClient.ToJsonElementForWire(sandbox) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.preparePickerPolicy", [request], cancellationToken); + } - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SessionFsReaddirWithTypesEntryType left, SessionFsReaddirWithTypesEntryType right) => left.Equals(right); + /// Checks a batch of `@`-file picker suggestions against a policy prepared by `sandbox.preparePickerPolicy` and returns one allow decision per candidate, positionally aligned with the request. Batched deliberately: each check canonicalizes a path component-by-component through the real filesystem, so one call amortizes that over a single hop rather than dozens while the user types. A directory the policy does not itself allow can still be kept as a waypoint to an allowed subtree. An absent policy keeps every candidate. + /// The candidates to check, in the order the answers are returned. + /// The session's working directory, matching the one the policy was prepared from. + /// The policy returned by `sandbox.preparePickerPolicy`. Omitted keeps every candidate. + /// The to monitor for cancellation requests. The default is . + /// Per-candidate allow decisions, positionally aligned with the request. + internal async Task FilterPickerCandidatesAsync(IList candidates, string cwd, object? sandbox = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(candidates); + ArgumentNullException.ThrowIfNull(cwd); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SessionFsReaddirWithTypesEntryType left, SessionFsReaddirWithTypesEntryType right) => !(left == right); + var request = new SandboxFilterPickerCandidatesParams { Candidates = candidates, Cwd = cwd, Sandbox = CopilotClient.ToJsonElementForWire(sandbox) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.filterPickerCandidates", [request], cancellationToken); + } - /// - public override bool Equals(object? obj) => obj is SessionFsReaddirWithTypesEntryType other && Equals(other); + /// The sandbox a single named feature actually launches under, which is not the same as the session's sandbox. A feature is routed out of the sandbox by its own flag — `sandboxMcpServers`, `sandboxLspServers` — so an enabled session can still start one server confined and another free. Returns a disabled sandbox rather than an error when the host has no sandbox slice at all, so an absent config and an opted-out feature read alike at the launch site. A host must ask per feature rather than reuse the session config, because reading only `enabled` confines a server the user opted out of, or reports as sandboxed one that is not. + /// The routing flag naming the feature being launched, such as `sandboxMcpServers` or `sandboxLspServers`. + /// The session's resolved `sandbox` slice. Omitted when the host has none, which yields a disabled sandbox rather than an error. + /// The to monitor for cancellation requests. The default is . + /// The sandbox a named feature actually launches under. + internal async Task ResolveForOptionalAsync(string routingFlag, object? sandbox = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(routingFlag); - /// - public bool Equals(SessionFsReaddirWithTypesEntryType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + var request = new SandboxEffectiveForOptionalParams { RoutingFlag = routingFlag, Sandbox = CopilotClient.ToJsonElementForWire(sandbox) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.resolveForOptional", [request], cancellationToken); + } - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + /// Reports whether this machine can run an OS-level command sandbox at all. A host must ask before it offers sandboxing, because the answer is a property of the machine rather than of any setting: on Linux it depends on bubblewrap being installed, and on Windows on the OS build supporting BaseContainer. Probing it requires spawning a process the first time, so the answer is cached for the life of the runtime. A host that assumes support and enables the sandbox anyway produces a session in which every shell command fails. + /// The to monitor for cancellation requests. The default is . + /// True when an OS-level sandbox can run on this host. + internal async Task CheckPlatformSupportAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.checkPlatformSupport", [], cancellationToken); + } - /// - public override string ToString() => Value; + /// Reports whether this Windows host's BaseContainer implementation can reach the host's loopback interface directly, which is what a local-network policy needs to avoid routing through the egress proxy. Like `sandbox.checkPlatformSupport`, the answer is a property of the machine's OS build rather than of any setting, and resolving it the first time spawns a platform probe. A host that offers the direct local-network option on a machine that lacks the capability produces a session whose sandboxed commands cannot reach local services. Always false off Windows. + /// The to monitor for cancellation requests. The default is . + /// True when the sandbox on this host can reach host loopback directly. + internal async Task CheckWindowsHostLoopbackSupportAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.checkWindowsHostLoopbackSupport", [], cancellationToken); + } - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + /// The explanation a host shows when it refuses an explicit request to turn the sandbox on for a machine that cannot run one. Carries the platform-specific remedy — install bubblewrap, update Windows — and the documentation link, so a host that got `false` from `sandbox.checkPlatformSupport` does not have to compose its own reason and cannot describe the same machine differently from the runtime's own spawn path. + /// The to monitor for cancellation requests. The default is . + /// The user-facing refusal, including the platform remedy and the documentation link. + internal async Task GetUnsupportedMessageAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.getUnsupportedMessage", [], cancellationToken); + } + + /// The notice a host shows when a stored `sandbox` setting is being ignored for this session because the machine cannot enforce it. Distinct from `sandbox.getUnsupportedMessage`, which refuses an explicit request: this one reports that a setting the user already saved is inert, states that commands will run unsandboxed, and confirms the stored setting itself is left alone. A host that stays silent here leaves the user believing a sandbox is active. + /// The to monitor for cancellation requests. The default is . + /// The user-facing notice that a saved sandbox setting is inert for this session. + internal async Task GetUnsupportedSettingDisabledNoticeAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.getUnsupportedSettingDisabledNotice", [], cancellationToken); + } + + /// The warning a host prints at startup when a session asked for a sandbox on a machine that cannot run one. The third of the unsupported notices, and the only one that depends on the policy in force: it names the remedy the reader can actually act on, which is the stored setting for an unmanaged host, an administrator for a managed one, and waiting for the policy to resolve when the sandbox stayed on only because the policy could not be determined. Returns no notice when the machine does support a sandbox, so a host can call it unconditionally on the startup path. A host that composes its own warning tells a managed user to change a setting their policy will overwrite. + /// The managed `sandbox` slice, when a policy supplies one. The notice treats the sandbox as enforced only when this both enables it and sets `failIfUnavailable`, because a managed sandbox that tolerates being unavailable still leaves the user able to turn it off. + /// True when the sandbox stayed on only because the managed policy could not be determined. Distinguishes a policy that positively enforces the sandbox from one that merely failed to resolve, which is the difference between telling the user to contact an administrator and telling them to wait. Defaults to false. + /// The to monitor for cancellation requests. The default is . + /// The startup warning, absent when the machine can run a sandbox. + internal async Task GetUnsupportedStartupNoticeAsync(object? managedSandbox = null, bool? enabledByUndeterminedPolicy = null, CancellationToken cancellationToken = default) + { + var request = new SandboxUnsupportedStartupNoticeParams { ManagedSandbox = CopilotClient.ToJsonElementForWire(managedSandbox), EnabledByUndeterminedPolicy = enabledByUndeterminedPolicy }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.getUnsupportedStartupNotice", [request], cancellationToken); + } + + /// Whether one slash command stays reachable while sandbox enforcement is unavailable and the session is otherwise blocked. The permitted set is deliberately narrow — commands that only report state, and the few that let the user repair or leave the situation — and it is keyed on the arguments as well as the name, so `/sandbox status` is admitted where `/sandbox enable` is not. A host must ask rather than keep its own list: a command this returns false for is one the runtime would refuse anyway, and a divergent list either strands the user with no way out or admits a command that acts on an unenforced session. + /// The command name as the user typed it, with or without its leading slash. + /// The command's arguments, in order. Pass an empty array for a bare command: several entries in the allowlist admit the bare form and refuse every argument. + /// The to monitor for cancellation requests. The default is . + /// True when the command stays available while enforcement is blocked. + internal async Task CheckEnforcementCommandAsync(string commandName, IList args, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(commandName); + ArgumentNullException.ThrowIfNull(args); + + var request = new SandboxEnforcementCommandAllowedParams { CommandName = commandName, Args = args }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.checkEnforcementCommand", [request], cancellationToken); + } + + /// Returns the documentation URL a host should point a user at when it declines or downgrades a sandbox setting. The runtime owns the address so every surface cites the same page and a host does not hard-code a link that later moves. + /// The to monitor for cancellation requests. The default is . + /// The documentation URL a host cites when it declines or downgrades a sandbox setting. + internal async Task GetDocsUrlAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.getDocsUrl", [], cancellationToken); + } + + /// Reports whether the host running this runtime can run the command sandbox, without starting a session or spawning a sandboxed command. + /// The to monitor for cancellation requests. The default is . + /// Whether the host running this runtime can run the command sandbox. The runtime checks `supported` once per process. A capability answer can change while the process runs, for example after the user installs a missing package. + public async Task GetHostSupportAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.getHostSupport", [], cancellationToken); + } + + /// ProxyCa APIs. + public ServerSandboxProxyCaApi ProxyCa => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// ProxySecret APIs. + public ServerSandboxProxySecretApi ProxySecret => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; + + /// Settings APIs. + public ServerSandboxSettingsApi Settings => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; +} + +/// Provides server-scoped SandboxProxyCa APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerSandboxProxyCaApi +{ + private readonly JsonRpc _rpc; + + internal ServerSandboxProxyCaApi(JsonRpc rpc) + { + _rpc = rpc; + } + + /// Reports whether this runtime process can offer installing the sandbox credential-proxy certificate authority into OS trust. + /// The to monitor for cancellation requests. The default is . + /// True when this process can offer installing the sandbox credential-proxy certificate authority into OS trust. + public async Task CheckInstallationSupportAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.checkInstallationSupport", [], cancellationToken); + } + + /// Reports whether this sandbox configuration uses the credential proxy and can need certificate-authority setup. + /// The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. + /// The to monitor for cancellation requests. The default is . + /// True when the sandbox configuration uses the credential proxy and can need certificate-authority setup. + public async Task CheckRelevanceAsync(SandboxConfig? sandboxConfig = null, CancellationToken cancellationToken = default) + { + var request = new SandboxProxyCaRequest { SandboxConfig = sandboxConfig }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.checkRelevance", [request], cancellationToken); + } + + /// Reports whether the persistent certificate authority of the sandbox credential proxy exists, whether OS trust includes it, and whether it must be rotated. Changes nothing. + /// The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. + /// The to monitor for cancellation requests. The default is . + /// Status of the persistent certificate authority of the sandbox credential proxy. + public async Task GetStatusAsync(SandboxConfig? sandboxConfig = null, CancellationToken cancellationToken = default) + { + var request = new SandboxProxyCaRequest { SandboxConfig = sandboxConfig }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.getStatus", [request], cancellationToken); + } + + /// Creates the persistent certificate authority of the sandbox credential proxy if none is stored, without changing OS trust, and returns the path of its public certificate. Keeps an existing certificate authority, even one that must be rotated. Fails where OS trust is unsupported. Trust it with sandbox.proxyCa.trust: the CLI trusts only the hosts in the saved user settings, so it refuses a certificate authority that also covers hosts from sandboxConfig. + /// The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. + /// The to monitor for cancellation requests. The default is . + /// Result of creating the persistent certificate authority of the sandbox credential proxy. + public async Task CreateAsync(SandboxConfig? sandboxConfig = null, CancellationToken cancellationToken = default) + { + var request = new SandboxProxyCaRequest { SandboxConfig = sandboxConfig }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.create", [request], cancellationToken); + } + + /// Replaces the persistent certificate authority of the sandbox credential proxy with a new one for the current credential hosts. If OS trust included the old one, removes it and trusts the new one, which can show an OS authentication prompt. Running sandboxed tools keep the old certificate authority until they restart. + /// The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. + /// The to monitor for cancellation requests. The default is . + /// Status of the persistent certificate authority of the sandbox credential proxy. + public async Task RotateAsync(SandboxConfig? sandboxConfig = null, CancellationToken cancellationToken = default) + { + var request = new SandboxProxyCaRequest { SandboxConfig = sandboxConfig }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.rotate", [request], cancellationToken); + } + + /// Adds the persistent certificate authority of the sandbox credential proxy to OS trust, so sandboxed clients that read only OS trust accept the proxy. Call create first. Refuses a certificate authority that is not constrained to the current credential hosts. Can show an OS authentication prompt. + /// The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. + /// The to monitor for cancellation requests. The default is . + /// Status of the persistent certificate authority of the sandbox credential proxy. + public async Task TrustAsync(SandboxConfig? sandboxConfig = null, CancellationToken cancellationToken = default) { - /// - public override SessionFsReaddirWithTypesEntryType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } + var request = new SandboxProxyCaRequest { SandboxConfig = sandboxConfig }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.trust", [request], cancellationToken); + } - /// - public override void Write(Utf8JsonWriter writer, SessionFsReaddirWithTypesEntryType value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionFsReaddirWithTypesEntryType)); - } + /// Removes the persistent certificate authority of the sandbox credential proxy from OS trust. Keeps the stored certificate authority. Can show an OS authentication prompt. Sandboxed clients that read only OS trust then reject the proxy; clients that read the per-process certificate bundle continue to work. + /// The to monitor for cancellation requests. The default is . + /// Status of the persistent certificate authority of the sandbox credential proxy. + public async Task RemoveAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.remove", [], cancellationToken); } } - -/// How to execute the query: 'exec' for DDL/multi-statement (no results), 'query' for SELECT (returns rows), 'run' for INSERT/UPDATE/DELETE (returns rowsAffected). +/// Provides server-scoped SandboxProxySecret APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct SessionFsSqliteQueryType : IEquatable +public sealed class ServerSandboxProxySecretApi { - private readonly string? _value; + private readonly JsonRpc _rpc; - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public SessionFsSqliteQueryType(string value) + internal ServerSandboxProxySecretApi(JsonRpc rpc) { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; + _rpc = rpc; } - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; + /// Reports where this runtime keeps the sandbox proxy password: the credential store directory and the entry identifier within it. Both are derived from the configuration directory this runtime was started with, so a host does not resolve them itself. Read this to recognize a `${secret:…}` value in stored sandbox settings as this runtime's own proxy password rather than a reference the user wrote by hand. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. + /// The to monitor for cancellation requests. The default is . + /// Where this runtime keeps the sandbox proxy password. + internal async Task GetLocationAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxySecret.getLocation", [], cancellationToken); + } - /// Execute DDL or multi-statement SQL without returning rows. - public static SessionFsSqliteQueryType Exec { get; } = new("exec"); + /// Reads the stored sandbox proxy password from the credential store `sandbox.proxySecret.getLocation` names, preferring the OS keychain and falling back to the on-disk store. Reports an absent value rather than failing when no entry exists. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. + /// The to monitor for cancellation requests. The default is . + /// The stored sandbox proxy password, if one is present. + internal async Task GetAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxySecret.get", [], cancellationToken); + } - /// Execute a SELECT-style query and return rows. - public static SessionFsSqliteQueryType Query { get; } = new("query"); + /// Stores the sandbox proxy password in the credential store `sandbox.proxySecret.getLocation` names, replacing any existing entry. Reports whether the OS keychain accepted it or it fell back to the on-disk store. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. + /// The password to store for the sandbox proxy. + /// The to monitor for cancellation requests. The default is . + /// Where the sandbox proxy password was stored. + internal async Task SaveAsync(string value, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(value); - /// Execute INSERT, UPDATE, or DELETE SQL and return affected-row metadata. - public static SessionFsSqliteQueryType Run { get; } = new("run"); + var request = new SandboxProxySecretSaveRequest { Value = value }; + return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxySecret.save", [request], cancellationToken); + } - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SessionFsSqliteQueryType left, SessionFsSqliteQueryType right) => left.Equals(right); + /// Removes the stored sandbox proxy password from the credential store `sandbox.proxySecret.getLocation` names. Succeeds when no entry exists, so it is safe to call while clearing a proxy password whose origin is unknown. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. + /// The to monitor for cancellation requests. The default is . + internal async Task DeleteAsync(CancellationToken cancellationToken = default) + { + await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxySecret.delete", [], cancellationToken); + } +} - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SessionFsSqliteQueryType left, SessionFsSqliteQueryType right) => !(left == right); +/// Provides server-scoped SandboxSettings APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerSandboxSettingsApi +{ + private readonly JsonRpc _rpc; - /// - public override bool Equals(object? obj) => obj is SessionFsSqliteQueryType other && Equals(other); + internal ServerSandboxSettingsApi(JsonRpc rpc) + { + _rpc = rpc; + } - /// - public bool Equals(SessionFsSqliteQueryType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + /// Resolves a stored sandbox settings object into the effective one, filling every value the user left unset with its default. Read this to render or reason about the sandbox configuration a session would actually run under, rather than the sparse document the user wrote. + /// The sandbox settings as stored in the settings file. An empty object resolves to the defaults alone. + /// The to monitor for cancellation requests. The default is . + /// The effective sandbox settings, with every unset value resolved to its default. + internal async Task> ApplyDefaultsAsync(object? stored, CancellationToken cancellationToken = default) + { + var request = new SandboxApplyDefaultsRequest { Stored = CopilotClient.ToJsonElementForWire(stored) ?? JsonElement.Parse("null") }; + return await CopilotClient.InvokeRpcAsync>(_rpc, "sandbox.settings.applyDefaults", [request], cancellationToken); + } +} - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); +/// Provides server-scoped Persistence APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerPersistenceApi +{ + private readonly JsonRpc _rpc; - /// - public override string ToString() => Value; + internal ServerPersistenceApi(JsonRpc rpc) + { + _rpc = rpc; + } - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + /// Atomically replaces a JSON file's entire contents while holding the runtime's per-path lock. The lock lives in the runtime process, so a host that writes these files itself takes no part in it and can tear a concurrent runtime write; route the write here instead. Unlike a merging write this never reads or parses the existing file, so a previously corrupted snapshot is replaced wholesale rather than failing every later write. Use it only for callers that always persist a complete snapshot. + /// Absolute path of the file to replace. Parent directories are created when missing. + /// The serialized JSON document to write. It replaces the file's contents entirely; nothing is merged. + /// Comment lines to emit above the document, for a format that tolerates them. Omit for strict JSON. + /// The to monitor for cancellation requests. The default is . + /// The outcome of a locked snapshot write. + internal async Task WriteRawJsonLockedAsync(string path, string dataJson, string? fileHeader = null, CancellationToken cancellationToken = default) { - /// - public override SessionFsSqliteQueryType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } + ArgumentNullException.ThrowIfNull(path); + ArgumentNullException.ThrowIfNull(dataJson); - /// - public override void Write(Utf8JsonWriter writer, SessionFsSqliteQueryType value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionFsSqliteQueryType)); - } + var request = new PersistenceWriteRawJsonLockedRequest { Path = path, DataJson = dataJson, FileHeader = fileHeader }; + return await CopilotClient.InvokeRpcAsync(_rpc, "persistence.writeRawJsonLocked", [request], cancellationToken); } } - -/// SQLite transaction failure classification. +/// Provides server-scoped User APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct SessionFsSqliteTransactionErrorClass : IEquatable +public sealed class ServerUserApi { - private readonly string? _value; + private readonly JsonRpc _rpc; - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public SessionFsSqliteTransactionErrorClass(string value) + internal ServerUserApi(JsonRpc rpc) { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; + _rpc = rpc; } - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// SQLite reported BUSY or LOCKED before commit; the transaction was rolled back and may be retried. - public static SessionFsSqliteTransactionErrorClass BusyOrLocked { get; } = new("busyOrLocked"); - - /// The statement, database, or provider failed definitively and must not be retried automatically. - public static SessionFsSqliteTransactionErrorClass Fatal { get; } = new("fatal"); + /// Settings APIs. + public ServerUserSettingsApi Settings => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; +} - /// The transport failed after the provider may have committed; retrying could duplicate effects. - public static SessionFsSqliteTransactionErrorClass PostCommitAmbiguous { get; } = new("postCommitAmbiguous"); +/// Provides server-scoped UserSettings APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerUserSettingsApi +{ + private readonly JsonRpc _rpc; - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(SessionFsSqliteTransactionErrorClass left, SessionFsSqliteTransactionErrorClass right) => left.Equals(right); + internal ServerUserSettingsApi(JsonRpc rpc) + { + _rpc = rpc; + } - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(SessionFsSqliteTransactionErrorClass left, SessionFsSqliteTransactionErrorClass right) => !(left == right); + /// Adds or removes one hook key in the user `disabledHooks` setting, rewriting settings.json in place and leaving every other setting untouched. Reports a typed outcome rather than failing the call, so a host can tell an unparseable settings file apart from a write that could not complete. + /// Path of the settings.json to rewrite. + /// Durable content-hash key of the hook, as `hooks.loadResources` reports it. + /// True adds the key to `disabledHooks`, false removes it. + /// The to monitor for cancellation requests. The default is . + /// Outcome of rewriting the `disabledHooks` setting. + internal async Task SetHookDisabledAsync(string settingsPath, string disableKey, bool disabled, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(settingsPath); + ArgumentNullException.ThrowIfNull(disableKey); - /// - public override bool Equals(object? obj) => obj is SessionFsSqliteTransactionErrorClass other && Equals(other); + var request = new UserSettingsSetHookDisabledRequest { SettingsPath = settingsPath, DisableKey = disableKey, Disabled = disabled }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.setHookDisabled", [request], cancellationToken); + } - /// - public bool Equals(SessionFsSqliteTransactionErrorClass other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + /// Reads the user's settings document exactly as `user.settings.load` does, but from a caller-supplied configuration directory instead of the one the server resolved for itself. Use this when a consumer scopes a session to its own Copilot home — the SDK's per-session `configDir` override — so the settings read match the directory that session actually uses. An absent or empty `configDir` resolves the server's own home, making this identical to `user.settings.load`. Hook-validation relaxations are deliberately not caller-supplied: they continue to come from the server's environment, so a consumer cannot widen the host's hook policy through this method. + /// Copilot configuration directory to read the settings document from, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to read the directory the server resolved for itself. + /// The to monitor for cancellation requests. The default is . + /// The stored user settings document, keyed by setting name. + internal async Task> LoadForConfigDirAsync(string? configDir = null, CancellationToken cancellationToken = default) + { + var request = new UserSettingsLoadForConfigDirRequest { ConfigDir = configDir }; + return await CopilotClient.InvokeRpcAsync>(_rpc, "user.settings.loadForConfigDir", [request], cancellationToken); + } - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + /// Reads a repository's checked-in settings document as stored, normalized, together with any diagnostic raised while reading it. This is the repository half of the layering `user.settings.get` reports: `user.settings.load` reads the user's own document, and this reads the one a repository checks in to govern the keys `user.settings.governanceKeys` lists as repo-governable. A document that fails to parse, or that sets a key a repository may not govern, is reported through `warning` while the settings that did load are still returned, so a consumer surfaces the diagnostic and continues rather than failing the session. When `repoRoot` is the user's home directory the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as repository policy. + /// Absolute path of the repository root whose settings to read. When this is the user's home directory, the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as if it were repository policy. + /// The to monitor for cancellation requests. The default is . + /// A repository's settings as stored, together with any diagnostic raised while reading them. + internal async Task LoadRepoAsync(string repoRoot, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(repoRoot); - /// - public override string ToString() => Value; + var request = new UserSettingsLoadRepoRequest { RepoRoot = repoRoot }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.loadRepo", [request], cancellationToken); + } - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + /// Reads a repository's settings and merges them over a supplied user layer in one step, returning the settings a consumer should act on inside that repository. Use this rather than reading the two layers separately: the merge is per setting and collection-aware, so a repository adds to the collections it is allowed to influence without replacing the user's own entries, and a whole-document overlay would get that wrong. Any diagnostic raised while reading the repository layer is returned rather than printed, so the consumer decides how to surface it; the settings that did load are merged regardless. + /// Absolute path of the repository root whose settings to read. When this is the user's home directory, the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as if it were repository policy. + /// The user's own settings, keyed by setting name. The repository layer is merged over this; a repository may only add to the collection settings it is allowed to influence, so a user setting it does not name survives unchanged. + /// The to monitor for cancellation requests. The default is . + /// The settings a consumer should act on inside a repository, together with any diagnostic raised while reading the repository layer. + internal async Task LoadAndMergeRepoAsync(string repoRoot, IDictionary userSettings, CancellationToken cancellationToken = default) { - /// - public override SessionFsSqliteTransactionErrorClass Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } + ArgumentNullException.ThrowIfNull(repoRoot); + ArgumentNullException.ThrowIfNull(userSettings); - /// - public override void Write(Utf8JsonWriter writer, SessionFsSqliteTransactionErrorClass value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionFsSqliteTransactionErrorClass)); - } + var request = new UserSettingsLoadAndMergeRepoRequest { RepoRoot = repoRoot, UserSettings = userSettings }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.loadAndMergeRepo", [request], cancellationToken); } -} + /// Reports the on-disk path of the settings document `user.settings.load` and `user.settings.set` read and write. Resolved the same way those methods resolve it, so a host that shows or opens the settings file names the file the runtime actually uses, including the extensionless legacy `settings` file when that is what is present. + /// The to monitor for cancellation requests. The default is . + /// The on-disk location of the user's settings document. + internal async Task GetPathAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.getPath", [], cancellationToken); + } -/// Defines the allowed values. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct HostExitReason : IEquatable -{ - private readonly string? _value; + /// Reads the user's stored settings together with the diagnostic raised while reading them. This is `user.settings.load` plus the reason part of the document was ignored: that one answers the document alone, so a caller cannot tell a clean read from a salvaged one. Read this when the caller is about to write the file back, where accepting a partial parse would discard every value the loader could not read. The settings that did load are still reported alongside the warning, so a consumer may surface it and continue instead of failing. + /// The to monitor for cancellation requests. The default is . + /// The user's stored settings, together with any diagnostic raised while reading them. + internal async Task LoadWithWarningAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.loadWithWarning", [], cancellationToken); + } - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public HostExitReason(string value) + /// Folds a user settings layer over a managed (enterprise policy) layer and returns the merged settings. The managed layer's governance keys win, `autoTier` resolves through its overridable form, and the two per-entry control maps (`enabledPlugins`, `extraKnownMarketplaces`) union across the layers and are then stamped back from the managed layer, so each entry an administrator declares wins while the user keeps control of the rest. The parameters are named for their layers rather than being a generic base/override pair: nothing about a settings object identifies which layer produced it, so the runtime cannot detect a transposed call, and transposing one resolves the governance keys in the user's favour instead of the administrator's. Supplying only one layer returns it unchanged, and supplying neither returns an empty object. Rejects a managed `autoTier` that is neither a user-configurable tier nor a single-key overridable form, rather than silently dropping it. + /// The managed layer. Its governance keys win, and the per-entry `enabledPlugins` and `extraKnownMarketplaces` control maps are stamped back from it after the union. Omitted when the host is unmanaged. + /// The user's own settings layer. Wins on every key the managed layer does not govern. Omitted when the user has no settings yet. + /// The to monitor for cancellation requests. The default is . + /// The user layer folded over the managed layer. + internal async Task MergeManagedAndUserAsync(object? managed = null, object? user = null, CancellationToken cancellationToken = default) { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; + var request = new UserSettingsMergeManagedAndUserParams { Managed = CopilotClient.ToJsonElementForWire(managed), User = CopilotClient.ToJsonElementForWire(user) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.mergeManagedAndUser", [request], cancellationToken); } - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; + /// Folds a repository's settings layer into the user layer. Each repo-overridable key carries a directional policy chosen so a repository can only add restrictions and never relax the user's own. The two per-entry managed control maps are the exception those directional rules cannot express — a repository may legitimately enable plugins and declare marketplaces — so they are re-stamped afterwards from the runtime's ambient managed policy. That makes the result depend on the runtime process's managed state and not on the arguments alone: a host must call this rather than reimplement the fold, or a repository could relax a restriction the administrator imposed. Rejects when either layer is not a JSON object. + /// The user's settings, already resolved against any managed layer. + /// The repository's checked-in settings layer. + /// The to monitor for cancellation requests. The default is . + /// The repository layer folded into the user layer. + internal async Task MergeRepoValueAsync(object? userSettings, object? repoSettings, CancellationToken cancellationToken = default) + { + var request = new UserSettingsMergeRepoValueParams { UserSettings = CopilotClient.ToJsonElementForWire(userSettings) ?? JsonElement.Parse("null"), RepoSettings = CopilotClient.ToJsonElementForWire(repoSettings) ?? JsonElement.Parse("null") }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.mergeRepoValue", [request], cancellationToken); + } - /// The owner requested disposal. - public static HostExitReason Disposed { get; } = new("disposed"); + /// Runs the one-time migration that moves a staff account's update channel to stable, and records that it ran. Idempotent and self-gating: it takes a lock over the global-state file, re-reads the completion stamp inside it, and returns `current` rather than migrating twice, so two hosts racing at startup cannot both migrate. Only a `migrated` status means the persisted settings changed and the caller should reload them. An account on the experimental channel is deliberately left alone and reported as `excluded-experimental`. + /// The user's home directory, used when neither a configuration directory nor `COPILOT_HOME` is set. + /// The host's environment variables. `COPILOT_HOME` is read from here, as are the variables a settings hook may expand. + /// The Copilot configuration directory, when the host set one. Takes precedence over `COPILOT_HOME` and the home directory. + /// The to monitor for cancellation requests. The default is . + /// The outcome of the one-time staff update-channel migration. + internal async Task MigrateStaffUpdateChannelOnceAsync(string homeDirectory, IDictionary environment, string? configDir = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(homeDirectory); + ArgumentNullException.ThrowIfNull(environment); - /// The hosting task or its SDK transport exited; this does not mean the runtime process exited. - public static HostExitReason Exited { get; } = new("exited"); + var request = new UserSettingsHostContext { HomeDirectory = homeDirectory, Environment = environment, ConfigDir = configDir }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.migrateStaffUpdateChannelOnce", [request], cancellationToken); + } - /// The owning SDK connection disconnected. - public static HostExitReason OwnerDisconnected { get; } = new("ownerDisconnected"); + /// Runs the one-time reset that clears a staff account's pinned model selection, and reports the timestamp the host should record. Idempotent and self-gating: the reset is gated on a fixed cutoff, so a caller that passes back the timestamp it recorded gets `didReset: false` rather than a second reset. It applies to staff accounts only; any other account is reported as not reset without the settings document being opened. Only `didReset: true` means the persisted settings changed, and only then are the updated settings returned for the host to adopt. + /// The configuration directory, home directory and environment to resolve the settings and global-state documents from. A host that scopes a session to its own Copilot home must pass that directory here, or the reset is evaluated against the server's own home instead. + /// Whether the signed-in account is a staff account. The reset applies only to staff, so anything other than `true` returns `didReset: false` without touching the settings document. + /// When the caller last recorded this reset, as an ISO-8601 timestamp. A timestamp at or after the cutoff means the reset already ran and is returned unchanged. + /// The to monitor for cancellation requests. The default is . + /// The outcome of the one-time staff model-selection reset. + internal async Task ResetStaffModelSelectionOnceAsync(UserSettingsHostContext context, bool? staff = null, string? staffModelResetAt = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(context); - /// The runtime is shutting down. - public static HostExitReason RuntimeShutdown { get; } = new("runtimeShutdown"); + var request = new UserSettingsResetStaffModelSelectionOnceRequest { Context = context, Staff = staff, StaffModelResetAt = staffModelResetAt }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.resetStaffModelSelectionOnce", [request], cancellationToken); + } - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(HostExitReason left, HostExitReason right) => left.Equals(right); + /// Reports the top-level keys in the user settings document that the runtime does not recognize, phrased for display to the user. This is a separate question from the warning `user.settings.loadWithWarning` returns: that one describes parts of the document the loader had to ignore to load the rest, whereas an unknown key parses cleanly and is simply not a setting, so a host that surfaces only the load warning silently accepts a misspelled key that will never take effect. Nothing is reported when the document is absent, unreadable, or failed to load, because an unknown-key list derived from a document the runtime could not read would be misleading rather than helpful. Inspection never modifies the document. + /// The configuration directory, home directory and environment to resolve the settings document from. A host that scopes a session to its own Copilot home must pass that directory here, or the server's own home is inspected instead. + /// The to monitor for cancellation requests. The default is . + /// The unrecognized top-level keys found in the user settings document, already phrased for display. + internal async Task GetUnknownKeysWarningAsync(UserSettingsHostContext context, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(context); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(HostExitReason left, HostExitReason right) => !(left == right); + var request = new UserSettingsUnknownKeysWarningRequest { Context = context }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.getUnknownKeysWarning", [request], cancellationToken); + } - /// - public override bool Equals(object? obj) => obj is HostExitReason other && Equals(other); + /// Resolves the effective runtime settings for a host that is about to start a session, layering the given overrides over the settings documents, the environment and the platform defaults. A host cannot assemble this itself: the precedence between a user document, a repository document, the managed layers and the environment is the runtime's own rule, and a host that re-implements it drifts from the server it is configuring. The working directory, environment and platform are taken as arguments rather than read from the server process, so a host resolving settings for a directory other than its own gets that directory's answer. Nothing is written; this only computes. + /// The directory the settings are being resolved for. This selects the repository-scoped document, so a host resolving settings for a directory other than its own process working directory must pass that directory here. + /// The environment to read settings-bearing variables from. Passed explicitly rather than read from the server process so a host can resolve settings for an environment it is about to create rather than the one it runs in. + /// The platform to apply platform-specific defaults for, in the same spelling the host's own runtime reports. + /// Settings that take precedence over every document and environment layer, such as the values a host derived from its own command line. Keyed by setting name, with each value carried verbatim, so a host may pass keys this runtime does not recognize. Absent when the host contributes no overrides of its own. + /// The to monitor for cancellation requests. The default is . + /// The effective runtime settings, keyed by setting name. Keys this runtime does not recognize are preserved rather than dropped, so a caller reading a document written by a newer runtime keeps every value. + internal async Task> BuildRuntimeAsync(string workingDirectory, IDictionary environment, string platform, IDictionary? overrides = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(workingDirectory); + ArgumentNullException.ThrowIfNull(environment); + ArgumentNullException.ThrowIfNull(platform); - /// - public bool Equals(HostExitReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + var request = new UserSettingsBuildRuntimeRequest { WorkingDirectory = workingDirectory, Environment = environment, Platform = platform, Overrides = overrides }; + return await CopilotClient.InvokeRpcAsync>(_rpc, "user.settings.buildRuntime", [request], cancellationToken); + } - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + /// Runs the one-time migration that moves a staff account's log level to the current default, and records that it ran. Idempotent and self-gating: it takes a lock over the global-state file and re-reads the completion stamp inside it, so two hosts racing at startup cannot both migrate. Only `refreshed` can have changed the persisted settings, and the settings it returns are the document re-read after the write, so a host should adopt them rather than reloading separately and racing the next writer. + /// The configuration directory, home directory and environment to resolve the settings and global-state documents from. A host that scopes a session to its own Copilot home must pass that directory here, or the migration is evaluated against the server's own home instead. + /// When the caller last recorded this migration, as an ISO-8601 timestamp. Supplying it lets the runtime answer `current` without re-running the evaluation. + /// The to monitor for cancellation requests. The default is . + /// The outcome of the one-time staff log-level migration. + internal async Task MigrateStaffLogLevelOnceAsync(UserSettingsHostContext context, string? cachedCompletedAt = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(context); - /// - public override string ToString() => Value; + var request = new UserSettingsMigrateStaffLogLevelOnceRequest { Context = context, CachedCompletedAt = cachedCompletedAt }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.migrateStaffLogLevelOnce", [request], cancellationToken); + } - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + /// Runs the one-time cleanup that removes obsolete CLI-owned settings and legacy rubber-duck keys from the user's settings document, and reports what it did. Idempotent and safe to call on every startup: with nothing obsolete left it reports `unchanged` and writes nothing. The cleanup preserves every key it does not recognize, so a setting written by a newer host is never dropped by an older one, and a document that fails to parse is reported `invalid` and left untouched rather than rewritten from a partial read. The cleaned document is not returned: it is written before this replies, so `user.settings.load` reads it authoritatively. A host that surfaces unrecognized keys through `user.settings.unknownKeys` wants this first, because the keys this retires would otherwise be shown to the user as if they were misspelled settings. + /// The configuration directory holding the settings document to clean. A host that scopes a session to its own Copilot home passes that directory here; omit it to clean the document under the home the server resolved for itself. The home directory and environment are deliberately not caller-supplied: they decide only the settings path root and the two hook-parsing flags, and those describe the process doing the reading rather than the caller. + /// The to monitor for cancellation requests. The default is . + /// The outcome of the one-time obsolete-settings cleanup. + internal async Task MigrateObsoleteOnDiskAsync(string? configDir = null, CancellationToken cancellationToken = default) { - /// - public override HostExitReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } + var request = new UserSettingsMigrateObsoleteOnDiskRequest { ConfigDir = configDir }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.migrateObsoleteOnDisk", [request], cancellationToken); + } - /// - public override void Write(Utf8JsonWriter writer, HostExitReason value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(HostExitReason)); - } + /// Lists every known user setting from settings.json, each with its effective value, its default, and whether it is at the default — so settings the user has never set still appear with their default value. Does not include repository- or enterprise-managed overrides that the runtime layers on top at session time. + /// The to monitor for cancellation requests. The default is . + /// Per-key metadata for every known user setting in settings.json, including settings left at their default. Excludes repository- and enterprise-managed overrides. + public async Task GetAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.get", [], cancellationToken); } -} + /// Resolves the on-disk locations of the settings files this runtime reads, so a consumer can show or open them. The user path is the same file `user.settings.get`, `user.settings.load`, and `user.settings.set` operate on. Supply `repoRoot` to also resolve that repository's checked-in and local settings paths. A path is reported whether or not the file exists. + /// Absolute path of a repository root. Supply it to also resolve that repository's two settings file paths; omit it to resolve only the user path. + /// The to monitor for cancellation requests. The default is . + /// On-disk locations of the settings files this runtime reads. A path is reported whether or not the file exists. + internal async Task GetPathsAsync(string? repoRoot = null, CancellationToken cancellationToken = default) + { + var request = new UserSettingsGetPathsRequest { RepoRoot = repoRoot }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.getPaths", [request], cancellationToken); + } -/// Transport the runtime would otherwise use for this request. `http` (the default when absent) covers plain HTTP and SSE responses; `websocket` indicates a full-duplex message channel where each body chunk maps to one WebSocket message and the `binary` flag distinguishes text from binary frames. The SDK consumer uses this to decide whether to service the request with an HTTP client or a WebSocket client. It is the one piece of request metadata the consumer cannot reliably infer from the URL or headers alone. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct LlmInferenceHttpRequestStartTransport : IEquatable -{ - private readonly string? _value; + /// Writes one or more user settings to settings.json, replacing each provided top-level key. A key whose value is null is removed. + /// Partial user settings to write, as a free-form object keyed by setting name. + /// The to monitor for cancellation requests. The default is . + public async Task SetAsync(object? settings, CancellationToken cancellationToken = default) + { + var request = new UserSettingsSetRequest { Settings = CopilotClient.ToJsonElementForWire(settings) ?? JsonElement.Parse("null") }; + await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.set", [request], cancellationToken); + } - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public LlmInferenceHttpRequestStartTransport(string value) + /// Lists the top-level user-setting keys by who is allowed to govern them: `repo` keys a repository may override through `.github/copilot/settings.json`, `claudeRepo` keys a repository may override through a Claude-compatible config, and `managed` keys an enterprise policy may fix. The lists are static for a given runtime build and fail closed: a key absent from a list cannot be governed that way. + /// The to monitor for cancellation requests. The default is . + /// Top-level user-setting keys grouped by who may govern them. + internal async Task ListGovernanceKeysAsync(CancellationToken cancellationToken = default) { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.listGovernanceKeys", [], cancellationToken); } - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; + /// Atomically edits one canonical user setting inside its settings-file lock. Reads, canonicalizes touched aliases, applies the edit, validates the resulting top-level setting and writes before releasing the lock. An explicit autoUpdatesChannel set completes the staff migration in the same transaction. Only a malformed existing file returns `invalid`; refused keys, invalid values and I/O errors reject the call. + /// Nonempty canonical path segments of the setting to edit, starting with its top-level key. + /// Set a scalar, add or remove a string list item, or remove the setting. The handler rejects a missing or incompatible value. + /// Configuration directory to edit. Omitted or empty resolves the server's own home, as in `user.settings.loadForConfigDir`. + /// Required boolean, string or number for set, required string for add-item and remove-item, and forbidden for remove. The runtime rejects all other JSON values. + /// The to monitor for cancellation requests. The default is . + /// Outcome of an atomic user or repository settings edit. + internal async Task EditAsync(IList canonicalPath, SettingsEditOperation operation, string? configDir = null, object? value = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(canonicalPath); - /// Plain HTTP or SSE response. Each body chunk is an opaque byte range; the response is a status line, headers, and a (possibly streamed) body. - public static LlmInferenceHttpRequestStartTransport Http { get; } = new("http"); + var request = new UserSettingsEditRequest { CanonicalPath = canonicalPath, Operation = operation, ConfigDir = configDir, Value = CopilotClient.ToJsonElementForWire(value) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.edit", [request], cancellationToken); + } - /// Full-duplex WebSocket channel. Each body chunk maps to exactly one WebSocket message and the `binary` flag distinguishes text from binary frames; request and response chunks flow concurrently. - public static LlmInferenceHttpRequestStartTransport Websocket { get; } = new("websocket"); + /// Rewrites legacy and snake_case setting names in a settings object to their canonical spelling. A caller editing settings.json must normalize before writing: a legacy key left in place survives the write, is re-normalized on the next load, and silently shadows the canonical value the write just stored. + /// Free-form settings object, possibly using legacy or snake_case key names. + /// The to monitor for cancellation requests. The default is . + /// Settings object with canonical key names. + internal async Task NormalizeAsync(object? settings, CancellationToken cancellationToken = default) + { + var request = new UserSettingsNormalizeRequest { Settings = CopilotClient.ToJsonElementForWire(settings) ?? JsonElement.Parse("null") }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.normalize", [request], cancellationToken); + } - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(LlmInferenceHttpRequestStartTransport left, LlmInferenceHttpRequestStartTransport right) => left.Equals(right); + /// Diagnoses a set of already-loaded settings layers, reporting each key that will not take effect and why. Settings load tolerantly so that one bad key does not stop a session from starting; this method surfaces what was dropped so a caller can report it instead of silently ignoring the user's intent. Takes the layers as given rather than reading them, so a caller can diagnose exactly the content it is showing, including unsaved edits. Never echoes a setting's value, because a value may be a token or another secret. Marked internal because it exists to carry a CLI call site off the native addon, not to serve a consumer-facing need; it becomes public once an SDK consumer needs to inspect settings health itself. + /// Layers to diagnose, in the precedence order the caller applies them. + /// The to monitor for cancellation requests. The default is . + /// The settings that will not take effect across the given layers. + internal async Task DiagnoseProblemsAsync(IList? sources = null, CancellationToken cancellationToken = default) + { + var request = new UserSettingsProblemsRequest { Sources = sources }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.diagnoseProblems", [request], cancellationToken); + } - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(LlmInferenceHttpRequestStartTransport left, LlmInferenceHttpRequestStartTransport right) => !(left == right); + /// Validates one top-level setting subtree and writes just that key to settings.json as a single step. Doing both here closes the race a caller cannot close itself: between a separate preflight read and the write, the file may change. Rewriting only the touched key keeps legacy siblings out of settings.json. Answers a status rather than failing, so a validation problem and a write problem stay distinguishable. + /// Canonical path of the setting the caller is editing. Currently informational only. + /// Top-level setting name to write. + /// Value to write for the whole top-level key. Omitted when `delete` is true. Explicit null is preserved and validated as null. + /// True to remove the top-level key instead of writing it. + /// Records that the user chose an update channel explicitly, so the one-time staff channel migration stops reapplying. Honored only for the `autoUpdatesChannel` key. + /// The to monitor for cancellation requests. The default is . + /// Outcome of validating and writing one top-level setting subtree. + internal async Task ApplyTopKeyAsync(IList canonicalPath, string topKey, object? value = null, bool? delete = null, bool? completeStaffUpdateChannelMigration = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(canonicalPath); + ArgumentNullException.ThrowIfNull(topKey); - /// - public override bool Equals(object? obj) => obj is LlmInferenceHttpRequestStartTransport other && Equals(other); + var request = new UserSettingsApplyTopKeyRequest { CanonicalPath = canonicalPath, TopKey = topKey, Value = CopilotClient.ToJsonElementForWire(value), Delete = delete, CompleteStaffUpdateChannelMigration = completeStaffUpdateChannelMigration }; + var payload = JsonSerializer.SerializeToNode(request, RpcJsonContext.Default.UserSettingsApplyTopKeyRequest)!.AsObject(); + if (request.Delete != true && request.Value is null) payload["value"] = null; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.applyTopKey", [payload], cancellationToken); + } - /// - public bool Equals(LlmInferenceHttpRequestStartTransport other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + /// Replaces the user settings file's entire content in one write. A key absent from `settings` is removed, which is what distinguishes this from `user.settings.set`: that one merges, so it can never clear a key the caller has dropped. For a caller saving the result of a raw edit, a merge would silently resurrect every key the user deleted. Records the same one-time mutation marks a per-key write records, so a setting the user has now chosen explicitly stops being migrated for them. + /// The settings object to store. It replaces the file's entire content, so a key absent here is removed. + /// The to monitor for cancellation requests. The default is . + internal async Task WriteAllAsync(object? settings, CancellationToken cancellationToken = default) + { + var request = new UserSettingsWriteAllRequest { Settings = CopilotClient.ToJsonElementForWire(settings) ?? JsonElement.Parse("null") }; + await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.writeAll", [request], cancellationToken); + } - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + /// Merges a partial object into one top-level user setting, re-reading the stored value inside this runtime process's settings.json write lock so that concurrent writers in this process to different sub-fields of the same key do not clobber each other. Unlike `user.settings.set`, which replaces a key's whole value with what the caller last read, this keeps sub-fields the caller did not name when both the stored value and supplied value are objects; otherwise the supplied value replaces the stored value. Use it whenever two independent surfaces own different sub-fields of one setting. Returns the key's stored value after the write, in `value`. + /// Top-level user-setting key to merge into, such as `extensions`. + /// Value to store for `key`. When both the stored value and this value are objects, their fields are shallow-merged and fields this object does not name are preserved. Otherwise this value replaces the stored value. + /// Copilot configuration directory to write the settings document in, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to use the directory the server resolved for itself. + /// Single-component name for the settings document at `<configDir>/settings/<subDir>.json`; path separators, `.` and `..` are rejected. Omit it, or pass an empty string, to use the main settings document. + /// The to monitor for cancellation requests. The default is . + /// The stored value of the user setting after the merge. + internal async Task UpdateAsync(string key, object? value, string? configDir = null, string? subDir = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(key); - /// - public override string ToString() => Value; + var request = new UserSettingsUpdateRequest { Key = key, Value = CopilotClient.ToJsonElementForWire(value) ?? JsonElement.Parse("null"), ConfigDir = configDir, SubDir = subDir }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.update", [request], cancellationToken); + } - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + /// Reads settings.json as stored for a caller that is about to edit it. Unlike `user.settings.get`, this returns file values rather than per-key metadata and defaults. Reports `missing` for an absent file and `invalid` when the existing file will not parse. Retired config.json and extensionless files are not read. + /// The to monitor for cancellation requests. The default is . + /// Contents of settings.json as stored, for a caller about to rewrite it. + internal async Task LoadForEditAsync(CancellationToken cancellationToken = default) { - /// - public override LlmInferenceHttpRequestStartTransport Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.loadForEdit", [], cancellationToken); + } - /// - public override void Write(Utf8JsonWriter writer, LlmInferenceHttpRequestStartTransport value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(LlmInferenceHttpRequestStartTransport)); - } + /// Validates one top-level setting subtree without writing it, reporting each problem with the path it applies to. Scoped to a single top-level key on purpose: validating the whole file would reject an edit whenever an unrelated pre-existing field is malformed, locking the user out of the very tool that could fix it. + /// Top-level setting name to validate. + /// Value to validate. Omitted when `delete` is true. + /// True to validate a removal of this key. The current settings file is not read. + /// The to monitor for cancellation requests. The default is . + /// Outcome of validating one top-level setting subtree. + internal async Task ValidateAsync(string topKey, object? value = null, bool? delete = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(topKey); + + var request = new UserSettingsValidateRequest { TopKey = topKey, Value = CopilotClient.ToJsonElementForWire(value), Delete = delete }; + return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.validate", [request], cancellationToken); } } +/// Provides server-scoped Repo APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerRepoApi +{ + private readonly JsonRpc _rpc; + + internal ServerRepoApi(JsonRpc rpc) + { + _rpc = rpc; + } -/// Why the runtime is requesting a GitHub credential. + /// Settings APIs. + public ServerRepoSettingsApi Settings => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; +} + +/// Provides server-scoped RepoSettings APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct GitHubTokenAcquireReason : IEquatable +public sealed class ServerRepoSettingsApi { - private readonly string? _value; + private readonly JsonRpc _rpc; - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public GitHubTokenAcquireReason(string value) + internal ServerRepoSettingsApi(JsonRpc rpc) { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; + _rpc = rpc; } - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; + /// Atomically edits one allowed top-level repository setting. Reads the raw file, preserves unrelated keys, applies one scalar or list edit, validates the result and writes under one file lock, so concurrent sibling or list edits are not lost. A malformed or unsafe existing file returns `invalid` without a write; rejected keys, invalid values and I/O errors reject the call. + /// Absolute path of the repository root. + /// Shared or local repository settings file. + /// One canonical top-level repository setting that the allowlist permits. + /// Set a scalar, add or remove a string list item, or remove the setting. The handler rejects a missing or incompatible value. + /// Required boolean, string or number for set, required string for add-item and remove-item, and forbidden for remove. The runtime rejects all other JSON values. + /// The to monitor for cancellation requests. The default is . + /// Outcome of an atomic user or repository settings edit. + internal async Task EditAsync(string repoRoot, RepoSettingsEditScope scope, string key, SettingsEditOperation operation, object? value = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(repoRoot); + ArgumentNullException.ThrowIfNull(key); - /// The runtime is acquiring the registration's first credential. - public static GitHubTokenAcquireReason Initial { get; } = new("initial"); + var request = new RepoSettingsEditRequest { RepoRoot = repoRoot, Scope = scope, Key = key, Operation = operation, Value = CopilotClient.ToJsonElementForWire(value) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "repo.settings.edit", [request], cancellationToken); + } - /// The runtime is replacing a credential that is approaching expiry. - public static GitHubTokenAcquireReason Refresh { get; } = new("refresh"); + /// Reads one repository settings file without settings normalization or layering. The existing JSONC parser accepts comments and trailing commas and applies its prototype-safety rules. Missing or blank files return an empty valid config. Invalid files return an empty config with invalid=true; other read failures reject. + /// Absolute path of the repository root. + /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + /// The to monitor for cancellation requests. The default is . + /// Parsed repository settings without normalization or layering. + internal async Task ReadRawAsync(string repoRoot, string scope, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(repoRoot); + ArgumentNullException.ThrowIfNull(scope); - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(GitHubTokenAcquireReason left, GitHubTokenAcquireReason right) => left.Equals(right); + var request = new RepoSettingsReadRawRequest { RepoRoot = repoRoot, Scope = scope }; + return await CopilotClient.InvokeRpcAsync(_rpc, "repo.settings.readRaw", [request], cancellationToken); + } + + /// Writes or removes one allowed top-level repository setting through the existing validator and file lock. Preserves unrelated stored keys. Invalid keys, values, existing documents, and I/O errors reject without replacing the file. Deletion requires delete=true; otherwise value must be present. + /// Absolute path of the repository root. + /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + /// Canonical top-level key permitted by the repository settings allowlist. + /// Value to validate and write. Required unless delete is true; a null value is validated, not treated as deletion. + /// True to remove the key instead of writing it. + /// The to monitor for cancellation requests. The default is . + internal async Task WriteKeyAsync(string repoRoot, string scope, string key, object? value = null, bool? delete = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(repoRoot); + ArgumentNullException.ThrowIfNull(scope); + ArgumentNullException.ThrowIfNull(key); + + var request = new RepoSettingsWriteKeyRequest { RepoRoot = repoRoot, Scope = scope, Key = key, Value = CopilotClient.ToJsonElementForWire(value), Delete = delete }; + var payload = JsonSerializer.SerializeToNode(request, RpcJsonContext.Default.RepoSettingsWriteKeyRequest)!.AsObject(); + if (request.Delete != true && request.Value is null) payload["value"] = null; + await CopilotClient.InvokeRpcAsync(_rpc, "repo.settings.writeKey", [payload], cancellationToken); + } + + /// Replaces the repository-overridable settings in one locked write. Allowed keys present in settings are validated and written; allowed keys absent from settings are removed. Other input keys are ignored, and unknown keys already stored in the file remain unchanged. Invalid values or an invalid existing file reject without a partial write. + /// Absolute path of the repository root. + /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + /// Object of allowed settings to store. Missing allowlisted keys are removed. Other input keys are ignored, while unknown stored keys are preserved. + /// The to monitor for cancellation requests. The default is . + internal async Task WriteAllAsync(string repoRoot, string scope, object? settings, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(repoRoot); + ArgumentNullException.ThrowIfNull(scope); - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(GitHubTokenAcquireReason left, GitHubTokenAcquireReason right) => !(left == right); + var request = new RepoSettingsWriteAllRequest { RepoRoot = repoRoot, Scope = scope, Settings = CopilotClient.ToJsonElementForWire(settings) ?? JsonElement.Parse("null") }; + await CopilotClient.InvokeRpcAsync(_rpc, "repo.settings.writeAll", [request], cancellationToken); + } +} - /// - public override bool Equals(object? obj) => obj is GitHubTokenAcquireReason other && Equals(other); +/// Provides server-scoped FeatureFlags APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerFeatureFlagsApi +{ + private readonly JsonRpc _rpc; - /// - public bool Equals(GitHubTokenAcquireReason other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + internal ServerFeatureFlagsApi(JsonRpc rpc) + { + _rpc = rpc; + } - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); + /// Resolves named gates against this installation's cached online-experiment assignment, for the account the runtime is already authenticated as. Unlike `featureFlags.resolve`, which layers static availability with the populations supplied, this reads the experiment assignment the runtime cached for its own current authentication, so a launch can honor a rollout before any session exists. The account is never taken from the request: naming one would read another account's cached assignments. The cached assignment answers immediately and any network refresh happens behind it, so this call does not wait on the network. Not available to an extension, which cannot carry the user's consent to read their assignment. + /// The feature flags to resolve. A name this runtime does not declare is reported as an error rather than as a disabled flag. + /// Whether the caller is GitHub or Microsoft staff. + /// Whether the caller is in an experimental population. + /// Whether the caller belongs to a team plan. + /// Whether streamer mode is on, which withholds the populations an experiment would otherwise segment on. + /// Whether the runtime may refresh the cached assignment over the network without an active session. The refresh never blocks this call: the answer comes from the cache either way, so a refresh only affects a later launch. + /// GitHub-staff membership. Omit when it was never recorded: a legacy staff account then counts as both staff populations and keeps every staff feature. + /// Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. + /// Environment to read flag overrides from. Defaults to this runtime process's own environment. + /// User settings document whose `featureFlags` block is layered on top of the resolved set. + /// When this installation first launched, in milliseconds since the Unix epoch. Experiments that segment on installation age read it. Omit when the first launch was never recorded. + /// The to monitor for cancellation requests. The default is . + /// The resolved gates, keyed by flag name. + internal async Task> ResolveStartupGatesAsync(IList flags, bool isStaff, bool isExperimental, bool isTeam, bool streamerMode, bool refreshWithoutSession, bool? isStaffGithub = null, bool? isStaffMicrosoft = null, IDictionary? environment = null, object? config = null, double? firstLaunchAtMillis = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(flags); - /// - public override string ToString() => Value; + var request = new FeatureFlagsResolveStartupGatesRequest { Flags = flags, IsStaff = isStaff, IsExperimental = isExperimental, IsTeam = isTeam, StreamerMode = streamerMode, RefreshWithoutSession = refreshWithoutSession, IsStaffGitHub = isStaffGithub, IsStaffMicrosoft = isStaffMicrosoft, Environment = environment, Config = CopilotClient.ToJsonElementForWire(config), FirstLaunchAtMillis = firstLaunchAtMillis }; + return await CopilotClient.InvokeRpcAsync>(_rpc, "featureFlags.resolveStartupGates", [request], cancellationToken); + } - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + /// Lists every feature flag this runtime declares, with the population each one is declared for, its experimental description, and the online-experiment flag it maps to. This is the static catalog: it describes how each flag is defined, not whether it is on for anyone. Use `featureFlags.resolve` for static values with caller overrides, not active runtime values or experiment assignments. + /// The to monitor for cancellation requests. The default is . + /// Every feature flag this runtime declares, with the shape each one was declared with. + internal async Task ListMetadataAsync(CancellationToken cancellationToken = default) { - /// - public override GitHubTokenAcquireReason Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } + return await CopilotClient.InvokeRpcAsync(_rpc, "featureFlags.listMetadata", [], cancellationToken); + } - /// - public override void Write(Utf8JsonWriter writer, GitHubTokenAcquireReason value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(GitHubTokenAcquireReason)); - } + /// Computes static feature flags from the supplied population and overrides without changing runtime state or verifying audience membership. Starts from declared availability, then applies direct feature-flag environment values, user settings, and explicit `flagOverrides`. It does not apply `COPILOT_EXP_*` experiment assignments, authenticated startup gates, or active runtime state. Settings include `enabledFeatureFlags`, the legacy `feature_flags.enabled` list, and supported convenience settings. Supply `baseFlags` to use an existing flag set instead of declared availability. Omit `isStaffGitHub` or `isStaffMicrosoft` when membership was never recorded: a legacy staff account then counts as both populations. + /// Whether the caller is GitHub or Microsoft staff. + /// Whether the caller is in an experimental population. + /// Whether the caller belongs to the team population used by feature availability. + /// GitHub-staff membership. Omit when it was never recorded: a legacy staff account then counts as both staff populations and keeps every staff feature. + /// Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. + /// Resolve against this already-computed flag set rather than each flag's declared availability. Keyed by flag name. + /// Environment for direct feature-flag overrides and `COPILOT_CLI_ENABLED_FEATURE_FLAGS`. Does not apply `COPILOT_EXP_*` experiment assignments. Defaults to this runtime process's own environment. + /// User settings to apply, including `enabledFeatureFlags`, legacy `feature_flags.enabled`, and supported convenience settings. + /// Flags forced to a value after every other layer, keyed by flag name. + /// The to monitor for cancellation requests. The default is . + /// The resolved feature flags, keyed by flag name. + internal async Task> ResolveAsync(bool isStaff, bool isExperimental, bool isTeam, bool? isStaffGithub = null, bool? isStaffMicrosoft = null, IDictionary? baseFlags = null, IDictionary? environment = null, object? config = null, IDictionary? flagOverrides = null, CancellationToken cancellationToken = default) + { + var request = new FeatureFlagsResolveRequest { IsStaff = isStaff, IsExperimental = isExperimental, IsTeam = isTeam, IsStaffGitHub = isStaffGithub, IsStaffMicrosoft = isStaffMicrosoft, BaseFlags = baseFlags, Environment = environment, Config = CopilotClient.ToJsonElementForWire(config), FlagOverrides = flagOverrides }; + return await CopilotClient.InvokeRpcAsync>(_rpc, "featureFlags.resolve", [request], cancellationToken); } } - -/// Explicit user decisions, never inferred from a permission grant or model response. +/// Provides server-scoped Permissions APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct InstallationDecision : IEquatable +public sealed class ServerPermissionsApi { - private readonly string? _value; + private readonly JsonRpc _rpc; - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public InstallationDecision(string value) + internal ServerPermissionsApi(JsonRpc rpc) { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; + _rpc = rpc; } - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// The user explicitly approved the exact review on this request. - public static InstallationDecision Confirm { get; } = new("confirm"); - - /// The user declined the reviewed operation. - public static InstallationDecision Decline { get; } = new("decline"); + /// Interprets a verbatim managed `permissions` slice into the three policy questions a host asks before granting elevated permissions: whether bypass-permissions mode is forbidden, whether a policy exists that this build could not determine, and whether the layer supplies permission rules the session must enforce. An absent or empty slice means no managed policy applies. The runtime and its permission service share one policy type, so a new managed permission setting is interpreted in exactly one place; a host that reimplements the reading would silently diverge the first time that set grows. Hosts must fail closed on an undetermined policy rather than treating it as permission granted. + /// The `permissions` object from a managed settings layer, for example `{"disableBypassPermissionsMode":"disable"}`. Omitted or null means no managed policy applies. + /// The to monitor for cancellation requests. The default is . + /// The policy questions a host asks before granting elevated permissions. + internal async Task EvaluateManagedPolicyAsync(object? permissions = null, CancellationToken cancellationToken = default) + { + var request = new PermissionsEvaluateManagedPolicyParams { Permissions = CopilotClient.ToJsonElementForWire(permissions) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "permissions.evaluateManagedPolicy", [request], cancellationToken); + } - /// The user cancelled the pending decision without granting consent. - public static InstallationDecision Cancel { get; } = new("cancel"); + /// Locations APIs. + public ServerPermissionsLocationsApi Locations => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(InstallationDecision left, InstallationDecision right) => left.Equals(right); + /// FolderTrust APIs. + public ServerPermissionsFolderTrustApi FolderTrust => + field ?? + Interlocked.CompareExchange(ref field, new(_rpc), null) ?? + field; +} - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(InstallationDecision left, InstallationDecision right) => !(left == right); +/// Provides server-scoped PermissionsLocations APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerPermissionsLocationsApi +{ + private readonly JsonRpc _rpc; - /// - public override bool Equals(object? obj) => obj is InstallationDecision other && Equals(other); + internal ServerPermissionsLocationsApi(JsonRpc rpc) + { + _rpc = rpc; + } - /// - public bool Equals(InstallationDecision other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); + /// Drops stored per-location permission grants whose directory no longer exists, and reports which location keys were removed. Runs against the permission store under the runtime's own Copilot home, the same store `session.permissions.locations.resolve` reads. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. It can become public once an SDK consumer needs to prune its own permission store. + /// The to monitor for cancellation requests. The default is . + /// Which stored location permissions were dropped because their directory is gone. + internal async Task CleanupOrphanedAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "permissions.locations.cleanupOrphaned", [], cancellationToken); + } +} - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); +/// Provides server-scoped PermissionsFolderTrust APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerPermissionsFolderTrustApi +{ + private readonly JsonRpc _rpc; - /// - public override string ToString() => Value; + internal ServerPermissionsFolderTrustApi(JsonRpc rpc) + { + _rpc = rpc; + } - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter + /// Reports whether a folder is trusted, reading the persisted trusted-folders list directly rather than through a session. Use this from a host that has no session yet, such as a one-shot command deciding whether to honor a checkout's own settings. It differs from the session-scoped check in two ways that matter: it takes the configuration directory to read the list from, instead of inheriting the session's, and it answers only from the persisted list, so trust a user granted for the lifetime of one session is not visible here. A host that has a session should prefer the session-scoped check, which also covers session-only trust. + /// Folder to check. A folder counts as trusted when it is itself listed, when an ancestor is listed, or when its git root is listed. + /// Configuration directory to read the trusted-folders list from. Omit it to read the default location; supply it when the host has redirected its configuration, or the check answers from a list the host is not using. + /// The to monitor for cancellation requests. The default is . + /// Folder trust check result. + internal async Task CheckTrustAsync(string path, string? configDir = null, CancellationToken cancellationToken = default) { - /// - public override InstallationDecision Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } + ArgumentNullException.ThrowIfNull(path); - /// - public override void Write(Utf8JsonWriter writer, InstallationDecision value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(InstallationDecision)); - } + var request = new FolderTrustIsTrustedParams { Path = path, ConfigDir = configDir }; + return await CopilotClient.InvokeRpcAsync(_rpc, "permissions.folderTrust.checkTrust", [request], cancellationToken); } } - -/// Provides server-scoped RPC methods (no session required). -public sealed class ServerRpc +/// Provides server-scoped ManagedSettings APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerManagedSettingsApi { private readonly JsonRpc _rpc; - internal ServerRpc(JsonRpc rpc) + internal ServerManagedSettingsApi(JsonRpc rpc) { _rpc = rpc; } - /// Checks server responsiveness and returns protocol information. - /// Optional message to echo back. + /// Discovers device-managed settings the way the runtime's own device layer does, and reports the sandbox floor and the load outcome alongside the validated document. This differs from `managedSettings.read` in three ways a policy-enforcing host depends on: a document that validates to an empty object is reported as absent rather than as an empty policy, a discovery error does not suppress a document that still validates, and a failure is reported as a flag rather than only as error text. Hosts that compose the device layer into an effective policy use this, because `managedSettings.read` cannot distinguish "no device policy" from "device policy could not be read" and would silently hand the user's own layer the win. /// The to monitor for cancellation requests. The default is . - /// Server liveness response, including the echoed message, current server timestamp, and protocol version. - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] - public async Task PingAsync(string? message = null, CancellationToken cancellationToken = default) + /// The device-managed settings layer, with the sandbox floor and the load outcome a host needs to compose it into an effective policy. + internal async Task ReadDeviceAsync(CancellationToken cancellationToken = default) { - var request = new PingRequest { Message = message }; - return await CopilotClient.InvokeRpcAsync(_rpc, "ping", [request], cancellationToken); + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.readDevice", [], cancellationToken); } - /// Performs the SDK server connection handshake and validates the optional connection token. Marked internal because this is JSON-RPC transport plumbing invoked automatically by an SDK client's own `connect()` wrapper, not a user-facing method. Stays internal as long as the SDK client owns the handshake; would only become public if the SDK ever exposed the raw schema surface to consumers without a connection wrapper. - /// Opt this connection in to GitHub telemetry forwarding for its lifetime. When set, the runtime forwards this host's telemetry across all its sessions, its sessionless events, and explicitly process-wide events over the `gitHubTelemetry.event` notification. Connections intentionally sharing one server receive that server's events; independently embedded runtime hosts do not receive each other's host-owned events. Regular events are also written to the runtime's normal GitHub/CTS path (dual-write); host-only compatibility events are forward-only and intentionally skip that path. Intended for first-party hosts that re-emit the events into their own telemetry stores. Both unrestricted and restricted events are forwarded, each tagged with a `restricted` discriminator; a backstop drops restricted events when restricted telemetry is disabled — using the process-global gate for ordinary events and an explicit session-scoped decision for host-only events. - /// Identity of the integrating host. Optional; omit it to keep the default attribution. - /// Task kinds this connection can decode when observing session tasks. Omit to retain agent and shell compatibility. - /// Connection token; required when the server was started with COPILOT_CONNECTION_TOKEN. + /// Retains the supplied managed layers as this runtime process's startup policy and re-applies the result to every live session. Hosts that own their own short-lived process policy use this, so a guarded mutation is checked against the policy the host actually fetched. Retaining is a whole-process replacement rather than a merge, so a host that already resolved a good policy must not retain a partial one over it. The failure flags are honest inputs rather than assumptions: reporting a fetch or load that failed keeps the layers already retained, and the interim fail-closed state, instead of clearing them. + /// Whether a device policy source demonstrably exists. This, not a read error, is the evidence a device is managed, so a fail-closed policy gates on it. + /// Whether any managed policy source exists, independently of fetch failures. + /// Whether the server policy source exists, even when its response is unavailable. + /// Whether a required fresh server-policy confirmation failed. + /// Preserve the retained server layer during a device-only resolution. + /// Whether the device sandbox intent is unreadable independently of its other settings. + /// Whether the shared sandbox policy is undetermined. Diagnostic errors alone do not imply this flag. + /// Whether permission policy is undetermined. Sandbox-only uncertainty does not imply this flag. + /// Whether uncertainty alone enabled the shared sandbox floor. + /// Whether the server fetch failed. Report it honestly: true keeps the already-retained server layer rather than replacing it with an absent one. + /// Whether the device load failed. Report it honestly, for the same reason as `serverFetchFailed`. + /// The resolved server policy. A known source can lack a response after a forced-refresh failure. + /// The device/MDM policy layer. + /// Sandbox floor declared by the device layer, carried separately so a document that failed validation can still raise the floor. + /// Shared server/device sandbox floor, excluding session-local helper policy. + /// The policy helper's response: the third managed layer that a process owning its startup policy resolves. It is retained with the other two so that every ambient read in this process, including the mutation guards and the governed marketplace allowlist that the `plugins.*` handlers derive, sees the whole policy the process fetched. A session-owning process omits it, because it resolves a helper per session against that session's working directory. /// The to monitor for cancellation requests. The default is . - /// Handshake result reporting the server's protocol version and package version on success. - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] - internal async Task ConnectAsync(bool? enableGitHubTelemetryForwarding = null, ConnectClientInfo? clientInfo = null, IList? supportedTaskKinds = null, string? token = null, CancellationToken cancellationToken = default) + internal async Task RetainPolicyAsync(bool deviceSourceFound, bool managedPolicyPresent, bool serverSourceFound, bool serverForcedRefreshFailure, bool preserveServerState, bool deviceSandboxUndetermined, bool sandboxFloorUndetermined, bool permissionPolicyUndetermined, bool sandboxEnabledByUndeterminedPolicy, bool serverFetchFailed, bool deviceLoadFailed, object? serverResponse = null, object? deviceResponse = null, object? deviceSandboxFloor = null, object? sharedSandboxFloor = null, object? policyHelperResponse = null, CancellationToken cancellationToken = default) { - var request = new ConnectRequest { EnableGitHubTelemetryForwarding = enableGitHubTelemetryForwarding, ClientInfo = clientInfo, SupportedTaskKinds = supportedTaskKinds, Token = token }; - return await CopilotClient.InvokeRpcAsync(_rpc, "connect", [request], cancellationToken); + var request = new ManagedSettingsRetainPolicyParams { DeviceSourceFound = deviceSourceFound, ManagedPolicyPresent = managedPolicyPresent, ServerSourceFound = serverSourceFound, ServerForcedRefreshFailure = serverForcedRefreshFailure, PreserveServerState = preserveServerState, DeviceSandboxUndetermined = deviceSandboxUndetermined, SandboxFloorUndetermined = sandboxFloorUndetermined, PermissionPolicyUndetermined = permissionPolicyUndetermined, SandboxEnabledByUndeterminedPolicy = sandboxEnabledByUndeterminedPolicy, ServerFetchFailed = serverFetchFailed, DeviceLoadFailed = deviceLoadFailed, ServerResponse = CopilotClient.ToJsonElementForWire(serverResponse), DeviceResponse = CopilotClient.ToJsonElementForWire(deviceResponse), DeviceSandboxFloor = CopilotClient.ToJsonElementForWire(deviceSandboxFloor), SharedSandboxFloor = CopilotClient.ToJsonElementForWire(sharedSandboxFloor), PolicyHelperResponse = CopilotClient.ToJsonElementForWire(policyHelperResponse) }; + await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.retainPolicy", [request], cancellationToken); } - /// Registers the calling SDK client as the per-entrypoint extension launch provider. Call before creating any sessions. When omitted, the runtime uses its built-in extension launcher. + /// Stamps an effective managed policy's individually-controlled entries onto a user settings document, returning the settings a host should actually act on. The managed layer wins on every plugin spec and marketplace name it names, and leaves everything it does not name as the user wrote it. Hosts use this rather than merging the two documents themselves, because the merge is per entry rather than per document and a whole-document overlay would either discard the user's unmanaged entries or let a user entry outrank a managed one. Omitting the managed layer returns the settings unchanged, which is what an unmanaged host wants. Rejects when either document is present but is not a JSON object rather than treating it as absent, since silently dropping a malformed policy hands the user's layer the win on exactly the entries the policy exists to control. + /// The user settings document to stamp. Entries the managed layer does not name are returned exactly as supplied. + /// The effective managed policy, as composed by `managedSettings.resolveEffectiveValue`. Omit it on an unmanaged host: the settings then come back unchanged. /// The to monitor for cancellation requests. The default is . - [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] - public async Task RegisterExtensionLaunchProviderAsync(CancellationToken cancellationToken = default) + /// The user settings with the managed layer's controlled entries stamped on. + internal async Task ApplyControlsAsync(object? settings, object? managed = null, CancellationToken cancellationToken = default) { - await CopilotClient.InvokeRpcAsync(_rpc, "registerExtensionLaunchProvider", [], cancellationToken); + var request = new ManagedSettingsApplyControlsParams { Settings = CopilotClient.ToJsonElementForWire(settings) ?? JsonElement.Parse("null"), Managed = CopilotClient.ToJsonElementForWire(managed) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.applyControls", [request], cancellationToken); } - /// Environments APIs. - public ServerEnvironmentsApi Environments => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; - - /// Host APIs. - public ServerHostApi Host => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; - - /// Hooks APIs. - public ServerHooksApi Hooks => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; - - /// Models APIs. - public ServerModelsApi Models => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; - - /// Sandbox APIs. - public ServerSandboxApi Sandbox => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; - - /// Tools APIs. - public ServerToolsApi Tools => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; - - /// Account APIs. - public ServerAccountApi Account => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; - - /// Secrets APIs. - public ServerSecretsApi Secrets => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; - - /// Mcp APIs. - public ServerMcpApi Mcp => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; - - /// Extensions APIs. - public ServerExtensionsApi Extensions => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Validates the managed settings a client is supplying for a session it is about to open, and returns them reduced to the keys a client is allowed to set. A client-supplied policy is not the same thing as an administrator's: it may only narrow permissions, so this accepts `permissions` and rejects every other key outright rather than ignoring it. Rejecting is the point — a host that silently dropped an unsupported key would report a policy as applied while running without it. Hosts call this before opening the session rather than letting the open fail, so a malformed policy is reported against the request that carried it. The runtime applies the same rule again when the session starts, so this cannot be used to smuggle a wider document past it. An accepted document that sets nothing comes back as an empty object, which is distinct from supplying nothing at all. + /// The managed settings a client is supplying for a session it is about to open. Omit them when the client is imposing no policy of its own. + /// The to monitor for cancellation requests. The default is . + /// The accepted managed settings, reduced to the keys a client is allowed to set. + internal async Task ParseClientValueAsync(object? settings = null, CancellationToken cancellationToken = default) + { + var request = new ManagedSettingsParseClientValueParams { Settings = CopilotClient.ToJsonElementForWire(settings) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.parseClientValue", [request], cancellationToken); + } - /// Instructions APIs. - public ServerInstructionsApi Instructions => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Composes the supplied server, device/MDM, device sandbox floor and policy-helper layers into the single effective managed policy a host should enforce, resolving each key across the layers by the runtime's own precedence rules. Hosts that assemble managed layers themselves use this so their precedence matches the runtime's exactly instead of reimplementing it. The composition is not a pure function of its inputs: an advisory sandbox force-on that arrived over the server channel is declined when this host cannot run a sandbox, so the result reflects the runtime host's capabilities, and the returned settings carry `sandboxAdvisoryFloorDeclined: true` when that happened. Enforced channels (device/MDM and policy helper) are never declined, and a server force-on carrying `failIfUnavailable` is preserved so the session fails loudly instead of quietly running unsandboxed. Rejects when a supplied layer is present but is not a JSON object, rather than treating it as unmanaged, because silently dropping a malformed policy would hand the user's own layer the win on exactly the keys the policy exists to control. + /// The account's server-delivered org policy, as returned by a managed-settings fetch. Omitted before sign-in or when the fetch has not landed. + /// The device layer: native MDM and managed-file settings describing the machine rather than the account. + /// The device sandbox floor, folded into the device layer under `sandbox` before composition. + /// The policy-helper layer, an enforced channel sourced from a platform policy helper process. + /// The to monitor for cancellation requests. The default is . + /// The effective managed policy composed from the supplied layers. + internal async Task ResolveEffectiveValueAsync(object? server = null, object? mdm = null, object? deviceSandboxFloor = null, object? policyHelper = null, CancellationToken cancellationToken = default) + { + var request = new ManagedSettingsResolveEffectiveValueParams { Server = CopilotClient.ToJsonElementForWire(server), Mdm = CopilotClient.ToJsonElementForWire(mdm), DeviceSandboxFloor = CopilotClient.ToJsonElementForWire(deviceSandboxFloor), PolicyHelper = CopilotClient.ToJsonElementForWire(policyHelper) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.resolveEffectiveValue", [request], cancellationToken); + } - /// Skills APIs. - public ServerSkillsApi Skills => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Decides what a host must do to its bypass-permissions state after a managed-policy resolution lands, given the state already in force and the account now signed in. A host holds two pieces of state — which layer disabled bypass mode, and for a server-delivered disable, the account it was pinned to — and cannot decide the next step from the new policy alone. Three rules make that so, and each one is a control rather than a preference. A device/MDM disable outranks the account, so a later server answer never lifts it. An unknown policy, which is what a failed fetch or a refusal this build cannot enforce yields, preserves whatever is in force instead of reverting to permissive. And a server disable is lifted only when the account it was pinned to is no longer the signed-in one, which is what makes signing in to an unrestricted account recover without a restart while a reconnect on the same restricted account does not. Hosts call this rather than reimplementing it because getting the pinning backwards either strands a disable on an account that never carried one or drops one that still applies. `setDisabledState` is omitted when the host must leave its stored flag untouched, which is distinct from being told to set it to false. + /// The account signed in now. A `managed` disable pinned to a different account is lifted. + /// What the resolution said about bypass mode. Send `unknown` rather than omitting the field when there is no verdict. + /// Which layer currently disables bypass mode. Omit it when nothing does. + /// The account a `managed` disable is pinned to. Omit it when the current source is not `managed`; it is ignored for the other sources. + /// The to monitor for cancellation requests. The default is . + /// The bypass-permissions state a host should hold after the resolution, and what it must do to get there. + internal async Task ResolveBypassDisableTransitionAsync(string activeIdentity, ManagedSettingsBypassPolicyResolution policy, ManagedSettingsBypassDisableSource? currentSource = null, string? currentManagedIdentity = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(activeIdentity); - /// Catalog APIs. - public ServerCatalogApi Catalog => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + var request = new ManagedSettingsResolveBypassDisableTransitionParams { ActiveIdentity = activeIdentity, Policy = policy, CurrentSource = currentSource, CurrentManagedIdentity = currentManagedIdentity }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.resolveBypassDisableTransition", [request], cancellationToken); + } - /// Plugins APIs. - public ServerPluginsApi Plugins => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Resolves managed (enterprise policy) settings for a host from every layer at once: the account's server-delivered policy, the device/MDM layer, and a platform policy helper. Hosts use this instead of fetching and composing the layers themselves, because the per-layer precedence and the fail-closed rules that apply when a layer cannot be confirmed are the runtime's own and must match the policy a session will later enforce. It does not retain or apply anything to process-global policy state, so a host may call it before any session exists — which is the point, since plugin activation and one-shot commands resolve policy before a session is available to carry it. The returned per-layer outcome flags are load-bearing rather than diagnostic: a host must distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. Reports its diagnostics in `logMessages` rather than logging them, so a host that runs before a log sink exists still sees them. + /// User agent to send with the policy fetch. + /// The host's environment variables, read for cache location and policy overrides. Supplied by the host rather than read from the runtime process so a command that selected its own configuration home is honored. + /// The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. + /// The host's home directory, used to resolve cache and managed-file locations. + /// The policy-helper invocation reason. Defaults to sessionStart. + /// Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. + /// The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched. + /// The session whose credential store and working directory the policy helper should use. Omit it when no session exists yet and the process-wide store applies. + /// A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + /// Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. + /// Whether to ignore a cached server policy when reading, forcing the resolution to come from a live fetch. + /// How this ingestion may use the on-disk server-policy cache. Defaults to the runtime's own policy when omitted. + /// Whether a configured platform policy helper may be run to produce an enforced helper layer. + /// Directory the policy helper runs in when this ingestion is not owned by a registered session. A host resolving policy before its session exists must pass this, or a directory-sensitive helper judges the wrong repository. + /// Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. Omit it and the runtime reports a generic identity; the runtime version sent alongside is the gate that actually matters. + /// The to monitor for cancellation requests. The default is . + /// The managed policy layers an ingestion resolved, together with the per-layer outcome flags a host needs to decide how much to trust the result. The flags are reported rather than folded into the settings because a host must be able to distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. + internal async Task IngestAsync(string userAgent, object? environment, string platform, string homeDirectory, ManagedSettingsPolicyHelperReason? policyHelperReason = null, bool? selfFetch = null, object? authInfo = null, string? sessionId = null, object? deviceResponse = null, bool? hasDeviceResponse = null, bool? bypassCacheRead = null, ManagedSettingsServerPolicyCacheMode? serverPolicyCacheMode = null, bool? policyHelperEnabled = null, string? policyHelperWorkingDirectory = null, string? clientName = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(userAgent); + ArgumentNullException.ThrowIfNull(platform); + ArgumentNullException.ThrowIfNull(homeDirectory); - /// Agents APIs. - public ServerAgentsApi Agents => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + var request = new ManagedSettingsIngestParams { UserAgent = userAgent, Environment = CopilotClient.ToJsonElementForWire(environment) ?? JsonElement.Parse("null"), Platform = platform, HomeDirectory = homeDirectory, PolicyHelperReason = policyHelperReason, SelfFetch = selfFetch, AuthInfo = CopilotClient.ToJsonElementForWire(authInfo), SessionId = sessionId, DeviceResponse = CopilotClient.ToJsonElementForWire(deviceResponse), HasDeviceResponse = hasDeviceResponse, BypassCacheRead = bypassCacheRead, ServerPolicyCacheMode = serverPolicyCacheMode, PolicyHelperEnabled = policyHelperEnabled, PolicyHelperWorkingDirectory = policyHelperWorkingDirectory, ClientName = clientName }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.ingest", [request], cancellationToken); + } + + /// Resolves the managed (enterprise policy) settings a host must enforce from startup, and judges the account against the enterprise sign-in pin in the same pass. This composes the layers the way `managedSettings.ingest` does and then answers the two questions a host cannot answer for itself: which fail-closed floors apply when a layer could not be confirmed, and whether this credential is allowed to sign in at all. The sign-in verdict is the reason a host must not assemble this itself from `managedSettings.ingest` — a pinned organization is an access control, and a host that composed the layers but skipped the pin would let a developer sign in with a personal or another enterprise's account and escape every control that keys off the signed-in identity. The verdict is computed on every resolution, including one that is not retained, so declining to apply policy never widens access. Set `retainAndApply` to keep the resolved policy as this runtime process's startup policy; leave it false to resolve without side effects. + /// User agent to send with the policy fetch. + /// The host's environment variables, read for cache location, policy overrides, and the variables that would make a membership snapshot forgeable. + /// The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. + /// The host's home directory, used to resolve cache and managed-file locations. + /// Whether to retain the resolved policy as this runtime process's startup policy, so later work in the process enforces it. Set false to resolve without side effects, which is what a protocol host wants before session creation: its sessions apply the complete policy through the normal lifecycle, and retaining here would let a readiness credential affect unrelated sessions. The returned verdict is identical either way — this decides only whether the process keeps it. + /// The policy-helper invocation reason. Defaults to sessionStart. + /// Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. + /// The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched and the sign-in pin is evaluated against no credential. + /// The session whose credential store, working directory and client kind the resolution should use. Omit it when no session exists yet and the process-wide store applies. A resolution whose session names a credential other than `authInfo` is returned but not retained, so a stale sign-in cannot apply policy for an account that has already been switched away from. + /// A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + /// Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. + /// Whether to ignore a cached server policy when reading, forcing the resolution to come from a live fetch. + /// How this resolution may use the on-disk server-policy cache. Defaults to the runtime's own policy when omitted. Rejected when combined with `bypassCacheRead`, because the two express the same decision and accepting both would leave the caller unsure which one the runtime honored. + /// Whether a configured platform policy helper may be run to produce an enforced helper layer. + /// Directory the policy helper runs in when this resolution is not owned by a registered session. A host resolving policy before its session exists must pass this, or a directory-sensitive helper judges the wrong repository. + /// Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. + /// The to monitor for cancellation requests. The default is . + /// The startup policy a resolution composed, the per-layer outcome flags a host needs to decide how much to trust it, and the enterprise sign-in verdict for the credential it ran against. The flags are reported rather than folded into the settings because a host must distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. + internal async Task ResolveStartupPolicyAsync(string userAgent, object? environment, string platform, string homeDirectory, bool retainAndApply, ManagedSettingsPolicyHelperReason? policyHelperReason = null, bool? selfFetch = null, object? authInfo = null, string? sessionId = null, object? deviceResponse = null, bool? hasDeviceResponse = null, bool? bypassCacheRead = null, ManagedSettingsServerPolicyCacheMode? serverPolicyCacheMode = null, bool? policyHelperEnabled = null, string? policyHelperWorkingDirectory = null, string? clientName = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(userAgent); + ArgumentNullException.ThrowIfNull(platform); + ArgumentNullException.ThrowIfNull(homeDirectory); - /// GlobalState APIs. - public ServerGlobalStateApi GlobalState => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + var request = new ManagedSettingsResolveStartupPolicyParams { UserAgent = userAgent, Environment = CopilotClient.ToJsonElementForWire(environment) ?? JsonElement.Parse("null"), Platform = platform, HomeDirectory = homeDirectory, RetainAndApply = retainAndApply, PolicyHelperReason = policyHelperReason, SelfFetch = selfFetch, AuthInfo = CopilotClient.ToJsonElementForWire(authInfo), SessionId = sessionId, DeviceResponse = CopilotClient.ToJsonElementForWire(deviceResponse), HasDeviceResponse = hasDeviceResponse, BypassCacheRead = bypassCacheRead, ServerPolicyCacheMode = serverPolicyCacheMode, PolicyHelperEnabled = policyHelperEnabled, PolicyHelperWorkingDirectory = policyHelperWorkingDirectory, ClientName = clientName }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.resolveStartupPolicy", [request], cancellationToken); + } - /// Commands APIs. - public ServerCommandsApi Commands => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Resolves the managed `remoteControl` policy for an account on its own, for a host deciding whether a remote-control session may start. Composes the same layers as `managedSettings.ingest` and returns only that one key, so a host does not have to know which layer won. An absent policy means the account is unmanaged for this capability and the host may proceed; that default is safe only while absence really does mean "no policy", so a service refusal that says an account policy exists which this client is too old to enforce resolves to an explicit disabled policy instead of to absence. A resolution that cannot be completed is rejected rather than answered as absence, for the same reason. + /// User agent to send with the policy fetch. + /// The host's environment variables, read for cache location and policy overrides. + /// The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. + /// The host's home directory, used to resolve cache and managed-file locations. + /// The policy-helper invocation reason. Defaults to sessionStart. + /// Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. + /// The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched. + /// A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + /// Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. + /// Whether a configured platform policy helper may be run to produce an enforced helper layer. + /// Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. That refusal is exactly what turns into an explicit `disabled` below, so a host that omits this field forfeits the protection. + /// The to monitor for cancellation requests. The default is . + /// The managed remote-control policy in force for an account, if any. An absent policy means the account is unmanaged for this capability, which a host reads as allowed — so absence here is a positive statement that no policy applies, never a stand-in for a resolution that failed. A resolution that cannot be completed is rejected instead. + internal async Task LoadRemoteControlAsync(string userAgent, object? environment, string platform, string homeDirectory, ManagedSettingsPolicyHelperReason? policyHelperReason = null, bool? selfFetch = null, object? authInfo = null, object? deviceResponse = null, bool? hasDeviceResponse = null, bool? policyHelperEnabled = null, string? clientName = null, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(userAgent); + ArgumentNullException.ThrowIfNull(platform); + ArgumentNullException.ThrowIfNull(homeDirectory); + + var request = new ManagedSettingsLoadRemoteControlParams { UserAgent = userAgent, Environment = CopilotClient.ToJsonElementForWire(environment) ?? JsonElement.Parse("null"), Platform = platform, HomeDirectory = homeDirectory, PolicyHelperReason = policyHelperReason, SelfFetch = selfFetch, AuthInfo = CopilotClient.ToJsonElementForWire(authInfo), DeviceResponse = CopilotClient.ToJsonElementForWire(deviceResponse), HasDeviceResponse = hasDeviceResponse, PolicyHelperEnabled = policyHelperEnabled, ClientName = clientName }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.loadRemoteControl", [request], cancellationToken); + } + + /// Evaluates the device-channel enterprise sign-in pin (MDM plist, registry, or managed-settings file) against a credential, without resolving any server-delivered policy. This is the gate an entry point runs before it branches, and the only one that can refuse a developer's first sign-in: it is local, needs no credential, and a server-delivered pin only ever reaches accounts already inside the organization. It fails closed by construction — a discovery that cannot determine whether a pin exists refuses rather than allows, because a control that fails open under a triggerable condition is not a control. Hosts that also want the server channel should call `managedSettings.resolveStartupPolicy`, which folds both channels into one verdict. + /// The host's environment variables. Read for the variables that would make an identity's membership snapshot forgeable, so a credential whose provenance cannot be trusted is refused rather than accepted. + /// The authenticated identity to judge. Omitted when signed out, which is the case the device channel exists to serve: it can refuse a first sign-in before any credential exists. + /// The to monitor for cancellation requests. The default is . + /// The verdict of the `forceLoginOrgs` enterprise sign-in pin for one credential. A managed device may pin Copilot to an approved set of GitHub organizations so a developer cannot sign in with a personal — or another enterprise's — account and escape every control that keys off the signed-in identity. A host must refuse to proceed when `allowed` is false; the remaining fields explain the refusal rather than qualifying it. + internal async Task ResolveDeviceForceLoginOrgsGateAsync(object? environment, object? authInfo = null, CancellationToken cancellationToken = default) + { + var request = new ManagedSettingsResolveDeviceForceLoginOrgsGateParams { Environment = CopilotClient.ToJsonElementForWire(environment) ?? JsonElement.Parse("null"), AuthInfo = CopilotClient.ToJsonElementForWire(authInfo) }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.resolveDeviceForceLoginOrgsGate", [request], cancellationToken); + } - /// User APIs. - public ServerUserApi User => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Discovers device-managed settings from production MDM and managed-file sources, validates them against the runtime-owned managed-settings schema, and returns the canonical JSON without requiring a session. `managedSettings.resolve` returns the same device settings together with the account's server policy. + /// The to monitor for cancellation requests. The default is . + /// Validated device-managed settings discovered before a session exists. + public async Task ReadAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.read", [], cancellationToken); + } - /// FeatureFlags APIs. - public ServerFeatureFlagsApi FeatureFlags => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Force-refreshes enterprise managed settings for every account: wipes the persistent server-policy cache (the whole `<cacheHome>/managed-settings` directory) and drops this runtime process's in-memory retained server policy. It does not itself fetch policy — the effect is that the next time a session resolves managed settings for an account, that resolution re-fetches the account's org policy from the network instead of serving a cached response. Note that `managedSettings.read` returns only device/MDM settings and never triggers the account server-policy fetch, so a host implementing "sync account policy" should call `managedSettings.resolve` or start a fresh session resolution rather than treat a subsequent `managedSettings.read` as the refreshed org policy. Mirrors the invalidation a sign-out performs, broadened from the one signing-out account to all of them; device/MDM layers describe the machine, not the account, and are left untouched. Rejects if the on-disk cache cannot be removed. + /// The to monitor for cancellation requests. The default is . + public async Task ClearCacheAsync(CancellationToken cancellationToken = default) + { + await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.clearCache", [], cancellationToken); + } - /// Repo APIs. - public ServerRepoApi Repo => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Resolves the effective enterprise managed settings without a session, from the device channel and, when an account is available, the account's server policy through the same per-account cache sessions use. A cached server policy less than an hour old is used without a fetch; otherwise the policy is fetched, and when the fetch fails a cached policy up to 24 hours old is used instead, unless `forceRemoteSettingsRefresh` requires a live fetch. With no account requested or signed in, it reports device policy only; signing out removes the account's cached policy. It can fetch server policy over the network when the cache is stale, so call it off latency-critical paths such as startup rather than before listing models. The policy helper is not run. `layers` lists each channel's document before merging, and `values` and `meta` carry typed effective values and their lock state for the keys typed so far. + /// Opaque account identifier returned by `account.getAllUsers`. When omitted, the current account is used, or device policy only when no account is signed in. + /// GitHub token to resolve instead of the current account. The call fails when the token cannot be resolved. + /// Embedding client identity for server policy requests, as in session creation. Omit for the CLI identity. + /// Working directory used to run an organization policy helper. When omitted, sessionless resolution does not run the helper. + /// The to monitor for cancellation requests. The default is . + /// Effective enterprise managed settings for an account, resolved without a session. + public async Task ResolveAsync(string? selectionId = null, string? gitHubToken = null, string? clientName = null, string? workingDirectory = null, CancellationToken cancellationToken = default) + { + var request = new ManagedSettingsResolveRequest { SelectionId = selectionId, GitHubToken = gitHubToken, ClientName = clientName, WorkingDirectory = workingDirectory }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.resolve", [request], cancellationToken); + } - /// GitHubRepository APIs. - public ServerGitHubRepositoryApi GitHubRepository => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Compatibility overload preserving the positional CancellationToken parameter from before workingDirectory was added. + public Task ResolveAsync(string? selectionId, string? gitHubToken, string? clientName, CancellationToken cancellationToken) + => ResolveAsync(selectionId, gitHubToken, clientName, workingDirectory: null, cancellationToken); - /// GitHubOwners APIs. - public ServerGitHubOwnersApi GitHubOwners => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Returns the managed-settings authoring JSON schema with descriptive `x-composition` annotations aligned with the shared settings-engine vocabulary. These annotations are not a complete runtime composition contract: model, effortLevel, and contextTier remain coupled. Use `managedSettings.compose` for the runtime's effective result. Performs no I/O. + /// The to monitor for cancellation requests. The default is . + /// The authoring JSON schema for managed settings recognized by this runtime. + public async Task SchemaAsync(CancellationToken cancellationToken = default) + { + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.schema", [], cancellationToken); + } - /// Git APIs. - public ServerGitApi Git => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Validates a candidate managed-settings document the way the runtime validates delivered policy, without applying it. Reports errors that would reject the document, warnings for content the runtime ignores, and the canonical document it would apply. Document text nested more than 64 levels deep is rejected. Performs no I/O. + /// The document to validate: a JSON object, or a string containing the document's JSON text. Preview documents are limited to 1 MiB and 64 levels of nesting, a stricter resource limit than delivered-policy parsing; violations are returned as diagnostics. + /// Channel the document is meant for (`device`, `server`, or `policyHelper`). Some keys are only honored in some channels; for example, a `policyHelper` registration is ignored in policy-helper output. When omitted, no channel-specific checks run. + /// The to monitor for cancellation requests. The default is . + /// Result of validating a managed-settings document. + public async Task ValidateAsync(object? content, string? layer = null, CancellationToken cancellationToken = default) + { + var request = new ManagedSettingsValidateRequest { Content = CopilotClient.ToJsonElementForWire(content) ?? JsonElement.Parse("null"), Layer = layer }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.validate", [request], cancellationToken); + } - /// ManagedSettings APIs. - public ServerManagedSettingsApi ManagedSettings => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Merges candidate managed-settings documents for the device, server, and policy-helper channels into the effective settings the runtime would enforce on this host, using the same precedence and composition rules as live resolution, without applying them. Like live resolution, a server's advisory sandbox force-enable is declined on a host that cannot run the sandbox. Does not fetch policy or read policy files, but may perform blocking OS or subprocess probes for sandbox support. Preview documents are limited to 1 MiB and 64 levels of nesting. + /// One entry per channel. `source` must be `device`, `server`, or `policyHelper`, each at most once (checked at runtime); order does not matter, because channel precedence is fixed. To preview documents from resolve output, map recognized source strings to ManagedSettingsChannel and copy their settings; generated resolve and compose layer types are distinct. Omitted settings means this channel delivered no document. Supplied documents must be valid within the preview limits; warnings are returned in diagnostics. Compose does not reproduce source-failure state or retained enforcement floors from resolve. + /// The to monitor for cancellation requests. The default is . + /// The effective managed settings the runtime would enforce for the given documents, in the same shape `managedSettings.resolve` returns. + public async Task ComposeAsync(IList layers, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(layers); - /// Runtime APIs. - public ServerRuntimeApi Runtime => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + var request = new ManagedSettingsComposeRequest { Layers = layers }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.compose", [request], cancellationToken); + } - /// SessionFs APIs. - public ServerSessionFsApi SessionFs => + /// Permissions APIs. + public ServerManagedSettingsPermissionsApi Permissions => field ?? Interlocked.CompareExchange(ref field, new(_rpc), null) ?? field; +} - /// LlmInference APIs. - public ServerLlmInferenceApi LlmInference => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; +/// Provides server-scoped ManagedSettingsPermissions APIs. +[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] +public sealed class ServerManagedSettingsPermissionsApi +{ + private readonly JsonRpc _rpc; - /// Sessions APIs. - public ServerSessionsApi Sessions => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + internal ServerManagedSettingsPermissionsApi(JsonRpc rpc) + { + _rpc = rpc; + } - /// AgentRegistry APIs. - public ServerAgentRegistryApi AgentRegistry => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + /// Pure, sessionless evaluation of operations against a supplied permissionsContext. Performs no policy discovery, I/O, prompting, navigation, permission grants, or sandbox changes. Obtain the context from managedSettings.resolve or session.managedSettings.get, or reuse an in-memory context. Results preserve input order and duplicates. Consumers must block deny, obtain approval for ask, and use their normal permission flow for unmanaged. Unknown policy returns failClosed with every operation denied. This is not a substitute for user permissions or other security controls. + /// Trusted, reusable managed permission policy snapshot; no policy is discovered during evaluation. + /// Operations to evaluate, preserving input order and duplicates. An empty batch is valid. + /// The to monitor for cancellation requests. The default is . + /// Ordered managed permission verdicts and the supplied policy's fail-closed posture. + public async Task EvaluateAsync(ManagedPermissionsContext context, IList operations, CancellationToken cancellationToken = default) + { + ArgumentNullException.ThrowIfNull(context); + ArgumentNullException.ThrowIfNull(operations); - /// Connectors APIs. - public ServerConnectorsApi Connectors => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; + var request = new ManagedSettingsPermissionsEvaluateRequest { Context = context, Operations = operations }; + return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.permissions.evaluate", [request], cancellationToken); + } } /// Provides server-scoped Environments APIs. @@ -45057,92 +48248,6 @@ public async Task GetBuiltInCatalogAsync(CancellationToken } } -/// Provides server-scoped Sandbox APIs. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerSandboxApi -{ - private readonly JsonRpc _rpc; - - internal ServerSandboxApi(JsonRpc rpc) - { - _rpc = rpc; - } - - /// Reports whether the host running this runtime can run the command sandbox, without starting a session or spawning a sandboxed command. - /// The to monitor for cancellation requests. The default is . - /// Whether the host running this runtime can run the command sandbox. The runtime checks `supported` once per process. A capability answer can change while the process runs, for example after the user installs a missing package. - public async Task GetHostSupportAsync(CancellationToken cancellationToken = default) - { - return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.getHostSupport", [], cancellationToken); - } - - /// ProxyCa APIs. - public ServerSandboxProxyCaApi ProxyCa => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; -} - -/// Provides server-scoped SandboxProxyCa APIs. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerSandboxProxyCaApi -{ - private readonly JsonRpc _rpc; - - internal ServerSandboxProxyCaApi(JsonRpc rpc) - { - _rpc = rpc; - } - - /// Reports whether the persistent certificate authority of the sandbox credential proxy exists, whether OS trust includes it, and whether it must be rotated. Changes nothing. - /// The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. - /// The to monitor for cancellation requests. The default is . - /// Status of the persistent certificate authority of the sandbox credential proxy. - public async Task GetStatusAsync(SandboxConfig? sandboxConfig = null, CancellationToken cancellationToken = default) - { - var request = new SandboxProxyCaRequest { SandboxConfig = sandboxConfig }; - return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.getStatus", [request], cancellationToken); - } - - /// Creates the persistent certificate authority of the sandbox credential proxy if none is stored, without changing OS trust, and returns the path of its public certificate. Keeps an existing certificate authority, even one that must be rotated. Fails where OS trust is unsupported. Trust it with sandbox.proxyCa.trust: the CLI trusts only the hosts in the saved user settings, so it refuses a certificate authority that also covers hosts from sandboxConfig. - /// The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. - /// The to monitor for cancellation requests. The default is . - /// Result of creating the persistent certificate authority of the sandbox credential proxy. - public async Task CreateAsync(SandboxConfig? sandboxConfig = null, CancellationToken cancellationToken = default) - { - var request = new SandboxProxyCaRequest { SandboxConfig = sandboxConfig }; - return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.create", [request], cancellationToken); - } - - /// Replaces the persistent certificate authority of the sandbox credential proxy with a new one for the current credential hosts. If OS trust included the old one, removes it and trusts the new one, which can show an OS authentication prompt. Running sandboxed tools keep the old certificate authority until they restart. - /// The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. - /// The to monitor for cancellation requests. The default is . - /// Status of the persistent certificate authority of the sandbox credential proxy. - public async Task RotateAsync(SandboxConfig? sandboxConfig = null, CancellationToken cancellationToken = default) - { - var request = new SandboxProxyCaRequest { SandboxConfig = sandboxConfig }; - return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.rotate", [request], cancellationToken); - } - - /// Adds the persistent certificate authority of the sandbox credential proxy to OS trust, so sandboxed clients that read only OS trust accept the proxy. Call create first. Refuses a certificate authority that is not constrained to the current credential hosts. Can show an OS authentication prompt. - /// The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. - /// The to monitor for cancellation requests. The default is . - /// Status of the persistent certificate authority of the sandbox credential proxy. - public async Task TrustAsync(SandboxConfig? sandboxConfig = null, CancellationToken cancellationToken = default) - { - var request = new SandboxProxyCaRequest { SandboxConfig = sandboxConfig }; - return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.trust", [request], cancellationToken); - } - - /// Removes the persistent certificate authority of the sandbox credential proxy from OS trust. Keeps the stored certificate authority. Can show an OS authentication prompt. Sandboxed clients that read only OS trust then reject the proxy; clients that read the per-process certificate bundle continue to work. - /// The to monitor for cancellation requests. The default is . - /// Status of the persistent certificate authority of the sandbox credential proxy. - public async Task RemoveAsync(CancellationToken cancellationToken = default) - { - return await CopilotClient.InvokeRpcAsync(_rpc, "sandbox.proxyCa.remove", [], cancellationToken); - } -} - /// Provides server-scoped Tools APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] public sealed class ServerToolsApi @@ -46459,286 +49564,6 @@ public async Task ListAsync(CancellationToken cancellationToken = d } } -/// Provides server-scoped User APIs. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerUserApi -{ - private readonly JsonRpc _rpc; - - internal ServerUserApi(JsonRpc rpc) - { - _rpc = rpc; - } - - /// Settings APIs. - public ServerUserSettingsApi Settings => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; -} - -/// Provides server-scoped UserSettings APIs. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerUserSettingsApi -{ - private readonly JsonRpc _rpc; - - internal ServerUserSettingsApi(JsonRpc rpc) - { - _rpc = rpc; - } - - /// Lists every known user setting from settings.json, each with its effective value, its default, and whether it is at the default — so settings the user has never set still appear with their default value. Does not include repository- or enterprise-managed overrides that the runtime layers on top at session time. - /// The to monitor for cancellation requests. The default is . - /// Per-key metadata for every known user setting in settings.json, including settings left at their default. Excludes repository- and enterprise-managed overrides. - public async Task GetAsync(CancellationToken cancellationToken = default) - { - return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.get", [], cancellationToken); - } - - /// Resolves the on-disk locations of the settings files this runtime reads, so a consumer can show or open them. The user path is the same file `user.settings.get`, `user.settings.load`, and `user.settings.set` operate on. Supply `repoRoot` to also resolve that repository's checked-in and local settings paths. A path is reported whether or not the file exists. - /// Absolute path of a repository root. Supply it to also resolve that repository's two settings file paths; omit it to resolve only the user path. - /// The to monitor for cancellation requests. The default is . - /// On-disk locations of the settings files this runtime reads. A path is reported whether or not the file exists. - internal async Task GetPathsAsync(string? repoRoot = null, CancellationToken cancellationToken = default) - { - var request = new UserSettingsGetPathsRequest { RepoRoot = repoRoot }; - return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.getPaths", [request], cancellationToken); - } - - /// Writes one or more user settings to settings.json, replacing each provided top-level key. A key whose value is null is removed. - /// Partial user settings to write, as a free-form object keyed by setting name. - /// The to monitor for cancellation requests. The default is . - public async Task SetAsync(object? settings, CancellationToken cancellationToken = default) - { - var request = new UserSettingsSetRequest { Settings = CopilotClient.ToJsonElementForWire(settings) ?? JsonElement.Parse("null") }; - await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.set", [request], cancellationToken); - } - - /// Lists the top-level user-setting keys by who is allowed to govern them: `repo` keys a repository may override through `.github/copilot/settings.json`, `claudeRepo` keys a repository may override through a Claude-compatible config, and `managed` keys an enterprise policy may fix. The lists are static for a given runtime build and fail closed: a key absent from a list cannot be governed that way. - /// The to monitor for cancellation requests. The default is . - /// Top-level user-setting keys grouped by who may govern them. - internal async Task ListGovernanceKeysAsync(CancellationToken cancellationToken = default) - { - return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.listGovernanceKeys", [], cancellationToken); - } - - /// Atomically edits one canonical user setting inside its settings-file lock. Reads, canonicalizes touched aliases, applies the edit, validates the resulting top-level setting and writes before releasing the lock. An explicit autoUpdatesChannel set completes the staff migration in the same transaction. Only a malformed existing file returns `invalid`; refused keys, invalid values and I/O errors reject the call. - /// Nonempty canonical path segments of the setting to edit, starting with its top-level key. - /// Set a scalar, add or remove a string list item, or remove the setting. The handler rejects a missing or incompatible value. - /// Configuration directory to edit. Omitted or empty resolves the server's own home, as in `user.settings.loadForConfigDir`. - /// Required boolean, string or number for set, required string for add-item and remove-item, and forbidden for remove. The runtime rejects all other JSON values. - /// The to monitor for cancellation requests. The default is . - /// Outcome of an atomic user or repository settings edit. - internal async Task EditAsync(IList canonicalPath, SettingsEditOperation operation, string? configDir = null, object? value = null, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(canonicalPath); - - var request = new UserSettingsEditRequest { CanonicalPath = canonicalPath, Operation = operation, ConfigDir = configDir, Value = CopilotClient.ToJsonElementForWire(value) }; - return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.edit", [request], cancellationToken); - } - - /// Rewrites legacy and snake_case setting names in a settings object to their canonical spelling. A caller editing settings.json must normalize before writing: a legacy key left in place survives the write, is re-normalized on the next load, and silently shadows the canonical value the write just stored. - /// Free-form settings object, possibly using legacy or snake_case key names. - /// The to monitor for cancellation requests. The default is . - /// Settings object with canonical key names. - internal async Task NormalizeAsync(object? settings, CancellationToken cancellationToken = default) - { - var request = new UserSettingsNormalizeRequest { Settings = CopilotClient.ToJsonElementForWire(settings) ?? JsonElement.Parse("null") }; - return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.normalize", [request], cancellationToken); - } - - /// Diagnoses a set of already-loaded settings layers, reporting each key that will not take effect and why. Settings load tolerantly so that one bad key does not stop a session from starting; this method surfaces what was dropped so a caller can report it instead of silently ignoring the user's intent. Takes the layers as given rather than reading them, so a caller can diagnose exactly the content it is showing, including unsaved edits. Never echoes a setting's value, because a value may be a token or another secret. Marked internal because it exists to carry a CLI call site off the native addon, not to serve a consumer-facing need; it becomes public once an SDK consumer needs to inspect settings health itself. - /// Layers to diagnose, in the precedence order the caller applies them. - /// The to monitor for cancellation requests. The default is . - /// The settings that will not take effect across the given layers. - internal async Task DiagnoseProblemsAsync(IList? sources = null, CancellationToken cancellationToken = default) - { - var request = new UserSettingsProblemsRequest { Sources = sources }; - return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.diagnoseProblems", [request], cancellationToken); - } - - /// Validates one top-level setting subtree and writes just that key to settings.json as a single step. Doing both here closes the race a caller cannot close itself: between a separate preflight read and the write, the file may change. Rewriting only the touched key keeps legacy siblings out of settings.json. Answers a status rather than failing, so a validation problem and a write problem stay distinguishable. - /// Canonical path of the setting the caller is editing. Currently informational only. - /// Top-level setting name to write. - /// Value to write for the whole top-level key. Omitted when `delete` is true. Explicit null is preserved and validated as null. - /// True to remove the top-level key instead of writing it. - /// Records that the user chose an update channel explicitly, so the one-time staff channel migration stops reapplying. Honored only for the `autoUpdatesChannel` key. - /// The to monitor for cancellation requests. The default is . - /// Outcome of validating and writing one top-level setting subtree. - internal async Task ApplyTopKeyAsync(IList canonicalPath, string topKey, object? value = null, bool? delete = null, bool? completeStaffUpdateChannelMigration = null, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(canonicalPath); - ArgumentNullException.ThrowIfNull(topKey); - - var request = new UserSettingsApplyTopKeyRequest { CanonicalPath = canonicalPath, TopKey = topKey, Value = CopilotClient.ToJsonElementForWire(value), Delete = delete, CompleteStaffUpdateChannelMigration = completeStaffUpdateChannelMigration }; - var payload = JsonSerializer.SerializeToNode(request, RpcJsonContext.Default.UserSettingsApplyTopKeyRequest)!.AsObject(); - if (request.Delete != true && request.Value is null) payload["value"] = null; - return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.applyTopKey", [payload], cancellationToken); - } - - /// Replaces the user settings file's entire content in one write. A key absent from `settings` is removed, which is what distinguishes this from `user.settings.set`: that one merges, so it can never clear a key the caller has dropped. For a caller saving the result of a raw edit, a merge would silently resurrect every key the user deleted. Records the same one-time mutation marks a per-key write records, so a setting the user has now chosen explicitly stops being migrated for them. - /// The settings object to store. It replaces the file's entire content, so a key absent here is removed. - /// The to monitor for cancellation requests. The default is . - internal async Task WriteAllAsync(object? settings, CancellationToken cancellationToken = default) - { - var request = new UserSettingsWriteAllRequest { Settings = CopilotClient.ToJsonElementForWire(settings) ?? JsonElement.Parse("null") }; - await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.writeAll", [request], cancellationToken); - } - - /// Merges a partial object into one top-level user setting, re-reading the stored value inside this runtime process's settings.json write lock so that concurrent writers in this process to different sub-fields of the same key do not clobber each other. Unlike `user.settings.set`, which replaces a key's whole value with what the caller last read, this keeps sub-fields the caller did not name when both the stored value and supplied value are objects; otherwise the supplied value replaces the stored value. Use it whenever two independent surfaces own different sub-fields of one setting. Returns the key's stored value after the write, in `value`. - /// Top-level user-setting key to merge into, such as `extensions`. - /// Value to store for `key`. When both the stored value and this value are objects, their fields are shallow-merged and fields this object does not name are preserved. Otherwise this value replaces the stored value. - /// Copilot configuration directory to write the settings document in, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to use the directory the server resolved for itself. - /// Single-component name for the settings document at `<configDir>/settings/<subDir>.json`; path separators, `.` and `..` are rejected. Omit it, or pass an empty string, to use the main settings document. - /// The to monitor for cancellation requests. The default is . - /// The stored value of the user setting after the merge. - internal async Task UpdateAsync(string key, object? value, string? configDir = null, string? subDir = null, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(key); - - var request = new UserSettingsUpdateRequest { Key = key, Value = CopilotClient.ToJsonElementForWire(value) ?? JsonElement.Parse("null"), ConfigDir = configDir, SubDir = subDir }; - return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.update", [request], cancellationToken); - } - - /// Reads settings.json as stored for a caller that is about to edit it. Unlike `user.settings.get`, this returns file values rather than per-key metadata and defaults. Reports `missing` for an absent file and `invalid` when the existing file will not parse. Retired config.json and extensionless files are not read. - /// The to monitor for cancellation requests. The default is . - /// Contents of settings.json as stored, for a caller about to rewrite it. - internal async Task LoadForEditAsync(CancellationToken cancellationToken = default) - { - return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.loadForEdit", [], cancellationToken); - } - - /// Validates one top-level setting subtree without writing it, reporting each problem with the path it applies to. Scoped to a single top-level key on purpose: validating the whole file would reject an edit whenever an unrelated pre-existing field is malformed, locking the user out of the very tool that could fix it. - /// Top-level setting name to validate. - /// Value to validate. Omitted when `delete` is true. - /// True to validate a removal of this key. The current settings file is not read. - /// The to monitor for cancellation requests. The default is . - /// Outcome of validating one top-level setting subtree. - internal async Task ValidateAsync(string topKey, object? value = null, bool? delete = null, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(topKey); - - var request = new UserSettingsValidateRequest { TopKey = topKey, Value = CopilotClient.ToJsonElementForWire(value), Delete = delete }; - return await CopilotClient.InvokeRpcAsync(_rpc, "user.settings.validate", [request], cancellationToken); - } -} - -/// Provides server-scoped FeatureFlags APIs. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerFeatureFlagsApi -{ - private readonly JsonRpc _rpc; - - internal ServerFeatureFlagsApi(JsonRpc rpc) - { - _rpc = rpc; - } - - /// Lists every feature flag this runtime declares, with the population each one is declared for, its experimental description, and the online-experiment flag it maps to. This is the static catalog: it describes how each flag is defined, not whether it is on for anyone. Use `featureFlags.resolve` for static values with caller overrides, not active runtime values or experiment assignments. - /// The to monitor for cancellation requests. The default is . - /// Every feature flag this runtime declares, with the shape each one was declared with. - internal async Task ListMetadataAsync(CancellationToken cancellationToken = default) - { - return await CopilotClient.InvokeRpcAsync(_rpc, "featureFlags.listMetadata", [], cancellationToken); - } - - /// Computes static feature flags from the supplied population and overrides without changing runtime state or verifying audience membership. Starts from declared availability, then applies direct feature-flag environment values, user settings, and explicit `flagOverrides`. It does not apply `COPILOT_EXP_*` experiment assignments, authenticated startup gates, or active runtime state. Settings include `enabledFeatureFlags`, the legacy `feature_flags.enabled` list, and supported convenience settings. Supply `baseFlags` to use an existing flag set instead of declared availability. Omit `isStaffGitHub` or `isStaffMicrosoft` when membership was never recorded: a legacy staff account then counts as both populations. - /// Whether the caller is GitHub or Microsoft staff. - /// Whether the caller is in an experimental population. - /// Whether the caller belongs to the team population used by feature availability. - /// GitHub-staff membership. Omit when it was never recorded: a legacy staff account then counts as both staff populations and keeps every staff feature. - /// Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. - /// Resolve against this already-computed flag set rather than each flag's declared availability. Keyed by flag name. - /// Environment for direct feature-flag overrides and `COPILOT_CLI_ENABLED_FEATURE_FLAGS`. Does not apply `COPILOT_EXP_*` experiment assignments. Defaults to this runtime process's own environment. - /// User settings to apply, including `enabledFeatureFlags`, legacy `feature_flags.enabled`, and supported convenience settings. - /// Flags forced to a value after every other layer, keyed by flag name. - /// The to monitor for cancellation requests. The default is . - /// The resolved feature flags, keyed by flag name. - internal async Task> ResolveAsync(bool isStaff, bool isExperimental, bool isTeam, bool? isStaffGithub = null, bool? isStaffMicrosoft = null, IDictionary? baseFlags = null, IDictionary? environment = null, object? config = null, IDictionary? flagOverrides = null, CancellationToken cancellationToken = default) - { - var request = new FeatureFlagsResolveRequest { IsStaff = isStaff, IsExperimental = isExperimental, IsTeam = isTeam, IsStaffGitHub = isStaffGithub, IsStaffMicrosoft = isStaffMicrosoft, BaseFlags = baseFlags, Environment = environment, Config = CopilotClient.ToJsonElementForWire(config), FlagOverrides = flagOverrides }; - return await CopilotClient.InvokeRpcAsync>(_rpc, "featureFlags.resolve", [request], cancellationToken); - } -} - -/// Provides server-scoped Repo APIs. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerRepoApi -{ - private readonly JsonRpc _rpc; - - internal ServerRepoApi(JsonRpc rpc) - { - _rpc = rpc; - } - - /// Settings APIs. - public ServerRepoSettingsApi Settings => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; -} - -/// Provides server-scoped RepoSettings APIs. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerRepoSettingsApi -{ - private readonly JsonRpc _rpc; - - internal ServerRepoSettingsApi(JsonRpc rpc) - { - _rpc = rpc; - } - - /// Reads one repository settings file without settings normalization or layering. The existing JSONC parser accepts comments and trailing commas and applies its prototype-safety rules. Missing or blank files return an empty valid config. Invalid files return an empty config with invalid=true; other read failures reject. - /// Absolute path of the repository root. - /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. - /// The to monitor for cancellation requests. The default is . - /// Parsed repository settings without normalization or layering. - internal async Task ReadRawAsync(string repoRoot, string scope, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(repoRoot); - ArgumentNullException.ThrowIfNull(scope); - - var request = new RepoSettingsReadRawRequest { RepoRoot = repoRoot, Scope = scope }; - return await CopilotClient.InvokeRpcAsync(_rpc, "repo.settings.readRaw", [request], cancellationToken); - } - - /// Writes or removes one allowed top-level repository setting through the existing validator and file lock. Preserves unrelated stored keys. Invalid keys, values, existing documents, and I/O errors reject without replacing the file. Deletion requires delete=true; otherwise value must be present. - /// Absolute path of the repository root. - /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. - /// Canonical top-level key permitted by the repository settings allowlist. - /// Value to validate and write. Required unless delete is true; a null value is validated, not treated as deletion. - /// True to remove the key instead of writing it. - /// The to monitor for cancellation requests. The default is . - internal async Task WriteKeyAsync(string repoRoot, string scope, string key, object? value = null, bool? delete = null, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(repoRoot); - ArgumentNullException.ThrowIfNull(scope); - ArgumentNullException.ThrowIfNull(key); - - var request = new RepoSettingsWriteKeyRequest { RepoRoot = repoRoot, Scope = scope, Key = key, Value = CopilotClient.ToJsonElementForWire(value), Delete = delete }; - var payload = JsonSerializer.SerializeToNode(request, RpcJsonContext.Default.RepoSettingsWriteKeyRequest)!.AsObject(); - if (request.Delete != true && request.Value is null) payload["value"] = null; - await CopilotClient.InvokeRpcAsync(_rpc, "repo.settings.writeKey", [payload], cancellationToken); - } - - /// Replaces the repository-overridable settings in one locked write. Allowed keys present in settings are validated and written; allowed keys absent from settings are removed. Other input keys are ignored, and unknown keys already stored in the file remain unchanged. Invalid values or an invalid existing file reject without a partial write. - /// Absolute path of the repository root. - /// Use repo for shared settings or local for settings.local.json. Other scopes are rejected. - /// Object of allowed settings to store. Missing allowlisted keys are removed. Other input keys are ignored, while unknown stored keys are preserved. - /// The to monitor for cancellation requests. The default is . - internal async Task WriteAllAsync(string repoRoot, string scope, object? settings, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(repoRoot); - ArgumentNullException.ThrowIfNull(scope); - - var request = new RepoSettingsWriteAllRequest { RepoRoot = repoRoot, Scope = scope, Settings = CopilotClient.ToJsonElementForWire(settings) ?? JsonElement.Parse("null") }; - await CopilotClient.InvokeRpcAsync(_rpc, "repo.settings.writeAll", [request], cancellationToken); - } -} - /// Provides server-scoped GitHubRepository APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] public sealed class ServerGitHubRepositoryApi @@ -46852,113 +49677,6 @@ internal async Task ReposFromRemotesAsync(string gitR } } -/// Provides server-scoped ManagedSettings APIs. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerManagedSettingsApi -{ - private readonly JsonRpc _rpc; - - internal ServerManagedSettingsApi(JsonRpc rpc) - { - _rpc = rpc; - } - - /// Discovers device-managed settings from production MDM and managed-file sources, validates them against the runtime-owned managed-settings schema, and returns the canonical JSON without requiring a session. `managedSettings.resolve` returns the same device settings together with the account's server policy. - /// The to monitor for cancellation requests. The default is . - /// Validated device-managed settings discovered before a session exists. - public async Task ReadAsync(CancellationToken cancellationToken = default) - { - return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.read", [], cancellationToken); - } - - /// Force-refreshes enterprise managed settings for every account: wipes the persistent server-policy cache (the whole `<cacheHome>/managed-settings` directory) and drops this runtime process's in-memory retained server policy. It does not itself fetch policy — the effect is that the next time a session resolves managed settings for an account, that resolution re-fetches the account's org policy from the network instead of serving a cached response. Note that `managedSettings.read` returns only device/MDM settings and never triggers the account server-policy fetch, so a host implementing "sync account policy" should call `managedSettings.resolve` or start a fresh session resolution rather than treat a subsequent `managedSettings.read` as the refreshed org policy. Mirrors the invalidation a sign-out performs, broadened from the one signing-out account to all of them; device/MDM layers describe the machine, not the account, and are left untouched. Rejects if the on-disk cache cannot be removed. - /// The to monitor for cancellation requests. The default is . - public async Task ClearCacheAsync(CancellationToken cancellationToken = default) - { - await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.clearCache", [], cancellationToken); - } - - /// Resolves the effective enterprise managed settings without a session, from the device channel and, when an account is available, the account's server policy through the same per-account cache sessions use. A cached server policy less than an hour old is used without a fetch; otherwise the policy is fetched, and when the fetch fails a cached policy up to 24 hours old is used instead, unless `forceRemoteSettingsRefresh` requires a live fetch. With no account requested or signed in, it reports device policy only; signing out removes the account's cached policy. It can fetch server policy over the network when the cache is stale, so call it off latency-critical paths such as startup rather than before listing models. The policy helper is not run. `layers` lists each channel's document before merging, and `values` and `meta` carry typed effective values and their lock state for the keys typed so far. - /// Opaque account identifier returned by `account.getAllUsers`. When omitted, the current account is used, or device policy only when no account is signed in. - /// GitHub token to resolve instead of the current account. The call fails when the token cannot be resolved. - /// Embedding client identity for server policy requests, as in session creation. Omit for the CLI identity. - /// Working directory used to run an organization policy helper. When omitted, sessionless resolution does not run the helper. - /// The to monitor for cancellation requests. The default is . - /// Effective enterprise managed settings for an account, resolved without a session. - public async Task ResolveAsync(string? selectionId = null, string? gitHubToken = null, string? clientName = null, string? workingDirectory = null, CancellationToken cancellationToken = default) - { - var request = new ManagedSettingsResolveRequest { SelectionId = selectionId, GitHubToken = gitHubToken, ClientName = clientName, WorkingDirectory = workingDirectory }; - return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.resolve", [request], cancellationToken); - } - - /// Compatibility overload preserving the positional CancellationToken parameter from before workingDirectory was added. - public Task ResolveAsync(string? selectionId, string? gitHubToken, string? clientName, CancellationToken cancellationToken) - => ResolveAsync(selectionId, gitHubToken, clientName, workingDirectory: null, cancellationToken); - - /// Returns the managed-settings authoring JSON schema with descriptive `x-composition` annotations aligned with the shared settings-engine vocabulary. These annotations are not a complete runtime composition contract: model, effortLevel, and contextTier remain coupled. Use `managedSettings.compose` for the runtime's effective result. Performs no I/O. - /// The to monitor for cancellation requests. The default is . - /// The authoring JSON schema for managed settings recognized by this runtime. - public async Task SchemaAsync(CancellationToken cancellationToken = default) - { - return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.schema", [], cancellationToken); - } - - /// Validates a candidate managed-settings document the way the runtime validates delivered policy, without applying it. Reports errors that would reject the document, warnings for content the runtime ignores, and the canonical document it would apply. Document text nested more than 64 levels deep is rejected. Performs no I/O. - /// The document to validate: a JSON object, or a string containing the document's JSON text. Preview documents are limited to 1 MiB and 64 levels of nesting, a stricter resource limit than delivered-policy parsing; violations are returned as diagnostics. - /// Channel the document is meant for (`device`, `server`, or `policyHelper`). Some keys are only honored in some channels; for example, a `policyHelper` registration is ignored in policy-helper output. When omitted, no channel-specific checks run. - /// The to monitor for cancellation requests. The default is . - /// Result of validating a managed-settings document. - public async Task ValidateAsync(object? content, string? layer = null, CancellationToken cancellationToken = default) - { - var request = new ManagedSettingsValidateRequest { Content = CopilotClient.ToJsonElementForWire(content) ?? JsonElement.Parse("null"), Layer = layer }; - return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.validate", [request], cancellationToken); - } - - /// Merges candidate managed-settings documents for the device, server, and policy-helper channels into the effective settings the runtime would enforce on this host, using the same precedence and composition rules as live resolution, without applying them. Like live resolution, a server's advisory sandbox force-enable is declined on a host that cannot run the sandbox. Does not fetch policy or read policy files, but may perform blocking OS or subprocess probes for sandbox support. Preview documents are limited to 1 MiB and 64 levels of nesting. - /// One entry per channel. `source` must be `device`, `server`, or `policyHelper`, each at most once (checked at runtime); order does not matter, because channel precedence is fixed. To preview documents from resolve output, map recognized source strings to ManagedSettingsChannel and copy their settings; generated resolve and compose layer types are distinct. Omitted settings means this channel delivered no document. Supplied documents must be valid within the preview limits; warnings are returned in diagnostics. Compose does not reproduce source-failure state or retained enforcement floors from resolve. - /// The to monitor for cancellation requests. The default is . - /// The effective managed settings the runtime would enforce for the given documents, in the same shape `managedSettings.resolve` returns. - public async Task ComposeAsync(IList layers, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(layers); - - var request = new ManagedSettingsComposeRequest { Layers = layers }; - return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.compose", [request], cancellationToken); - } - - /// Permissions APIs. - public ServerManagedSettingsPermissionsApi Permissions => - field ?? - Interlocked.CompareExchange(ref field, new(_rpc), null) ?? - field; -} - -/// Provides server-scoped ManagedSettingsPermissions APIs. -[Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] -public sealed class ServerManagedSettingsPermissionsApi -{ - private readonly JsonRpc _rpc; - - internal ServerManagedSettingsPermissionsApi(JsonRpc rpc) - { - _rpc = rpc; - } - - /// Pure, sessionless evaluation of operations against a supplied permissionsContext. Performs no policy discovery, I/O, prompting, navigation, permission grants, or sandbox changes. Obtain the context from managedSettings.resolve or session.managedSettings.get, or reuse an in-memory context. Results preserve input order and duplicates. Consumers must block deny, obtain approval for ask, and use their normal permission flow for unmanaged. Unknown policy returns failClosed with every operation denied. This is not a substitute for user permissions or other security controls. - /// Trusted, reusable managed permission policy snapshot; no policy is discovered during evaluation. - /// Operations to evaluate, preserving input order and duplicates. An empty batch is valid. - /// The to monitor for cancellation requests. The default is . - /// Ordered managed permission verdicts and the supplied policy's fail-closed posture. - public async Task EvaluateAsync(ManagedPermissionsContext context, IList operations, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(context); - ArgumentNullException.ThrowIfNull(operations); - - var request = new ManagedSettingsPermissionsEvaluateRequest { Context = context, Operations = operations }; - return await CopilotClient.InvokeRpcAsync(_rpc, "managedSettings.permissions.evaluate", [request], cancellationToken); - } -} - /// Provides server-scoped Runtime APIs. [Experimental(global::GitHub.Copilot.Diagnostics.Experimental)] public sealed class ServerRuntimeApi @@ -50086,14 +52804,13 @@ internal async Task ReloadWithConfigAsync(CancellationTok /// Raw MCP CreateMessageRequest params, as received in the `sampling.requested` event. Treated as opaque at the schema layer; the runtime converts the embedded MCP messages into the OpenAI chat-completion shape internally. /// The to monitor for cancellation requests. The default is . /// Outcome of an MCP sampling execution: success result, failure error, or cancellation. - public async Task ExecuteSamplingAsync(string requestId, string serverName, object? mcpRequestId, McpExecuteSamplingRequest request, CancellationToken cancellationToken = default) + public async Task ExecuteSamplingAsync(string requestId, string serverName, object? mcpRequestId, object? request, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(requestId); ArgumentNullException.ThrowIfNull(serverName); - ArgumentNullException.ThrowIfNull(request); _session.ThrowIfDisposed(); - var rpcRequest = new McpExecuteSamplingParams { SessionId = _session.SessionId, RequestId = requestId, ServerName = serverName, McpRequestId = CopilotClient.ToJsonElementForWire(mcpRequestId) ?? JsonElement.Parse("null"), Request = request }; + var rpcRequest = new McpExecuteSamplingParams { SessionId = _session.SessionId, RequestId = requestId, ServerName = serverName, McpRequestId = CopilotClient.ToJsonElementForWire(mcpRequestId) ?? JsonElement.Parse("null"), Request = CopilotClient.ToJsonElementForWire(request) ?? JsonElement.Parse("null") }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.mcp.executeSampling", [rpcRequest], cancellationToken); } @@ -51532,7 +54249,7 @@ public async Task InvokeAsync(string name, string? /// Whether the host applied or cancelled the pending invocation effect. /// The to monitor for cancellation requests. The default is . /// Whether finalizing the invocation effect succeeded, and the failure reason when it did not. - internal async Task FinalizeInvocationEffectAsync(CommandsFinalizeInvocationEffectRequestEffect effect, CommandsInvocationEffectOutcome outcome, CancellationToken cancellationToken = default) + internal async Task FinalizeInvocationEffectAsync(IDictionary effect, CommandsInvocationEffectOutcome outcome, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(effect); _session.ThrowIfDisposed(); @@ -51742,12 +54459,12 @@ internal async Task HandleHumanUserInputAsync(string requ /// Optional sampling result payload. Omit to reject/cancel the sampling request without providing a result. /// The to monitor for cancellation requests. The default is . /// Indicates whether the pending UI request was resolved by this call. - public async Task HandlePendingSamplingAsync(string requestId, UIHandlePendingSamplingResponse? response = null, CancellationToken cancellationToken = default) + public async Task HandlePendingSamplingAsync(string requestId, object? response = null, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(requestId); _session.ThrowIfDisposed(); - var request = new UIHandlePendingSamplingRequest { SessionId = _session.SessionId, RequestId = requestId, Response = response }; + var request = new UIHandlePendingSamplingRequest { SessionId = _session.SessionId, RequestId = requestId, Response = CopilotClient.ToJsonElementForWire(response) }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.ui.handlePendingSampling", [request], cancellationToken); } @@ -54319,7 +57036,6 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(ClientTaskCancelResult))] [JsonSerializable(typeof(CommandList))] [JsonSerializable(typeof(CommandsFinalizeInvocationEffectRequest))] -[JsonSerializable(typeof(CommandsFinalizeInvocationEffectRequestEffect))] [JsonSerializable(typeof(CommandsFinalizeInvocationEffectResult))] [JsonSerializable(typeof(CommandsHandlePendingCommandRequest))] [JsonSerializable(typeof(CommandsHandlePendingCommandResult))] @@ -54424,11 +57140,14 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(FeatureFlagMetadata))] [JsonSerializable(typeof(FeatureFlagsMetadataResult))] [JsonSerializable(typeof(FeatureFlagsResolveRequest))] +[JsonSerializable(typeof(FeatureFlagsResolveStartupGatesRequest))] [JsonSerializable(typeof(FleetStartRequest))] [JsonSerializable(typeof(FleetStartResult))] [JsonSerializable(typeof(FolderTrustAddParams))] [JsonSerializable(typeof(FolderTrustCheckParams))] [JsonSerializable(typeof(FolderTrustCheckResult))] +[JsonSerializable(typeof(FolderTrustIsTrustedParams))] +[JsonSerializable(typeof(ForceLoginOrgsDecision))] [JsonSerializable(typeof(GitCurrentBranchRemoteResult))] [JsonSerializable(typeof(GitCwdRequest))] [JsonSerializable(typeof(GitHubEnvironment))] @@ -54530,6 +57249,7 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(LlmInferenceHttpResponseStartResult))] [JsonSerializable(typeof(LlmInferenceSetProviderResult))] [JsonSerializable(typeof(LocalSessionMetadataValue))] +[JsonSerializable(typeof(LocationPermissionsCleanupResult))] [JsonSerializable(typeof(LogRequest))] [JsonSerializable(typeof(LogResult))] [JsonSerializable(typeof(LoggedInUser))] @@ -54538,18 +57258,36 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(ManagedPermissionOperation))] [JsonSerializable(typeof(ManagedPluginRetryEntry))] [JsonSerializable(typeof(ManagedSettingMeta))] +[JsonSerializable(typeof(ManagedSettingsApplyControlsParams))] +[JsonSerializable(typeof(ManagedSettingsApplyControlsResult))] [JsonSerializable(typeof(ManagedSettingsComposeLayer))] [JsonSerializable(typeof(ManagedSettingsComposeRequest))] [JsonSerializable(typeof(ManagedSettingsComposeResult))] [JsonSerializable(typeof(ManagedSettingsDiagnostic))] +[JsonSerializable(typeof(ManagedSettingsIngestParams))] +[JsonSerializable(typeof(ManagedSettingsIngestResult))] [JsonSerializable(typeof(ManagedSettingsLayer))] +[JsonSerializable(typeof(ManagedSettingsLoadRemoteControlParams))] +[JsonSerializable(typeof(ManagedSettingsLoadRemoteControlResult))] +[JsonSerializable(typeof(ManagedSettingsLogMessage))] [JsonSerializable(typeof(ManagedSettingsMeta))] +[JsonSerializable(typeof(ManagedSettingsParseClientValueParams))] +[JsonSerializable(typeof(ManagedSettingsParseClientValueResult))] [JsonSerializable(typeof(ManagedSettingsPermissionsEvaluateRequest))] [JsonSerializable(typeof(ManagedSettingsPermissionsEvaluateResult))] +[JsonSerializable(typeof(ManagedSettingsReadDeviceResult))] [JsonSerializable(typeof(ManagedSettingsReadResult))] +[JsonSerializable(typeof(ManagedSettingsResolveBypassDisableTransitionParams))] +[JsonSerializable(typeof(ManagedSettingsResolveBypassDisableTransitionResult))] +[JsonSerializable(typeof(ManagedSettingsResolveDeviceForceLoginOrgsGateParams))] +[JsonSerializable(typeof(ManagedSettingsResolveEffectiveValueParams))] +[JsonSerializable(typeof(ManagedSettingsResolveEffectiveValueResult))] [JsonSerializable(typeof(ManagedSettingsResolveRequest))] [JsonSerializable(typeof(ManagedSettingsResolveResult))] +[JsonSerializable(typeof(ManagedSettingsResolveStartupPolicyParams))] +[JsonSerializable(typeof(ManagedSettingsResolveStartupPolicyResult))] [JsonSerializable(typeof(ManagedSettingsResolvedData))] +[JsonSerializable(typeof(ManagedSettingsRetainPolicyParams))] [JsonSerializable(typeof(ManagedSettingsSchemaResult))] [JsonSerializable(typeof(ManagedSettingsValidateRequest))] [JsonSerializable(typeof(ManagedSettingsValidateResult))] @@ -54601,8 +57339,6 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(McpEnableRequest))] [JsonSerializable(typeof(McpEnableRequestWithSession))] [JsonSerializable(typeof(McpExecuteSamplingParams))] -[JsonSerializable(typeof(McpExecuteSamplingRequest))] -[JsonSerializable(typeof(McpExecuteSamplingResult))] [JsonSerializable(typeof(McpFailedServer))] [JsonSerializable(typeof(McpFilteredServer))] [JsonSerializable(typeof(McpHeadersHandlePendingHeadersRefreshRequest))] @@ -54750,7 +57486,6 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(ModelMessage))] [JsonSerializable(typeof(ModelPickerPersistenceRequest))] [JsonSerializable(typeof(ModelPickerSettingsContext))] -[JsonSerializable(typeof(ModelPickerSettingsContextEnvironment))] [JsonSerializable(typeof(ModelPolicy))] [JsonSerializable(typeof(ModelProviderAdapterCatalog))] [JsonSerializable(typeof(ModelProviderAdapterDescriptor))] @@ -54824,6 +57559,8 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(PermissionsConfigureAdditionalContentExclusionPolicyRuleSource))] [JsonSerializable(typeof(PermissionsConfigureParams))] [JsonSerializable(typeof(PermissionsConfigureResult))] +[JsonSerializable(typeof(PermissionsEvaluateManagedPolicyParams))] +[JsonSerializable(typeof(PermissionsEvaluateManagedPolicyResult))] [JsonSerializable(typeof(PermissionsFolderTrustAddTrustedResult))] [JsonSerializable(typeof(PermissionsGetModeRequest))] [JsonSerializable(typeof(PermissionsGetModeResult))] @@ -54845,6 +57582,8 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(PermissionsSetRequiredRequest))] [JsonSerializable(typeof(PermissionsSetRequiredResult))] [JsonSerializable(typeof(PermissionsUrlsSetUnrestrictedModeResult))] +[JsonSerializable(typeof(PersistenceWriteRawJsonLockedRequest))] +[JsonSerializable(typeof(PersistenceWriteRawJsonLockedResult))] [JsonSerializable(typeof(PingRequest))] [JsonSerializable(typeof(PingResult))] [JsonSerializable(typeof(PlanReadResult))] @@ -54952,11 +57691,13 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(RemoteSessionConnectionResult))] [JsonSerializable(typeof(RemoteSessionMetadataRepository))] [JsonSerializable(typeof(RemoteSessionMetadataValue))] +[JsonSerializable(typeof(RepoSettingsEditRequest))] [JsonSerializable(typeof(RepoSettingsReadRawRequest))] [JsonSerializable(typeof(RepoSettingsReadRawResult))] [JsonSerializable(typeof(RepoSettingsWriteAllRequest))] [JsonSerializable(typeof(RepoSettingsWriteKeyRequest))] [JsonSerializable(typeof(ResponseFormat))] +[JsonSerializable(typeof(SandboxApplyDefaultsRequest))] [JsonSerializable(typeof(SandboxConfig))] [JsonSerializable(typeof(SandboxConfigAuth))] [JsonSerializable(typeof(SandboxConfigUserPolicy))] @@ -54971,15 +57712,32 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(SandboxCredentialsConfig))] [JsonSerializable(typeof(SandboxDisableForSessionRequest))] [JsonSerializable(typeof(SandboxDisableForSessionResult))] +[JsonSerializable(typeof(SandboxDocsUrlResult))] +[JsonSerializable(typeof(SandboxEffectiveForOptionalParams))] +[JsonSerializable(typeof(SandboxEffectiveForOptionalResult))] +[JsonSerializable(typeof(SandboxEnforcementCommandAllowedParams))] [JsonSerializable(typeof(SandboxEnforcementStatus))] +[JsonSerializable(typeof(SandboxFilterPickerCandidatesParams))] +[JsonSerializable(typeof(SandboxFilterPickerCandidatesResult))] [JsonSerializable(typeof(SandboxGrantPathForRequestRequest))] [JsonSerializable(typeof(SandboxGrantPathForRequestResult))] [JsonSerializable(typeof(SandboxHostCapability))] [JsonSerializable(typeof(SandboxHostSupport))] [JsonSerializable(typeof(SandboxMaskedEnvVar))] +[JsonSerializable(typeof(SandboxPickerCandidate))] +[JsonSerializable(typeof(SandboxPreparePickerPolicyParams))] +[JsonSerializable(typeof(SandboxPreparePickerPolicyResult))] [JsonSerializable(typeof(SandboxProxyCaCreateResult))] [JsonSerializable(typeof(SandboxProxyCaRequest))] [JsonSerializable(typeof(SandboxProxyCaStatus))] +[JsonSerializable(typeof(SandboxProxySecretGetResult))] +[JsonSerializable(typeof(SandboxProxySecretLocation))] +[JsonSerializable(typeof(SandboxProxySecretSaveRequest))] +[JsonSerializable(typeof(SandboxProxySecretSaveResult))] +[JsonSerializable(typeof(SandboxResolveFlooredConfigParams))] +[JsonSerializable(typeof(SandboxResolveFlooredConfigResult))] +[JsonSerializable(typeof(SandboxUnsupportedStartupNoticeParams))] +[JsonSerializable(typeof(SandboxUnsupportedStartupNoticeResult))] [JsonSerializable(typeof(ScheduleAddAtRequest))] [JsonSerializable(typeof(ScheduleAddCronRequest))] [JsonSerializable(typeof(ScheduleAddRequest))] @@ -55300,7 +58058,6 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(SlashCommandInput))] [JsonSerializable(typeof(SlashCommandInputChoice))] [JsonSerializable(typeof(SlashCommandInvocationResult))] -[JsonSerializable(typeof(SlashCommandInvocationResultSetModelRevertOnCancel))] [JsonSerializable(typeof(SlashCommandModelPickerDialog))] [JsonSerializable(typeof(SlashCommandSelectSubcommandOption))] [JsonSerializable(typeof(SlashCommandTimelineEntry))] @@ -55364,7 +58121,6 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(UIHandlePendingExitPlanModeRequest))] [JsonSerializable(typeof(UIHandlePendingResult))] [JsonSerializable(typeof(UIHandlePendingSamplingRequest))] -[JsonSerializable(typeof(UIHandlePendingSamplingResponse))] [JsonSerializable(typeof(UIHandlePendingSessionLimitsExhaustedRequest))] [JsonSerializable(typeof(UIHandlePendingUserInputRequest))] [JsonSerializable(typeof(UIRegisterDirectAutoModeSwitchHandlerResult))] @@ -55378,20 +58134,44 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(UserSettingMetadata))] [JsonSerializable(typeof(UserSettingsApplyTopKeyRequest))] [JsonSerializable(typeof(UserSettingsApplyTopKeyResult))] +[JsonSerializable(typeof(UserSettingsBuildRuntimeRequest))] [JsonSerializable(typeof(UserSettingsEditRequest))] [JsonSerializable(typeof(UserSettingsGetPathsRequest))] [JsonSerializable(typeof(UserSettingsGetPathsResult))] [JsonSerializable(typeof(UserSettingsGetResult))] [JsonSerializable(typeof(UserSettingsGovernanceKeysResult))] +[JsonSerializable(typeof(UserSettingsHostContext))] +[JsonSerializable(typeof(UserSettingsLoadAndMergeRepoRequest))] +[JsonSerializable(typeof(UserSettingsLoadAndMergeRepoResult))] +[JsonSerializable(typeof(UserSettingsLoadForConfigDirRequest))] [JsonSerializable(typeof(UserSettingsLoadForEditResult))] +[JsonSerializable(typeof(UserSettingsLoadRepoRequest))] +[JsonSerializable(typeof(UserSettingsLoadRepoResult))] +[JsonSerializable(typeof(UserSettingsLoadWithWarningResult))] +[JsonSerializable(typeof(UserSettingsMergeManagedAndUserParams))] +[JsonSerializable(typeof(UserSettingsMergeManagedAndUserResult))] +[JsonSerializable(typeof(UserSettingsMergeRepoValueParams))] +[JsonSerializable(typeof(UserSettingsMergeRepoValueResult))] +[JsonSerializable(typeof(UserSettingsMigrateObsoleteOnDiskRequest))] +[JsonSerializable(typeof(UserSettingsMigrateObsoleteOnDiskResult))] +[JsonSerializable(typeof(UserSettingsMigrateStaffLogLevelOnceRequest))] +[JsonSerializable(typeof(UserSettingsMigrateStaffLogLevelOnceResult))] +[JsonSerializable(typeof(UserSettingsMigrateStaffUpdateChannelOnceResult))] [JsonSerializable(typeof(UserSettingsNormalizeRequest))] [JsonSerializable(typeof(UserSettingsNormalizeResult))] +[JsonSerializable(typeof(UserSettingsPathResult))] [JsonSerializable(typeof(UserSettingsProblem))] [JsonSerializable(typeof(UserSettingsProblemLocation))] [JsonSerializable(typeof(UserSettingsProblemSource))] [JsonSerializable(typeof(UserSettingsProblemsRequest))] [JsonSerializable(typeof(UserSettingsProblemsResult))] +[JsonSerializable(typeof(UserSettingsResetStaffModelSelectionOnceRequest))] +[JsonSerializable(typeof(UserSettingsResetStaffModelSelectionOnceResult))] +[JsonSerializable(typeof(UserSettingsSetHookDisabledRequest))] +[JsonSerializable(typeof(UserSettingsSetHookDisabledResult))] [JsonSerializable(typeof(UserSettingsSetRequest))] +[JsonSerializable(typeof(UserSettingsUnknownKeysWarningRequest))] +[JsonSerializable(typeof(UserSettingsUnknownKeysWarningResult))] [JsonSerializable(typeof(UserSettingsUpdateRequest))] [JsonSerializable(typeof(UserSettingsUpdateResult))] [JsonSerializable(typeof(UserSettingsValidateRequest))] @@ -55446,8 +58226,6 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH [JsonSerializable(typeof(WorkspaceDiffResult))] [JsonSerializable(typeof(WorkspacesAddSummaryRequest))] [JsonSerializable(typeof(WorkspacesAddSummaryResult))] -[JsonSerializable(typeof(WorkspacesAddSummaryResultSummary))] -[JsonSerializable(typeof(WorkspacesAddSummaryResultWorkspace))] [JsonSerializable(typeof(WorkspacesAutopilotObjectiveExistsResult))] [JsonSerializable(typeof(WorkspacesCheckpoints))] [JsonSerializable(typeof(WorkspacesCreateDirectoryRequest))] diff --git a/go/rpc/zrpc.go b/go/rpc/zrpc.go index fb0ba50714..cc7b86d136 100644 --- a/go/rpc/zrpc.go +++ b/go/rpc/zrpc.go @@ -5122,6 +5122,50 @@ type FeatureFlagsResolveRequest struct { // be removed. type FeatureFlagsResolveResult map[string]bool +// Caller population and startup inputs to resolve named online-experiment gates for. +// Carries no account: the runtime resolves the assignment for the authentication it already +// holds. +// Experimental: FeatureFlagsResolveStartupGatesRequest is part of an experimental API and +// may change or be removed. +// Internal: FeatureFlagsResolveStartupGatesRequest is an internal SDK API and is not part +// of the public surface. +type FeatureFlagsResolveStartupGatesRequest struct { + // User settings document whose `featureFlags` block is layered on top of the resolved set. + Config any `json:"config,omitempty"` + // Environment to read flag overrides from. Defaults to this runtime process's own + // environment. + Environment map[string]string `json:"environment,omitzero"` + // When this installation first launched, in milliseconds since the Unix epoch. Experiments + // that segment on installation age read it. Omit when the first launch was never recorded. + FirstLaunchAtMillis *float64 `json:"firstLaunchAtMillis,omitempty"` + // The feature flags to resolve. A name this runtime does not declare is reported as an + // error rather than as a disabled flag. + Flags []string `json:"flags"` + // Whether the caller is in an experimental population. + IsExperimental bool `json:"isExperimental"` + // Whether the caller is GitHub or Microsoft staff. + IsStaff bool `json:"isStaff"` + // GitHub-staff membership. Omit when it was never recorded: a legacy staff account then + // counts as both staff populations and keeps every staff feature. + IsStaffGitHub *bool `json:"isStaffGithub,omitempty"` + // Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. + IsStaffMicrosoft *bool `json:"isStaffMicrosoft,omitempty"` + // Whether the caller belongs to a team plan. + IsTeam bool `json:"isTeam"` + // Whether the runtime may refresh the cached assignment over the network without an active + // session. The refresh never blocks this call: the answer comes from the cache either way, + // so a refresh only affects a later launch. + RefreshWithoutSession bool `json:"refreshWithoutSession"` + // Whether streamer mode is on, which withholds the populations an experiment would + // otherwise segment on. + StreamerMode bool `json:"streamerMode"` +} + +// The resolved gates, keyed by flag name. +// Experimental: FeatureFlagsResolveStartupGatesResult is part of an experimental API and +// may change or be removed. +type FeatureFlagsResolveStartupGatesResult map[string]bool + // Content filtering mode to apply to all tools, or a map of tool name to content filtering // mode. // Experimental: FilterMapping is part of an experimental API and may change or be removed. @@ -5187,6 +5231,59 @@ type FolderTrustCheckResult struct { Trusted bool `json:"trusted"` } +// A folder to check against a persisted trusted-folders list, and the configuration +// directory holding that list. +// Experimental: FolderTrustIsTrustedParams is part of an experimental API and may change or +// be removed. +// Internal: FolderTrustIsTrustedParams is an internal SDK API and is not part of the public +// surface. +type FolderTrustIsTrustedParams struct { + // Configuration directory to read the trusted-folders list from. Omit it to read the + // default location; supply it when the host has redirected its configuration, or the check + // answers from a list the host is not using. + ConfigDir *string `json:"configDir,omitempty"` + // Folder to check. A folder counts as trusted when it is itself listed, when an ancestor is + // listed, or when its git root is listed. + Path string `json:"path"` +} + +// The verdict of the `forceLoginOrgs` enterprise sign-in pin for one credential. A managed +// device may pin Copilot to an approved set of GitHub organizations so a developer cannot +// sign in with a personal — or another enterprise's — account and escape every control that +// keys off the signed-in identity. A host must refuse to proceed when `allowed` is false; +// the remaining fields explain the refusal rather than qualifying it. +// Experimental: ForceLoginOrgsDecision is part of an experimental API and may change or be +// removed. +// Internal: ForceLoginOrgsDecision is an internal SDK API and is not part of the public +// surface. +type ForceLoginOrgsDecision struct { + // Whether the client may proceed. True whenever no pin is in force, so an unmanaged host is + // never blocked. + Allowed bool `json:"allowed"` + // A stable kebab-case reason code when refused: `org-not-approved`, + // `unverifiable-credential`, `policy-undetermined`, `policy-invalid`, `not-signed-in`, or + // `membership-unknown`. Omitted when allowed. Treat an unrecognized code as a refusal + // rather than mapping it to an allow: a code this host has not been taught about still + // denied the credential. + Denial *string `json:"denial,omitempty"` + // Whether a pin applies at all. Distinguishes "allowed because unmanaged" from "allowed + // because the account is approved", which a diagnostics surface needs and which also + // decides whether a bring-your-own-key provider may serve inference. + Enforced bool `json:"enforced"` + // The approved organization the account matched, when allowed under a pin. + MatchedOrg *string `json:"matchedOrg,omitempty"` + // A developer-facing explanation of the refusal. Omitted when allowed. + Message *string `json:"message,omitempty"` + // Error-level detail from managed-policy discovery — which file failed to load, which field + // failed validation. Carried on the decision rather than left to the log because a refusal + // can exit the process before a log sink exists, which would discard the only actionable + // diagnostic a misconfigured managed device produces. + PolicyDiagnostics []string `json:"policyDiagnostics"` + // The approved organization logins, as configured. Enterprise configuration rather than + // user data, so it is safe to name in a message or a log line. + RequiredOrgs []string `json:"requiredOrgs"` +} + // The remote the checked-out branch tracks. // Experimental: GitCurrentBranchRemoteResult is part of an experimental API and may change // or be removed. @@ -6940,6 +7037,16 @@ type LocalSessionMetadataValue struct { Summary *string `json:"summary,omitempty"` } +// Which stored location permissions were dropped because their directory is gone. +// Experimental: LocationPermissionsCleanupResult is part of an experimental API and may +// change or be removed. +// Internal: LocationPermissionsCleanupResult is an internal SDK API and is not part of the +// public surface. +type LocationPermissionsCleanupResult struct { + // Location keys whose grants were removed. Empty when every stored location still exists. + RemovedLocationKeys []string `json:"removedLocationKeys"` +} + // An account the host has signed in to, identified by the server it lives on and the login // it uses there. The same person can appear more than once when they use both github.com // and an Enterprise server. @@ -7095,6 +7202,31 @@ type ManagedSettingMeta struct { Source string `json:"source"` } +// A user settings document and the effective managed policy whose controlled entries should +// be stamped onto it. +// Experimental: ManagedSettingsApplyControlsParams is part of an experimental API and may +// change or be removed. +// Internal: ManagedSettingsApplyControlsParams is an internal SDK API and is not part of +// the public surface. +type ManagedSettingsApplyControlsParams struct { + // The effective managed policy, as composed by `managedSettings.resolveEffectiveValue`. + // Omit it on an unmanaged host: the settings then come back unchanged. + Managed any `json:"managed,omitempty"` + // The user settings document to stamp. Entries the managed layer does not name are returned + // exactly as supplied. + Settings any `json:"settings"` +} + +// The user settings with the managed layer's controlled entries stamped on. +// Experimental: ManagedSettingsApplyControlsResult is part of an experimental API and may +// change or be removed. +// Internal: ManagedSettingsApplyControlsResult is an internal SDK API and is not part of +// the public surface. +type ManagedSettingsApplyControlsResult struct { + // The resulting settings document. + SettingsJSON any `json:"settingsJson"` +} + // Experimental: ManagedSettingsClearCacheResult is part of an experimental API and may // change or be removed. type ManagedSettingsClearCacheResult struct { @@ -7157,6 +7289,151 @@ type ManagedSettingsDiagnostic struct { Severity ManagedSettingsDiagnosticSeverity `json:"severity"` } +// Inputs describing the host and account an ingestion should resolve managed policy for. +// Experimental: ManagedSettingsIngestParams is part of an experimental API and may change +// or be removed. +// Internal: ManagedSettingsIngestParams is an internal SDK API and is not part of the +// public surface. +type ManagedSettingsIngestParams struct { + // The authenticated identity to resolve policy for. Omitted before sign-in, in which case + // no server layer is fetched. + AuthInfo any `json:"authInfo,omitempty"` + // Whether to ignore a cached server policy when reading, forcing the resolution to come + // from a live fetch. + BypassCacheRead *bool `json:"bypassCacheRead,omitempty"` + // Name of the embedding client, reported to the managed-settings service as `client_id` so + // it can refuse to deliver a policy this client is too old to enforce. Omit it and the + // runtime reports a generic identity; the runtime version sent alongside is the gate that + // actually matters. + ClientName *string `json:"clientName,omitempty"` + // A device layer supplied by the host instead of discovered from the machine. Pair it with + // `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + DeviceResponse any `json:"deviceResponse,omitempty"` + // The host's environment variables, read for cache location and policy overrides. Supplied + // by the host rather than read from the runtime process so a command that selected its own + // configuration home is honored. + Environment any `json:"environment"` + // Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts + // the device layer is empty; false discovers it from the machine. + HasDeviceResponse *bool `json:"hasDeviceResponse,omitempty"` + // The host's home directory, used to resolve cache and managed-file locations. + HomeDirectory string `json:"homeDirectory"` + // The host's platform, in Node's `process.platform` spelling, used to locate + // platform-specific cache and policy paths. + Platform string `json:"platform"` + // Whether a configured platform policy helper may be run to produce an enforced helper + // layer. + PolicyHelperEnabled *bool `json:"policyHelperEnabled,omitempty"` + // The policy-helper invocation reason. Defaults to sessionStart. + // Internal: PolicyHelperReason is part of the SDK's internal API surface and is not + // intended for external use. + PolicyHelperReason *ManagedSettingsPolicyHelperReason `json:"policyHelperReason,omitempty"` + // Directory the policy helper runs in when this ingestion is not owned by a registered + // session. A host resolving policy before its session exists must pass this, or a + // directory-sensitive helper judges the wrong repository. + PolicyHelperWorkingDirectory *string `json:"policyHelperWorkingDirectory,omitempty"` + // Whether to run ingestion. Omit or set false to return an empty result without discovering + // or fetching policy. + SelfFetch *bool `json:"selfFetch,omitempty"` + // How this ingestion may use the on-disk server-policy cache. Defaults to the runtime's own + // policy when omitted. + // Internal: ServerPolicyCacheMode is part of the SDK's internal API surface and is not + // intended for external use. + ServerPolicyCacheMode *ManagedSettingsServerPolicyCacheMode `json:"serverPolicyCacheMode,omitempty"` + // The session whose credential store and working directory the policy helper should use. + // Omit it when no session exists yet and the process-wide store applies. + SessionID *string `json:"sessionId,omitempty"` + // User agent to send with the policy fetch. + UserAgent string `json:"userAgent"` +} + +// The managed policy layers an ingestion resolved, together with the per-layer outcome +// flags a host needs to decide how much to trust the result. The flags are reported rather +// than folded into the settings because a host must be able to distinguish an unmanaged +// device from a managed device whose policy could not be confirmed, and apply its +// fail-closed gates in the second case. +// Experimental: ManagedSettingsIngestResult is part of an experimental API and may change +// or be removed. +// Internal: ManagedSettingsIngestResult is an internal SDK API and is not part of the +// public surface. +type ManagedSettingsIngestResult struct { + // The device layer could not be read, so it is unconfirmed rather than known-absent. + DeviceLoadFailed bool `json:"deviceLoadFailed"` + // The device layer discovered from the machine, when one exists. + DeviceResponse any `json:"deviceResponse,omitempty"` + // The sandbox floor contributed by the device layer. + DeviceSandboxFloor any `json:"deviceSandboxFloor,omitempty"` + // Whether the device layer's sandbox intent could not be determined, so a consumer must not + // read its absence as permission to run unsandboxed. + DeviceSandboxUndetermined bool `json:"deviceSandboxUndetermined"` + // A device-managed policy is known to exist. + DeviceSourceFound bool `json:"deviceSourceFound"` + // Diagnostics emitted while resolving the layers, in the order they occurred. + // Internal: LogMessages is part of the SDK's internal API surface and is not intended for + // external use. + LogMessages []ManagedSettingsLogMessage `json:"logMessages"` + // The effective managed permissions layer, when the resolved policy carries one. + Permissions any `json:"permissions,omitempty"` + // Which channel registered the policy helper that produced the helper layer. + // Internal: PolicyHelperAuthority is part of the SDK's internal API surface and is not + // intended for external use. + PolicyHelperAuthority *ManagedSettingsPolicyHelperAuthority `json:"policyHelperAuthority,omitempty"` + // A policy helper is configured for this host. + PolicyHelperConfigured bool `json:"policyHelperConfigured"` + // The policy helper's failure must be treated as fail-closed rather than ignored. + PolicyHelperFailClosed bool `json:"policyHelperFailClosed"` + // The policy helper was configured but could not be run or its output could not be read. + PolicyHelperLoadFailed bool `json:"policyHelperLoadFailed"` + // The layer produced by the platform policy helper, when one ran. + PolicyHelperResponse any `json:"policyHelperResponse,omitempty"` + // A live fetch failed but a recent cached entry was served in its place, so + // `serverFetchFailed` stays false. Lets a consumer distinguish a clean fetch from a + // cache-backed fallback. + ServerCacheFallback bool `json:"serverCacheFallback"` + // Minimum client version requested by a successful response. Advisory only; the delivered + // policy remains active. + ServerClientUpdateRequested *string `json:"serverClientUpdateRequested,omitempty"` + // The server refused to deliver a policy because this client is too old to enforce it, + // carrying the user-facing sentence describing the refusal. No retry will help; the remedy + // is a client update. Gates that exist only because of managed policy should deny on this + // rather than falling back to their unmanaged default. + ServerClientUpdateRequired *string `json:"serverClientUpdateRequired,omitempty"` + // The error that made the server fetch fail, when one did. + ServerFetchError *string `json:"serverFetchError,omitempty"` + // The server fetch failed and no cached entry stood in for it, so the server layer is + // unconfirmed and fail-closed gates apply. + ServerFetchFailed bool `json:"serverFetchFailed"` + // The server fetch failed while a policy demanded a fresh confirmation, which is the strict + // posture an enterprise opted into rather than an ordinary transient failure. + ServerForcedRefreshFailure bool `json:"serverForcedRefreshFailure"` + // The synthesized fail-closed permissions layer applied in place of a policy a refused + // client may not enforce. + ServerPermissionsFloor any `json:"serverPermissionsFloor,omitempty"` + // How the server layer was resolved. + // Internal: ServerResolution is part of the SDK's internal API surface and is not intended + // for external use. + ServerResolution ManagedSettingsServerPolicyResolution `json:"serverResolution"` + // The account's server-delivered policy, when one was resolved. + ServerResponse any `json:"serverResponse,omitempty"` + // The server fetch failed in a way a later retry could succeed at, as opposed to a refusal + // that no retry will change. + ServerRetryableFailure bool `json:"serverRetryableFailure"` + // The sandbox object from a cached server policy that a forced refresh declined to serve in + // full. Folded back into the effective sandbox layer so an outage during a forced refresh + // still synthesizes the fail-closed sandbox floor from the administrator's known intent. + ServerSandboxFloor any `json:"serverSandboxFloor,omitempty"` + // A server-managed policy is known to exist even though `serverResponse` is intentionally + // unset. Consumers should OR this with the presence of `serverResponse` when deciding + // whether the device is managed, so a fresh start during an outage still applies the + // fail-closed gates instead of treating the device as unmanaged. + ServerSourceFound bool `json:"serverSourceFound"` + // No usable token was available, so no server fetch was attempted. + ServerTokenUnavailable bool `json:"serverTokenUnavailable"` + // The effective managed settings composed from every resolved layer. Omitted when no layer + // set anything, so an unmanaged host locks nothing. + Settings any `json:"settings,omitempty"` +} + // One managed-settings channel and the document it delivered. // Experimental: ManagedSettingsLayer is part of an experimental API and may change or be // removed. @@ -7170,6 +7447,80 @@ type ManagedSettingsLayer struct { Source string `json:"source"` } +// Inputs describing the host and account whose managed remote-control policy should be +// resolved. Mirrors `managedSettings.ingest`, and deliberately carries no retention +// decision: reading this gate never becomes this runtime process's startup policy. +// Experimental: ManagedSettingsLoadRemoteControlParams is part of an experimental API and +// may change or be removed. +// Internal: ManagedSettingsLoadRemoteControlParams is an internal SDK API and is not part +// of the public surface. +type ManagedSettingsLoadRemoteControlParams struct { + // The authenticated identity to resolve policy for. Omitted before sign-in, in which case + // no server layer is fetched. + AuthInfo any `json:"authInfo,omitempty"` + // Name of the embedding client, reported to the managed-settings service as `client_id` so + // it can refuse to deliver a policy this client is too old to enforce. That refusal is + // exactly what turns into an explicit `disabled` below, so a host that omits this field + // forfeits the protection. + ClientName *string `json:"clientName,omitempty"` + // A device layer supplied by the host instead of discovered from the machine. Pair it with + // `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + DeviceResponse any `json:"deviceResponse,omitempty"` + // The host's environment variables, read for cache location and policy overrides. + Environment any `json:"environment"` + // Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts + // the device layer is empty; false discovers it from the machine. + HasDeviceResponse *bool `json:"hasDeviceResponse,omitempty"` + // The host's home directory, used to resolve cache and managed-file locations. + HomeDirectory string `json:"homeDirectory"` + // The host's platform, in Node's `process.platform` spelling, used to locate + // platform-specific cache and policy paths. + Platform string `json:"platform"` + // Whether a configured platform policy helper may be run to produce an enforced helper + // layer. + PolicyHelperEnabled *bool `json:"policyHelperEnabled,omitempty"` + // The policy-helper invocation reason. Defaults to sessionStart. + // Internal: PolicyHelperReason is part of the SDK's internal API surface and is not + // intended for external use. + PolicyHelperReason *ManagedSettingsPolicyHelperReason `json:"policyHelperReason,omitempty"` + // Whether to run ingestion. Omit or set false to return an empty result without discovering + // or fetching policy. + SelfFetch *bool `json:"selfFetch,omitempty"` + // User agent to send with the policy fetch. + UserAgent string `json:"userAgent"` +} + +// The managed remote-control policy in force for an account, if any. An absent policy means +// the account is unmanaged for this capability, which a host reads as allowed — so absence +// here is a positive statement that no policy applies, never a stand-in for a resolution +// that failed. A resolution that cannot be completed is rejected instead. +// Experimental: ManagedSettingsLoadRemoteControlResult is part of an experimental API and +// may change or be removed. +// Internal: ManagedSettingsLoadRemoteControlResult is an internal SDK API and is not part +// of the public surface. +type ManagedSettingsLoadRemoteControlResult struct { + // The account's `remoteControl` policy document. Absent when no managed policy governs + // remote control for this account. Reported as an explicit disabled policy, rather than as + // absence, when the service refused to deliver a policy this client is too old to enforce. + RemoteControl any `json:"remoteControl,omitempty"` +} + +// One diagnostic emitted while ingesting managed settings. Returned rather than logged by +// the runtime so the host decides where ingestion diagnostics go, which matters because an +// ingestion runs before a session exists to carry a log sink. +// Experimental: ManagedSettingsLogMessage is part of an experimental API and may change or +// be removed. +// Internal: ManagedSettingsLogMessage is an internal SDK API and is not part of the public +// surface. +type ManagedSettingsLogMessage struct { + // Severity of this diagnostic. + // Internal: Level is part of the SDK's internal API surface and is not intended for + // external use. + Level ManagedSettingsLogLevel `json:"level"` + // Human-readable diagnostic text. + Message string `json:"message"` +} + // Per-key lock state and provenance for `ManagedSettingsValues`, with the same field names. // Producers emit each typed key in values and meta together; both outer objects are omitted // when no typed key is set. @@ -7186,6 +7537,29 @@ type ManagedSettingsMeta struct { Model *ManagedSettingMeta `json:"model,omitempty"` } +// The client-supplied managed settings to validate and normalize. Omitting them is valid +// and yields no policy. +// Experimental: ManagedSettingsParseClientValueParams is part of an experimental API and +// may change or be removed. +// Internal: ManagedSettingsParseClientValueParams is an internal SDK API and is not part of +// the public surface. +type ManagedSettingsParseClientValueParams struct { + // The managed settings a client is supplying for a session it is about to open. Omit them + // when the client is imposing no policy of its own. + Settings any `json:"settings,omitempty"` +} + +// The accepted managed settings, reduced to the keys a client is allowed to set. +// Experimental: ManagedSettingsParseClientValueResult is part of an experimental API and +// may change or be removed. +// Internal: ManagedSettingsParseClientValueResult is an internal SDK API and is not part of +// the public surface. +type ManagedSettingsParseClientValueResult struct { + // The normalized settings. Omitted when the client supplied none. An accepted document that + // sets nothing comes back as an empty object, which is distinct from omission. + SettingsJSON any `json:"settingsJson,omitempty"` +} + // Ordered managed permission verdicts and the supplied policy's fail-closed posture. // Experimental: ManagedSettingsPermissionsEvaluateResult is part of an experimental API and // may change or be removed. @@ -7196,6 +7570,26 @@ type ManagedSettingsPermissionsEvaluateResult struct { Results []ManagedPermissionEvaluation `json:"results"` } +// The device-managed settings layer, with the sandbox floor and the load outcome a host +// needs to compose it into an effective policy. +// Experimental: ManagedSettingsReadDeviceResult is part of an experimental API and may +// change or be removed. +// Internal: ManagedSettingsReadDeviceResult is an internal SDK API and is not part of the +// public surface. +type ManagedSettingsReadDeviceResult struct { + // Whether discovery or validation failed. A host must treat this as "policy unknown" rather + // than "no policy": absent settings with this set false mean the device genuinely has none. + LoadFailed bool `json:"loadFailed"` + // Sandbox floor read from the discovered document before validation, so a document that is + // otherwise rejected can still raise the floor it declared. + SandboxFloor any `json:"sandboxFloor,omitempty"` + // Validated, canonical device-managed settings. Omitted when no device policy was + // discovered, when the discovered document failed validation, or when it validated to an + // empty object — an empty document carries no policy, and reporting it as present would + // outrank layers that do. + Settings any `json:"settings,omitempty"` +} + // Validated device-managed settings discovered before a session exists. // Experimental: ManagedSettingsReadResult is part of an experimental API and may change or // be removed. @@ -7207,6 +7601,53 @@ type ManagedSettingsReadResult struct { SettingsJSON any `json:"settingsJson,omitempty"` } +// The bypass-permissions state a host holds today, the account now signed in, and what the +// managed-policy resolution said. +// Experimental: ManagedSettingsResolveBypassDisableTransitionParams is part of an +// experimental API and may change or be removed. +// Internal: ManagedSettingsResolveBypassDisableTransitionParams is an internal SDK API and +// is not part of the public surface. +type ManagedSettingsResolveBypassDisableTransitionParams struct { + // The account signed in now. A `managed` disable pinned to a different account is lifted. + ActiveIdentity string `json:"activeIdentity"` + // The account a `managed` disable is pinned to. Omit it when the current source is not + // `managed`; it is ignored for the other sources. + CurrentManagedIdentity *string `json:"currentManagedIdentity,omitempty"` + // Which layer currently disables bypass mode. Omit it when nothing does. + // Internal: CurrentSource is part of the SDK's internal API surface and is not intended for + // external use. + CurrentSource *ManagedSettingsBypassDisableSource `json:"currentSource,omitempty"` + // What the resolution said about bypass mode. Send `unknown` rather than omitting the field + // when there is no verdict. + // Internal: Policy is part of the SDK's internal API surface and is not intended for + // external use. + Policy ManagedSettingsBypassPolicyResolution `json:"policy"` +} + +// The bypass-permissions state a host should hold after the resolution, and what it must do +// to get there. +// Experimental: ManagedSettingsResolveBypassDisableTransitionResult is part of an +// experimental API and may change or be removed. +// Internal: ManagedSettingsResolveBypassDisableTransitionResult is an internal SDK API and +// is not part of the public surface. +type ManagedSettingsResolveBypassDisableTransitionResult struct { + // The account the returned `managed` source is pinned to. Store it alongside `source`; the + // next call needs it to decide whether an account switch lifts the disable. + ManagedIdentity *string `json:"managedIdentity,omitempty"` + // The value to store in the host's own bypass-disabled flag. Omitted means leave it exactly + // as it is, which is not the same as being told to store `false`. + SetDisabledState *bool `json:"setDisabledState,omitempty"` + // Which layer disables bypass mode after this resolution. Omitted when none does, which is + // what a lifted disable looks like. + // Internal: Source is part of the SDK's internal API surface and is not intended for + // external use. + Source *ManagedSettingsBypassDisableSource `json:"source,omitempty"` + // Whether a bypass-permissions session already running must be turned off. True only when + // this resolution newly disables bypass mode, so a host that is already compliant is not + // interrupted. + SuppressRuntimeAllowAll bool `json:"suppressRuntimeAllowAll"` +} + // Effective enterprise managed settings and contributing channels. Session events report // applied policy; sessionless resolve reports an account/device snapshot, and compose // reports a non-applying preview of candidate documents. Device values take precedence over @@ -7258,6 +7699,54 @@ type ManagedSettingsResolvedData struct { Source ManagedSettingsResolvedSource `json:"source"` } +// The credential and environment to evaluate the device-channel sign-in pin against. +// Experimental: ManagedSettingsResolveDeviceForceLoginOrgsGateParams is part of an +// experimental API and may change or be removed. +// Internal: ManagedSettingsResolveDeviceForceLoginOrgsGateParams is an internal SDK API and +// is not part of the public surface. +type ManagedSettingsResolveDeviceForceLoginOrgsGateParams struct { + // The authenticated identity to judge. Omitted when signed out, which is the case the + // device channel exists to serve: it can refuse a first sign-in before any credential + // exists. + AuthInfo any `json:"authInfo,omitempty"` + // The host's environment variables. Read for the variables that would make an identity's + // membership snapshot forgeable, so a credential whose provenance cannot be trusted is + // refused rather than accepted. + Environment any `json:"environment"` +} + +// The managed-settings layers to compose into an effective policy. Every layer is optional; +// omitting all of them yields no effective policy. +// Experimental: ManagedSettingsResolveEffectiveValueParams is part of an experimental API +// and may change or be removed. +// Internal: ManagedSettingsResolveEffectiveValueParams is an internal SDK API and is not +// part of the public surface. +type ManagedSettingsResolveEffectiveValueParams struct { + // The device sandbox floor, folded into the device layer under `sandbox` before composition. + DeviceSandboxFloor any `json:"deviceSandboxFloor,omitempty"` + // The device layer: native MDM and managed-file settings describing the machine rather than + // the account. + Mdm any `json:"mdm,omitempty"` + // The policy-helper layer, an enforced channel sourced from a platform policy helper + // process. + PolicyHelper any `json:"policyHelper,omitempty"` + // The account's server-delivered org policy, as returned by a managed-settings fetch. + // Omitted before sign-in or when the fetch has not landed. + Server any `json:"server,omitempty"` +} + +// The effective managed policy composed from the supplied layers. +// Experimental: ManagedSettingsResolveEffectiveValueResult is part of an experimental API +// and may change or be removed. +// Internal: ManagedSettingsResolveEffectiveValueResult is an internal SDK API and is not +// part of the public surface. +type ManagedSettingsResolveEffectiveValueResult struct { + // The composed effective managed settings. Omitted when no layer sets anything, so an + // unmanaged host locks nothing. Carries `sandboxAdvisoryFloorDeclined: true` when an + // advisory server force-on was dropped because this host cannot run the sandbox. + SettingsJSON any `json:"settingsJson,omitempty"` +} + // Experimental: ManagedSettingsResolveRequest is part of an experimental API and may change // or be removed. type ManagedSettingsResolveRequest struct { @@ -7308,6 +7797,197 @@ type ManagedSettingsResolveResult struct { Values *ManagedSettingsValues `json:"values,omitempty"` } +// Inputs describing the host and account a startup policy resolution should run for. +// Mirrors `managedSettings.ingest`, and adds the decision of whether the resolved policy is +// retained for this runtime process. +// Experimental: ManagedSettingsResolveStartupPolicyParams is part of an experimental API +// and may change or be removed. +// Internal: ManagedSettingsResolveStartupPolicyParams is an internal SDK API and is not +// part of the public surface. +type ManagedSettingsResolveStartupPolicyParams struct { + // The authenticated identity to resolve policy for. Omitted before sign-in, in which case + // no server layer is fetched and the sign-in pin is evaluated against no credential. + AuthInfo any `json:"authInfo,omitempty"` + // Whether to ignore a cached server policy when reading, forcing the resolution to come + // from a live fetch. + BypassCacheRead *bool `json:"bypassCacheRead,omitempty"` + // Name of the embedding client, reported to the managed-settings service as `client_id` so + // it can refuse to deliver a policy this client is too old to enforce. + ClientName *string `json:"clientName,omitempty"` + // A device layer supplied by the host instead of discovered from the machine. Pair it with + // `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + DeviceResponse any `json:"deviceResponse,omitempty"` + // The host's environment variables, read for cache location, policy overrides, and the + // variables that would make a membership snapshot forgeable. + Environment any `json:"environment"` + // Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts + // the device layer is empty; false discovers it from the machine. + HasDeviceResponse *bool `json:"hasDeviceResponse,omitempty"` + // The host's home directory, used to resolve cache and managed-file locations. + HomeDirectory string `json:"homeDirectory"` + // The host's platform, in Node's `process.platform` spelling, used to locate + // platform-specific cache and policy paths. + Platform string `json:"platform"` + // Whether a configured platform policy helper may be run to produce an enforced helper + // layer. + PolicyHelperEnabled *bool `json:"policyHelperEnabled,omitempty"` + // The policy-helper invocation reason. Defaults to sessionStart. + // Internal: PolicyHelperReason is part of the SDK's internal API surface and is not + // intended for external use. + PolicyHelperReason *ManagedSettingsPolicyHelperReason `json:"policyHelperReason,omitempty"` + // Directory the policy helper runs in when this resolution is not owned by a registered + // session. A host resolving policy before its session exists must pass this, or a + // directory-sensitive helper judges the wrong repository. + PolicyHelperWorkingDirectory *string `json:"policyHelperWorkingDirectory,omitempty"` + // Whether to retain the resolved policy as this runtime process's startup policy, so later + // work in the process enforces it. Set false to resolve without side effects, which is what + // a protocol host wants before session creation: its sessions apply the complete policy + // through the normal lifecycle, and retaining here would let a readiness credential affect + // unrelated sessions. The returned verdict is identical either way — this decides only + // whether the process keeps it. + RetainAndApply bool `json:"retainAndApply"` + // Whether to run ingestion. Omit or set false to return an empty result without discovering + // or fetching policy. + SelfFetch *bool `json:"selfFetch,omitempty"` + // How this resolution may use the on-disk server-policy cache. Defaults to the runtime's + // own policy when omitted. Rejected when combined with `bypassCacheRead`, because the two + // express the same decision and accepting both would leave the caller unsure which one the + // runtime honored. + // Internal: ServerPolicyCacheMode is part of the SDK's internal API surface and is not + // intended for external use. + ServerPolicyCacheMode *ManagedSettingsServerPolicyCacheMode `json:"serverPolicyCacheMode,omitempty"` + // The session whose credential store, working directory and client kind the resolution + // should use. Omit it when no session exists yet and the process-wide store applies. A + // resolution whose session names a credential other than `authInfo` is returned but not + // retained, so a stale sign-in cannot apply policy for an account that has already been + // switched away from. + SessionID *string `json:"sessionId,omitempty"` + // User agent to send with the policy fetch. + UserAgent string `json:"userAgent"` +} + +// The startup policy a resolution composed, the per-layer outcome flags a host needs to +// decide how much to trust it, and the enterprise sign-in verdict for the credential it ran +// against. The flags are reported rather than folded into the settings because a host must +// distinguish an unmanaged device from a managed device whose policy could not be +// confirmed, and apply its fail-closed gates in the second case. +// Experimental: ManagedSettingsResolveStartupPolicyResult is part of an experimental API +// and may change or be removed. +// Internal: ManagedSettingsResolveStartupPolicyResult is an internal SDK API and is not +// part of the public surface. +type ManagedSettingsResolveStartupPolicyResult struct { + // Advisory minimum client version from a successful server response. + ClientUpdateRequested *string `json:"clientUpdateRequested,omitempty"` + // The server refused to deliver a policy because this client is too old to enforce it, + // carrying the user-facing sentence describing the refusal. No retry will help; the remedy + // is a client update. + ClientUpdateRequired *string `json:"clientUpdateRequired,omitempty"` + // The device layer could not be read, so it is unconfirmed rather than known-absent. + DeviceLoadFailed bool `json:"deviceLoadFailed"` + // The device layer discovered from the machine, when one exists. + DeviceResponse any `json:"deviceResponse,omitempty"` + // The sandbox floor contributed by the device layer. + DeviceSandboxFloor any `json:"deviceSandboxFloor,omitempty"` + // The enterprise sign-in verdict for the credential this resolution ran against, evaluated + // over the effective policy so a server-delivered pin is honored alongside a device one. + // Computed on every resolution, including one that was not retained, so a host that + // declines to apply policy still cannot proceed past a pin. + // Internal: ForceLoginOrgs is part of the SDK's internal API surface and is not intended + // for external use. + ForceLoginOrgs ForceLoginOrgsDecision `json:"forceLoginOrgs"` + // A managed policy is known to apply to this host, from a discovered source or a resolved + // document. + ManagedPolicyPresent bool `json:"managedPolicyPresent"` + // The permissions layer specifically could not be confirmed, so permission gates apply + // their fail-closed posture. + PermissionPolicyUndetermined bool `json:"permissionPolicyUndetermined"` + // The policy helper was configured but could not be run, or its output could not be read. + PolicyHelperLoadFailed bool `json:"policyHelperLoadFailed"` + // The layer produced by the platform policy helper, when one ran. + PolicyHelperResponse any `json:"policyHelperResponse,omitempty"` + // Some layer of the policy could not be confirmed, so its absence must not be read as + // permission. Folds in a failed server fetch as well as an unreadable device layer. + PolicyUndetermined bool `json:"policyUndetermined"` + // The sandbox was enabled because policy could not be confirmed rather than because an + // administrator asked for it. Lets a host explain a sandbox the user did not configure. + SandboxEnabledByUndeterminedPolicy bool `json:"sandboxEnabledByUndeterminedPolicy"` + // The effective sandbox floor composed across every layer, which a host must apply rather + // than its own default. + SandboxFloor any `json:"sandboxFloor,omitempty"` + // The server fetch failed and no cached entry stood in for it, so the server layer is + // unconfirmed and fail-closed gates apply. + ServerFetchFailed bool `json:"serverFetchFailed"` + // How the current runtime resolved the server layer. + // Internal: ServerResolution is part of the SDK's internal API surface and is not intended + // for external use. + ServerResolution ManagedSettingsServerPolicyResolution `json:"serverResolution"` + // The account's server-delivered policy, when one was resolved. + ServerResponse any `json:"serverResponse,omitempty"` + // Telemetry describing which layers answered and how, for the host to report alongside its + // own startup events. + Telemetry any `json:"telemetry"` + // Warnings raised while resolving, in the order they occurred. + Warnings []string `json:"warnings"` +} + +// The managed layers to retain as this process's startup policy, with the outcome of +// fetching each one. +// Experimental: ManagedSettingsRetainPolicyParams is part of an experimental API and may +// change or be removed. +// Internal: ManagedSettingsRetainPolicyParams is an internal SDK API and is not part of the +// public surface. +type ManagedSettingsRetainPolicyParams struct { + // Whether the device load failed. Report it honestly, for the same reason as + // `serverFetchFailed`. + DeviceLoadFailed bool `json:"deviceLoadFailed"` + // The device/MDM policy layer. + DeviceResponse any `json:"deviceResponse,omitempty"` + // Sandbox floor declared by the device layer, carried separately so a document that failed + // validation can still raise the floor. + DeviceSandboxFloor any `json:"deviceSandboxFloor,omitempty"` + // Whether the device sandbox intent is unreadable independently of its other settings. + DeviceSandboxUndetermined bool `json:"deviceSandboxUndetermined"` + // Whether a device policy source demonstrably exists. This, not a read error, is the + // evidence a device is managed, so a fail-closed policy gates on it. + DeviceSourceFound bool `json:"deviceSourceFound"` + // Whether any managed policy source exists, independently of fetch failures. + ManagedPolicyPresent bool `json:"managedPolicyPresent"` + // Whether permission policy is undetermined. Sandbox-only uncertainty does not imply this + // flag. + PermissionPolicyUndetermined bool `json:"permissionPolicyUndetermined"` + // The policy helper's response: the third managed layer that a process owning its startup + // policy resolves. It is retained with the other two so that every ambient read in this + // process, including the mutation guards and the governed marketplace allowlist that the + // `plugins.*` handlers derive, sees the whole policy the process fetched. A session-owning + // process omits it, because it resolves a helper per session against that session's working + // directory. + PolicyHelperResponse any `json:"policyHelperResponse,omitempty"` + // Preserve the retained server layer during a device-only resolution. + PreserveServerState bool `json:"preserveServerState"` + // Whether uncertainty alone enabled the shared sandbox floor. + SandboxEnabledByUndeterminedPolicy bool `json:"sandboxEnabledByUndeterminedPolicy"` + // Whether the shared sandbox policy is undetermined. Diagnostic errors alone do not imply + // this flag. + SandboxFloorUndetermined bool `json:"sandboxFloorUndetermined"` + // Whether the server fetch failed. Report it honestly: true keeps the already-retained + // server layer rather than replacing it with an absent one. + ServerFetchFailed bool `json:"serverFetchFailed"` + // Whether a required fresh server-policy confirmation failed. + ServerForcedRefreshFailure bool `json:"serverForcedRefreshFailure"` + // The resolved server policy. A known source can lack a response after a forced-refresh + // failure. + ServerResponse any `json:"serverResponse,omitempty"` + // Whether the server policy source exists, even when its response is unavailable. + ServerSourceFound bool `json:"serverSourceFound"` + // Shared server/device sandbox floor, excluding session-local helper policy. + SharedSandboxFloor any `json:"sharedSandboxFloor,omitempty"` +} + +// Experimental: ManagedSettingsRetainPolicyResult is part of an experimental API and may +// change or be removed. +type ManagedSettingsRetainPolicyResult struct { +} + // The authoring JSON schema for managed settings recognized by this runtime. // Experimental: ManagedSettingsSchemaResult is part of an experimental API and may change // or be removed. @@ -12766,6 +13446,32 @@ type PermissionsConfigureResult struct { Success bool `json:"success"` } +// The verbatim managed `permissions` slice to interpret. +// Experimental: PermissionsEvaluateManagedPolicyParams is part of an experimental API and +// may change or be removed. +// Internal: PermissionsEvaluateManagedPolicyParams is an internal SDK API and is not part +// of the public surface. +type PermissionsEvaluateManagedPolicyParams struct { + // The `permissions` object from a managed settings layer, for example + // `{"disableBypassPermissionsMode":"disable"}`. Omitted or null means no managed policy + // applies. + Permissions any `json:"permissions,omitempty"` +} + +// The policy questions a host asks before granting elevated permissions. +// Experimental: PermissionsEvaluateManagedPolicyResult is part of an experimental API and +// may change or be removed. +type PermissionsEvaluateManagedPolicyResult struct { + // True when managed policy forbids bypass-permissions mode, so allow-all style flags must + // not take effect. + BypassPermissionsDisabled bool `json:"bypassPermissionsDisabled"` + // True when the managed layer supplies permission rules that the session must enforce. + PermissionRulesActive bool `json:"permissionRulesActive"` + // True when a managed policy exists but this build could not determine its meaning. Hosts + // fail closed on it rather than assuming permission was granted. + PolicyUndetermined bool `json:"policyUndetermined"` +} + // Indicates whether the operation succeeded. // Experimental: PermissionsFolderTrustAddTrustedResult is part of an experimental API and // may change or be removed. @@ -13145,6 +13851,31 @@ type PermissionURLsSetUnrestrictedModeParams struct { Enabled bool `json:"enabled"` } +// A complete JSON snapshot to write under the runtime's per-path file lock. +// Experimental: PersistenceWriteRawJSONLockedRequest is part of an experimental API and may +// change or be removed. +type PersistenceWriteRawJSONLockedRequest struct { + // The serialized JSON document to write. It replaces the file's contents entirely; nothing + // is merged. + DataJSON string `json:"dataJson"` + // Comment lines to emit above the document, for a format that tolerates them. Omit for + // strict JSON. + FileHeader *string `json:"fileHeader,omitempty"` + // Absolute path of the file to replace. Parent directories are created when missing. + Path string `json:"path"` +} + +// The outcome of a locked snapshot write. +// Experimental: PersistenceWriteRawJSONLockedResult is part of an experimental API and may +// change or be removed. +type PersistenceWriteRawJSONLockedResult struct { + // Why the write failed. Absent when `success` is true. A lock the runtime could not acquire + // in time reports here rather than raising. + Error *string `json:"error,omitempty"` + // Whether the file now holds the requested contents. + Success bool `json:"success"` +} + // Optional message to echo back to the caller. // Experimental: PingRequest is part of an experimental API and may change or be removed. type PingRequest struct { @@ -14989,6 +15720,30 @@ type RemoteSessionRepository struct { Owner string `json:"owner"` } +// One atomic edit of an allowed top-level repository setting. +// Experimental: RepoSettingsEditRequest is part of an experimental API and may change or be +// removed. +// Internal: RepoSettingsEditRequest is an internal SDK API and is not part of the public +// surface. +type RepoSettingsEditRequest struct { + // One canonical top-level repository setting that the allowlist permits. + Key string `json:"key"` + // Set a scalar, add or remove a string list item, or remove the setting. The handler + // rejects a missing or incompatible value. + // Internal: Operation is part of the SDK's internal API surface and is not intended for + // external use. + Operation SettingsEditOperation `json:"operation"` + // Absolute path of the repository root. + RepoRoot string `json:"repoRoot"` + // Shared or local repository settings file. + // Internal: Scope is part of the SDK's internal API surface and is not intended for + // external use. + Scope RepoSettingsEditScope `json:"scope"` + // Required boolean, string or number for set, required string for add-item and remove-item, + // and forbidden for remove. The runtime rejects all other JSON values. + Value any `json:"value,omitempty"` +} + // Which repository settings file to read. // Experimental: RepoSettingsReadRawRequest is part of an experimental API and may change or // be removed. @@ -15072,6 +15827,30 @@ type ResponseFormat struct { type RuntimeShutdownResult struct { } +// The stored sandbox settings to resolve against the defaults. +// Experimental: SandboxApplyDefaultsRequest is part of an experimental API and may change +// or be removed. +type SandboxApplyDefaultsRequest struct { + // The sandbox settings as stored in the settings file. An empty object resolves to the + // defaults alone. + Stored any `json:"stored"` +} + +// True when the command stays available while enforcement is blocked. +// Experimental: SandboxCheckEnforcementCommandResult is part of an experimental API and may +// change or be removed. +type SandboxCheckEnforcementCommandResult bool + +// True when an OS-level sandbox can run on this host. +// Experimental: SandboxCheckPlatformSupportResult is part of an experimental API and may +// change or be removed. +type SandboxCheckPlatformSupportResult bool + +// True when the sandbox on this host can reach host loopback directly. +// Experimental: SandboxCheckWindowsHostLoopbackSupportResult is part of an experimental API +// and may change or be removed. +type SandboxCheckWindowsHostLoopbackSupportResult bool + // Resolved sandbox configuration. // Experimental: SandboxConfig is part of an experimental API and may change or be removed. type SandboxConfig struct { @@ -15306,6 +16085,52 @@ type SandboxDisableForSessionResult struct { Success bool `json:"success"` } +// The documentation URL a host cites when it declines or downgrades a sandbox setting. +// Experimental: SandboxDocsURLResult is part of an experimental API and may change or be +// removed. +type SandboxDocsURLResult struct { + // Documentation URL describing the sandbox and the settings that control it. + URL string `json:"url"` +} + +// A sandbox config and the per-feature routing flag to resolve it for. +// Experimental: SandboxEffectiveForOptionalParams is part of an experimental API and may +// change or be removed. +// Internal: SandboxEffectiveForOptionalParams is an internal SDK API and is not part of the +// public surface. +type SandboxEffectiveForOptionalParams struct { + // The routing flag naming the feature being launched, such as `sandboxMcpServers` or + // `sandboxLspServers`. + RoutingFlag string `json:"routingFlag"` + // The session's resolved `sandbox` slice. Omitted when the host has none, which yields a + // disabled sandbox rather than an error. + Sandbox any `json:"sandbox,omitempty"` +} + +// The sandbox a named feature actually launches under. +// Experimental: SandboxEffectiveForOptionalResult is part of an experimental API and may +// change or be removed. +// Internal: SandboxEffectiveForOptionalResult is an internal SDK API and is not part of the +// public surface. +type SandboxEffectiveForOptionalResult struct { + // The effective sandbox config for the requested feature, or a disabled sandbox when the + // feature is routed out of it. + SandboxJSON any `json:"sandboxJson"` +} + +// One slash command, as typed, to test against the enforcement-block allowlist. +// Experimental: SandboxEnforcementCommandAllowedParams is part of an experimental API and +// may change or be removed. +// Internal: SandboxEnforcementCommandAllowedParams is an internal SDK API and is not part +// of the public surface. +type SandboxEnforcementCommandAllowedParams struct { + // The command's arguments, in order. Pass an empty array for a bare command: several + // entries in the allowlist admit the bare form and refuse every argument. + Args []string `json:"args"` + // The command name as the user typed it, with or without its leading slash. + CommandName string `json:"commandName"` +} + // Managed sandbox enforcement state for a session. // Experimental: SandboxEnforcementStatus is part of an experimental API and may change or // be removed. @@ -15318,6 +16143,43 @@ type SandboxEnforcementStatus struct { Required bool `json:"required"` } +// A batch of file-picker candidates to check against a prepared policy. +// Experimental: SandboxFilterPickerCandidatesParams is part of an experimental API and may +// change or be removed. +// Internal: SandboxFilterPickerCandidatesParams is an internal SDK API and is not part of +// the public surface. +type SandboxFilterPickerCandidatesParams struct { + // The candidates to check, in the order the answers are returned. + // Internal: Candidates is part of the SDK's internal API surface and is not intended for + // external use. + Candidates []SandboxPickerCandidate `json:"candidates"` + // The session's working directory, matching the one the policy was prepared from. + Cwd string `json:"cwd"` + // The policy returned by `sandbox.preparePickerPolicy`. Omitted keeps every candidate. + Sandbox any `json:"sandbox,omitempty"` +} + +// Per-candidate allow decisions, positionally aligned with the request. +// Experimental: SandboxFilterPickerCandidatesResult is part of an experimental API and may +// change or be removed. +// Internal: SandboxFilterPickerCandidatesResult is an internal SDK API and is not part of +// the public surface. +type SandboxFilterPickerCandidatesResult struct { + // One decision per candidate, in the same order. Always the same length as the request's + // `candidates`. + Allowed []bool `json:"allowed"` +} + +// The user-facing refusal, including the platform remedy and the documentation link. +// Experimental: SandboxGetUnsupportedMessageResult is part of an experimental API and may +// change or be removed. +type SandboxGetUnsupportedMessageResult string + +// The user-facing notice that a saved sandbox setting is inert for this session. +// Experimental: SandboxGetUnsupportedSettingDisabledNoticeResult is part of an experimental +// API and may change or be removed. +type SandboxGetUnsupportedSettingDisabledNoticeResult string + // Request to accept the sandbox path grant offered on an active sandbox escalation // permission prompt. // Experimental: SandboxGrantPathForRequestRequest is part of an experimental API and may @@ -15421,6 +16283,56 @@ type SandboxMaskedEnvVar struct { InjectHosts []string `json:"injectHosts"` } +// One file-picker suggestion offered up for the sandbox filesystem check. +// Experimental: SandboxPickerCandidate is part of an experimental API and may change or be +// removed. +// Internal: SandboxPickerCandidate is an internal SDK API and is not part of the public +// surface. +type SandboxPickerCandidate struct { + // Whether the suggestion is a directory. A directory the policy does not itself allow may + // still be needed as a waypoint to an allowed subtree. + IsDirectory bool `json:"isDirectory"` + // Absolute path the suggestion would attach. + Path string `json:"path"` +} + +// The working directory and sandbox settings to build a file-picker policy from. +// Experimental: SandboxPreparePickerPolicyParams is part of an experimental API and may +// change or be removed. +// Internal: SandboxPreparePickerPolicyParams is an internal SDK API and is not part of the +// public surface. +type SandboxPreparePickerPolicyParams struct { + // The session's working directory. Git discovery and grant canonicalization are resolved + // against it. + Cwd string `json:"cwd"` + // The session's resolved `sandbox` slice. Omitted, or disabled, yields no policy and every + // candidate is kept. + Sandbox any `json:"sandbox,omitempty"` +} + +// The prepared file-picker policy, or none when the sandbox is disabled. +// Experimental: SandboxPreparePickerPolicyResult is part of an experimental API and may +// change or be removed. +// Internal: SandboxPreparePickerPolicyResult is an internal SDK API and is not part of the +// public surface. +type SandboxPreparePickerPolicyResult struct { + // The prepared policy to pass back to `sandbox.filterPickerCandidates`. Absent when the + // sandbox is disabled or absent, in which case filtering keeps every candidate. + SandboxJSON any `json:"sandboxJson,omitempty"` +} + +// True when this process can offer installing the sandbox credential-proxy certificate +// authority into OS trust. +// Experimental: SandboxProxyCaCheckInstallationSupportResult is part of an experimental API +// and may change or be removed. +type SandboxProxyCaCheckInstallationSupportResult bool + +// True when the sandbox configuration uses the credential proxy and can need +// certificate-authority setup. +// Experimental: SandboxProxyCaCheckRelevanceResult is part of an experimental API and may +// change or be removed. +type SandboxProxyCaCheckRelevanceResult bool + // Result of creating the persistent certificate authority of the sandbox credential proxy. // Experimental: SandboxProxyCaCreateResult is part of an experimental API and may change or // be removed. @@ -15456,28 +16368,130 @@ type SandboxProxyCaStatus struct { State SandboxProxyCaState `json:"state"` } -// Register an absolute-time scheduled prompt. -// Experimental: ScheduleAddAtRequest is part of an experimental API and may change or be -// removed. -type ScheduleAddAtRequest struct { - // Epoch milliseconds when the prompt should fire. - At int64 `json:"at"` - // Optional display-only prompt label. - DisplayPrompt *string `json:"displayPrompt,omitempty"` - // Prompt text to enqueue when the schedule fires. - Prompt string `json:"prompt"` - // Whether the schedule should re-arm after each tick. Defaults to false. - Recurring *bool `json:"recurring,omitempty"` +// Experimental: SandboxProxySecretDeleteResult is part of an experimental API and may +// change or be removed. +type SandboxProxySecretDeleteResult struct { } -// Register a cron scheduled prompt. -// Experimental: ScheduleAddCronRequest is part of an experimental API and may change or be -// removed. -type ScheduleAddCronRequest struct { - // 5-field cron expression. - Cron string `json:"cron"` - // Optional display-only prompt label. - DisplayPrompt *string `json:"displayPrompt,omitempty"` +// The stored sandbox proxy password, if one is present. +// Experimental: SandboxProxySecretGetResult is part of an experimental API and may change +// or be removed. +type SandboxProxySecretGetResult struct { + // The stored password. Absent when no entry exists in either the keychain or the on-disk + // fallback store. + Value *string `json:"value,omitempty"` +} + +// Where this runtime keeps the sandbox proxy password. +// Experimental: SandboxProxySecretLocation is part of an experimental API and may change or +// be removed. +type SandboxProxySecretLocation struct { + // Absolute path of the credential store holding the sandbox proxy password. The proxy + // password belongs to no MCP server, so it is kept in its own directory rather than in the + // MCP secret store. + ConfigDir string `json:"configDir"` + // Identifier of the proxy password entry within that store. Derived from the configuration + // directory, so two Copilot homes on one machine never share an entry. Use it to recognize + // a `${secret:…}` reference in stored settings as this runtime's own proxy password. + SecretID string `json:"secretId"` +} + +// The sandbox proxy password to store. +// Experimental: SandboxProxySecretSaveRequest is part of an experimental API and may change +// or be removed. +type SandboxProxySecretSaveRequest struct { + // The password to store for the sandbox proxy. + Value string `json:"value"` +} + +// Where the sandbox proxy password was stored. +// Experimental: SandboxProxySecretSaveResult is part of an experimental API and may change +// or be removed. +type SandboxProxySecretSaveResult struct { + // Whether the OS keychain accepted the value. False means it was written to the on-disk + // fallback store instead, which is still readable by `sandbox.proxySecret.get`. + StoredInKeychain bool `json:"storedInKeychain"` +} + +// The user's sandbox settings and the managed sandbox floor to raise them to. +// Experimental: SandboxResolveFlooredConfigParams is part of an experimental API and may +// change or be removed. +// Internal: SandboxResolveFlooredConfigParams is an internal SDK API and is not part of the +// public surface. +type SandboxResolveFlooredConfigParams struct { + // The effective managed `sandbox` slice acting as a floor. Omitted when no administrator + // policy applies, in which case the user's own settings stand unchanged. + ManagedSandbox any `json:"managedSandbox,omitempty"` + // The user's own `sandbox` settings slice. Omitted when the user has configured none, which + // still yields the managed floor rather than a disabled sandbox. + UserSandbox any `json:"userSandbox,omitempty"` +} + +// The user's sandbox settings raised to the managed floor. +// Experimental: SandboxResolveFlooredConfigResult is part of an experimental API and may +// change or be removed. +type SandboxResolveFlooredConfigResult struct { + // The floored sandbox config, normalized through the declared sandbox shape so only + // declared fields in a fixed order are present. + SandboxJSON any `json:"sandboxJson"` +} + +// The effective sandbox settings, with every unset value resolved to its default. +// Experimental: SandboxSettingsApplyDefaultsResult is part of an experimental API and may +// change or be removed. +type SandboxSettingsApplyDefaultsResult map[string]any + +// The managed sandbox policy in force, which selects which remedy the notice offers. +// Experimental: SandboxUnsupportedStartupNoticeParams is part of an experimental API and +// may change or be removed. +// Internal: SandboxUnsupportedStartupNoticeParams is an internal SDK API and is not part of +// the public surface. +type SandboxUnsupportedStartupNoticeParams struct { + // True when the sandbox stayed on only because the managed policy could not be determined. + // Distinguishes a policy that positively enforces the sandbox from one that merely failed + // to resolve, which is the difference between telling the user to contact an administrator + // and telling them to wait. Defaults to false. + EnabledByUndeterminedPolicy *bool `json:"enabledByUndeterminedPolicy,omitempty"` + // The managed `sandbox` slice, when a policy supplies one. The notice treats the sandbox as + // enforced only when this both enables it and sets `failIfUnavailable`, because a managed + // sandbox that tolerates being unavailable still leaves the user able to turn it off. + ManagedSandbox any `json:"managedSandbox,omitempty"` +} + +// The startup warning, absent when the machine can run a sandbox. +// Experimental: SandboxUnsupportedStartupNoticeResult is part of an experimental API and +// may change or be removed. +// Internal: SandboxUnsupportedStartupNoticeResult is an internal SDK API and is not part of +// the public surface. +type SandboxUnsupportedStartupNoticeResult struct { + // The user-facing warning, carrying the platform remedy and the recovery the policy in + // force actually allows. Absent when this machine supports a sandbox, so a host can call + // unconditionally and print only what it gets. + Notice *string `json:"notice,omitempty"` +} + +// Register an absolute-time scheduled prompt. +// Experimental: ScheduleAddAtRequest is part of an experimental API and may change or be +// removed. +type ScheduleAddAtRequest struct { + // Epoch milliseconds when the prompt should fire. + At int64 `json:"at"` + // Optional display-only prompt label. + DisplayPrompt *string `json:"displayPrompt,omitempty"` + // Prompt text to enqueue when the schedule fires. + Prompt string `json:"prompt"` + // Whether the schedule should re-arm after each tick. Defaults to false. + Recurring *bool `json:"recurring,omitempty"` +} + +// Register a cron scheduled prompt. +// Experimental: ScheduleAddCronRequest is part of an experimental API and may change or be +// removed. +type ScheduleAddCronRequest struct { + // 5-field cron expression. + Cron string `json:"cron"` + // Optional display-only prompt label. + DisplayPrompt *string `json:"displayPrompt,omitempty"` // Prompt text to enqueue when the schedule fires. Prompt string `json:"prompt"` // Whether the schedule should re-arm after each tick. Defaults to true. @@ -22016,6 +23030,37 @@ type UserSettingsApplyTopKeyResult struct { Status string `json:"status"` } +// The overrides and host context to resolve effective runtime settings from. +// Experimental: UserSettingsBuildRuntimeRequest is part of an experimental API and may +// change or be removed. +// Internal: UserSettingsBuildRuntimeRequest is an internal SDK API and is not part of the +// public surface. +type UserSettingsBuildRuntimeRequest struct { + // The environment to read settings-bearing variables from. Passed explicitly rather than + // read from the server process so a host can resolve settings for an environment it is + // about to create rather than the one it runs in. + Environment map[string]string `json:"environment"` + // Settings that take precedence over every document and environment layer, such as the + // values a host derived from its own command line. Keyed by setting name, with each value + // carried verbatim, so a host may pass keys this runtime does not recognize. Absent when + // the host contributes no overrides of its own. + Overrides map[string]any `json:"overrides,omitzero"` + // The platform to apply platform-specific defaults for, in the same spelling the host's own + // runtime reports. + Platform string `json:"platform"` + // The directory the settings are being resolved for. This selects the repository-scoped + // document, so a host resolving settings for a directory other than its own process working + // directory must pass that directory here. + WorkingDirectory string `json:"workingDirectory"` +} + +// The effective runtime settings, keyed by setting name. Keys this runtime does not +// recognize are preserved rather than dropped, so a caller reading a document written by a +// newer runtime keeps every value. +// Experimental: UserSettingsBuildRuntimeResult is part of an experimental API and may +// change or be removed. +type UserSettingsBuildRuntimeResult map[string]any + // One atomic edit of a canonical setting in settings.json. // Experimental: UserSettingsEditRequest is part of an experimental API and may change or be // removed. @@ -22084,6 +23129,73 @@ type UserSettingsGovernanceKeysResult struct { Repo []string `json:"repo"` } +// The filesystem and environment facts a user-settings file is resolved from. Passed +// explicitly rather than read from the runtime's own process, so a host whose configuration +// directory differs from its process environment resolves the file it means. +// Experimental: UserSettingsHostContext is part of an experimental API and may change or be +// removed. +type UserSettingsHostContext struct { + // The Copilot configuration directory, when the host set one. Takes precedence over + // `COPILOT_HOME` and the home directory. + ConfigDir *string `json:"configDir,omitempty"` + // The host's environment variables. `COPILOT_HOME` is read from here, as are the variables + // a settings hook may expand. + Environment any `json:"environment"` + // The user's home directory, used when neither a configuration directory nor `COPILOT_HOME` + // is set. + HomeDirectory string `json:"homeDirectory"` +} + +// A repository to read settings from, and the user layer they are merged over. +// Experimental: UserSettingsLoadAndMergeRepoRequest is part of an experimental API and may +// change or be removed. +// Internal: UserSettingsLoadAndMergeRepoRequest is an internal SDK API and is not part of +// the public surface. +type UserSettingsLoadAndMergeRepoRequest struct { + // Absolute path of the repository root whose settings to read. When this is the user's home + // directory, the Claude-compatible configuration is skipped, so a home-directory session + // does not inherit a personal config as if it were repository policy. + RepoRoot string `json:"repoRoot"` + // The user's own settings, keyed by setting name. The repository layer is merged over this; + // a repository may only add to the collection settings it is allowed to influence, so a + // user setting it does not name survives unchanged. + UserSettings map[string]any `json:"userSettings"` +} + +// The settings a consumer should act on inside a repository, together with any diagnostic +// raised while reading the repository layer. +// Experimental: UserSettingsLoadAndMergeRepoResult is part of an experimental API and may +// change or be removed. +// Internal: UserSettingsLoadAndMergeRepoResult is an internal SDK API and is not part of +// the public surface. +type UserSettingsLoadAndMergeRepoResult struct { + // The merged settings document, keyed by setting name. Equals the supplied user layer when + // the repository declares no settings. + Settings map[string]any `json:"settings"` + // Why part of the repository document was ignored, as a single human-readable string + // joining every diagnostic with `; `. Null when it loaded cleanly. The settings that did + // load are still merged, so a consumer should surface this and continue rather than treat + // it as a failure. + Warning *string `json:"warning,omitempty"` +} + +// Selects the configuration directory whose user settings to read. +// Experimental: UserSettingsLoadForConfigDirRequest is part of an experimental API and may +// change or be removed. +// Internal: UserSettingsLoadForConfigDirRequest is an internal SDK API and is not part of +// the public surface. +type UserSettingsLoadForConfigDirRequest struct { + // Copilot configuration directory to read the settings document from, taking precedence + // over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, + // to read the directory the server resolved for itself. + ConfigDir *string `json:"configDir,omitempty"` +} + +// The stored user settings document, keyed by setting name. +// Experimental: UserSettingsLoadForConfigDirResult is part of an experimental API and may +// change or be removed. +type UserSettingsLoadForConfigDirResult map[string]any + // Contents of settings.json as stored, for a caller about to rewrite it. // Experimental: UserSettingsLoadForEditResult is part of an experimental API and may change // or be removed. @@ -22095,6 +23207,166 @@ type UserSettingsLoadForEditResult struct { Status string `json:"status"` } +// Selects the repository whose checked-in settings to read. +// Experimental: UserSettingsLoadRepoRequest is part of an experimental API and may change +// or be removed. +type UserSettingsLoadRepoRequest struct { + // Absolute path of the repository root whose settings to read. When this is the user's home + // directory, the Claude-compatible configuration is skipped, so a home-directory session + // does not inherit a personal config as if it were repository policy. + RepoRoot string `json:"repoRoot"` +} + +// A repository's settings as stored, together with any diagnostic raised while reading them. +// Experimental: UserSettingsLoadRepoResult is part of an experimental API and may change or +// be removed. +type UserSettingsLoadRepoResult struct { + // The repository's settings document, keyed by setting name, with each value carried + // verbatim. Null when the repository declares no settings. + Settings map[string]any `json:"settings,omitzero"` + // Why part of the document was ignored, as a single human-readable string joining every + // diagnostic with `; `. Null when the document loaded cleanly. The settings that did load + // are still reported, so a consumer should surface this and continue rather than treat it + // as a failure. + Warning *string `json:"warning,omitempty"` +} + +// The user's stored settings, together with any diagnostic raised while reading them. +// Experimental: UserSettingsLoadWithWarningResult is part of an experimental API and may +// change or be removed. +type UserSettingsLoadWithWarningResult struct { + // The stored user settings document, keyed by setting name, with each value carried + // verbatim. Empty when the file could not be read at all. + Settings map[string]any `json:"settings"` + // Why part of the document was ignored, phrased for display to the user. Null when the + // document loaded cleanly. The settings that did load are still reported, so a consumer may + // surface this and continue rather than treat it as a failure. + Warning *string `json:"warning,omitempty"` +} + +// The managed (enterprise policy) layer and the user layer to fold together. The field +// names carry the layer identity: nothing about a settings object identifies which layer +// produced it, so a generic base/override pair would let a caller transpose them and +// silently resolve the governance keys in the user's favour. +// Experimental: UserSettingsMergeManagedAndUserParams is part of an experimental API and +// may change or be removed. +// Internal: UserSettingsMergeManagedAndUserParams is an internal SDK API and is not part of +// the public surface. +type UserSettingsMergeManagedAndUserParams struct { + // The managed layer. Its governance keys win, and the per-entry `enabledPlugins` and + // `extraKnownMarketplaces` control maps are stamped back from it after the union. Omitted + // when the host is unmanaged. + Managed any `json:"managed,omitempty"` + // The user's own settings layer. Wins on every key the managed layer does not govern. + // Omitted when the user has no settings yet. + User any `json:"user,omitempty"` +} + +// The user layer folded over the managed layer. +// Experimental: UserSettingsMergeManagedAndUserResult is part of an experimental API and +// may change or be removed. +type UserSettingsMergeManagedAndUserResult struct { + // The merged settings. An empty object when neither layer was supplied, so an unmanaged + // host with no user settings governs nothing. + SettingsJSON any `json:"settingsJson"` +} + +// The user layer and the repository layer to fold together. +// Experimental: UserSettingsMergeRepoValueParams is part of an experimental API and may +// change or be removed. +// Internal: UserSettingsMergeRepoValueParams is an internal SDK API and is not part of the +// public surface. +type UserSettingsMergeRepoValueParams struct { + // The repository's checked-in settings layer. + RepoSettings any `json:"repoSettings"` + // The user's settings, already resolved against any managed layer. + UserSettings any `json:"userSettings"` +} + +// The repository layer folded into the user layer. +// Experimental: UserSettingsMergeRepoValueResult is part of an experimental API and may +// change or be removed. +type UserSettingsMergeRepoValueResult struct { + // The merged settings, with the per-entry managed control maps re-stamped from the + // runtime's ambient managed policy. + SettingsJSON any `json:"settingsJson"` +} + +// Selects the configuration directory whose settings document to clean. +// Experimental: UserSettingsMigrateObsoleteOnDiskRequest is part of an experimental API and +// may change or be removed. +// Internal: UserSettingsMigrateObsoleteOnDiskRequest is an internal SDK API and is not part +// of the public surface. +type UserSettingsMigrateObsoleteOnDiskRequest struct { + // The configuration directory holding the settings document to clean. A host that scopes a + // session to its own Copilot home passes that directory here; omit it to clean the document + // under the home the server resolved for itself. The home directory and environment are + // deliberately not caller-supplied: they decide only the settings path root and the two + // hook-parsing flags, and those describe the process doing the reading rather than the + // caller. + ConfigDir *string `json:"configDir,omitempty"` +} + +// The outcome of the one-time obsolete-settings cleanup. +// Experimental: UserSettingsMigrateObsoleteOnDiskResult is part of an experimental API and +// may change or be removed. +// Internal: UserSettingsMigrateObsoleteOnDiskResult is an internal SDK API and is not part +// of the public surface. +type UserSettingsMigrateObsoleteOnDiskResult struct { + // What the cleanup did. Only `changed` rewrote the document. The cleaned settings are not + // returned here: the document is written before this replies, so `user.settings.load` reads + // it authoritatively. + // Internal: Status is part of the SDK's internal API surface and is not intended for + // external use. + Status UserSettingsMigrateObsoleteOnDiskStatus `json:"status"` +} + +// Selects the configuration directory to run the one-time staff log-level migration +// against, and supplies the caller's record of whether it has already run. +// Experimental: UserSettingsMigrateStaffLogLevelOnceRequest is part of an experimental API +// and may change or be removed. +// Internal: UserSettingsMigrateStaffLogLevelOnceRequest is an internal SDK API and is not +// part of the public surface. +type UserSettingsMigrateStaffLogLevelOnceRequest struct { + // When the caller last recorded this migration, as an ISO-8601 timestamp. Supplying it lets + // the runtime answer `current` without re-running the evaluation. + CachedCompletedAt *string `json:"cachedCompletedAt,omitempty"` + // The configuration directory, home directory and environment to resolve the settings and + // global-state documents from. A host that scopes a session to its own Copilot home must + // pass that directory here, or the migration is evaluated against the server's own home + // instead. + Context UserSettingsHostContext `json:"context"` +} + +// The outcome of the one-time staff log-level migration. +// Experimental: UserSettingsMigrateStaffLogLevelOnceResult is part of an experimental API +// and may change or be removed. +// Internal: UserSettingsMigrateStaffLogLevelOnceResult is an internal SDK API and is not +// part of the public surface. +type UserSettingsMigrateStaffLogLevelOnceResult struct { + // When the migration was recorded as done, as an ISO-8601 timestamp. Absent only for + // `ineligible`, which records nothing. + CompletedAt *string `json:"completedAt,omitempty"` + // The settings document as it stands after the migration, keyed by setting name. Present + // only for `refreshed`, and only when the document could be re-read cleanly. + Settings any `json:"settings,omitempty"` + // What the migration did. Only `refreshed` can have changed the persisted settings. + Status StaffLogLevelMigrationStatus `json:"status"` +} + +// The outcome of the one-time staff update-channel migration. +// Experimental: UserSettingsMigrateStaffUpdateChannelOnceResult is part of an experimental +// API and may change or be removed. +// Internal: UserSettingsMigrateStaffUpdateChannelOnceResult is an internal SDK API and is +// not part of the public surface. +type UserSettingsMigrateStaffUpdateChannelOnceResult struct { + // When the migration was recorded as done, as an ISO-8601 timestamp. Absent only for + // `ineligible`, which records nothing. + CompletedAt *string `json:"completedAt,omitempty"` + // What the migration did. Only `migrated` means the persisted settings changed. + Status StaffUpdateChannelMigrationStatus `json:"status"` +} + // Settings object whose key names should be canonicalized. // Experimental: UserSettingsNormalizeRequest is part of an experimental API and may change // or be removed. @@ -22111,6 +23383,16 @@ type UserSettingsNormalizeResult struct { Settings any `json:"settings"` } +// The on-disk location of the user's settings document. +// Experimental: UserSettingsPathResult is part of an experimental API and may change or be +// removed. +type UserSettingsPathResult struct { + // Absolute path to the settings file this runtime reads and writes. Normally + // `settings.json` under the Copilot configuration directory; an extensionless legacy + // `settings` file is reported instead when it exists and `settings.json` does not. + Path string `json:"path"` +} + // One setting that will not take effect, and why. // Experimental: UserSettingsProblem is part of an experimental API and may change or be // removed. @@ -22179,6 +23461,73 @@ type UserSettingsProblemsResult struct { Problems []UserSettingsProblem `json:"problems,omitzero"` } +// Selects the configuration directory to run the one-time staff model-selection reset +// against, and supplies the caller's record of whether it has already run. +// Experimental: UserSettingsResetStaffModelSelectionOnceRequest is part of an experimental +// API and may change or be removed. +// Internal: UserSettingsResetStaffModelSelectionOnceRequest is an internal SDK API and is +// not part of the public surface. +type UserSettingsResetStaffModelSelectionOnceRequest struct { + // The configuration directory, home directory and environment to resolve the settings and + // global-state documents from. A host that scopes a session to its own Copilot home must + // pass that directory here, or the reset is evaluated against the server's own home instead. + Context UserSettingsHostContext `json:"context"` + // Whether the signed-in account is a staff account. The reset applies only to staff, so + // anything other than `true` returns `didReset: false` without touching the settings + // document. + Staff *bool `json:"staff,omitempty"` + // When the caller last recorded this reset, as an ISO-8601 timestamp. A timestamp at or + // after the cutoff means the reset already ran and is returned unchanged. + StaffModelResetAt *string `json:"staffModelResetAt,omitempty"` +} + +// The outcome of the one-time staff model-selection reset. +// Experimental: UserSettingsResetStaffModelSelectionOnceResult is part of an experimental +// API and may change or be removed. +// Internal: UserSettingsResetStaffModelSelectionOnceResult is an internal SDK API and is +// not part of the public surface. +type UserSettingsResetStaffModelSelectionOnceResult struct { + // The cutoff this reset is gated on, as an ISO-8601 timestamp. A recorded timestamp at or + // after it means the reset is already done. + Cutoff string `json:"cutoff"` + // Whether the persisted model selection was cleared. Only `true` means the settings + // document changed and the host should adopt the returned settings. + DidReset bool `json:"didReset"` + // The timestamp the host should now record, as an ISO-8601 timestamp. Carries the caller's + // own value back unchanged when nothing was reset. + ResetAt *string `json:"resetAt,omitempty"` + // The settings document as it stands after the reset, keyed by setting name. Present only + // when `didReset` is true. + Settings any `json:"settings,omitempty"` +} + +// One hook to disable or re-enable. +// Experimental: UserSettingsSetHookDisabledRequest is part of an experimental API and may +// change or be removed. +// Internal: UserSettingsSetHookDisabledRequest is an internal SDK API and is not part of +// the public surface. +type UserSettingsSetHookDisabledRequest struct { + // True adds the key to `disabledHooks`, false removes it. + Disabled bool `json:"disabled"` + // Durable content-hash key of the hook, as `hooks.loadResources` reports it. + DisableKey string `json:"disableKey"` + // Path of the settings.json to rewrite. + SettingsPath string `json:"settingsPath"` +} + +// Outcome of rewriting the `disabledHooks` setting. +// Experimental: UserSettingsSetHookDisabledResult is part of an experimental API and may +// change or be removed. +// Internal: UserSettingsSetHookDisabledResult is an internal SDK API and is not part of the +// public surface. +type UserSettingsSetHookDisabledResult struct { + // Why the write failed. Absent when the status is `ok`. + ErrorMessage *string `json:"errorMessage,omitempty"` + // `ok` when the setting was written, `invalid` when settings.json could not be parsed and + // was left alone, `error` when the write itself failed. + Status string `json:"status"` +} + // Partial user settings to write to settings.json. Each top-level key is written // individually, replacing the existing value; a key whose value is null is removed. // Experimental: UserSettingsSetRequest is part of an experimental API and may change or be @@ -22193,6 +23542,33 @@ type UserSettingsSetRequest struct { type UserSettingsSetResult struct { } +// Selects the configuration directory whose user settings document should be inspected for +// unrecognized top-level keys. +// Experimental: UserSettingsUnknownKeysWarningRequest is part of an experimental API and +// may change or be removed. +// Internal: UserSettingsUnknownKeysWarningRequest is an internal SDK API and is not part of +// the public surface. +type UserSettingsUnknownKeysWarningRequest struct { + // The configuration directory, home directory and environment to resolve the settings + // document from. A host that scopes a session to its own Copilot home must pass that + // directory here, or the server's own home is inspected instead. + Context UserSettingsHostContext `json:"context"` +} + +// The unrecognized top-level keys found in the user settings document, already phrased for +// display. +// Experimental: UserSettingsUnknownKeysWarningResult is part of an experimental API and may +// change or be removed. +// Internal: UserSettingsUnknownKeysWarningResult is an internal SDK API and is not part of +// the public surface. +type UserSettingsUnknownKeysWarningResult struct { + // The warning to show the user, naming the unrecognized keys and the file they were found + // in. Absent when every top-level key is recognized, and also when the document is missing + // or could not be read, because an unknown-key list taken from a document the runtime could + // not load would name keys that may not be there. + Warning *string `json:"warning,omitempty"` +} + // Names the user setting to merge into, and the partial object to merge. // Experimental: UserSettingsUpdateRequest is part of an experimental API and may change or // be removed. @@ -25598,6 +26974,41 @@ const ( ManagedPluginRetryStatusUpdated ManagedPluginRetryStatus = "updated" ) +// Which layer disabled bypass-permissions mode. The layer matters because only a +// server-delivered disable is pinned to an account and can later be lifted by signing in +// elsewhere. +// Experimental: ManagedSettingsBypassDisableSource is part of an experimental API and may +// change or be removed. +type ManagedSettingsBypassDisableSource string + +const ( + // The account's server-delivered org policy disabled it. Pinned to the account named by + // `currentManagedIdentity`. + ManagedSettingsBypassDisableSourceManaged ManagedSettingsBypassDisableSource = "managed" + // The device/MDM layer disabled it. Outranks the account, so no server answer lifts it. + ManagedSettingsBypassDisableSourceMdm ManagedSettingsBypassDisableSource = "mdm" + // The user turned bypass mode off themselves. + ManagedSettingsBypassDisableSourceUser ManagedSettingsBypassDisableSource = "user" +) + +// What the managed-policy resolution said about bypass-permissions mode. `unknown` is a +// third answer rather than a missing one, and the caller must send it explicitly when it +// has no verdict. +// Experimental: ManagedSettingsBypassPolicyResolution is part of an experimental API and +// may change or be removed. +type ManagedSettingsBypassPolicyResolution string + +const ( + // The policy resolved and does not disable bypass mode. + ManagedSettingsBypassPolicyResolutionAllowed ManagedSettingsBypassPolicyResolution = "allowed" + // The policy resolved and disables bypass mode. + ManagedSettingsBypassPolicyResolutionDisabled ManagedSettingsBypassPolicyResolution = "disabled" + // No verdict: the fetch failed, or the service declared a policy this build may not + // enforce. Whatever is in force is preserved, because reverting to permissive on an + // unreadable policy would widen access. + ManagedSettingsBypassPolicyResolutionUnknown ManagedSettingsBypassPolicyResolution = "unknown" +) + // A channel accepted by managedSettings.compose. // Experimental: ManagedSettingsChannel is part of an experimental API and may change or be // removed. @@ -25624,6 +27035,46 @@ const ( ManagedSettingsDiagnosticSeverityWarning ManagedSettingsDiagnosticSeverity = "warning" ) +// Severity of a diagnostic emitted while ingesting managed settings. +// Experimental: ManagedSettingsLogLevel is part of an experimental API and may change or be +// removed. +type ManagedSettingsLogLevel string + +const ( + // Detail useful only when diagnosing an ingestion. + ManagedSettingsLogLevelDebug ManagedSettingsLogLevel = "debug" + // A failure that changed the outcome of the ingestion. + ManagedSettingsLogLevelError ManagedSettingsLogLevel = "error" + // Ordinary progress worth surfacing under a verbose flag. + ManagedSettingsLogLevelInfo ManagedSettingsLogLevel = "info" + // A condition the operator should see but which did not stop the ingestion. + ManagedSettingsLogLevelWarning ManagedSettingsLogLevel = "warning" +) + +// Which channel registered the policy helper that produced a helper layer. +// Experimental: ManagedSettingsPolicyHelperAuthority is part of an experimental API and may +// change or be removed. +type ManagedSettingsPolicyHelperAuthority string + +const ( + // The helper was registered by the device (MDM or managed file) layer. + ManagedSettingsPolicyHelperAuthorityDevice ManagedSettingsPolicyHelperAuthority = "device" + // The helper was registered by the account's server-delivered policy. + ManagedSettingsPolicyHelperAuthorityServer ManagedSettingsPolicyHelperAuthority = "server" +) + +// The operation that requires a policy-helper response. +// Experimental: ManagedSettingsPolicyHelperReason is part of an experimental API and may +// change or be removed. +type ManagedSettingsPolicyHelperReason string + +const ( + // Resolve policy before plugin activation. + ManagedSettingsPolicyHelperReasonPluginActivation ManagedSettingsPolicyHelperReason = "pluginActivation" + // Resolve policy for session startup. + ManagedSettingsPolicyHelperReasonSessionStart ManagedSettingsPolicyHelperReason = "sessionStart" +) + // Summary of which managed-settings channels contributed to the effective session policy. // Use the per-channel booleans for exact provenance. // Experimental: ManagedSettingsResolvedSource is part of an experimental API and may change @@ -25647,6 +27098,44 @@ const ( ManagedSettingsResolvedSourceServer ManagedSettingsResolvedSource = "server" ) +// How an ingestion may use the on-disk server-policy cache. +// Experimental: ManagedSettingsServerPolicyCacheMode is part of an experimental API and may +// change or be removed. +type ManagedSettingsServerPolicyCacheMode string + +const ( + // Read cached policy without a network request. + ManagedSettingsServerPolicyCacheModeCacheOnly ManagedSettingsServerPolicyCacheMode = "cacheOnly" + // Ignore the cache entirely and rely on the live fetch alone. + ManagedSettingsServerPolicyCacheModeDisabled ManagedSettingsServerPolicyCacheMode = "disabled" + // Serve a cached entry only as a fallback after a failed live fetch. + ManagedSettingsServerPolicyCacheModeFallbackOnly ManagedSettingsServerPolicyCacheMode = "fallbackOnly" + // Serve a recent cache entry before a live fetch. + ManagedSettingsServerPolicyCacheModePreferFresh ManagedSettingsServerPolicyCacheMode = "preferFresh" +) + +// How the server layer of an ingestion was resolved. +// Experimental: ManagedSettingsServerPolicyResolution is part of an experimental API and +// may change or be removed. +type ManagedSettingsServerPolicyResolution string + +const ( + // No cached policy or confirmed no-policy result exists. + ManagedSettingsServerPolicyResolutionCacheMiss ManagedSettingsServerPolicyResolution = "cacheMiss" + // No policy could be resolved and the host applies the fail-closed gates. + ManagedSettingsServerPolicyResolutionFailClosed ManagedSettingsServerPolicyResolution = "failClosed" + // No policy could be resolved and the host proceeds unmanaged. + ManagedSettingsServerPolicyResolutionFailOpen ManagedSettingsServerPolicyResolution = "failOpen" + // A live fetch failed and a cached entry was served in its place. + ManagedSettingsServerPolicyResolutionFallbackCache ManagedSettingsServerPolicyResolution = "fallbackCache" + // A recent cached entry was served without a live fetch. + ManagedSettingsServerPolicyResolutionFreshCache ManagedSettingsServerPolicyResolution = "freshCache" + // A live fetch succeeded. + ManagedSettingsServerPolicyResolutionLive ManagedSettingsServerPolicyResolution = "live" + // No fetch was attempted because no usable token was available. + ManagedSettingsServerPolicyResolutionSkippedNoToken ManagedSettingsServerPolicyResolution = "skippedNoToken" +) + // Allowed values for the `McpAppsHostContextDetailsAvailableDisplayMode` enumeration. // Experimental: MCPAppsHostContextDetailsAvailableDisplayMode is part of an experimental // API and may change or be removed. @@ -27526,6 +29015,18 @@ const ( RemoteSessionModeOn RemoteSessionMode = "on" ) +// Which repository settings file to edit. +// Experimental: RepoSettingsEditScope is part of an experimental API and may change or be +// removed. +type RepoSettingsEditScope string + +const ( + // The local repository settings file. + RepoSettingsEditScopeLocal RepoSettingsEditScope = "local" + // The shared repository settings file. + RepoSettingsEditScopeRepo RepoSettingsEditScope = "repo" +) + // Output format discriminator. Currently only json_schema is supported. type ResponseFormatType string @@ -28435,6 +29936,45 @@ const ( SlashCommandModelPickerDialogKindModelPicker SlashCommandModelPickerDialogKind = "model-picker" ) +// What the one-time staff log-level migration did. +// Experimental: StaffLogLevelMigrationStatus is part of an experimental API and may change +// or be removed. +type StaffLogLevelMigrationStatus string + +const ( + // The migration already ran; the stored completion timestamp is returned unchanged. + StaffLogLevelMigrationStatusCurrent StaffLogLevelMigrationStatus = "current" + // The account is not a staff account, so the migration does not apply and nothing was + // recorded. + StaffLogLevelMigrationStatusIneligible StaffLogLevelMigrationStatus = "ineligible" + // The migration ran now. The persisted settings may have changed, so the host should adopt + // the returned settings when they are present. + StaffLogLevelMigrationStatusRefreshed StaffLogLevelMigrationStatus = "refreshed" +) + +// What the one-time staff update-channel migration did. +// Experimental: StaffUpdateChannelMigrationStatus is part of an experimental API and may +// change or be removed. +type StaffUpdateChannelMigrationStatus string + +const ( + // The persisted channel was already stable, so nothing changed, but the migration is now + // recorded as done. + StaffUpdateChannelMigrationStatusCompleted StaffUpdateChannelMigrationStatus = "completed" + // The migration already ran within the cutoff window; the stored completion timestamp is + // returned unchanged. + StaffUpdateChannelMigrationStatusCurrent StaffUpdateChannelMigrationStatus = "current" + // The account is on the experimental channel, which the migration deliberately leaves + // alone, and the migration is recorded as done. + StaffUpdateChannelMigrationStatusExcludedExperimental StaffUpdateChannelMigrationStatus = "excluded-experimental" + // The account is not a staff account, so the migration does not apply and nothing was + // recorded. + StaffUpdateChannelMigrationStatusIneligible StaffUpdateChannelMigrationStatus = "ineligible" + // The persisted update channel was changed to stable. Only this outcome requires the host + // to reload its configuration. + StaffUpdateChannelMigrationStatusMigrated StaffUpdateChannelMigrationStatus = "migrated" +) + // Context tier override for matching subagents // Experimental: SubagentSettingsEntryContextTier is part of an experimental API and may // change or be removed. @@ -28761,6 +30301,23 @@ const ( UISessionLimitsExhaustedResponseActionUnset UISessionLimitsExhaustedResponseAction = "unset" ) +// What the one-time obsolete-settings cleanup did to the document. +// Experimental: UserSettingsMigrateObsoleteOnDiskStatus is part of an experimental API and +// may change or be removed. +type UserSettingsMigrateObsoleteOnDiskStatus string + +const ( + // Obsolete keys were removed and the document was rewritten. + UserSettingsMigrateObsoleteOnDiskStatusChanged UserSettingsMigrateObsoleteOnDiskStatus = "changed" + // The document could not be parsed, so it was left untouched rather than rewritten from a + // partial read. + UserSettingsMigrateObsoleteOnDiskStatusInvalid UserSettingsMigrateObsoleteOnDiskStatus = "invalid" + // No settings document exists, so there was nothing to clean. + UserSettingsMigrateObsoleteOnDiskStatusMissing UserSettingsMigrateObsoleteOnDiskStatus = "missing" + // The document parsed and held nothing obsolete, so nothing was written. + UserSettingsMigrateObsoleteOnDiskStatusUnchanged UserSettingsMigrateObsoleteOnDiskStatus = "unchanged" +) + // Kind discriminator for UserToolSessionApproval. type UserToolSessionApprovalKind string @@ -30554,6 +32111,48 @@ func (a *ServerSandboxAPI) GetHostSupport(ctx context.Context) (*SandboxHostSupp // removed. type ServerSandboxProxyCaAPI serverAPI +// CheckInstallationSupport reports whether this runtime process can offer installing the +// sandbox credential-proxy certificate authority into OS trust. +// +// RPC method: sandbox.proxyCa.checkInstallationSupport. +// +// Returns: True when this process can offer installing the sandbox credential-proxy +// certificate authority into OS trust. +func (a *ServerSandboxProxyCaAPI) CheckInstallationSupport(ctx context.Context) (*SandboxProxyCaCheckInstallationSupportResult, error) { + raw, err := a.client.Request(ctx, "sandbox.proxyCa.checkInstallationSupport", nil) + if err != nil { + return nil, err + } + var result SandboxProxyCaCheckInstallationSupportResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// CheckRelevance reports whether this sandbox configuration uses the credential proxy and +// can need certificate-authority setup. +// +// RPC method: sandbox.proxyCa.checkRelevance. +// +// Parameters: Identifies the credential hosts that the persistent certificate authority of +// the sandbox credential proxy must cover. The runtime always adds the hosts from the saved +// user settings. +// +// Returns: True when the sandbox configuration uses the credential proxy and can need +// certificate-authority setup. +func (a *ServerSandboxProxyCaAPI) CheckRelevance(ctx context.Context, params *SandboxProxyCaRequest) (*SandboxProxyCaCheckRelevanceResult, error) { + raw, err := a.client.Request(ctx, "sandbox.proxyCa.checkRelevance", params) + if err != nil { + return nil, err + } + var result SandboxProxyCaCheckRelevanceResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // Creates the persistent certificate authority of the sandbox credential proxy if none is // stored, without changing OS trust, and returns the path of its public certificate. Keeps // an existing certificate authority, even one that must be rotated. Fails where OS trust is @@ -32046,6 +33645,37 @@ func (a *InternalServerFeatureFlagsAPI) Resolve(ctx context.Context, params *Fea return &result, nil } +// ResolveStartupGates resolves named gates against this installation's cached +// online-experiment assignment, for the account the runtime is already authenticated as. +// Unlike `featureFlags.resolve`, which layers static availability with the populations +// supplied, this reads the experiment assignment the runtime cached for its own current +// authentication, so a launch can honor a rollout before any session exists. The account is +// never taken from the request: naming one would read another account's cached assignments. +// The cached assignment answers immediately and any network refresh happens behind it, so +// this call does not wait on the network. Not available to an extension, which cannot carry +// the user's consent to read their assignment. +// +// RPC method: featureFlags.resolveStartupGates. +// +// Parameters: Caller population and startup inputs to resolve named online-experiment gates +// for. Carries no account: the runtime resolves the assignment for the authentication it +// already holds. +// +// Returns: The resolved gates, keyed by flag name. +// Internal: ResolveStartupGates is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerFeatureFlagsAPI) ResolveStartupGates(ctx context.Context, params *FeatureFlagsResolveStartupGatesRequest) (*FeatureFlagsResolveStartupGatesResult, error) { + raw, err := a.client.Request(ctx, "featureFlags.resolveStartupGates", params) + if err != nil { + return nil, err + } + var result FeatureFlagsResolveStartupGatesResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // Experimental: InternalServerGitAPI contains experimental APIs that may change or be // removed. type InternalServerGitAPI internalServerAPI @@ -32539,7 +34169,345 @@ func (a *InternalServerInstructionsAPI) GetInitPrompt(ctx context.Context) (*Ins return &result, nil } -// Experimental: InternalServerMCPAPI contains experimental APIs that may change or be +// Experimental: InternalServerManagedSettingsAPI contains experimental APIs that may change +// or be removed. +type InternalServerManagedSettingsAPI internalServerAPI + +// ApplyControls stamps an effective managed policy's individually-controlled entries onto a +// user settings document, returning the settings a host should actually act on. The managed +// layer wins on every plugin spec and marketplace name it names, and leaves everything it +// does not name as the user wrote it. Hosts use this rather than merging the two documents +// themselves, because the merge is per entry rather than per document and a whole-document +// overlay would either discard the user's unmanaged entries or let a user entry outrank a +// managed one. Omitting the managed layer returns the settings unchanged, which is what an +// unmanaged host wants. Rejects when either document is present but is not a JSON object +// rather than treating it as absent, since silently dropping a malformed policy hands the +// user's layer the win on exactly the entries the policy exists to control. +// +// RPC method: managedSettings.applyControls. +// +// Parameters: A user settings document and the effective managed policy whose controlled +// entries should be stamped onto it. +// +// Returns: The user settings with the managed layer's controlled entries stamped on. +// Internal: ApplyControls is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerManagedSettingsAPI) ApplyControls(ctx context.Context, params *ManagedSettingsApplyControlsParams) (*ManagedSettingsApplyControlsResult, error) { + raw, err := a.client.Request(ctx, "managedSettings.applyControls", params) + if err != nil { + return nil, err + } + var result ManagedSettingsApplyControlsResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Ingest resolves managed (enterprise policy) settings for a host from every layer at once: +// the account's server-delivered policy, the device/MDM layer, and a platform policy +// helper. Hosts use this instead of fetching and composing the layers themselves, because +// the per-layer precedence and the fail-closed rules that apply when a layer cannot be +// confirmed are the runtime's own and must match the policy a session will later enforce. +// It does not retain or apply anything to process-global policy state, so a host may call +// it before any session exists — which is the point, since plugin activation and one-shot +// commands resolve policy before a session is available to carry it. The returned per-layer +// outcome flags are load-bearing rather than diagnostic: a host must distinguish an +// unmanaged device from a managed device whose policy could not be confirmed, and apply its +// fail-closed gates in the second case. Reports its diagnostics in `logMessages` rather +// than logging them, so a host that runs before a log sink exists still sees them. +// +// RPC method: managedSettings.ingest. +// +// Parameters: Inputs describing the host and account an ingestion should resolve managed +// policy for. +// +// Returns: The managed policy layers an ingestion resolved, together with the per-layer +// outcome flags a host needs to decide how much to trust the result. The flags are reported +// rather than folded into the settings because a host must be able to distinguish an +// unmanaged device from a managed device whose policy could not be confirmed, and apply its +// fail-closed gates in the second case. +// Internal: Ingest is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerManagedSettingsAPI) Ingest(ctx context.Context, params *ManagedSettingsIngestParams) (*ManagedSettingsIngestResult, error) { + raw, err := a.client.Request(ctx, "managedSettings.ingest", params) + if err != nil { + return nil, err + } + var result ManagedSettingsIngestResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// LoadRemoteControl resolves the managed `remoteControl` policy for an account on its own, +// for a host deciding whether a remote-control session may start. Composes the same layers +// as `managedSettings.ingest` and returns only that one key, so a host does not have to +// know which layer won. An absent policy means the account is unmanaged for this capability +// and the host may proceed; that default is safe only while absence really does mean "no +// policy", so a service refusal that says an account policy exists which this client is too +// old to enforce resolves to an explicit disabled policy instead of to absence. A +// resolution that cannot be completed is rejected rather than answered as absence, for the +// same reason. +// +// RPC method: managedSettings.loadRemoteControl. +// +// Parameters: Inputs describing the host and account whose managed remote-control policy +// should be resolved. Mirrors `managedSettings.ingest`, and deliberately carries no +// retention decision: reading this gate never becomes this runtime process's startup policy. +// +// Returns: The managed remote-control policy in force for an account, if any. An absent +// policy means the account is unmanaged for this capability, which a host reads as allowed +// — so absence here is a positive statement that no policy applies, never a stand-in for a +// resolution that failed. A resolution that cannot be completed is rejected instead. +// Internal: LoadRemoteControl is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerManagedSettingsAPI) LoadRemoteControl(ctx context.Context, params *ManagedSettingsLoadRemoteControlParams) (*ManagedSettingsLoadRemoteControlResult, error) { + raw, err := a.client.Request(ctx, "managedSettings.loadRemoteControl", params) + if err != nil { + return nil, err + } + var result ManagedSettingsLoadRemoteControlResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ParseClientValue validates the managed settings a client is supplying for a session it is +// about to open, and returns them reduced to the keys a client is allowed to set. A +// client-supplied policy is not the same thing as an administrator's: it may only narrow +// permissions, so this accepts `permissions` and rejects every other key outright rather +// than ignoring it. Rejecting is the point — a host that silently dropped an unsupported +// key would report a policy as applied while running without it. Hosts call this before +// opening the session rather than letting the open fail, so a malformed policy is reported +// against the request that carried it. The runtime applies the same rule again when the +// session starts, so this cannot be used to smuggle a wider document past it. An accepted +// document that sets nothing comes back as an empty object, which is distinct from +// supplying nothing at all. +// +// RPC method: managedSettings.parseClientValue. +// +// Parameters: The client-supplied managed settings to validate and normalize. Omitting them +// is valid and yields no policy. +// +// Returns: The accepted managed settings, reduced to the keys a client is allowed to set. +// Internal: ParseClientValue is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerManagedSettingsAPI) ParseClientValue(ctx context.Context, params *ManagedSettingsParseClientValueParams) (*ManagedSettingsParseClientValueResult, error) { + raw, err := a.client.Request(ctx, "managedSettings.parseClientValue", params) + if err != nil { + return nil, err + } + var result ManagedSettingsParseClientValueResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ReadDevice discovers device-managed settings the way the runtime's own device layer does, +// and reports the sandbox floor and the load outcome alongside the validated document. This +// differs from `managedSettings.read` in three ways a policy-enforcing host depends on: a +// document that validates to an empty object is reported as absent rather than as an empty +// policy, a discovery error does not suppress a document that still validates, and a +// failure is reported as a flag rather than only as error text. Hosts that compose the +// device layer into an effective policy use this, because `managedSettings.read` cannot +// distinguish "no device policy" from "device policy could not be read" and would silently +// hand the user's own layer the win. +// +// RPC method: managedSettings.readDevice. +// +// Returns: The device-managed settings layer, with the sandbox floor and the load outcome a +// host needs to compose it into an effective policy. +// Internal: ReadDevice is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerManagedSettingsAPI) ReadDevice(ctx context.Context) (*ManagedSettingsReadDeviceResult, error) { + raw, err := a.client.Request(ctx, "managedSettings.readDevice", nil) + if err != nil { + return nil, err + } + var result ManagedSettingsReadDeviceResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ResolveBypassDisableTransition decides what a host must do to its bypass-permissions +// state after a managed-policy resolution lands, given the state already in force and the +// account now signed in. A host holds two pieces of state — which layer disabled bypass +// mode, and for a server-delivered disable, the account it was pinned to — and cannot +// decide the next step from the new policy alone. Three rules make that so, and each one is +// a control rather than a preference. A device/MDM disable outranks the account, so a later +// server answer never lifts it. An unknown policy, which is what a failed fetch or a +// refusal this build cannot enforce yields, preserves whatever is in force instead of +// reverting to permissive. And a server disable is lifted only when the account it was +// pinned to is no longer the signed-in one, which is what makes signing in to an +// unrestricted account recover without a restart while a reconnect on the same restricted +// account does not. Hosts call this rather than reimplementing it because getting the +// pinning backwards either strands a disable on an account that never carried one or drops +// one that still applies. `setDisabledState` is omitted when the host must leave its stored +// flag untouched, which is distinct from being told to set it to false. +// +// RPC method: managedSettings.resolveBypassDisableTransition. +// +// Parameters: The bypass-permissions state a host holds today, the account now signed in, +// and what the managed-policy resolution said. +// +// Returns: The bypass-permissions state a host should hold after the resolution, and what +// it must do to get there. +// Internal: ResolveBypassDisableTransition is part of the SDK's internal +// handshake/plumbing; external callers should not use it. +func (a *InternalServerManagedSettingsAPI) ResolveBypassDisableTransition(ctx context.Context, params *ManagedSettingsResolveBypassDisableTransitionParams) (*ManagedSettingsResolveBypassDisableTransitionResult, error) { + raw, err := a.client.Request(ctx, "managedSettings.resolveBypassDisableTransition", params) + if err != nil { + return nil, err + } + var result ManagedSettingsResolveBypassDisableTransitionResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ResolveDeviceForceLoginOrgsGate evaluates the device-channel enterprise sign-in pin (MDM +// plist, registry, or managed-settings file) against a credential, without resolving any +// server-delivered policy. This is the gate an entry point runs before it branches, and the +// only one that can refuse a developer's first sign-in: it is local, needs no credential, +// and a server-delivered pin only ever reaches accounts already inside the organization. It +// fails closed by construction — a discovery that cannot determine whether a pin exists +// refuses rather than allows, because a control that fails open under a triggerable +// condition is not a control. Hosts that also want the server channel should call +// `managedSettings.resolveStartupPolicy`, which folds both channels into one verdict. +// +// RPC method: managedSettings.resolveDeviceForceLoginOrgsGate. +// +// Parameters: The credential and environment to evaluate the device-channel sign-in pin +// against. +// +// Returns: The verdict of the `forceLoginOrgs` enterprise sign-in pin for one credential. A +// managed device may pin Copilot to an approved set of GitHub organizations so a developer +// cannot sign in with a personal — or another enterprise's — account and escape every +// control that keys off the signed-in identity. A host must refuse to proceed when +// `allowed` is false; the remaining fields explain the refusal rather than qualifying it. +// Internal: ResolveDeviceForceLoginOrgsGate is part of the SDK's internal +// handshake/plumbing; external callers should not use it. +func (a *InternalServerManagedSettingsAPI) ResolveDeviceForceLoginOrgsGate(ctx context.Context, params *ManagedSettingsResolveDeviceForceLoginOrgsGateParams) (*ForceLoginOrgsDecision, error) { + raw, err := a.client.Request(ctx, "managedSettings.resolveDeviceForceLoginOrgsGate", params) + if err != nil { + return nil, err + } + var result ForceLoginOrgsDecision + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ResolveEffectiveValue composes the supplied server, device/MDM, device sandbox floor and +// policy-helper layers into the single effective managed policy a host should enforce, +// resolving each key across the layers by the runtime's own precedence rules. Hosts that +// assemble managed layers themselves use this so their precedence matches the runtime's +// exactly instead of reimplementing it. The composition is not a pure function of its +// inputs: an advisory sandbox force-on that arrived over the server channel is declined +// when this host cannot run a sandbox, so the result reflects the runtime host's +// capabilities, and the returned settings carry `sandboxAdvisoryFloorDeclined: true` when +// that happened. Enforced channels (device/MDM and policy helper) are never declined, and a +// server force-on carrying `failIfUnavailable` is preserved so the session fails loudly +// instead of quietly running unsandboxed. Rejects when a supplied layer is present but is +// not a JSON object, rather than treating it as unmanaged, because silently dropping a +// malformed policy would hand the user's own layer the win on exactly the keys the policy +// exists to control. +// +// RPC method: managedSettings.resolveEffectiveValue. +// +// Parameters: The managed-settings layers to compose into an effective policy. Every layer +// is optional; omitting all of them yields no effective policy. +// +// Returns: The effective managed policy composed from the supplied layers. +// Internal: ResolveEffectiveValue is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerManagedSettingsAPI) ResolveEffectiveValue(ctx context.Context, params *ManagedSettingsResolveEffectiveValueParams) (*ManagedSettingsResolveEffectiveValueResult, error) { + raw, err := a.client.Request(ctx, "managedSettings.resolveEffectiveValue", params) + if err != nil { + return nil, err + } + var result ManagedSettingsResolveEffectiveValueResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ResolveStartupPolicy resolves the managed (enterprise policy) settings a host must +// enforce from startup, and judges the account against the enterprise sign-in pin in the +// same pass. This composes the layers the way `managedSettings.ingest` does and then +// answers the two questions a host cannot answer for itself: which fail-closed floors apply +// when a layer could not be confirmed, and whether this credential is allowed to sign in at +// all. The sign-in verdict is the reason a host must not assemble this itself from +// `managedSettings.ingest` — a pinned organization is an access control, and a host that +// composed the layers but skipped the pin would let a developer sign in with a personal or +// another enterprise's account and escape every control that keys off the signed-in +// identity. The verdict is computed on every resolution, including one that is not +// retained, so declining to apply policy never widens access. Set `retainAndApply` to keep +// the resolved policy as this runtime process's startup policy; leave it false to resolve +// without side effects. +// +// RPC method: managedSettings.resolveStartupPolicy. +// +// Parameters: Inputs describing the host and account a startup policy resolution should run +// for. Mirrors `managedSettings.ingest`, and adds the decision of whether the resolved +// policy is retained for this runtime process. +// +// Returns: The startup policy a resolution composed, the per-layer outcome flags a host +// needs to decide how much to trust it, and the enterprise sign-in verdict for the +// credential it ran against. The flags are reported rather than folded into the settings +// because a host must distinguish an unmanaged device from a managed device whose policy +// could not be confirmed, and apply its fail-closed gates in the second case. +// Internal: ResolveStartupPolicy is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerManagedSettingsAPI) ResolveStartupPolicy(ctx context.Context, params *ManagedSettingsResolveStartupPolicyParams) (*ManagedSettingsResolveStartupPolicyResult, error) { + raw, err := a.client.Request(ctx, "managedSettings.resolveStartupPolicy", params) + if err != nil { + return nil, err + } + var result ManagedSettingsResolveStartupPolicyResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// RetainPolicy retains the supplied managed layers as this runtime process's startup policy +// and re-applies the result to every live session. Hosts that own their own short-lived +// process policy use this, so a guarded mutation is checked against the policy the host +// actually fetched. Retaining is a whole-process replacement rather than a merge, so a host +// that already resolved a good policy must not retain a partial one over it. The failure +// flags are honest inputs rather than assumptions: reporting a fetch or load that failed +// keeps the layers already retained, and the interim fail-closed state, instead of clearing +// them. +// +// RPC method: managedSettings.retainPolicy. +// +// Parameters: The managed layers to retain as this process's startup policy, with the +// outcome of fetching each one. +// Internal: RetainPolicy is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerManagedSettingsAPI) RetainPolicy(ctx context.Context, params *ManagedSettingsRetainPolicyParams) (*ManagedSettingsRetainPolicyResult, error) { + raw, err := a.client.Request(ctx, "managedSettings.retainPolicy", params) + if err != nil { + return nil, err + } + var result ManagedSettingsRetainPolicyResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: InternalServerMCPAPI contains experimental APIs that may change or be // removed. type InternalServerMCPAPI internalServerAPI @@ -32661,96 +34629,681 @@ func (a *InternalServerMCPRegistryAPI) Cancel(ctx context.Context, params *MCPRe // Parameters: Registry search terms, the credential to search under, and the request id // that makes the search cancellable. // -// Returns: Servers selected from the registry response. -// Internal: Search is part of the SDK's internal handshake/plumbing; external callers +// Returns: Servers selected from the registry response. +// Internal: Search is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerMCPRegistryAPI) Search(ctx context.Context, params *MCPRegistrySearchRequest) (*MCPRegistrySearchResult, error) { + raw, err := a.client.Request(ctx, "mcp.registry.search", params) + if err != nil { + return nil, err + } + var result MCPRegistrySearchResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: Registry returns experimental APIs that may change or be removed. +func (s *InternalServerMCPAPI) Registry() *InternalServerMCPRegistryAPI { + return (*InternalServerMCPRegistryAPI)(s) +} + +// Experimental: InternalServerPermissionsAPI contains experimental APIs that may change or +// be removed. +type InternalServerPermissionsAPI internalServerAPI + +// EvaluateManagedPolicy interprets a verbatim managed `permissions` slice into the three +// policy questions a host asks before granting elevated permissions: whether +// bypass-permissions mode is forbidden, whether a policy exists that this build could not +// determine, and whether the layer supplies permission rules the session must enforce. An +// absent or empty slice means no managed policy applies. The runtime and its permission +// service share one policy type, so a new managed permission setting is interpreted in +// exactly one place; a host that reimplements the reading would silently diverge the first +// time that set grows. Hosts must fail closed on an undetermined policy rather than +// treating it as permission granted. +// +// RPC method: permissions.evaluateManagedPolicy. +// +// Parameters: The verbatim managed `permissions` slice to interpret. +// +// Returns: The policy questions a host asks before granting elevated permissions. +// Internal: EvaluateManagedPolicy is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerPermissionsAPI) EvaluateManagedPolicy(ctx context.Context, params *PermissionsEvaluateManagedPolicyParams) (*PermissionsEvaluateManagedPolicyResult, error) { + raw, err := a.client.Request(ctx, "permissions.evaluateManagedPolicy", params) + if err != nil { + return nil, err + } + var result PermissionsEvaluateManagedPolicyResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: InternalServerPermissionsFolderTrustAPI contains experimental APIs that may +// change or be removed. +type InternalServerPermissionsFolderTrustAPI internalServerAPI + +// CheckTrust reports whether a folder is trusted, reading the persisted trusted-folders +// list directly rather than through a session. Use this from a host that has no session +// yet, such as a one-shot command deciding whether to honor a checkout's own settings. It +// differs from the session-scoped check in two ways that matter: it takes the configuration +// directory to read the list from, instead of inheriting the session's, and it answers only +// from the persisted list, so trust a user granted for the lifetime of one session is not +// visible here. A host that has a session should prefer the session-scoped check, which +// also covers session-only trust. +// +// RPC method: permissions.folderTrust.checkTrust. +// +// Parameters: A folder to check against a persisted trusted-folders list, and the +// configuration directory holding that list. +// +// Returns: Folder trust check result. +// Internal: CheckTrust is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerPermissionsFolderTrustAPI) CheckTrust(ctx context.Context, params *FolderTrustIsTrustedParams) (*FolderTrustCheckResult, error) { + raw, err := a.client.Request(ctx, "permissions.folderTrust.checkTrust", params) + if err != nil { + return nil, err + } + var result FolderTrustCheckResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: FolderTrust returns experimental APIs that may change or be removed. +func (s *InternalServerPermissionsAPI) FolderTrust() *InternalServerPermissionsFolderTrustAPI { + return (*InternalServerPermissionsFolderTrustAPI)(s) +} + +// Experimental: InternalServerPermissionsLocationsAPI contains experimental APIs that may +// change or be removed. +type InternalServerPermissionsLocationsAPI internalServerAPI + +// CleanupOrphaned drops stored per-location permission grants whose directory no longer +// exists, and reports which location keys were removed. Runs against the permission store +// under the runtime's own Copilot home, the same store +// `session.permissions.locations.resolve` reads. Marked internal because it exists to carry +// a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, +// not a surface consumers are meant to depend on. It can become public once an SDK consumer +// needs to prune its own permission store. +// +// RPC method: permissions.locations.cleanupOrphaned. +// +// Returns: Which stored location permissions were dropped because their directory is gone. +// Internal: CleanupOrphaned is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerPermissionsLocationsAPI) CleanupOrphaned(ctx context.Context) (*LocationPermissionsCleanupResult, error) { + raw, err := a.client.Request(ctx, "permissions.locations.cleanupOrphaned", nil) + if err != nil { + return nil, err + } + var result LocationPermissionsCleanupResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: Locations returns experimental APIs that may change or be removed. +func (s *InternalServerPermissionsAPI) Locations() *InternalServerPermissionsLocationsAPI { + return (*InternalServerPermissionsLocationsAPI)(s) +} + +// Experimental: InternalServerPersistenceAPI contains experimental APIs that may change or +// be removed. +type InternalServerPersistenceAPI internalServerAPI + +// WriteRawJsonLocked atomically replaces a JSON file's entire contents while holding the +// runtime's per-path lock. The lock lives in the runtime process, so a host that writes +// these files itself takes no part in it and can tear a concurrent runtime write; route the +// write here instead. Unlike a merging write this never reads or parses the existing file, +// so a previously corrupted snapshot is replaced wholesale rather than failing every later +// write. Use it only for callers that always persist a complete snapshot. +// +// RPC method: persistence.writeRawJsonLocked. +// +// Parameters: A complete JSON snapshot to write under the runtime's per-path file lock. +// +// Returns: The outcome of a locked snapshot write. +// Internal: WriteRawJsonLocked is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerPersistenceAPI) WriteRawJsonLocked(ctx context.Context, params *PersistenceWriteRawJSONLockedRequest) (*PersistenceWriteRawJSONLockedResult, error) { + raw, err := a.client.Request(ctx, "persistence.writeRawJsonLocked", params) + if err != nil { + return nil, err + } + var result PersistenceWriteRawJSONLockedResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: InternalServerRepoAPI contains experimental APIs that may change or be +// removed. +type InternalServerRepoAPI internalServerAPI + +// Experimental: InternalServerRepoSettingsAPI contains experimental APIs that may change or +// be removed. +type InternalServerRepoSettingsAPI internalServerAPI + +// Edit atomically edits one allowed top-level repository setting. Reads the raw file, +// preserves unrelated keys, applies one scalar or list edit, validates the result and +// writes under one file lock, so concurrent sibling or list edits are not lost. A malformed +// or unsafe existing file returns `invalid` without a write; rejected keys, invalid values +// and I/O errors reject the call. +// +// RPC method: repo.settings.edit. +// +// Parameters: One atomic edit of an allowed top-level repository setting. +// +// Returns: Outcome of an atomic user or repository settings edit. +// Internal: Edit is part of the SDK's internal handshake/plumbing; external callers should +// not use it. +func (a *InternalServerRepoSettingsAPI) Edit(ctx context.Context, params *RepoSettingsEditRequest) (*SettingsEditResult, error) { + raw, err := a.client.Request(ctx, "repo.settings.edit", params) + if err != nil { + return nil, err + } + var result SettingsEditResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ReadRaw reads one repository settings file without settings normalization or layering. +// The existing JSONC parser accepts comments and trailing commas and applies its +// prototype-safety rules. Missing or blank files return an empty valid config. Invalid +// files return an empty config with invalid=true; other read failures reject. +// +// RPC method: repo.settings.readRaw. +// +// Parameters: Which repository settings file to read. +// +// Returns: Parsed repository settings without normalization or layering. +// Internal: ReadRaw is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerRepoSettingsAPI) ReadRaw(ctx context.Context, params *RepoSettingsReadRawRequest) (*RepoSettingsReadRawResult, error) { + raw, err := a.client.Request(ctx, "repo.settings.readRaw", params) + if err != nil { + return nil, err + } + var result RepoSettingsReadRawResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// WriteAll replaces the repository-overridable settings in one locked write. Allowed keys +// present in settings are validated and written; allowed keys absent from settings are +// removed. Other input keys are ignored, and unknown keys already stored in the file remain +// unchanged. Invalid values or an invalid existing file reject without a partial write. +// +// RPC method: repo.settings.writeAll. +// +// Parameters: The complete set of repository-overridable settings to store. +// Internal: WriteAll is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerRepoSettingsAPI) WriteAll(ctx context.Context, params *RepoSettingsWriteAllRequest) (*RepoSettingsWriteAllResult, error) { + raw, err := a.client.Request(ctx, "repo.settings.writeAll", params) + if err != nil { + return nil, err + } + var result RepoSettingsWriteAllResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// WriteKey writes or removes one allowed top-level repository setting through the existing +// validator and file lock. Preserves unrelated stored keys. Invalid keys, values, existing +// documents, and I/O errors reject without replacing the file. Deletion requires +// delete=true; otherwise value must be present. +// +// RPC method: repo.settings.writeKey. +// +// Parameters: One key to write or remove in a repository settings file. +// Internal: WriteKey is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerRepoSettingsAPI) WriteKey(ctx context.Context, params *RepoSettingsWriteKeyRequest) (*RepoSettingsWriteKeyResult, error) { + raw, err := a.client.Request(ctx, "repo.settings.writeKey", params) + if err != nil { + return nil, err + } + var result RepoSettingsWriteKeyResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: Settings returns experimental APIs that may change or be removed. +func (s *InternalServerRepoAPI) Settings() *InternalServerRepoSettingsAPI { + return (*InternalServerRepoSettingsAPI)(s) +} + +// Experimental: InternalServerSandboxAPI contains experimental APIs that may change or be +// removed. +type InternalServerSandboxAPI internalServerAPI + +// CheckEnforcementCommand whether one slash command stays reachable while sandbox +// enforcement is unavailable and the session is otherwise blocked. The permitted set is +// deliberately narrow — commands that only report state, and the few that let the user +// repair or leave the situation — and it is keyed on the arguments as well as the name, so +// `/sandbox status` is admitted where `/sandbox enable` is not. A host must ask rather than +// keep its own list: a command this returns false for is one the runtime would refuse +// anyway, and a divergent list either strands the user with no way out or admits a command +// that acts on an unenforced session. +// +// RPC method: sandbox.checkEnforcementCommand. +// +// Parameters: One slash command, as typed, to test against the enforcement-block allowlist. +// +// Returns: True when the command stays available while enforcement is blocked. +// Internal: CheckEnforcementCommand is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerSandboxAPI) CheckEnforcementCommand(ctx context.Context, params *SandboxEnforcementCommandAllowedParams) (*SandboxCheckEnforcementCommandResult, error) { + raw, err := a.client.Request(ctx, "sandbox.checkEnforcementCommand", params) + if err != nil { + return nil, err + } + var result SandboxCheckEnforcementCommandResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// CheckPlatformSupport reports whether this machine can run an OS-level command sandbox at +// all. A host must ask before it offers sandboxing, because the answer is a property of the +// machine rather than of any setting: on Linux it depends on bubblewrap being installed, +// and on Windows on the OS build supporting BaseContainer. Probing it requires spawning a +// process the first time, so the answer is cached for the life of the runtime. A host that +// assumes support and enables the sandbox anyway produces a session in which every shell +// command fails. +// +// RPC method: sandbox.checkPlatformSupport. +// +// Returns: True when an OS-level sandbox can run on this host. +// Internal: CheckPlatformSupport is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerSandboxAPI) CheckPlatformSupport(ctx context.Context) (*SandboxCheckPlatformSupportResult, error) { + raw, err := a.client.Request(ctx, "sandbox.checkPlatformSupport", nil) + if err != nil { + return nil, err + } + var result SandboxCheckPlatformSupportResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// CheckWindowsHostLoopbackSupport reports whether this Windows host's BaseContainer +// implementation can reach the host's loopback interface directly, which is what a +// local-network policy needs to avoid routing through the egress proxy. Like +// `sandbox.checkPlatformSupport`, the answer is a property of the machine's OS build rather +// than of any setting, and resolving it the first time spawns a platform probe. A host that +// offers the direct local-network option on a machine that lacks the capability produces a +// session whose sandboxed commands cannot reach local services. Always false off Windows. +// +// RPC method: sandbox.checkWindowsHostLoopbackSupport. +// +// Returns: True when the sandbox on this host can reach host loopback directly. +// Internal: CheckWindowsHostLoopbackSupport is part of the SDK's internal +// handshake/plumbing; external callers should not use it. +func (a *InternalServerSandboxAPI) CheckWindowsHostLoopbackSupport(ctx context.Context) (*SandboxCheckWindowsHostLoopbackSupportResult, error) { + raw, err := a.client.Request(ctx, "sandbox.checkWindowsHostLoopbackSupport", nil) + if err != nil { + return nil, err + } + var result SandboxCheckWindowsHostLoopbackSupportResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// FilterPickerCandidates checks a batch of `@`-file picker suggestions against a policy +// prepared by `sandbox.preparePickerPolicy` and returns one allow decision per candidate, +// positionally aligned with the request. Batched deliberately: each check canonicalizes a +// path component-by-component through the real filesystem, so one call amortizes that over +// a single hop rather than dozens while the user types. A directory the policy does not +// itself allow can still be kept as a waypoint to an allowed subtree. An absent policy +// keeps every candidate. +// +// RPC method: sandbox.filterPickerCandidates. +// +// Parameters: A batch of file-picker candidates to check against a prepared policy. +// +// Returns: Per-candidate allow decisions, positionally aligned with the request. +// Internal: FilterPickerCandidates is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerSandboxAPI) FilterPickerCandidates(ctx context.Context, params *SandboxFilterPickerCandidatesParams) (*SandboxFilterPickerCandidatesResult, error) { + raw, err := a.client.Request(ctx, "sandbox.filterPickerCandidates", params) + if err != nil { + return nil, err + } + var result SandboxFilterPickerCandidatesResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetDocsUrl returns the documentation URL a host should point a user at when it declines +// or downgrades a sandbox setting. The runtime owns the address so every surface cites the +// same page and a host does not hard-code a link that later moves. +// +// RPC method: sandbox.getDocsUrl. +// +// Returns: The documentation URL a host cites when it declines or downgrades a sandbox +// setting. +// Internal: GetDocsUrl is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerSandboxAPI) GetDocsUrl(ctx context.Context) (*SandboxDocsURLResult, error) { + raw, err := a.client.Request(ctx, "sandbox.getDocsUrl", nil) + if err != nil { + return nil, err + } + var result SandboxDocsURLResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetUnsupportedMessage the explanation a host shows when it refuses an explicit request to +// turn the sandbox on for a machine that cannot run one. Carries the platform-specific +// remedy — install bubblewrap, update Windows — and the documentation link, so a host that +// got `false` from `sandbox.checkPlatformSupport` does not have to compose its own reason +// and cannot describe the same machine differently from the runtime's own spawn path. +// +// RPC method: sandbox.getUnsupportedMessage. +// +// Returns: The user-facing refusal, including the platform remedy and the documentation +// link. +// Internal: GetUnsupportedMessage is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerSandboxAPI) GetUnsupportedMessage(ctx context.Context) (*SandboxGetUnsupportedMessageResult, error) { + raw, err := a.client.Request(ctx, "sandbox.getUnsupportedMessage", nil) + if err != nil { + return nil, err + } + var result SandboxGetUnsupportedMessageResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetUnsupportedSettingDisabledNotice the notice a host shows when a stored `sandbox` +// setting is being ignored for this session because the machine cannot enforce it. Distinct +// from `sandbox.getUnsupportedMessage`, which refuses an explicit request: this one reports +// that a setting the user already saved is inert, states that commands will run +// unsandboxed, and confirms the stored setting itself is left alone. A host that stays +// silent here leaves the user believing a sandbox is active. +// +// RPC method: sandbox.getUnsupportedSettingDisabledNotice. +// +// Returns: The user-facing notice that a saved sandbox setting is inert for this session. +// Internal: GetUnsupportedSettingDisabledNotice is part of the SDK's internal +// handshake/plumbing; external callers should not use it. +func (a *InternalServerSandboxAPI) GetUnsupportedSettingDisabledNotice(ctx context.Context) (*SandboxGetUnsupportedSettingDisabledNoticeResult, error) { + raw, err := a.client.Request(ctx, "sandbox.getUnsupportedSettingDisabledNotice", nil) + if err != nil { + return nil, err + } + var result SandboxGetUnsupportedSettingDisabledNoticeResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// GetUnsupportedStartupNotice the warning a host prints at startup when a session asked for +// a sandbox on a machine that cannot run one. The third of the unsupported notices, and the +// only one that depends on the policy in force: it names the remedy the reader can actually +// act on, which is the stored setting for an unmanaged host, an administrator for a managed +// one, and waiting for the policy to resolve when the sandbox stayed on only because the +// policy could not be determined. Returns no notice when the machine does support a +// sandbox, so a host can call it unconditionally on the startup path. A host that composes +// its own warning tells a managed user to change a setting their policy will overwrite. +// +// RPC method: sandbox.getUnsupportedStartupNotice. +// +// Parameters: The managed sandbox policy in force, which selects which remedy the notice +// offers. +// +// Returns: The startup warning, absent when the machine can run a sandbox. +// Internal: GetUnsupportedStartupNotice is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerSandboxAPI) GetUnsupportedStartupNotice(ctx context.Context, params *SandboxUnsupportedStartupNoticeParams) (*SandboxUnsupportedStartupNoticeResult, error) { + raw, err := a.client.Request(ctx, "sandbox.getUnsupportedStartupNotice", params) + if err != nil { + return nil, err + } + var result SandboxUnsupportedStartupNoticeResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// PreparePickerPolicy builds the effective filesystem policy one `@`-file picker checks its +// suggestions against, so Git discovery and grant canonicalization run once for the +// picker's lifetime instead of on every debounced keystroke. Returns no policy when the +// sandbox is absent or disabled, which the paired filter reads as "keep every candidate". A +// host must pair this with `sandbox.filterPickerCandidates` rather than resolve a grant +// list itself, because the picker's grants are narrower than a file tool's — the same path +// a built-in tool may read can be one the picker must not offer. +// +// RPC method: sandbox.preparePickerPolicy. +// +// Parameters: The working directory and sandbox settings to build a file-picker policy from. +// +// Returns: The prepared file-picker policy, or none when the sandbox is disabled. +// Internal: PreparePickerPolicy is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerSandboxAPI) PreparePickerPolicy(ctx context.Context, params *SandboxPreparePickerPolicyParams) (*SandboxPreparePickerPolicyResult, error) { + raw, err := a.client.Request(ctx, "sandbox.preparePickerPolicy", params) + if err != nil { + return nil, err + } + var result SandboxPreparePickerPolicyResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ResolveFlooredConfig raises a user's sandbox settings to an administrator's managed +// sandbox floor and returns the result a session should actually run under. The floor can +// only tighten: an enterprise force-on is reflected even when the user's own `enabled` is +// false, and a user cannot lower a setting the floor raised. The result is normalized +// through the declared sandbox shape, so a key reorder or an undeclared passthrough key is +// not mistaken for a policy change by callers that diff two results. A host must call this +// rather than merge the two layers itself, because reimplementing the direction of the fold +// is what turns an administrator's floor into a suggestion. +// +// RPC method: sandbox.resolveFlooredConfig. +// +// Parameters: The user's sandbox settings and the managed sandbox floor to raise them to. +// +// Returns: The user's sandbox settings raised to the managed floor. +// Internal: ResolveFlooredConfig is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerSandboxAPI) ResolveFlooredConfig(ctx context.Context, params *SandboxResolveFlooredConfigParams) (*SandboxResolveFlooredConfigResult, error) { + raw, err := a.client.Request(ctx, "sandbox.resolveFlooredConfig", params) + if err != nil { + return nil, err + } + var result SandboxResolveFlooredConfigResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// ResolveForOptional the sandbox a single named feature actually launches under, which is +// not the same as the session's sandbox. A feature is routed out of the sandbox by its own +// flag — `sandboxMcpServers`, `sandboxLspServers` — so an enabled session can still start +// one server confined and another free. Returns a disabled sandbox rather than an error +// when the host has no sandbox slice at all, so an absent config and an opted-out feature +// read alike at the launch site. A host must ask per feature rather than reuse the session +// config, because reading only `enabled` confines a server the user opted out of, or +// reports as sandboxed one that is not. +// +// RPC method: sandbox.resolveForOptional. +// +// Parameters: A sandbox config and the per-feature routing flag to resolve it for. +// +// Returns: The sandbox a named feature actually launches under. +// Internal: ResolveForOptional is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerSandboxAPI) ResolveForOptional(ctx context.Context, params *SandboxEffectiveForOptionalParams) (*SandboxEffectiveForOptionalResult, error) { + raw, err := a.client.Request(ctx, "sandbox.resolveForOptional", params) + if err != nil { + return nil, err + } + var result SandboxEffectiveForOptionalResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Experimental: InternalServerSandboxProxySecretAPI contains experimental APIs that may +// change or be removed. +type InternalServerSandboxProxySecretAPI internalServerAPI + +// Delete removes the stored sandbox proxy password from the credential store +// `sandbox.proxySecret.getLocation` names. Succeeds when no entry exists, so it is safe to +// call while clearing a proxy password whose origin is unknown. Marked internal because it +// exists to carry a CLI call site off the napi boundary onto the SDK contract. +// +// RPC method: sandbox.proxySecret.delete. +// Internal: Delete is part of the SDK's internal handshake/plumbing; external callers // should not use it. -func (a *InternalServerMCPRegistryAPI) Search(ctx context.Context, params *MCPRegistrySearchRequest) (*MCPRegistrySearchResult, error) { - raw, err := a.client.Request(ctx, "mcp.registry.search", params) +func (a *InternalServerSandboxProxySecretAPI) Delete(ctx context.Context) (*SandboxProxySecretDeleteResult, error) { + raw, err := a.client.Request(ctx, "sandbox.proxySecret.delete", nil) if err != nil { return nil, err } - var result MCPRegistrySearchResult + var result SandboxProxySecretDeleteResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// Experimental: Registry returns experimental APIs that may change or be removed. -func (s *InternalServerMCPAPI) Registry() *InternalServerMCPRegistryAPI { - return (*InternalServerMCPRegistryAPI)(s) +// Get reads the stored sandbox proxy password from the credential store +// `sandbox.proxySecret.getLocation` names, preferring the OS keychain and falling back to +// the on-disk store. Reports an absent value rather than failing when no entry exists. +// Marked internal because it exists to carry a CLI call site off the napi boundary onto the +// SDK contract. +// +// RPC method: sandbox.proxySecret.get. +// +// Returns: The stored sandbox proxy password, if one is present. +// Internal: Get is part of the SDK's internal handshake/plumbing; external callers should +// not use it. +func (a *InternalServerSandboxProxySecretAPI) Get(ctx context.Context) (*SandboxProxySecretGetResult, error) { + raw, err := a.client.Request(ctx, "sandbox.proxySecret.get", nil) + if err != nil { + return nil, err + } + var result SandboxProxySecretGetResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil } -// Experimental: InternalServerRepoAPI contains experimental APIs that may change or be -// removed. -type InternalServerRepoAPI internalServerAPI - -// Experimental: InternalServerRepoSettingsAPI contains experimental APIs that may change or -// be removed. -type InternalServerRepoSettingsAPI internalServerAPI - -// ReadRaw reads one repository settings file without settings normalization or layering. -// The existing JSONC parser accepts comments and trailing commas and applies its -// prototype-safety rules. Missing or blank files return an empty valid config. Invalid -// files return an empty config with invalid=true; other read failures reject. -// -// RPC method: repo.settings.readRaw. +// GetLocation reports where this runtime keeps the sandbox proxy password: the credential +// store directory and the entry identifier within it. Both are derived from the +// configuration directory this runtime was started with, so a host does not resolve them +// itself. Read this to recognize a `${secret:…}` value in stored sandbox settings as this +// runtime's own proxy password rather than a reference the user wrote by hand. Marked +// internal because it exists to carry a CLI call site off the napi boundary onto the SDK +// contract. // -// Parameters: Which repository settings file to read. +// RPC method: sandbox.proxySecret.getLocation. // -// Returns: Parsed repository settings without normalization or layering. -// Internal: ReadRaw is part of the SDK's internal handshake/plumbing; external callers +// Returns: Where this runtime keeps the sandbox proxy password. +// Internal: GetLocation is part of the SDK's internal handshake/plumbing; external callers // should not use it. -func (a *InternalServerRepoSettingsAPI) ReadRaw(ctx context.Context, params *RepoSettingsReadRawRequest) (*RepoSettingsReadRawResult, error) { - raw, err := a.client.Request(ctx, "repo.settings.readRaw", params) +func (a *InternalServerSandboxProxySecretAPI) GetLocation(ctx context.Context) (*SandboxProxySecretLocation, error) { + raw, err := a.client.Request(ctx, "sandbox.proxySecret.getLocation", nil) if err != nil { return nil, err } - var result RepoSettingsReadRawResult + var result SandboxProxySecretLocation if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// WriteAll replaces the repository-overridable settings in one locked write. Allowed keys -// present in settings are validated and written; allowed keys absent from settings are -// removed. Other input keys are ignored, and unknown keys already stored in the file remain -// unchanged. Invalid values or an invalid existing file reject without a partial write. +// Save stores the sandbox proxy password in the credential store +// `sandbox.proxySecret.getLocation` names, replacing any existing entry. Reports whether +// the OS keychain accepted it or it fell back to the on-disk store. Marked internal because +// it exists to carry a CLI call site off the napi boundary onto the SDK contract. // -// RPC method: repo.settings.writeAll. +// RPC method: sandbox.proxySecret.save. // -// Parameters: The complete set of repository-overridable settings to store. -// Internal: WriteAll is part of the SDK's internal handshake/plumbing; external callers -// should not use it. -func (a *InternalServerRepoSettingsAPI) WriteAll(ctx context.Context, params *RepoSettingsWriteAllRequest) (*RepoSettingsWriteAllResult, error) { - raw, err := a.client.Request(ctx, "repo.settings.writeAll", params) +// Parameters: The sandbox proxy password to store. +// +// Returns: Where the sandbox proxy password was stored. +// Internal: Save is part of the SDK's internal handshake/plumbing; external callers should +// not use it. +func (a *InternalServerSandboxProxySecretAPI) Save(ctx context.Context, params *SandboxProxySecretSaveRequest) (*SandboxProxySecretSaveResult, error) { + raw, err := a.client.Request(ctx, "sandbox.proxySecret.save", params) if err != nil { return nil, err } - var result RepoSettingsWriteAllResult + var result SandboxProxySecretSaveResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -// WriteKey writes or removes one allowed top-level repository setting through the existing -// validator and file lock. Preserves unrelated stored keys. Invalid keys, values, existing -// documents, and I/O errors reject without replacing the file. Deletion requires -// delete=true; otherwise value must be present. +// Experimental: ProxySecret returns experimental APIs that may change or be removed. +func (s *InternalServerSandboxAPI) ProxySecret() *InternalServerSandboxProxySecretAPI { + return (*InternalServerSandboxProxySecretAPI)(s) +} + +// Experimental: InternalServerSandboxSettingsAPI contains experimental APIs that may change +// or be removed. +type InternalServerSandboxSettingsAPI internalServerAPI + +// ApplyDefaults resolves a stored sandbox settings object into the effective one, filling +// every value the user left unset with its default. Read this to render or reason about the +// sandbox configuration a session would actually run under, rather than the sparse document +// the user wrote. // -// RPC method: repo.settings.writeKey. +// RPC method: sandbox.settings.applyDefaults. // -// Parameters: One key to write or remove in a repository settings file. -// Internal: WriteKey is part of the SDK's internal handshake/plumbing; external callers -// should not use it. -func (a *InternalServerRepoSettingsAPI) WriteKey(ctx context.Context, params *RepoSettingsWriteKeyRequest) (*RepoSettingsWriteKeyResult, error) { - raw, err := a.client.Request(ctx, "repo.settings.writeKey", params) +// Parameters: The stored sandbox settings to resolve against the defaults. +// +// Returns: The effective sandbox settings, with every unset value resolved to its default. +// Internal: ApplyDefaults is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerSandboxSettingsAPI) ApplyDefaults(ctx context.Context, params *SandboxApplyDefaultsRequest) (*SandboxSettingsApplyDefaultsResult, error) { + raw, err := a.client.Request(ctx, "sandbox.settings.applyDefaults", params) if err != nil { return nil, err } - var result RepoSettingsWriteKeyResult + var result SandboxSettingsApplyDefaultsResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } @@ -32758,8 +35311,8 @@ func (a *InternalServerRepoSettingsAPI) WriteKey(ctx context.Context, params *Re } // Experimental: Settings returns experimental APIs that may change or be removed. -func (s *InternalServerRepoAPI) Settings() *InternalServerRepoSettingsAPI { - return (*InternalServerRepoSettingsAPI)(s) +func (s *InternalServerSandboxAPI) Settings() *InternalServerSandboxSettingsAPI { + return (*InternalServerSandboxSettingsAPI)(s) } // Experimental: InternalServerSessionsAPI contains experimental APIs that may change or be @@ -33042,6 +35595,36 @@ func (a *InternalServerUserSettingsAPI) ApplyTopKey(ctx context.Context, params return &result, nil } +// BuildRuntime resolves the effective runtime settings for a host that is about to start a +// session, layering the given overrides over the settings documents, the environment and +// the platform defaults. A host cannot assemble this itself: the precedence between a user +// document, a repository document, the managed layers and the environment is the runtime's +// own rule, and a host that re-implements it drifts from the server it is configuring. The +// working directory, environment and platform are taken as arguments rather than read from +// the server process, so a host resolving settings for a directory other than its own gets +// that directory's answer. Nothing is written; this only computes. +// +// RPC method: user.settings.buildRuntime. +// +// Parameters: The overrides and host context to resolve effective runtime settings from. +// +// Returns: The effective runtime settings, keyed by setting name. Keys this runtime does +// not recognize are preserved rather than dropped, so a caller reading a document written +// by a newer runtime keeps every value. +// Internal: BuildRuntime is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerUserSettingsAPI) BuildRuntime(ctx context.Context, params *UserSettingsBuildRuntimeRequest) (*UserSettingsBuildRuntimeResult, error) { + raw, err := a.client.Request(ctx, "user.settings.buildRuntime", params) + if err != nil { + return nil, err + } + var result UserSettingsBuildRuntimeResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // DiagnoseProblems diagnoses a set of already-loaded settings layers, reporting each key // that will not take effect and why. Settings load tolerantly so that one bad key does not // stop a session from starting; this method surfaces what was dropped so a caller can @@ -33112,6 +35695,28 @@ func (a *InternalServerUserSettingsAPI) Edit(ctx context.Context, params *UserSe return &result, nil } +// GetPath reports the on-disk path of the settings document `user.settings.load` and +// `user.settings.set` read and write. Resolved the same way those methods resolve it, so a +// host that shows or opens the settings file names the file the runtime actually uses, +// including the extensionless legacy `settings` file when that is what is present. +// +// RPC method: user.settings.getPath. +// +// Returns: The on-disk location of the user's settings document. +// Internal: GetPath is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerUserSettingsAPI) GetPath(ctx context.Context) (*UserSettingsPathResult, error) { + raw, err := a.client.Request(ctx, "user.settings.getPath", nil) + if err != nil { + return nil, err + } + var result UserSettingsPathResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // GetPaths resolves the on-disk locations of the settings files this runtime reads, so a // consumer can show or open them. The user path is the same file `user.settings.get`, // `user.settings.load`, and `user.settings.set` operate on. Supply `repoRoot` to also @@ -33138,6 +35743,37 @@ func (a *InternalServerUserSettingsAPI) GetPaths(ctx context.Context, params *Us return &result, nil } +// GetUnknownKeysWarning reports the top-level keys in the user settings document that the +// runtime does not recognize, phrased for display to the user. This is a separate question +// from the warning `user.settings.loadWithWarning` returns: that one describes parts of the +// document the loader had to ignore to load the rest, whereas an unknown key parses cleanly +// and is simply not a setting, so a host that surfaces only the load warning silently +// accepts a misspelled key that will never take effect. Nothing is reported when the +// document is absent, unreadable, or failed to load, because an unknown-key list derived +// from a document the runtime could not read would be misleading rather than helpful. +// Inspection never modifies the document. +// +// RPC method: user.settings.getUnknownKeysWarning. +// +// Parameters: Selects the configuration directory whose user settings document should be +// inspected for unrecognized top-level keys. +// +// Returns: The unrecognized top-level keys found in the user settings document, already +// phrased for display. +// Internal: GetUnknownKeysWarning is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerUserSettingsAPI) GetUnknownKeysWarning(ctx context.Context, params *UserSettingsUnknownKeysWarningRequest) (*UserSettingsUnknownKeysWarningResult, error) { + raw, err := a.client.Request(ctx, "user.settings.getUnknownKeysWarning", params) + if err != nil { + return nil, err + } + var result UserSettingsUnknownKeysWarningResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // ListGovernanceKeys lists the top-level user-setting keys by who is allowed to govern // them: `repo` keys a repository may override through `.github/copilot/settings.json`, // `claudeRepo` keys a repository may override through a Claude-compatible config, and @@ -33161,6 +35797,63 @@ func (a *InternalServerUserSettingsAPI) ListGovernanceKeys(ctx context.Context) return &result, nil } +// LoadAndMergeRepo reads a repository's settings and merges them over a supplied user layer +// in one step, returning the settings a consumer should act on inside that repository. Use +// this rather than reading the two layers separately: the merge is per setting and +// collection-aware, so a repository adds to the collections it is allowed to influence +// without replacing the user's own entries, and a whole-document overlay would get that +// wrong. Any diagnostic raised while reading the repository layer is returned rather than +// printed, so the consumer decides how to surface it; the settings that did load are merged +// regardless. +// +// RPC method: user.settings.loadAndMergeRepo. +// +// Parameters: A repository to read settings from, and the user layer they are merged over. +// +// Returns: The settings a consumer should act on inside a repository, together with any +// diagnostic raised while reading the repository layer. +// Internal: LoadAndMergeRepo is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerUserSettingsAPI) LoadAndMergeRepo(ctx context.Context, params *UserSettingsLoadAndMergeRepoRequest) (*UserSettingsLoadAndMergeRepoResult, error) { + raw, err := a.client.Request(ctx, "user.settings.loadAndMergeRepo", params) + if err != nil { + return nil, err + } + var result UserSettingsLoadAndMergeRepoResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// LoadForConfigDir reads the user's settings document exactly as `user.settings.load` does, +// but from a caller-supplied configuration directory instead of the one the server resolved +// for itself. Use this when a consumer scopes a session to its own Copilot home — the SDK's +// per-session `configDir` override — so the settings read match the directory that session +// actually uses. An absent or empty `configDir` resolves the server's own home, making this +// identical to `user.settings.load`. Hook-validation relaxations are deliberately not +// caller-supplied: they continue to come from the server's environment, so a consumer +// cannot widen the host's hook policy through this method. +// +// RPC method: user.settings.loadForConfigDir. +// +// Parameters: Selects the configuration directory whose user settings to read. +// +// Returns: The stored user settings document, keyed by setting name. +// Internal: LoadForConfigDir is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerUserSettingsAPI) LoadForConfigDir(ctx context.Context, params *UserSettingsLoadForConfigDirRequest) (*UserSettingsLoadForConfigDirResult, error) { + raw, err := a.client.Request(ctx, "user.settings.loadForConfigDir", params) + if err != nil { + return nil, err + } + var result UserSettingsLoadForConfigDirResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // LoadForEdit reads settings.json as stored for a caller that is about to edit it. Unlike // `user.settings.get`, this returns file values rather than per-key metadata and defaults. // Reports `missing` for an absent file and `invalid` when the existing file will not parse. @@ -33183,6 +35876,213 @@ func (a *InternalServerUserSettingsAPI) LoadForEdit(ctx context.Context) (*UserS return &result, nil } +// LoadRepo reads a repository's checked-in settings document as stored, normalized, +// together with any diagnostic raised while reading it. This is the repository half of the +// layering `user.settings.get` reports: `user.settings.load` reads the user's own document, +// and this reads the one a repository checks in to govern the keys +// `user.settings.governanceKeys` lists as repo-governable. A document that fails to parse, +// or that sets a key a repository may not govern, is reported through `warning` while the +// settings that did load are still returned, so a consumer surfaces the diagnostic and +// continues rather than failing the session. When `repoRoot` is the user's home directory +// the Claude-compatible configuration is skipped, so a home-directory session does not +// inherit a personal config as repository policy. +// +// RPC method: user.settings.loadRepo. +// +// Parameters: Selects the repository whose checked-in settings to read. +// +// Returns: A repository's settings as stored, together with any diagnostic raised while +// reading them. +// Internal: LoadRepo is part of the SDK's internal handshake/plumbing; external callers +// should not use it. +func (a *InternalServerUserSettingsAPI) LoadRepo(ctx context.Context, params *UserSettingsLoadRepoRequest) (*UserSettingsLoadRepoResult, error) { + raw, err := a.client.Request(ctx, "user.settings.loadRepo", params) + if err != nil { + return nil, err + } + var result UserSettingsLoadRepoResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// LoadWithWarning reads the user's stored settings together with the diagnostic raised +// while reading them. This is `user.settings.load` plus the reason part of the document was +// ignored: that one answers the document alone, so a caller cannot tell a clean read from a +// salvaged one. Read this when the caller is about to write the file back, where accepting +// a partial parse would discard every value the loader could not read. The settings that +// did load are still reported alongside the warning, so a consumer may surface it and +// continue instead of failing. +// +// RPC method: user.settings.loadWithWarning. +// +// Returns: The user's stored settings, together with any diagnostic raised while reading +// them. +// Internal: LoadWithWarning is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerUserSettingsAPI) LoadWithWarning(ctx context.Context) (*UserSettingsLoadWithWarningResult, error) { + raw, err := a.client.Request(ctx, "user.settings.loadWithWarning", nil) + if err != nil { + return nil, err + } + var result UserSettingsLoadWithWarningResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// MergeManagedAndUser folds a user settings layer over a managed (enterprise policy) layer +// and returns the merged settings. The managed layer's governance keys win, `autoTier` +// resolves through its overridable form, and the two per-entry control maps +// (`enabledPlugins`, `extraKnownMarketplaces`) union across the layers and are then stamped +// back from the managed layer, so each entry an administrator declares wins while the user +// keeps control of the rest. The parameters are named for their layers rather than being a +// generic base/override pair: nothing about a settings object identifies which layer +// produced it, so the runtime cannot detect a transposed call, and transposing one resolves +// the governance keys in the user's favour instead of the administrator's. Supplying only +// one layer returns it unchanged, and supplying neither returns an empty object. Rejects a +// managed `autoTier` that is neither a user-configurable tier nor a single-key overridable +// form, rather than silently dropping it. +// +// RPC method: user.settings.mergeManagedAndUser. +// +// Parameters: The managed (enterprise policy) layer and the user layer to fold together. +// The field names carry the layer identity: nothing about a settings object identifies +// which layer produced it, so a generic base/override pair would let a caller transpose +// them and silently resolve the governance keys in the user's favour. +// +// Returns: The user layer folded over the managed layer. +// Internal: MergeManagedAndUser is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerUserSettingsAPI) MergeManagedAndUser(ctx context.Context, params *UserSettingsMergeManagedAndUserParams) (*UserSettingsMergeManagedAndUserResult, error) { + raw, err := a.client.Request(ctx, "user.settings.mergeManagedAndUser", params) + if err != nil { + return nil, err + } + var result UserSettingsMergeManagedAndUserResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// MergeRepoValue folds a repository's settings layer into the user layer. Each +// repo-overridable key carries a directional policy chosen so a repository can only add +// restrictions and never relax the user's own. The two per-entry managed control maps are +// the exception those directional rules cannot express — a repository may legitimately +// enable plugins and declare marketplaces — so they are re-stamped afterwards from the +// runtime's ambient managed policy. That makes the result depend on the runtime process's +// managed state and not on the arguments alone: a host must call this rather than +// reimplement the fold, or a repository could relax a restriction the administrator +// imposed. Rejects when either layer is not a JSON object. +// +// RPC method: user.settings.mergeRepoValue. +// +// Parameters: The user layer and the repository layer to fold together. +// +// Returns: The repository layer folded into the user layer. +// Internal: MergeRepoValue is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerUserSettingsAPI) MergeRepoValue(ctx context.Context, params *UserSettingsMergeRepoValueParams) (*UserSettingsMergeRepoValueResult, error) { + raw, err := a.client.Request(ctx, "user.settings.mergeRepoValue", params) + if err != nil { + return nil, err + } + var result UserSettingsMergeRepoValueResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// MigrateObsoleteOnDisk runs the one-time cleanup that removes obsolete CLI-owned settings +// and legacy rubber-duck keys from the user's settings document, and reports what it did. +// Idempotent and safe to call on every startup: with nothing obsolete left it reports +// `unchanged` and writes nothing. The cleanup preserves every key it does not recognize, so +// a setting written by a newer host is never dropped by an older one, and a document that +// fails to parse is reported `invalid` and left untouched rather than rewritten from a +// partial read. The cleaned document is not returned: it is written before this replies, so +// `user.settings.load` reads it authoritatively. A host that surfaces unrecognized keys +// through `user.settings.unknownKeys` wants this first, because the keys this retires would +// otherwise be shown to the user as if they were misspelled settings. +// +// RPC method: user.settings.migrateObsoleteOnDisk. +// +// Parameters: Selects the configuration directory whose settings document to clean. +// +// Returns: The outcome of the one-time obsolete-settings cleanup. +// Internal: MigrateObsoleteOnDisk is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerUserSettingsAPI) MigrateObsoleteOnDisk(ctx context.Context, params *UserSettingsMigrateObsoleteOnDiskRequest) (*UserSettingsMigrateObsoleteOnDiskResult, error) { + raw, err := a.client.Request(ctx, "user.settings.migrateObsoleteOnDisk", params) + if err != nil { + return nil, err + } + var result UserSettingsMigrateObsoleteOnDiskResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// MigrateStaffLogLevelOnce runs the one-time migration that moves a staff account's log +// level to the current default, and records that it ran. Idempotent and self-gating: it +// takes a lock over the global-state file and re-reads the completion stamp inside it, so +// two hosts racing at startup cannot both migrate. Only `refreshed` can have changed the +// persisted settings, and the settings it returns are the document re-read after the write, +// so a host should adopt them rather than reloading separately and racing the next writer. +// +// RPC method: user.settings.migrateStaffLogLevelOnce. +// +// Parameters: Selects the configuration directory to run the one-time staff log-level +// migration against, and supplies the caller's record of whether it has already run. +// +// Returns: The outcome of the one-time staff log-level migration. +// Internal: MigrateStaffLogLevelOnce is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerUserSettingsAPI) MigrateStaffLogLevelOnce(ctx context.Context, params *UserSettingsMigrateStaffLogLevelOnceRequest) (*UserSettingsMigrateStaffLogLevelOnceResult, error) { + raw, err := a.client.Request(ctx, "user.settings.migrateStaffLogLevelOnce", params) + if err != nil { + return nil, err + } + var result UserSettingsMigrateStaffLogLevelOnceResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// MigrateStaffUpdateChannelOnce runs the one-time migration that moves a staff account's +// update channel to stable, and records that it ran. Idempotent and self-gating: it takes a +// lock over the global-state file, re-reads the completion stamp inside it, and returns +// `current` rather than migrating twice, so two hosts racing at startup cannot both +// migrate. Only a `migrated` status means the persisted settings changed and the caller +// should reload them. An account on the experimental channel is deliberately left alone and +// reported as `excluded-experimental`. +// +// RPC method: user.settings.migrateStaffUpdateChannelOnce. +// +// Parameters: The filesystem and environment facts a user-settings file is resolved from. +// Passed explicitly rather than read from the runtime's own process, so a host whose +// configuration directory differs from its process environment resolves the file it means. +// +// Returns: The outcome of the one-time staff update-channel migration. +// Internal: MigrateStaffUpdateChannelOnce is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerUserSettingsAPI) MigrateStaffUpdateChannelOnce(ctx context.Context, params *UserSettingsHostContext) (*UserSettingsMigrateStaffUpdateChannelOnceResult, error) { + raw, err := a.client.Request(ctx, "user.settings.migrateStaffUpdateChannelOnce", params) + if err != nil { + return nil, err + } + var result UserSettingsMigrateStaffUpdateChannelOnceResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // Normalize rewrites legacy and snake_case setting names in a settings object to their // canonical spelling. A caller editing settings.json must normalize before writing: a // legacy key left in place survives the write, is re-normalized on the next load, and @@ -33207,6 +36107,58 @@ func (a *InternalServerUserSettingsAPI) Normalize(ctx context.Context, params *U return &result, nil } +// ResetStaffModelSelectionOnce runs the one-time reset that clears a staff account's pinned +// model selection, and reports the timestamp the host should record. Idempotent and +// self-gating: the reset is gated on a fixed cutoff, so a caller that passes back the +// timestamp it recorded gets `didReset: false` rather than a second reset. It applies to +// staff accounts only; any other account is reported as not reset without the settings +// document being opened. Only `didReset: true` means the persisted settings changed, and +// only then are the updated settings returned for the host to adopt. +// +// RPC method: user.settings.resetStaffModelSelectionOnce. +// +// Parameters: Selects the configuration directory to run the one-time staff model-selection +// reset against, and supplies the caller's record of whether it has already run. +// +// Returns: The outcome of the one-time staff model-selection reset. +// Internal: ResetStaffModelSelectionOnce is part of the SDK's internal handshake/plumbing; +// external callers should not use it. +func (a *InternalServerUserSettingsAPI) ResetStaffModelSelectionOnce(ctx context.Context, params *UserSettingsResetStaffModelSelectionOnceRequest) (*UserSettingsResetStaffModelSelectionOnceResult, error) { + raw, err := a.client.Request(ctx, "user.settings.resetStaffModelSelectionOnce", params) + if err != nil { + return nil, err + } + var result UserSettingsResetStaffModelSelectionOnceResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +// SetHookDisabled adds or removes one hook key in the user `disabledHooks` setting, +// rewriting settings.json in place and leaving every other setting untouched. Reports a +// typed outcome rather than failing the call, so a host can tell an unparseable settings +// file apart from a write that could not complete. +// +// RPC method: user.settings.setHookDisabled. +// +// Parameters: One hook to disable or re-enable. +// +// Returns: Outcome of rewriting the `disabledHooks` setting. +// Internal: SetHookDisabled is part of the SDK's internal handshake/plumbing; external +// callers should not use it. +func (a *InternalServerUserSettingsAPI) SetHookDisabled(ctx context.Context, params *UserSettingsSetHookDisabledRequest) (*UserSettingsSetHookDisabledResult, error) { + raw, err := a.client.Request(ctx, "user.settings.setHookDisabled", params) + if err != nil { + return nil, err + } + var result UserSettingsSetHookDisabledResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + // Update merges a partial object into one top-level user setting, re-reading the stored // value inside this runtime process's settings.json write lock so that concurrent writers // in this process to different sub-fields of the same key do not clobber each other. Unlike @@ -33303,8 +36255,12 @@ type InternalServerRPC struct { GlobalState *InternalServerGlobalStateAPI Host *InternalServerHostAPI Instructions *InternalServerInstructionsAPI + ManagedSettings *InternalServerManagedSettingsAPI MCP *InternalServerMCPAPI + Permissions *InternalServerPermissionsAPI + Persistence *InternalServerPersistenceAPI Repo *InternalServerRepoAPI + Sandbox *InternalServerSandboxAPI Sessions *InternalServerSessionsAPI User *InternalServerUserAPI } @@ -33350,8 +36306,12 @@ func NewInternalServerRPC(client *jsonrpc2.Client) *InternalServerRPC { r.GlobalState = (*InternalServerGlobalStateAPI)(&r.common) r.Host = (*InternalServerHostAPI)(&r.common) r.Instructions = (*InternalServerInstructionsAPI)(&r.common) + r.ManagedSettings = (*InternalServerManagedSettingsAPI)(&r.common) r.MCP = (*InternalServerMCPAPI)(&r.common) + r.Permissions = (*InternalServerPermissionsAPI)(&r.common) + r.Persistence = (*InternalServerPersistenceAPI)(&r.common) r.Repo = (*InternalServerRepoAPI)(&r.common) + r.Sandbox = (*InternalServerSandboxAPI)(&r.common) r.Sessions = (*InternalServerSessionsAPI)(&r.common) r.User = (*InternalServerUserAPI)(&r.common) return r diff --git a/java/scripts/codegen/java.ts b/java/scripts/codegen/java.ts index eff9e6d2bc..9f932aef75 100644 --- a/java/scripts/codegen/java.ts +++ b/java/scripts/codegen/java.ts @@ -3173,6 +3173,10 @@ function wrapperResultClassName(method: RpcMethodNode): string { // Inline result schema with properties let result = originalResult; if (result.$ref) result = resolveRef(result) as JSONSchema7; + if (result.type === "boolean" || result.type === "integer" || result.type === "number" + || (result.type === "string" && !result.enum)) { + return schemaTypeToJava(result, false, rpcResultClassName(method.rpcMethod), "value", new Map()).javaType; + } if ( result && typeof result === "object" && @@ -3230,6 +3234,11 @@ function addWrapperResultImports(resultType: string, allImports: Set, pa return; } + if (resultType === "UUID" || resultType === "OffsetDateTime") { + allImports.add(resultType === "UUID" ? "java.util.UUID" : "java.time.OffsetDateTime"); + return; + } + if (resultType.startsWith("List<")) { allImports.add("java.util.List"); } diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagsResolveStartupGatesParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagsResolveStartupGatesParams.java new file mode 100644 index 0000000000..3a08c2e5b8 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FeatureFlagsResolveStartupGatesParams.java @@ -0,0 +1,52 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * Caller population and startup inputs to resolve named online-experiment gates for. Carries no account: the runtime resolves the assignment for the authentication it already holds. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record FeatureFlagsResolveStartupGatesParams( + /** The feature flags to resolve. A name this runtime does not declare is reported as an error rather than as a disabled flag. */ + @JsonProperty("flags") List flags, + /** Whether the caller is GitHub or Microsoft staff. */ + @JsonProperty("isStaff") Boolean isStaff, + /** Whether the caller is in an experimental population. */ + @JsonProperty("isExperimental") Boolean isExperimental, + /** Whether the caller belongs to a team plan. */ + @JsonProperty("isTeam") Boolean isTeam, + /** GitHub-staff membership. Omit when it was never recorded: a legacy staff account then counts as both staff populations and keeps every staff feature. */ + @JsonProperty("isStaffGithub") Boolean isStaffGitHub, + /** Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. */ + @JsonProperty("isStaffMicrosoft") Boolean isStaffMicrosoft, + /** Environment to read flag overrides from. Defaults to this runtime process's own environment. */ + @JsonProperty("environment") Map environment, + /** User settings document whose `featureFlags` block is layered on top of the resolved set. */ + @JsonProperty("config") Object config, + /** Whether streamer mode is on, which withholds the populations an experiment would otherwise segment on. */ + @JsonProperty("streamerMode") Boolean streamerMode, + /** When this installation first launched, in milliseconds since the Unix epoch. Experiments that segment on installation age read it. Omit when the first launch was never recorded. */ + @JsonProperty("firstLaunchAtMillis") Double firstLaunchAtMillis, + /** Whether the runtime may refresh the cached assignment over the network without an active session. The refresh never blocks this call: the answer comes from the cache either way, so a refresh only affects a later launch. */ + @JsonProperty("refreshWithoutSession") Boolean refreshWithoutSession +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FolderTrustCheckResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FolderTrustCheckResult.java new file mode 100644 index 0000000000..746ad554f5 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/FolderTrustCheckResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Folder trust check result. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record FolderTrustCheckResult( + /** Whether the folder is trusted */ + @JsonProperty("trusted") Boolean trusted +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ForceLoginOrgsDecision.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ForceLoginOrgsDecision.java new file mode 100644 index 0000000000..24218c69e5 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ForceLoginOrgsDecision.java @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The verdict of the `forceLoginOrgs` enterprise sign-in pin for one credential. A managed device may pin Copilot to an approved set of GitHub organizations so a developer cannot sign in with a personal — or another enterprise's — account and escape every control that keys off the signed-in identity. A host must refuse to proceed when `allowed` is false; the remaining fields explain the refusal rather than qualifying it. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ForceLoginOrgsDecision( + /** Whether the client may proceed. True whenever no pin is in force, so an unmanaged host is never blocked. */ + @JsonProperty("allowed") Boolean allowed, + /** Whether a pin applies at all. Distinguishes "allowed because unmanaged" from "allowed because the account is approved", which a diagnostics surface needs and which also decides whether a bring-your-own-key provider may serve inference. */ + @JsonProperty("enforced") Boolean enforced, + /** The approved organization logins, as configured. Enterprise configuration rather than user data, so it is safe to name in a message or a log line. */ + @JsonProperty("requiredOrgs") List requiredOrgs, + /** The approved organization the account matched, when allowed under a pin. */ + @JsonProperty("matchedOrg") String matchedOrg, + /** A stable kebab-case reason code when refused: `org-not-approved`, `unverifiable-credential`, `policy-undetermined`, `policy-invalid`, `not-signed-in`, or `membership-unknown`. Omitted when allowed. Treat an unrecognized code as a refusal rather than mapping it to an allow: a code this host has not been taught about still denied the credential. */ + @JsonProperty("denial") String denial, + /** A developer-facing explanation of the refusal. Omitted when allowed. */ + @JsonProperty("message") String message, + /** Error-level detail from managed-policy discovery — which file failed to load, which field failed validation. Carried on the decision rather than left to the log because a refusal can exit the process before a log sink exists, which would discard the only actionable diagnostic a misconfigured managed device produces. */ + @JsonProperty("policyDiagnostics") List policyDiagnostics +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/LocationPermissionsCleanupResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/LocationPermissionsCleanupResult.java new file mode 100644 index 0000000000..ea8b72d7aa --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/LocationPermissionsCleanupResult.java @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Which stored location permissions were dropped because their directory is gone. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record LocationPermissionsCleanupResult( + /** Location keys whose grants were removed. Empty when every stored location still exists. */ + @JsonProperty("removedLocationKeys") List removedLocationKeys +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsApplyControlsParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsApplyControlsParams.java new file mode 100644 index 0000000000..fa5802b6f7 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsApplyControlsParams.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * A user settings document and the effective managed policy whose controlled entries should be stamped onto it. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsApplyControlsParams( + /** The user settings document to stamp. Entries the managed layer does not name are returned exactly as supplied. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("settings") Object settings, + /** The effective managed policy, as composed by `managedSettings.resolveEffectiveValue`. Omit it on an unmanaged host: the settings then come back unchanged. */ + @JsonProperty("managed") Object managed +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsApplyControlsResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsApplyControlsResult.java new file mode 100644 index 0000000000..c5a85c72bb --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsApplyControlsResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The user settings with the managed layer's controlled entries stamped on. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsApplyControlsResult( + /** The resulting settings document. */ + @JsonProperty("settingsJson") Object settingsJson +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsBypassDisableSource.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsBypassDisableSource.java new file mode 100644 index 0000000000..f2f64e075f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsBypassDisableSource.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * Which layer disabled bypass-permissions mode. The layer matters because only a server-delivered disable is pinned to an account and can later be lifted by signing in elsewhere. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum ManagedSettingsBypassDisableSource { + /** The {@code user} variant. */ + USER("user"), + /** The {@code managed} variant. */ + MANAGED("managed"), + /** The {@code mdm} variant. */ + MDM("mdm"); + + private final String value; + ManagedSettingsBypassDisableSource(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ManagedSettingsBypassDisableSource fromValue(String value) { + for (ManagedSettingsBypassDisableSource v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ManagedSettingsBypassDisableSource value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsBypassPolicyResolution.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsBypassPolicyResolution.java new file mode 100644 index 0000000000..3101cf80fd --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsBypassPolicyResolution.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * What the managed-policy resolution said about bypass-permissions mode. `unknown` is a third answer rather than a missing one, and the caller must send it explicitly when it has no verdict. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum ManagedSettingsBypassPolicyResolution { + /** The {@code allowed} variant. */ + ALLOWED("allowed"), + /** The {@code disabled} variant. */ + DISABLED("disabled"), + /** The {@code unknown} variant. */ + UNKNOWN("unknown"); + + private final String value; + ManagedSettingsBypassPolicyResolution(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ManagedSettingsBypassPolicyResolution fromValue(String value) { + for (ManagedSettingsBypassPolicyResolution v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ManagedSettingsBypassPolicyResolution value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsIngestParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsIngestParams.java new file mode 100644 index 0000000000..78e71c35cf --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsIngestParams.java @@ -0,0 +1,59 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Inputs describing the host and account an ingestion should resolve managed policy for. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsIngestParams( + /** The policy-helper invocation reason. Defaults to sessionStart. */ + @JsonProperty("policyHelperReason") ManagedSettingsPolicyHelperReason policyHelperReason, + /** Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. */ + @JsonProperty("selfFetch") Boolean selfFetch, + /** The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched. */ + @JsonProperty("authInfo") Object authInfo, + /** The session whose credential store and working directory the policy helper should use. Omit it when no session exists yet and the process-wide store applies. */ + @JsonProperty("sessionId") String sessionId, + /** A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. */ + @JsonProperty("deviceResponse") Object deviceResponse, + /** Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. */ + @JsonProperty("hasDeviceResponse") Boolean hasDeviceResponse, + /** Whether to ignore a cached server policy when reading, forcing the resolution to come from a live fetch. */ + @JsonProperty("bypassCacheRead") Boolean bypassCacheRead, + /** How this ingestion may use the on-disk server-policy cache. Defaults to the runtime's own policy when omitted. */ + @JsonProperty("serverPolicyCacheMode") ManagedSettingsServerPolicyCacheMode serverPolicyCacheMode, + /** Whether a configured platform policy helper may be run to produce an enforced helper layer. */ + @JsonProperty("policyHelperEnabled") Boolean policyHelperEnabled, + /** Directory the policy helper runs in when this ingestion is not owned by a registered session. A host resolving policy before its session exists must pass this, or a directory-sensitive helper judges the wrong repository. */ + @JsonProperty("policyHelperWorkingDirectory") String policyHelperWorkingDirectory, + /** User agent to send with the policy fetch. */ + @JsonProperty("userAgent") String userAgent, + /** Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. Omit it and the runtime reports a generic identity; the runtime version sent alongside is the gate that actually matters. */ + @JsonProperty("clientName") String clientName, + /** The host's environment variables, read for cache location and policy overrides. Supplied by the host rather than read from the runtime process so a command that selected its own configuration home is honored. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("environment") Object environment, + /** The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. */ + @JsonProperty("platform") String platform, + /** The host's home directory, used to resolve cache and managed-file locations. */ + @JsonProperty("homeDirectory") String homeDirectory +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsIngestResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsIngestResult.java new file mode 100644 index 0000000000..d5372cf860 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsIngestResult.java @@ -0,0 +1,78 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The managed policy layers an ingestion resolved, together with the per-layer outcome flags a host needs to decide how much to trust the result. The flags are reported rather than folded into the settings because a host must be able to distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsIngestResult( + /** The effective managed settings composed from every resolved layer. Omitted when no layer set anything, so an unmanaged host locks nothing. */ + @JsonProperty("settings") Object settings, + /** The effective managed permissions layer, when the resolved policy carries one. */ + @JsonProperty("permissions") Object permissions, + /** The server fetch failed and no cached entry stood in for it, so the server layer is unconfirmed and fail-closed gates apply. */ + @JsonProperty("serverFetchFailed") Boolean serverFetchFailed, + /** No usable token was available, so no server fetch was attempted. */ + @JsonProperty("serverTokenUnavailable") Boolean serverTokenUnavailable, + /** The error that made the server fetch fail, when one did. */ + @JsonProperty("serverFetchError") String serverFetchError, + /** How the server layer was resolved. */ + @JsonProperty("serverResolution") ManagedSettingsServerPolicyResolution serverResolution, + /** The server fetch failed in a way a later retry could succeed at, as opposed to a refusal that no retry will change. */ + @JsonProperty("serverRetryableFailure") Boolean serverRetryableFailure, + /** A live fetch failed but a recent cached entry was served in its place, so `serverFetchFailed` stays false. Lets a consumer distinguish a clean fetch from a cache-backed fallback. */ + @JsonProperty("serverCacheFallback") Boolean serverCacheFallback, + /** A server-managed policy is known to exist even though `serverResponse` is intentionally unset. Consumers should OR this with the presence of `serverResponse` when deciding whether the device is managed, so a fresh start during an outage still applies the fail-closed gates instead of treating the device as unmanaged. */ + @JsonProperty("serverSourceFound") Boolean serverSourceFound, + /** The account's server-delivered policy, when one was resolved. */ + @JsonProperty("serverResponse") Object serverResponse, + /** The sandbox object from a cached server policy that a forced refresh declined to serve in full. Folded back into the effective sandbox layer so an outage during a forced refresh still synthesizes the fail-closed sandbox floor from the administrator's known intent. */ + @JsonProperty("serverSandboxFloor") Object serverSandboxFloor, + /** The server fetch failed while a policy demanded a fresh confirmation, which is the strict posture an enterprise opted into rather than an ordinary transient failure. */ + @JsonProperty("serverForcedRefreshFailure") Boolean serverForcedRefreshFailure, + /** The server refused to deliver a policy because this client is too old to enforce it, carrying the user-facing sentence describing the refusal. No retry will help; the remedy is a client update. Gates that exist only because of managed policy should deny on this rather than falling back to their unmanaged default. */ + @JsonProperty("serverClientUpdateRequired") String serverClientUpdateRequired, + /** Minimum client version requested by a successful response. Advisory only; the delivered policy remains active. */ + @JsonProperty("serverClientUpdateRequested") String serverClientUpdateRequested, + /** The synthesized fail-closed permissions layer applied in place of a policy a refused client may not enforce. */ + @JsonProperty("serverPermissionsFloor") Object serverPermissionsFloor, + /** The device layer discovered from the machine, when one exists. */ + @JsonProperty("deviceResponse") Object deviceResponse, + /** The device layer could not be read, so it is unconfirmed rather than known-absent. */ + @JsonProperty("deviceLoadFailed") Boolean deviceLoadFailed, + /** The sandbox floor contributed by the device layer. */ + @JsonProperty("deviceSandboxFloor") Object deviceSandboxFloor, + /** A device-managed policy is known to exist. */ + @JsonProperty("deviceSourceFound") Boolean deviceSourceFound, + /** Whether the device layer's sandbox intent could not be determined, so a consumer must not read its absence as permission to run unsandboxed. */ + @JsonProperty("deviceSandboxUndetermined") Boolean deviceSandboxUndetermined, + /** The layer produced by the platform policy helper, when one ran. */ + @JsonProperty("policyHelperResponse") Object policyHelperResponse, + /** Which channel registered the policy helper that produced the helper layer. */ + @JsonProperty("policyHelperAuthority") ManagedSettingsPolicyHelperAuthority policyHelperAuthority, + /** The policy helper was configured but could not be run or its output could not be read. */ + @JsonProperty("policyHelperLoadFailed") Boolean policyHelperLoadFailed, + /** A policy helper is configured for this host. */ + @JsonProperty("policyHelperConfigured") Boolean policyHelperConfigured, + /** The policy helper's failure must be treated as fail-closed rather than ignored. */ + @JsonProperty("policyHelperFailClosed") Boolean policyHelperFailClosed, + /** Diagnostics emitted while resolving the layers, in the order they occurred. */ + @JsonProperty("logMessages") List logMessages +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLoadRemoteControlParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLoadRemoteControlParams.java new file mode 100644 index 0000000000..ff434c10ae --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLoadRemoteControlParams.java @@ -0,0 +1,51 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Inputs describing the host and account whose managed remote-control policy should be resolved. Mirrors `managedSettings.ingest`, and deliberately carries no retention decision: reading this gate never becomes this runtime process's startup policy. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsLoadRemoteControlParams( + /** The policy-helper invocation reason. Defaults to sessionStart. */ + @JsonProperty("policyHelperReason") ManagedSettingsPolicyHelperReason policyHelperReason, + /** Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. */ + @JsonProperty("selfFetch") Boolean selfFetch, + /** The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched. */ + @JsonProperty("authInfo") Object authInfo, + /** A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. */ + @JsonProperty("deviceResponse") Object deviceResponse, + /** Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. */ + @JsonProperty("hasDeviceResponse") Boolean hasDeviceResponse, + /** Whether a configured platform policy helper may be run to produce an enforced helper layer. */ + @JsonProperty("policyHelperEnabled") Boolean policyHelperEnabled, + /** User agent to send with the policy fetch. */ + @JsonProperty("userAgent") String userAgent, + /** Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. That refusal is exactly what turns into an explicit `disabled` below, so a host that omits this field forfeits the protection. */ + @JsonProperty("clientName") String clientName, + /** The host's environment variables, read for cache location and policy overrides. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("environment") Object environment, + /** The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. */ + @JsonProperty("platform") String platform, + /** The host's home directory, used to resolve cache and managed-file locations. */ + @JsonProperty("homeDirectory") String homeDirectory +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLoadRemoteControlResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLoadRemoteControlResult.java new file mode 100644 index 0000000000..2acf5180c5 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLoadRemoteControlResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The managed remote-control policy in force for an account, if any. An absent policy means the account is unmanaged for this capability, which a host reads as allowed — so absence here is a positive statement that no policy applies, never a stand-in for a resolution that failed. A resolution that cannot be completed is rejected instead. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsLoadRemoteControlResult( + /** The account's `remoteControl` policy document. Absent when no managed policy governs remote control for this account. Reported as an explicit disabled policy, rather than as absence, when the service refused to deliver a policy this client is too old to enforce. */ + @JsonProperty("remoteControl") Object remoteControl +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLogLevel.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLogLevel.java new file mode 100644 index 0000000000..1775a5db19 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLogLevel.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * Severity of a diagnostic emitted while ingesting managed settings. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum ManagedSettingsLogLevel { + /** The {@code debug} variant. */ + DEBUG("debug"), + /** The {@code info} variant. */ + INFO("info"), + /** The {@code warning} variant. */ + WARNING("warning"), + /** The {@code error} variant. */ + ERROR("error"); + + private final String value; + ManagedSettingsLogLevel(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ManagedSettingsLogLevel fromValue(String value) { + for (ManagedSettingsLogLevel v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ManagedSettingsLogLevel value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLogMessage.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLogMessage.java new file mode 100644 index 0000000000..be859afde3 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsLogMessage.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * One diagnostic emitted while ingesting managed settings. Returned rather than logged by the runtime so the host decides where ingestion diagnostics go, which matters because an ingestion runs before a session exists to carry a log sink. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsLogMessage( + /** Severity of this diagnostic. */ + @JsonProperty("level") ManagedSettingsLogLevel level, + /** Human-readable diagnostic text. */ + @JsonProperty("message") String message +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsParseClientValueParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsParseClientValueParams.java new file mode 100644 index 0000000000..27effeabae --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsParseClientValueParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The client-supplied managed settings to validate and normalize. Omitting them is valid and yields no policy. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsParseClientValueParams( + /** The managed settings a client is supplying for a session it is about to open. Omit them when the client is imposing no policy of its own. */ + @JsonProperty("settings") Object settings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsParseClientValueResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsParseClientValueResult.java new file mode 100644 index 0000000000..695248ea4a --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsParseClientValueResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The accepted managed settings, reduced to the keys a client is allowed to set. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsParseClientValueResult( + /** The normalized settings. Omitted when the client supplied none. An accepted document that sets nothing comes back as an empty object, which is distinct from omission. */ + @JsonProperty("settingsJson") Object settingsJson +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPolicyHelperAuthority.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPolicyHelperAuthority.java new file mode 100644 index 0000000000..34b33ad56f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPolicyHelperAuthority.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * Which channel registered the policy helper that produced a helper layer. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum ManagedSettingsPolicyHelperAuthority { + /** The {@code device} variant. */ + DEVICE("device"), + /** The {@code server} variant. */ + SERVER("server"); + + private final String value; + ManagedSettingsPolicyHelperAuthority(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ManagedSettingsPolicyHelperAuthority fromValue(String value) { + for (ManagedSettingsPolicyHelperAuthority v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ManagedSettingsPolicyHelperAuthority value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPolicyHelperReason.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPolicyHelperReason.java new file mode 100644 index 0000000000..509e98f5e7 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsPolicyHelperReason.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * The operation that requires a policy-helper response. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum ManagedSettingsPolicyHelperReason { + /** The {@code sessionStart} variant. */ + SESSIONSTART("sessionStart"), + /** The {@code pluginActivation} variant. */ + PLUGINACTIVATION("pluginActivation"); + + private final String value; + ManagedSettingsPolicyHelperReason(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ManagedSettingsPolicyHelperReason fromValue(String value) { + for (ManagedSettingsPolicyHelperReason v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ManagedSettingsPolicyHelperReason value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsReadDeviceResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsReadDeviceResult.java new file mode 100644 index 0000000000..880044dc83 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsReadDeviceResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The device-managed settings layer, with the sandbox floor and the load outcome a host needs to compose it into an effective policy. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsReadDeviceResult( + /** Validated, canonical device-managed settings. Omitted when no device policy was discovered, when the discovered document failed validation, or when it validated to an empty object — an empty document carries no policy, and reporting it as present would outrank layers that do. */ + @JsonProperty("settings") Object settings, + /** Sandbox floor read from the discovered document before validation, so a document that is otherwise rejected can still raise the floor it declared. */ + @JsonProperty("sandboxFloor") Object sandboxFloor, + /** Whether discovery or validation failed. A host must treat this as "policy unknown" rather than "no policy": absent settings with this set false mean the device genuinely has none. */ + @JsonProperty("loadFailed") Boolean loadFailed +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveBypassDisableTransitionParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveBypassDisableTransitionParams.java new file mode 100644 index 0000000000..3b56f24c92 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveBypassDisableTransitionParams.java @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The bypass-permissions state a host holds today, the account now signed in, and what the managed-policy resolution said. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsResolveBypassDisableTransitionParams( + /** Which layer currently disables bypass mode. Omit it when nothing does. */ + @JsonProperty("currentSource") ManagedSettingsBypassDisableSource currentSource, + /** The account a `managed` disable is pinned to. Omit it when the current source is not `managed`; it is ignored for the other sources. */ + @JsonProperty("currentManagedIdentity") String currentManagedIdentity, + /** The account signed in now. A `managed` disable pinned to a different account is lifted. */ + @JsonProperty("activeIdentity") String activeIdentity, + /** What the resolution said about bypass mode. Send `unknown` rather than omitting the field when there is no verdict. */ + @JsonProperty("policy") ManagedSettingsBypassPolicyResolution policy +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveBypassDisableTransitionResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveBypassDisableTransitionResult.java new file mode 100644 index 0000000000..2557cd5cb3 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveBypassDisableTransitionResult.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The bypass-permissions state a host should hold after the resolution, and what it must do to get there. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsResolveBypassDisableTransitionResult( + /** Which layer disables bypass mode after this resolution. Omitted when none does, which is what a lifted disable looks like. */ + @JsonProperty("source") ManagedSettingsBypassDisableSource source, + /** The account the returned `managed` source is pinned to. Store it alongside `source`; the next call needs it to decide whether an account switch lifts the disable. */ + @JsonProperty("managedIdentity") String managedIdentity, + /** The value to store in the host's own bypass-disabled flag. Omitted means leave it exactly as it is, which is not the same as being told to store `false`. */ + @JsonProperty("setDisabledState") Boolean setDisabledState, + /** Whether a bypass-permissions session already running must be turned off. True only when this resolution newly disables bypass mode, so a host that is already compliant is not interrupted. */ + @JsonProperty("suppressRuntimeAllowAll") Boolean suppressRuntimeAllowAll +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveDeviceForceLoginOrgsGateParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveDeviceForceLoginOrgsGateParams.java new file mode 100644 index 0000000000..75b89cb8bd --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveDeviceForceLoginOrgsGateParams.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The credential and environment to evaluate the device-channel sign-in pin against. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsResolveDeviceForceLoginOrgsGateParams( + /** The authenticated identity to judge. Omitted when signed out, which is the case the device channel exists to serve: it can refuse a first sign-in before any credential exists. */ + @JsonProperty("authInfo") Object authInfo, + /** The host's environment variables. Read for the variables that would make an identity's membership snapshot forgeable, so a credential whose provenance cannot be trusted is refused rather than accepted. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("environment") Object environment +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveEffectiveValueParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveEffectiveValueParams.java new file mode 100644 index 0000000000..7e82bf0b3c --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveEffectiveValueParams.java @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The managed-settings layers to compose into an effective policy. Every layer is optional; omitting all of them yields no effective policy. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsResolveEffectiveValueParams( + /** The account's server-delivered org policy, as returned by a managed-settings fetch. Omitted before sign-in or when the fetch has not landed. */ + @JsonProperty("server") Object server, + /** The device layer: native MDM and managed-file settings describing the machine rather than the account. */ + @JsonProperty("mdm") Object mdm, + /** The device sandbox floor, folded into the device layer under `sandbox` before composition. */ + @JsonProperty("deviceSandboxFloor") Object deviceSandboxFloor, + /** The policy-helper layer, an enforced channel sourced from a platform policy helper process. */ + @JsonProperty("policyHelper") Object policyHelper +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveEffectiveValueResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveEffectiveValueResult.java new file mode 100644 index 0000000000..441bb9039f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveEffectiveValueResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The effective managed policy composed from the supplied layers. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsResolveEffectiveValueResult( + /** The composed effective managed settings. Omitted when no layer sets anything, so an unmanaged host locks nothing. Carries `sandboxAdvisoryFloorDeclined: true` when an advisory server force-on was dropped because this host cannot run the sandbox. */ + @JsonProperty("settingsJson") Object settingsJson +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveStartupPolicyParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveStartupPolicyParams.java new file mode 100644 index 0000000000..e0074bb8bc --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveStartupPolicyParams.java @@ -0,0 +1,61 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Inputs describing the host and account a startup policy resolution should run for. Mirrors `managedSettings.ingest`, and adds the decision of whether the resolved policy is retained for this runtime process. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsResolveStartupPolicyParams( + /** The policy-helper invocation reason. Defaults to sessionStart. */ + @JsonProperty("policyHelperReason") ManagedSettingsPolicyHelperReason policyHelperReason, + /** Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. */ + @JsonProperty("selfFetch") Boolean selfFetch, + /** The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched and the sign-in pin is evaluated against no credential. */ + @JsonProperty("authInfo") Object authInfo, + /** The session whose credential store, working directory and client kind the resolution should use. Omit it when no session exists yet and the process-wide store applies. A resolution whose session names a credential other than `authInfo` is returned but not retained, so a stale sign-in cannot apply policy for an account that has already been switched away from. */ + @JsonProperty("sessionId") String sessionId, + /** A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. */ + @JsonProperty("deviceResponse") Object deviceResponse, + /** Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. */ + @JsonProperty("hasDeviceResponse") Boolean hasDeviceResponse, + /** Whether to ignore a cached server policy when reading, forcing the resolution to come from a live fetch. */ + @JsonProperty("bypassCacheRead") Boolean bypassCacheRead, + /** How this resolution may use the on-disk server-policy cache. Defaults to the runtime's own policy when omitted. Rejected when combined with `bypassCacheRead`, because the two express the same decision and accepting both would leave the caller unsure which one the runtime honored. */ + @JsonProperty("serverPolicyCacheMode") ManagedSettingsServerPolicyCacheMode serverPolicyCacheMode, + /** Whether a configured platform policy helper may be run to produce an enforced helper layer. */ + @JsonProperty("policyHelperEnabled") Boolean policyHelperEnabled, + /** Directory the policy helper runs in when this resolution is not owned by a registered session. A host resolving policy before its session exists must pass this, or a directory-sensitive helper judges the wrong repository. */ + @JsonProperty("policyHelperWorkingDirectory") String policyHelperWorkingDirectory, + /** User agent to send with the policy fetch. */ + @JsonProperty("userAgent") String userAgent, + /** Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. */ + @JsonProperty("clientName") String clientName, + /** The host's environment variables, read for cache location, policy overrides, and the variables that would make a membership snapshot forgeable. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("environment") Object environment, + /** The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. */ + @JsonProperty("platform") String platform, + /** The host's home directory, used to resolve cache and managed-file locations. */ + @JsonProperty("homeDirectory") String homeDirectory, + /** Whether to retain the resolved policy as this runtime process's startup policy, so later work in the process enforces it. Set false to resolve without side effects, which is what a protocol host wants before session creation: its sessions apply the complete policy through the normal lifecycle, and retaining here would let a readiness credential affect unrelated sessions. The returned verdict is identical either way — this decides only whether the process keeps it. */ + @JsonProperty("retainAndApply") Boolean retainAndApply +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveStartupPolicyResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveStartupPolicyResult.java new file mode 100644 index 0000000000..69def35f89 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsResolveStartupPolicyResult.java @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * The startup policy a resolution composed, the per-layer outcome flags a host needs to decide how much to trust it, and the enterprise sign-in verdict for the credential it ran against. The flags are reported rather than folded into the settings because a host must distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsResolveStartupPolicyResult( + /** How the current runtime resolved the server layer. */ + @JsonProperty("serverResolution") ManagedSettingsServerPolicyResolution serverResolution, + /** Advisory minimum client version from a successful server response. */ + @JsonProperty("clientUpdateRequested") String clientUpdateRequested, + /** The account's server-delivered policy, when one was resolved. */ + @JsonProperty("serverResponse") Object serverResponse, + /** The device layer discovered from the machine, when one exists. */ + @JsonProperty("deviceResponse") Object deviceResponse, + /** The sandbox floor contributed by the device layer. */ + @JsonProperty("deviceSandboxFloor") Object deviceSandboxFloor, + /** The layer produced by the platform policy helper, when one ran. */ + @JsonProperty("policyHelperResponse") Object policyHelperResponse, + /** The server fetch failed and no cached entry stood in for it, so the server layer is unconfirmed and fail-closed gates apply. */ + @JsonProperty("serverFetchFailed") Boolean serverFetchFailed, + /** The device layer could not be read, so it is unconfirmed rather than known-absent. */ + @JsonProperty("deviceLoadFailed") Boolean deviceLoadFailed, + /** The policy helper was configured but could not be run, or its output could not be read. */ + @JsonProperty("policyHelperLoadFailed") Boolean policyHelperLoadFailed, + /** Telemetry describing which layers answered and how, for the host to report alongside its own startup events. */ + @JsonProperty("telemetry") Object telemetry, + /** The effective sandbox floor composed across every layer, which a host must apply rather than its own default. */ + @JsonProperty("sandboxFloor") Object sandboxFloor, + /** Some layer of the policy could not be confirmed, so its absence must not be read as permission. Folds in a failed server fetch as well as an unreadable device layer. */ + @JsonProperty("policyUndetermined") Boolean policyUndetermined, + /** The permissions layer specifically could not be confirmed, so permission gates apply their fail-closed posture. */ + @JsonProperty("permissionPolicyUndetermined") Boolean permissionPolicyUndetermined, + /** A managed policy is known to apply to this host, from a discovered source or a resolved document. */ + @JsonProperty("managedPolicyPresent") Boolean managedPolicyPresent, + /** The sandbox was enabled because policy could not be confirmed rather than because an administrator asked for it. Lets a host explain a sandbox the user did not configure. */ + @JsonProperty("sandboxEnabledByUndeterminedPolicy") Boolean sandboxEnabledByUndeterminedPolicy, + /** The enterprise sign-in verdict for the credential this resolution ran against, evaluated over the effective policy so a server-delivered pin is honored alongside a device one. Computed on every resolution, including one that was not retained, so a host that declines to apply policy still cannot proceed past a pin. */ + @JsonProperty("forceLoginOrgs") ForceLoginOrgsDecision forceLoginOrgs, + /** The server refused to deliver a policy because this client is too old to enforce it, carrying the user-facing sentence describing the refusal. No retry will help; the remedy is a client update. */ + @JsonProperty("clientUpdateRequired") String clientUpdateRequired, + /** Warnings raised while resolving, in the order they occurred. */ + @JsonProperty("warnings") List warnings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsRetainPolicyParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsRetainPolicyParams.java new file mode 100644 index 0000000000..5ea352e817 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsRetainPolicyParams.java @@ -0,0 +1,60 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The managed layers to retain as this process's startup policy, with the outcome of fetching each one. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record ManagedSettingsRetainPolicyParams( + /** The resolved server policy. A known source can lack a response after a forced-refresh failure. */ + @JsonProperty("serverResponse") Object serverResponse, + /** The device/MDM policy layer. */ + @JsonProperty("deviceResponse") Object deviceResponse, + /** Sandbox floor declared by the device layer, carried separately so a document that failed validation can still raise the floor. */ + @JsonProperty("deviceSandboxFloor") Object deviceSandboxFloor, + /** Whether a device policy source demonstrably exists. This, not a read error, is the evidence a device is managed, so a fail-closed policy gates on it. */ + @JsonProperty("deviceSourceFound") Boolean deviceSourceFound, + /** Whether any managed policy source exists, independently of fetch failures. */ + @JsonProperty("managedPolicyPresent") Boolean managedPolicyPresent, + /** Whether the server policy source exists, even when its response is unavailable. */ + @JsonProperty("serverSourceFound") Boolean serverSourceFound, + /** Whether a required fresh server-policy confirmation failed. */ + @JsonProperty("serverForcedRefreshFailure") Boolean serverForcedRefreshFailure, + /** Preserve the retained server layer during a device-only resolution. */ + @JsonProperty("preserveServerState") Boolean preserveServerState, + /** Whether the device sandbox intent is unreadable independently of its other settings. */ + @JsonProperty("deviceSandboxUndetermined") Boolean deviceSandboxUndetermined, + /** Whether the shared sandbox policy is undetermined. Diagnostic errors alone do not imply this flag. */ + @JsonProperty("sandboxFloorUndetermined") Boolean sandboxFloorUndetermined, + /** Whether permission policy is undetermined. Sandbox-only uncertainty does not imply this flag. */ + @JsonProperty("permissionPolicyUndetermined") Boolean permissionPolicyUndetermined, + /** Whether uncertainty alone enabled the shared sandbox floor. */ + @JsonProperty("sandboxEnabledByUndeterminedPolicy") Boolean sandboxEnabledByUndeterminedPolicy, + /** Shared server/device sandbox floor, excluding session-local helper policy. */ + @JsonProperty("sharedSandboxFloor") Object sharedSandboxFloor, + /** Whether the server fetch failed. Report it honestly: true keeps the already-retained server layer rather than replacing it with an absent one. */ + @JsonProperty("serverFetchFailed") Boolean serverFetchFailed, + /** Whether the device load failed. Report it honestly, for the same reason as `serverFetchFailed`. */ + @JsonProperty("deviceLoadFailed") Boolean deviceLoadFailed, + /** The policy helper's response: the third managed layer that a process owning its startup policy resolves. It is retained with the other two so that every ambient read in this process, including the mutation guards and the governed marketplace allowlist that the `plugins.*` handlers derive, sees the whole policy the process fetched. A session-owning process omits it, because it resolves a helper per session against that session's working directory. */ + @JsonProperty("policyHelperResponse") Object policyHelperResponse +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsServerPolicyCacheMode.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsServerPolicyCacheMode.java new file mode 100644 index 0000000000..7258e376b5 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsServerPolicyCacheMode.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * How an ingestion may use the on-disk server-policy cache. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum ManagedSettingsServerPolicyCacheMode { + /** The {@code preferFresh} variant. */ + PREFERFRESH("preferFresh"), + /** The {@code cacheOnly} variant. */ + CACHEONLY("cacheOnly"), + /** The {@code fallbackOnly} variant. */ + FALLBACKONLY("fallbackOnly"), + /** The {@code disabled} variant. */ + DISABLED("disabled"); + + private final String value; + ManagedSettingsServerPolicyCacheMode(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ManagedSettingsServerPolicyCacheMode fromValue(String value) { + for (ManagedSettingsServerPolicyCacheMode v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ManagedSettingsServerPolicyCacheMode value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsServerPolicyResolution.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsServerPolicyResolution.java new file mode 100644 index 0000000000..8315739063 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ManagedSettingsServerPolicyResolution.java @@ -0,0 +1,45 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * How the server layer of an ingestion was resolved. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum ManagedSettingsServerPolicyResolution { + /** The {@code live} variant. */ + LIVE("live"), + /** The {@code freshCache} variant. */ + FRESHCACHE("freshCache"), + /** The {@code cacheMiss} variant. */ + CACHEMISS("cacheMiss"), + /** The {@code fallbackCache} variant. */ + FALLBACKCACHE("fallbackCache"), + /** The {@code failOpen} variant. */ + FAILOPEN("failOpen"), + /** The {@code failClosed} variant. */ + FAILCLOSED("failClosed"), + /** The {@code skippedNoToken} variant. */ + SKIPPEDNOTOKEN("skippedNoToken"); + + private final String value; + ManagedSettingsServerPolicyResolution(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ManagedSettingsServerPolicyResolution fromValue(String value) { + for (ManagedSettingsServerPolicyResolution v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ManagedSettingsServerPolicyResolution value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionsEvaluateManagedPolicyParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionsEvaluateManagedPolicyParams.java new file mode 100644 index 0000000000..65a15a044e --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionsEvaluateManagedPolicyParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The verbatim managed `permissions` slice to interpret. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record PermissionsEvaluateManagedPolicyParams( + /** The `permissions` object from a managed settings layer, for example `{"disableBypassPermissionsMode":"disable"}`. Omitted or null means no managed policy applies. */ + @JsonProperty("permissions") Object permissions +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionsEvaluateManagedPolicyResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionsEvaluateManagedPolicyResult.java new file mode 100644 index 0000000000..2690dad76f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionsEvaluateManagedPolicyResult.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The policy questions a host asks before granting elevated permissions. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record PermissionsEvaluateManagedPolicyResult( + /** True when managed policy forbids bypass-permissions mode, so allow-all style flags must not take effect. */ + @JsonProperty("bypassPermissionsDisabled") Boolean bypassPermissionsDisabled, + /** True when a managed policy exists but this build could not determine its meaning. Hosts fail closed on it rather than assuming permission was granted. */ + @JsonProperty("policyUndetermined") Boolean policyUndetermined, + /** True when the managed layer supplies permission rules that the session must enforce. */ + @JsonProperty("permissionRulesActive") Boolean permissionRulesActive +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionsFolderTrustCheckTrustParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionsFolderTrustCheckTrustParams.java new file mode 100644 index 0000000000..5fadba2eec --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PermissionsFolderTrustCheckTrustParams.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * A folder to check against a persisted trusted-folders list, and the configuration directory holding that list. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record PermissionsFolderTrustCheckTrustParams( + /** Folder to check. A folder counts as trusted when it is itself listed, when an ancestor is listed, or when its git root is listed. */ + @JsonProperty("path") String path, + /** Configuration directory to read the trusted-folders list from. Omit it to read the default location; supply it when the host has redirected its configuration, or the check answers from a list the host is not using. */ + @JsonProperty("configDir") String configDir +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PersistenceWriteRawJsonLockedParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PersistenceWriteRawJsonLockedParams.java new file mode 100644 index 0000000000..eff9c61d51 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PersistenceWriteRawJsonLockedParams.java @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * A complete JSON snapshot to write under the runtime's per-path file lock. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record PersistenceWriteRawJsonLockedParams( + /** Absolute path of the file to replace. Parent directories are created when missing. */ + @JsonProperty("path") String path, + /** The serialized JSON document to write. It replaces the file's contents entirely; nothing is merged. */ + @JsonProperty("dataJson") String dataJson, + /** Comment lines to emit above the document, for a format that tolerates them. Omit for strict JSON. */ + @JsonProperty("fileHeader") String fileHeader +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PersistenceWriteRawJsonLockedResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PersistenceWriteRawJsonLockedResult.java new file mode 100644 index 0000000000..5f8616d042 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/PersistenceWriteRawJsonLockedResult.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The outcome of a locked snapshot write. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record PersistenceWriteRawJsonLockedResult( + /** Whether the file now holds the requested contents. */ + @JsonProperty("success") Boolean success, + /** Why the write failed. Absent when `success` is true. A lock the runtime could not acquire in time reports here rather than raising. */ + @JsonProperty("error") String error +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsEditParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsEditParams.java new file mode 100644 index 0000000000..c871a3aed7 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsEditParams.java @@ -0,0 +1,38 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * One atomic edit of an allowed top-level repository setting. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record RepoSettingsEditParams( + /** Absolute path of the repository root. */ + @JsonProperty("repoRoot") String repoRoot, + /** Shared or local repository settings file. */ + @JsonProperty("scope") RepoSettingsEditScope scope, + /** One canonical top-level repository setting that the allowlist permits. */ + @JsonProperty("key") String key, + /** Set a scalar, add or remove a string list item, or remove the setting. The handler rejects a missing or incompatible value. */ + @JsonProperty("operation") SettingsEditOperation operation, + /** Required boolean, string or number for set, required string for add-item and remove-item, and forbidden for remove. The runtime rejects all other JSON values. */ + @JsonProperty("value") Object value +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsEditScope.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsEditScope.java new file mode 100644 index 0000000000..43b64573d5 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/RepoSettingsEditScope.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Which repository settings file to edit. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum RepoSettingsEditScope { + /** The {@code repo} variant. */ + REPO("repo"), + /** The {@code local} variant. */ + LOCAL("local"); + + private final String value; + RepoSettingsEditScope(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static RepoSettingsEditScope fromValue(String value) { + for (RepoSettingsEditScope v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown RepoSettingsEditScope value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxCheckEnforcementCommandParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxCheckEnforcementCommandParams.java new file mode 100644 index 0000000000..b7401231f7 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxCheckEnforcementCommandParams.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * One slash command, as typed, to test against the enforcement-block allowlist. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxCheckEnforcementCommandParams( + /** The command name as the user typed it, with or without its leading slash. */ + @JsonProperty("commandName") String commandName, + /** The command's arguments, in order. Pass an empty array for a bare command: several entries in the allowlist admit the bare form and refuse every argument. */ + @JsonProperty("args") List args +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxDocsUrlResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxDocsUrlResult.java new file mode 100644 index 0000000000..bb2ed5c1a2 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxDocsUrlResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The documentation URL a host cites when it declines or downgrades a sandbox setting. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxDocsUrlResult( + /** Documentation URL describing the sandbox and the settings that control it. */ + @JsonProperty("url") String url +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxEffectiveForOptionalResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxEffectiveForOptionalResult.java new file mode 100644 index 0000000000..2336d4f195 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxEffectiveForOptionalResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The sandbox a named feature actually launches under. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxEffectiveForOptionalResult( + /** The effective sandbox config for the requested feature, or a disabled sandbox when the feature is routed out of it. */ + @JsonProperty("sandboxJson") Object sandboxJson +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxFilterPickerCandidatesParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxFilterPickerCandidatesParams.java new file mode 100644 index 0000000000..663040c87e --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxFilterPickerCandidatesParams.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * A batch of file-picker candidates to check against a prepared policy. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxFilterPickerCandidatesParams( + /** The candidates to check, in the order the answers are returned. */ + @JsonProperty("candidates") List candidates, + /** The session's working directory, matching the one the policy was prepared from. */ + @JsonProperty("cwd") String cwd, + /** The policy returned by `sandbox.preparePickerPolicy`. Omitted keeps every candidate. */ + @JsonProperty("sandbox") Object sandbox +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxFilterPickerCandidatesResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxFilterPickerCandidatesResult.java new file mode 100644 index 0000000000..cbf29a25f3 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxFilterPickerCandidatesResult.java @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.processing.Generated; + +/** + * Per-candidate allow decisions, positionally aligned with the request. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxFilterPickerCandidatesResult( + /** One decision per candidate, in the same order. Always the same length as the request's `candidates`. */ + @JsonProperty("allowed") List allowed +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxGetUnsupportedStartupNoticeParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxGetUnsupportedStartupNoticeParams.java new file mode 100644 index 0000000000..c082b52e7d --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxGetUnsupportedStartupNoticeParams.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The managed sandbox policy in force, which selects which remedy the notice offers. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxGetUnsupportedStartupNoticeParams( + /** The managed `sandbox` slice, when a policy supplies one. The notice treats the sandbox as enforced only when this both enables it and sets `failIfUnavailable`, because a managed sandbox that tolerates being unavailable still leaves the user able to turn it off. */ + @JsonProperty("managedSandbox") Object managedSandbox, + /** True when the sandbox stayed on only because the managed policy could not be determined. Distinguishes a policy that positively enforces the sandbox from one that merely failed to resolve, which is the difference between telling the user to contact an administrator and telling them to wait. Defaults to false. */ + @JsonProperty("enabledByUndeterminedPolicy") Boolean enabledByUndeterminedPolicy +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxPickerCandidate.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxPickerCandidate.java new file mode 100644 index 0000000000..f3c7712a82 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxPickerCandidate.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * One file-picker suggestion offered up for the sandbox filesystem check. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxPickerCandidate( + /** Absolute path the suggestion would attach. */ + @JsonProperty("path") String path, + /** Whether the suggestion is a directory. A directory the policy does not itself allow may still be needed as a waypoint to an allowed subtree. */ + @JsonProperty("isDirectory") Boolean isDirectory +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxPreparePickerPolicyParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxPreparePickerPolicyParams.java new file mode 100644 index 0000000000..2895a57e73 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxPreparePickerPolicyParams.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The working directory and sandbox settings to build a file-picker policy from. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxPreparePickerPolicyParams( + /** The session's working directory. Git discovery and grant canonicalization are resolved against it. */ + @JsonProperty("cwd") String cwd, + /** The session's resolved `sandbox` slice. Omitted, or disabled, yields no policy and every candidate is kept. */ + @JsonProperty("sandbox") Object sandbox +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxPreparePickerPolicyResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxPreparePickerPolicyResult.java new file mode 100644 index 0000000000..07cae03587 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxPreparePickerPolicyResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The prepared file-picker policy, or none when the sandbox is disabled. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxPreparePickerPolicyResult( + /** The prepared policy to pass back to `sandbox.filterPickerCandidates`. Absent when the sandbox is disabled or absent, in which case filtering keeps every candidate. */ + @JsonProperty("sandboxJson") Object sandboxJson +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxyCaCheckRelevanceParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxyCaCheckRelevanceParams.java new file mode 100644 index 0000000000..6d66db0a30 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxyCaCheckRelevanceParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public record SandboxProxyCaCheckRelevanceParams( + /** The sandbox configuration that the host gives its sessions. The runtime reads the credential hosts from `auth` and `credentials`; it ignores `enabled` and the other fields. */ + @JsonProperty("sandboxConfig") SandboxConfig sandboxConfig +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretGetResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretGetResult.java new file mode 100644 index 0000000000..5afa3f89d3 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretGetResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The stored sandbox proxy password, if one is present. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxProxySecretGetResult( + /** The stored password. Absent when no entry exists in either the keychain or the on-disk fallback store. */ + @JsonProperty("value") String value +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretLocation.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretLocation.java new file mode 100644 index 0000000000..d72162ee2e --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretLocation.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Where this runtime keeps the sandbox proxy password. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxProxySecretLocation( + /** Absolute path of the credential store holding the sandbox proxy password. The proxy password belongs to no MCP server, so it is kept in its own directory rather than in the MCP secret store. */ + @JsonProperty("configDir") String configDir, + /** Identifier of the proxy password entry within that store. Derived from the configuration directory, so two Copilot homes on one machine never share an entry. Use it to recognize a `${secret:…}` reference in stored settings as this runtime's own proxy password. */ + @JsonProperty("secretId") String secretId +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretSaveParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretSaveParams.java new file mode 100644 index 0000000000..610fb09681 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretSaveParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The sandbox proxy password to store. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxProxySecretSaveParams( + /** The password to store for the sandbox proxy. */ + @JsonProperty("value") String value +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretSaveResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretSaveResult.java new file mode 100644 index 0000000000..543b38083f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxProxySecretSaveResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * Where the sandbox proxy password was stored. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxProxySecretSaveResult( + /** Whether the OS keychain accepted the value. False means it was written to the on-disk fallback store instead, which is still readable by `sandbox.proxySecret.get`. */ + @JsonProperty("storedInKeychain") Boolean storedInKeychain +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxResolveFlooredConfigParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxResolveFlooredConfigParams.java new file mode 100644 index 0000000000..738642fa05 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxResolveFlooredConfigParams.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The user's sandbox settings and the managed sandbox floor to raise them to. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxResolveFlooredConfigParams( + /** The user's own `sandbox` settings slice. Omitted when the user has configured none, which still yields the managed floor rather than a disabled sandbox. */ + @JsonProperty("userSandbox") Object userSandbox, + /** The effective managed `sandbox` slice acting as a floor. Omitted when no administrator policy applies, in which case the user's own settings stand unchanged. */ + @JsonProperty("managedSandbox") Object managedSandbox +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxResolveFlooredConfigResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxResolveFlooredConfigResult.java new file mode 100644 index 0000000000..043eaaead9 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxResolveFlooredConfigResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The user's sandbox settings raised to the managed floor. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxResolveFlooredConfigResult( + /** The floored sandbox config, normalized through the declared sandbox shape so only declared fields in a fixed order are present. */ + @JsonProperty("sandboxJson") Object sandboxJson +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxResolveForOptionalParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxResolveForOptionalParams.java new file mode 100644 index 0000000000..9a523b274e --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxResolveForOptionalParams.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * A sandbox config and the per-feature routing flag to resolve it for. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxResolveForOptionalParams( + /** The session's resolved `sandbox` slice. Omitted when the host has none, which yields a disabled sandbox rather than an error. */ + @JsonProperty("sandbox") Object sandbox, + /** The routing flag naming the feature being launched, such as `sandboxMcpServers` or `sandboxLspServers`. */ + @JsonProperty("routingFlag") String routingFlag +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxSettingsApplyDefaultsParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxSettingsApplyDefaultsParams.java new file mode 100644 index 0000000000..4b129d0d41 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxSettingsApplyDefaultsParams.java @@ -0,0 +1,31 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The stored sandbox settings to resolve against the defaults. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxSettingsApplyDefaultsParams( + /** The sandbox settings as stored in the settings file. An empty object resolves to the defaults alone. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("stored") Object stored +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxUnsupportedStartupNoticeResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxUnsupportedStartupNoticeResult.java new file mode 100644 index 0000000000..2d31660a33 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SandboxUnsupportedStartupNoticeResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The startup warning, absent when the machine can run a sandbox. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record SandboxUnsupportedStartupNoticeResult( + /** The user-facing warning, carrying the platform remedy and the recovery the policy in force actually allows. Absent when this machine supports a sandbox, so a host can call unconditionally and print only what it gets. */ + @JsonProperty("notice") String notice +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerFeatureFlagsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerFeatureFlagsApi.java index 83c807baa6..b2f3444b0a 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerFeatureFlagsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerFeatureFlagsApi.java @@ -27,6 +27,17 @@ final class ServerFeatureFlagsApi { this.caller = caller; } + /** + * Resolves named gates against this installation's cached online-experiment assignment, for the account the runtime is already authenticated as. Unlike `featureFlags.resolve`, which layers static availability with the populations supplied, this reads the experiment assignment the runtime cached for its own current authentication, so a launch can honor a rollout before any session exists. The account is never taken from the request: naming one would read another account's cached assignments. The cached assignment answers immediately and any network refresh happens behind it, so this call does not wait on the network. Not available to an extension, which cannot carry the user's consent to read their assignment. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture> resolveStartupGates(FeatureFlagsResolveStartupGatesParams params) { + return caller.invoke("featureFlags.resolveStartupGates", params, RpcMapper.INSTANCE.getTypeFactory().constructMapType(Map.class, String.class, Boolean.class)); + } + /** * Lists every feature flag this runtime declares, with the population each one is declared for, its experimental description, and the online-experiment flag it maps to. This is the static catalog: it describes how each flag is defined, not whether it is on for anyone. Use `featureFlags.resolve` for static values with caller overrides, not active runtime values or experiment assignments. * diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerManagedSettingsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerManagedSettingsApi.java index 579ef69f90..666a1052e0 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerManagedSettingsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerManagedSettingsApi.java @@ -30,6 +30,116 @@ public final class ServerManagedSettingsApi { this.permissions = new ServerManagedSettingsPermissionsApi(caller); } + /** + * Discovers device-managed settings the way the runtime's own device layer does, and reports the sandbox floor and the load outcome alongside the validated document. This differs from `managedSettings.read` in three ways a policy-enforcing host depends on: a document that validates to an empty object is reported as absent rather than as an empty policy, a discovery error does not suppress a document that still validates, and a failure is reported as a flag rather than only as error text. Hosts that compose the device layer into an effective policy use this, because `managedSettings.read` cannot distinguish "no device policy" from "device policy could not be read" and would silently hand the user's own layer the win. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture readDevice() { + return caller.invoke("managedSettings.readDevice", java.util.Map.of(), ManagedSettingsReadDeviceResult.class); + } + + /** + * Retains the supplied managed layers as this runtime process's startup policy and re-applies the result to every live session. Hosts that own their own short-lived process policy use this, so a guarded mutation is checked against the policy the host actually fetched. Retaining is a whole-process replacement rather than a merge, so a host that already resolved a good policy must not retain a partial one over it. The failure flags are honest inputs rather than assumptions: reporting a fetch or load that failed keeps the layers already retained, and the interim fail-closed state, instead of clearing them. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture retainPolicy(ManagedSettingsRetainPolicyParams params) { + return caller.invoke("managedSettings.retainPolicy", params, Void.class); + } + + /** + * Stamps an effective managed policy's individually-controlled entries onto a user settings document, returning the settings a host should actually act on. The managed layer wins on every plugin spec and marketplace name it names, and leaves everything it does not name as the user wrote it. Hosts use this rather than merging the two documents themselves, because the merge is per entry rather than per document and a whole-document overlay would either discard the user's unmanaged entries or let a user entry outrank a managed one. Omitting the managed layer returns the settings unchanged, which is what an unmanaged host wants. Rejects when either document is present but is not a JSON object rather than treating it as absent, since silently dropping a malformed policy hands the user's layer the win on exactly the entries the policy exists to control. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture applyControls(ManagedSettingsApplyControlsParams params) { + return caller.invoke("managedSettings.applyControls", params, ManagedSettingsApplyControlsResult.class); + } + + /** + * Validates the managed settings a client is supplying for a session it is about to open, and returns them reduced to the keys a client is allowed to set. A client-supplied policy is not the same thing as an administrator's: it may only narrow permissions, so this accepts `permissions` and rejects every other key outright rather than ignoring it. Rejecting is the point — a host that silently dropped an unsupported key would report a policy as applied while running without it. Hosts call this before opening the session rather than letting the open fail, so a malformed policy is reported against the request that carried it. The runtime applies the same rule again when the session starts, so this cannot be used to smuggle a wider document past it. An accepted document that sets nothing comes back as an empty object, which is distinct from supplying nothing at all. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture parseClientValue(ManagedSettingsParseClientValueParams params) { + return caller.invoke("managedSettings.parseClientValue", params, ManagedSettingsParseClientValueResult.class); + } + + /** + * Composes the supplied server, device/MDM, device sandbox floor and policy-helper layers into the single effective managed policy a host should enforce, resolving each key across the layers by the runtime's own precedence rules. Hosts that assemble managed layers themselves use this so their precedence matches the runtime's exactly instead of reimplementing it. The composition is not a pure function of its inputs: an advisory sandbox force-on that arrived over the server channel is declined when this host cannot run a sandbox, so the result reflects the runtime host's capabilities, and the returned settings carry `sandboxAdvisoryFloorDeclined: true` when that happened. Enforced channels (device/MDM and policy helper) are never declined, and a server force-on carrying `failIfUnavailable` is preserved so the session fails loudly instead of quietly running unsandboxed. Rejects when a supplied layer is present but is not a JSON object, rather than treating it as unmanaged, because silently dropping a malformed policy would hand the user's own layer the win on exactly the keys the policy exists to control. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture resolveEffectiveValue(ManagedSettingsResolveEffectiveValueParams params) { + return caller.invoke("managedSettings.resolveEffectiveValue", params, ManagedSettingsResolveEffectiveValueResult.class); + } + + /** + * Decides what a host must do to its bypass-permissions state after a managed-policy resolution lands, given the state already in force and the account now signed in. A host holds two pieces of state — which layer disabled bypass mode, and for a server-delivered disable, the account it was pinned to — and cannot decide the next step from the new policy alone. Three rules make that so, and each one is a control rather than a preference. A device/MDM disable outranks the account, so a later server answer never lifts it. An unknown policy, which is what a failed fetch or a refusal this build cannot enforce yields, preserves whatever is in force instead of reverting to permissive. And a server disable is lifted only when the account it was pinned to is no longer the signed-in one, which is what makes signing in to an unrestricted account recover without a restart while a reconnect on the same restricted account does not. Hosts call this rather than reimplementing it because getting the pinning backwards either strands a disable on an account that never carried one or drops one that still applies. `setDisabledState` is omitted when the host must leave its stored flag untouched, which is distinct from being told to set it to false. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture resolveBypassDisableTransition(ManagedSettingsResolveBypassDisableTransitionParams params) { + return caller.invoke("managedSettings.resolveBypassDisableTransition", params, ManagedSettingsResolveBypassDisableTransitionResult.class); + } + + /** + * Resolves managed (enterprise policy) settings for a host from every layer at once: the account's server-delivered policy, the device/MDM layer, and a platform policy helper. Hosts use this instead of fetching and composing the layers themselves, because the per-layer precedence and the fail-closed rules that apply when a layer cannot be confirmed are the runtime's own and must match the policy a session will later enforce. It does not retain or apply anything to process-global policy state, so a host may call it before any session exists — which is the point, since plugin activation and one-shot commands resolve policy before a session is available to carry it. The returned per-layer outcome flags are load-bearing rather than diagnostic: a host must distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. Reports its diagnostics in `logMessages` rather than logging them, so a host that runs before a log sink exists still sees them. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture ingest(ManagedSettingsIngestParams params) { + return caller.invoke("managedSettings.ingest", params, ManagedSettingsIngestResult.class); + } + + /** + * Resolves the managed (enterprise policy) settings a host must enforce from startup, and judges the account against the enterprise sign-in pin in the same pass. This composes the layers the way `managedSettings.ingest` does and then answers the two questions a host cannot answer for itself: which fail-closed floors apply when a layer could not be confirmed, and whether this credential is allowed to sign in at all. The sign-in verdict is the reason a host must not assemble this itself from `managedSettings.ingest` — a pinned organization is an access control, and a host that composed the layers but skipped the pin would let a developer sign in with a personal or another enterprise's account and escape every control that keys off the signed-in identity. The verdict is computed on every resolution, including one that is not retained, so declining to apply policy never widens access. Set `retainAndApply` to keep the resolved policy as this runtime process's startup policy; leave it false to resolve without side effects. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture resolveStartupPolicy(ManagedSettingsResolveStartupPolicyParams params) { + return caller.invoke("managedSettings.resolveStartupPolicy", params, ManagedSettingsResolveStartupPolicyResult.class); + } + + /** + * Resolves the managed `remoteControl` policy for an account on its own, for a host deciding whether a remote-control session may start. Composes the same layers as `managedSettings.ingest` and returns only that one key, so a host does not have to know which layer won. An absent policy means the account is unmanaged for this capability and the host may proceed; that default is safe only while absence really does mean "no policy", so a service refusal that says an account policy exists which this client is too old to enforce resolves to an explicit disabled policy instead of to absence. A resolution that cannot be completed is rejected rather than answered as absence, for the same reason. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture loadRemoteControl(ManagedSettingsLoadRemoteControlParams params) { + return caller.invoke("managedSettings.loadRemoteControl", params, ManagedSettingsLoadRemoteControlResult.class); + } + + /** + * Evaluates the device-channel enterprise sign-in pin (MDM plist, registry, or managed-settings file) against a credential, without resolving any server-delivered policy. This is the gate an entry point runs before it branches, and the only one that can refuse a developer's first sign-in: it is local, needs no credential, and a server-delivered pin only ever reaches accounts already inside the organization. It fails closed by construction — a discovery that cannot determine whether a pin exists refuses rather than allows, because a control that fails open under a triggerable condition is not a control. Hosts that also want the server channel should call `managedSettings.resolveStartupPolicy`, which folds both channels into one verdict. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture resolveDeviceForceLoginOrgsGate(ManagedSettingsResolveDeviceForceLoginOrgsGateParams params) { + return caller.invoke("managedSettings.resolveDeviceForceLoginOrgsGate", params, ForceLoginOrgsDecision.class); + } + /** * Discovers device-managed settings from production MDM and managed-file sources, validates them against the runtime-owned managed-settings schema, and returns the canonical JSON without requiring a session. `managedSettings.resolve` returns the same device settings together with the account's server policy. * diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPermissionsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPermissionsApi.java new file mode 100644 index 0000000000..7e1c94d468 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPermissionsApi.java @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code permissions} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerPermissionsApi { + + private final RpcCaller caller; + + /** API methods for the {@code permissions.locations} sub-namespace. */ + final ServerPermissionsLocationsApi locations; + /** API methods for the {@code permissions.folderTrust} sub-namespace. */ + final ServerPermissionsFolderTrustApi folderTrust; + + /** @param caller the RPC transport function */ + ServerPermissionsApi(RpcCaller caller) { + this.caller = caller; + this.locations = new ServerPermissionsLocationsApi(caller); + this.folderTrust = new ServerPermissionsFolderTrustApi(caller); + } + + /** + * Interprets a verbatim managed `permissions` slice into the three policy questions a host asks before granting elevated permissions: whether bypass-permissions mode is forbidden, whether a policy exists that this build could not determine, and whether the layer supplies permission rules the session must enforce. An absent or empty slice means no managed policy applies. The runtime and its permission service share one policy type, so a new managed permission setting is interpreted in exactly one place; a host that reimplements the reading would silently diverge the first time that set grows. Hosts must fail closed on an undetermined policy rather than treating it as permission granted. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture evaluateManagedPolicy(PermissionsEvaluateManagedPolicyParams params) { + return caller.invoke("permissions.evaluateManagedPolicy", params, PermissionsEvaluateManagedPolicyResult.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPermissionsFolderTrustApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPermissionsFolderTrustApi.java new file mode 100644 index 0000000000..f27b5f0ed1 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPermissionsFolderTrustApi.java @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code permissions.folderTrust} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerPermissionsFolderTrustApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerPermissionsFolderTrustApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Reports whether a folder is trusted, reading the persisted trusted-folders list directly rather than through a session. Use this from a host that has no session yet, such as a one-shot command deciding whether to honor a checkout's own settings. It differs from the session-scoped check in two ways that matter: it takes the configuration directory to read the list from, instead of inheriting the session's, and it answers only from the persisted list, so trust a user granted for the lifetime of one session is not visible here. A host that has a session should prefer the session-scoped check, which also covers session-only trust. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture checkTrust(PermissionsFolderTrustCheckTrustParams params) { + return caller.invoke("permissions.folderTrust.checkTrust", params, FolderTrustCheckResult.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPermissionsLocationsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPermissionsLocationsApi.java new file mode 100644 index 0000000000..7b23a73b3f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPermissionsLocationsApi.java @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code permissions.locations} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerPermissionsLocationsApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerPermissionsLocationsApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Drops stored per-location permission grants whose directory no longer exists, and reports which location keys were removed. Runs against the permission store under the runtime's own Copilot home, the same store `session.permissions.locations.resolve` reads. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. It can become public once an SDK consumer needs to prune its own permission store. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture cleanupOrphaned() { + return caller.invoke("permissions.locations.cleanupOrphaned", java.util.Map.of(), LocationPermissionsCleanupResult.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPersistenceApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPersistenceApi.java new file mode 100644 index 0000000000..a98b036d8a --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerPersistenceApi.java @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code persistence} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerPersistenceApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerPersistenceApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Atomically replaces a JSON file's entire contents while holding the runtime's per-path lock. The lock lives in the runtime process, so a host that writes these files itself takes no part in it and can tear a concurrent runtime write; route the write here instead. Unlike a merging write this never reads or parses the existing file, so a previously corrupted snapshot is replaced wholesale rather than failing every later write. Use it only for callers that always persist a complete snapshot. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture writeRawJsonLocked(PersistenceWriteRawJsonLockedParams params) { + return caller.invoke("persistence.writeRawJsonLocked", params, PersistenceWriteRawJsonLockedResult.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRepoSettingsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRepoSettingsApi.java index 2c5aea2e10..247545adbc 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRepoSettingsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRepoSettingsApi.java @@ -26,6 +26,17 @@ final class ServerRepoSettingsApi { this.caller = caller; } + /** + * Atomically edits one allowed top-level repository setting. Reads the raw file, preserves unrelated keys, applies one scalar or list edit, validates the result and writes under one file lock, so concurrent sibling or list edits are not lost. A malformed or unsafe existing file returns `invalid` without a write; rejected keys, invalid values and I/O errors reject the call. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture edit(RepoSettingsEditParams params) { + return caller.invoke("repo.settings.edit", params, SettingsEditResult.class); + } + /** * Reads one repository settings file without settings normalization or layering. The existing JSONC parser accepts comments and trailing commas and applies its prototype-safety rules. Missing or blank files return an empty valid config. Invalid files return an empty config with invalid=true; other read failures reject. * diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRpc.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRpc.java index 556c3cf07a..51b83f9864 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRpc.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerRpc.java @@ -25,6 +25,20 @@ public final class ServerRpc { private final RpcCaller caller; + /** API methods for the {@code sandbox} namespace. */ + public final ServerSandboxApi sandbox; + /** API methods for the {@code persistence} namespace. */ + final ServerPersistenceApi persistence; + /** API methods for the {@code user} namespace. */ + public final ServerUserApi user; + /** API methods for the {@code repo} namespace. */ + final ServerRepoApi repo; + /** API methods for the {@code featureFlags} namespace. */ + final ServerFeatureFlagsApi featureFlags; + /** API methods for the {@code permissions} namespace. */ + final ServerPermissionsApi permissions; + /** API methods for the {@code managedSettings} namespace. */ + public final ServerManagedSettingsApi managedSettings; /** API methods for the {@code environments} namespace. */ public final ServerEnvironmentsApi environments; /** API methods for the {@code host} namespace. */ @@ -33,8 +47,6 @@ public final class ServerRpc { public final ServerHooksApi hooks; /** API methods for the {@code models} namespace. */ public final ServerModelsApi models; - /** API methods for the {@code sandbox} namespace. */ - public final ServerSandboxApi sandbox; /** API methods for the {@code tools} namespace. */ public final ServerToolsApi tools; /** API methods for the {@code account} namespace. */ @@ -59,20 +71,12 @@ public final class ServerRpc { final ServerGlobalStateApi globalState; /** API methods for the {@code commands} namespace. */ public final ServerCommandsApi commands; - /** API methods for the {@code user} namespace. */ - public final ServerUserApi user; - /** API methods for the {@code featureFlags} namespace. */ - final ServerFeatureFlagsApi featureFlags; - /** API methods for the {@code repo} namespace. */ - final ServerRepoApi repo; /** API methods for the {@code gitHubRepository} namespace. */ final ServerGitHubRepositoryApi gitHubRepository; /** API methods for the {@code gitHubOwners} namespace. */ final ServerGitHubOwnersApi gitHubOwners; /** API methods for the {@code git} namespace. */ final ServerGitApi git; - /** API methods for the {@code managedSettings} namespace. */ - public final ServerManagedSettingsApi managedSettings; /** API methods for the {@code runtime} namespace. */ public final ServerRuntimeApi runtime; /** API methods for the {@code sessionFs} namespace. */ @@ -93,11 +97,17 @@ public final class ServerRpc { */ public ServerRpc(RpcCaller caller) { this.caller = caller; + this.sandbox = new ServerSandboxApi(caller); + this.persistence = new ServerPersistenceApi(caller); + this.user = new ServerUserApi(caller); + this.repo = new ServerRepoApi(caller); + this.featureFlags = new ServerFeatureFlagsApi(caller); + this.permissions = new ServerPermissionsApi(caller); + this.managedSettings = new ServerManagedSettingsApi(caller); this.environments = new ServerEnvironmentsApi(caller); this.host = new ServerHostApi(caller); this.hooks = new ServerHooksApi(caller); this.models = new ServerModelsApi(caller); - this.sandbox = new ServerSandboxApi(caller); this.tools = new ServerToolsApi(caller); this.account = new ServerAccountApi(caller); this.secrets = new ServerSecretsApi(caller); @@ -110,13 +120,9 @@ public ServerRpc(RpcCaller caller) { this.agents = new ServerAgentsApi(caller); this.globalState = new ServerGlobalStateApi(caller); this.commands = new ServerCommandsApi(caller); - this.user = new ServerUserApi(caller); - this.featureFlags = new ServerFeatureFlagsApi(caller); - this.repo = new ServerRepoApi(caller); this.gitHubRepository = new ServerGitHubRepositoryApi(caller); this.gitHubOwners = new ServerGitHubOwnersApi(caller); this.git = new ServerGitApi(caller); - this.managedSettings = new ServerManagedSettingsApi(caller); this.runtime = new ServerRuntimeApi(caller); this.sessionFs = new ServerSessionFsApi(caller); this.llmInference = new ServerLlmInferenceApi(caller); diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxApi.java index 1484140f6a..2db9adfedd 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxApi.java @@ -23,11 +23,138 @@ public final class ServerSandboxApi { /** API methods for the {@code sandbox.proxyCa} sub-namespace. */ public final ServerSandboxProxyCaApi proxyCa; + /** API methods for the {@code sandbox.proxySecret} sub-namespace. */ + final ServerSandboxProxySecretApi proxySecret; + /** API methods for the {@code sandbox.settings} sub-namespace. */ + final ServerSandboxSettingsApi settings; /** @param caller the RPC transport function */ ServerSandboxApi(RpcCaller caller) { this.caller = caller; this.proxyCa = new ServerSandboxProxyCaApi(caller); + this.proxySecret = new ServerSandboxProxySecretApi(caller); + this.settings = new ServerSandboxSettingsApi(caller); + } + + /** + * Raises a user's sandbox settings to an administrator's managed sandbox floor and returns the result a session should actually run under. The floor can only tighten: an enterprise force-on is reflected even when the user's own `enabled` is false, and a user cannot lower a setting the floor raised. The result is normalized through the declared sandbox shape, so a key reorder or an undeclared passthrough key is not mistaken for a policy change by callers that diff two results. A host must call this rather than merge the two layers itself, because reimplementing the direction of the fold is what turns an administrator's floor into a suggestion. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture resolveFlooredConfig(SandboxResolveFlooredConfigParams params) { + return caller.invoke("sandbox.resolveFlooredConfig", params, SandboxResolveFlooredConfigResult.class); + } + + /** + * Builds the effective filesystem policy one `@`-file picker checks its suggestions against, so Git discovery and grant canonicalization run once for the picker's lifetime instead of on every debounced keystroke. Returns no policy when the sandbox is absent or disabled, which the paired filter reads as "keep every candidate". A host must pair this with `sandbox.filterPickerCandidates` rather than resolve a grant list itself, because the picker's grants are narrower than a file tool's — the same path a built-in tool may read can be one the picker must not offer. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture preparePickerPolicy(SandboxPreparePickerPolicyParams params) { + return caller.invoke("sandbox.preparePickerPolicy", params, SandboxPreparePickerPolicyResult.class); + } + + /** + * Checks a batch of `@`-file picker suggestions against a policy prepared by `sandbox.preparePickerPolicy` and returns one allow decision per candidate, positionally aligned with the request. Batched deliberately: each check canonicalizes a path component-by-component through the real filesystem, so one call amortizes that over a single hop rather than dozens while the user types. A directory the policy does not itself allow can still be kept as a waypoint to an allowed subtree. An absent policy keeps every candidate. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture filterPickerCandidates(SandboxFilterPickerCandidatesParams params) { + return caller.invoke("sandbox.filterPickerCandidates", params, SandboxFilterPickerCandidatesResult.class); + } + + /** + * The sandbox a single named feature actually launches under, which is not the same as the session's sandbox. A feature is routed out of the sandbox by its own flag — `sandboxMcpServers`, `sandboxLspServers` — so an enabled session can still start one server confined and another free. Returns a disabled sandbox rather than an error when the host has no sandbox slice at all, so an absent config and an opted-out feature read alike at the launch site. A host must ask per feature rather than reuse the session config, because reading only `enabled` confines a server the user opted out of, or reports as sandboxed one that is not. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture resolveForOptional(SandboxResolveForOptionalParams params) { + return caller.invoke("sandbox.resolveForOptional", params, SandboxEffectiveForOptionalResult.class); + } + + /** + * Reports whether this machine can run an OS-level command sandbox at all. A host must ask before it offers sandboxing, because the answer is a property of the machine rather than of any setting: on Linux it depends on bubblewrap being installed, and on Windows on the OS build supporting BaseContainer. Probing it requires spawning a process the first time, so the answer is cached for the life of the runtime. A host that assumes support and enables the sandbox anyway produces a session in which every shell command fails. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture checkPlatformSupport() { + return caller.invoke("sandbox.checkPlatformSupport", java.util.Map.of(), Boolean.class); + } + + /** + * Reports whether this Windows host's BaseContainer implementation can reach the host's loopback interface directly, which is what a local-network policy needs to avoid routing through the egress proxy. Like `sandbox.checkPlatformSupport`, the answer is a property of the machine's OS build rather than of any setting, and resolving it the first time spawns a platform probe. A host that offers the direct local-network option on a machine that lacks the capability produces a session whose sandboxed commands cannot reach local services. Always false off Windows. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture checkWindowsHostLoopbackSupport() { + return caller.invoke("sandbox.checkWindowsHostLoopbackSupport", java.util.Map.of(), Boolean.class); + } + + /** + * The explanation a host shows when it refuses an explicit request to turn the sandbox on for a machine that cannot run one. Carries the platform-specific remedy — install bubblewrap, update Windows — and the documentation link, so a host that got `false` from `sandbox.checkPlatformSupport` does not have to compose its own reason and cannot describe the same machine differently from the runtime's own spawn path. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getUnsupportedMessage() { + return caller.invoke("sandbox.getUnsupportedMessage", java.util.Map.of(), String.class); + } + + /** + * The notice a host shows when a stored `sandbox` setting is being ignored for this session because the machine cannot enforce it. Distinct from `sandbox.getUnsupportedMessage`, which refuses an explicit request: this one reports that a setting the user already saved is inert, states that commands will run unsandboxed, and confirms the stored setting itself is left alone. A host that stays silent here leaves the user believing a sandbox is active. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getUnsupportedSettingDisabledNotice() { + return caller.invoke("sandbox.getUnsupportedSettingDisabledNotice", java.util.Map.of(), String.class); + } + + /** + * The warning a host prints at startup when a session asked for a sandbox on a machine that cannot run one. The third of the unsupported notices, and the only one that depends on the policy in force: it names the remedy the reader can actually act on, which is the stored setting for an unmanaged host, an administrator for a managed one, and waiting for the policy to resolve when the sandbox stayed on only because the policy could not be determined. Returns no notice when the machine does support a sandbox, so a host can call it unconditionally on the startup path. A host that composes its own warning tells a managed user to change a setting their policy will overwrite. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getUnsupportedStartupNotice(SandboxGetUnsupportedStartupNoticeParams params) { + return caller.invoke("sandbox.getUnsupportedStartupNotice", params, SandboxUnsupportedStartupNoticeResult.class); + } + + /** + * Whether one slash command stays reachable while sandbox enforcement is unavailable and the session is otherwise blocked. The permitted set is deliberately narrow — commands that only report state, and the few that let the user repair or leave the situation — and it is keyed on the arguments as well as the name, so `/sandbox status` is admitted where `/sandbox enable` is not. A host must ask rather than keep its own list: a command this returns false for is one the runtime would refuse anyway, and a divergent list either strands the user with no way out or admits a command that acts on an unenforced session. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture checkEnforcementCommand(SandboxCheckEnforcementCommandParams params) { + return caller.invoke("sandbox.checkEnforcementCommand", params, Boolean.class); + } + + /** + * Returns the documentation URL a host should point a user at when it declines or downgrades a sandbox setting. The runtime owns the address so every surface cites the same page and a host does not hard-code a link that later moves. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getDocsUrl() { + return caller.invoke("sandbox.getDocsUrl", java.util.Map.of(), SandboxDocsUrlResult.class); } /** diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxProxyCaApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxProxyCaApi.java index 0cc59738e9..5559a0dbcb 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxProxyCaApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxProxyCaApi.java @@ -26,6 +26,28 @@ public final class ServerSandboxProxyCaApi { this.caller = caller; } + /** + * Reports whether this runtime process can offer installing the sandbox credential-proxy certificate authority into OS trust. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture checkInstallationSupport() { + return caller.invoke("sandbox.proxyCa.checkInstallationSupport", java.util.Map.of(), Boolean.class); + } + + /** + * Reports whether this sandbox configuration uses the credential proxy and can need certificate-authority setup. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + public CompletableFuture checkRelevance(SandboxProxyCaCheckRelevanceParams params) { + return caller.invoke("sandbox.proxyCa.checkRelevance", params, Boolean.class); + } + /** * Reports whether the persistent certificate authority of the sandbox credential proxy exists, whether OS trust includes it, and whether it must be rotated. Changes nothing. * diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxProxySecretApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxProxySecretApi.java new file mode 100644 index 0000000000..1432755fac --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxProxySecretApi.java @@ -0,0 +1,73 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code sandbox.proxySecret} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerSandboxProxySecretApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerSandboxProxySecretApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Reports where this runtime keeps the sandbox proxy password: the credential store directory and the entry identifier within it. Both are derived from the configuration directory this runtime was started with, so a host does not resolve them itself. Read this to recognize a `${secret:…}` value in stored sandbox settings as this runtime's own proxy password rather than a reference the user wrote by hand. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getLocation() { + return caller.invoke("sandbox.proxySecret.getLocation", java.util.Map.of(), SandboxProxySecretLocation.class); + } + + /** + * Reads the stored sandbox proxy password from the credential store `sandbox.proxySecret.getLocation` names, preferring the OS keychain and falling back to the on-disk store. Reports an absent value rather than failing when no entry exists. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture get() { + return caller.invoke("sandbox.proxySecret.get", java.util.Map.of(), SandboxProxySecretGetResult.class); + } + + /** + * Stores the sandbox proxy password in the credential store `sandbox.proxySecret.getLocation` names, replacing any existing entry. Reports whether the OS keychain accepted it or it fell back to the on-disk store. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture save(SandboxProxySecretSaveParams params) { + return caller.invoke("sandbox.proxySecret.save", params, SandboxProxySecretSaveResult.class); + } + + /** + * Removes the stored sandbox proxy password from the credential store `sandbox.proxySecret.getLocation` names. Succeeds when no entry exists, so it is safe to call while clearing a proxy password whose origin is unknown. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture delete() { + return caller.invoke("sandbox.proxySecret.delete", java.util.Map.of(), Void.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxSettingsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxSettingsApi.java new file mode 100644 index 0000000000..4d323a03ac --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerSandboxSettingsApi.java @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.copilot.CopilotExperimental; +import java.util.concurrent.CompletableFuture; +import javax.annotation.processing.Generated; + +/** + * API methods for the {@code sandbox.settings} namespace. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +final class ServerSandboxSettingsApi { + + private final RpcCaller caller; + + /** @param caller the RPC transport function */ + ServerSandboxSettingsApi(RpcCaller caller) { + this.caller = caller; + } + + /** + * Resolves a stored sandbox settings object into the effective one, filling every value the user left unset with its default. Read this to render or reason about the sandbox configuration a session would actually run under, rather than the sparse document the user wrote. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture applyDefaults(SandboxSettingsApplyDefaultsParams params) { + return caller.invoke("sandbox.settings.applyDefaults", params, JsonNode.class); + } + +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerUserSettingsApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerUserSettingsApi.java index 627d1c9866..75c8e38934 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerUserSettingsApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/ServerUserSettingsApi.java @@ -7,6 +7,7 @@ package com.github.copilot.generated.rpc; +import com.fasterxml.jackson.databind.JsonNode; import com.github.copilot.CopilotExperimental; import java.util.concurrent.CompletableFuture; import javax.annotation.processing.Generated; @@ -26,6 +27,160 @@ public final class ServerUserSettingsApi { this.caller = caller; } + /** + * Adds or removes one hook key in the user `disabledHooks` setting, rewriting settings.json in place and leaving every other setting untouched. Reports a typed outcome rather than failing the call, so a host can tell an unparseable settings file apart from a write that could not complete. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture setHookDisabled(UserSettingsSetHookDisabledParams params) { + return caller.invoke("user.settings.setHookDisabled", params, UserSettingsSetHookDisabledResult.class); + } + + /** + * Reads the user's settings document exactly as `user.settings.load` does, but from a caller-supplied configuration directory instead of the one the server resolved for itself. Use this when a consumer scopes a session to its own Copilot home — the SDK's per-session `configDir` override — so the settings read match the directory that session actually uses. An absent or empty `configDir` resolves the server's own home, making this identical to `user.settings.load`. Hook-validation relaxations are deliberately not caller-supplied: they continue to come from the server's environment, so a consumer cannot widen the host's hook policy through this method. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture loadForConfigDir(UserSettingsLoadForConfigDirParams params) { + return caller.invoke("user.settings.loadForConfigDir", params, JsonNode.class); + } + + /** + * Reads a repository's checked-in settings document as stored, normalized, together with any diagnostic raised while reading it. This is the repository half of the layering `user.settings.get` reports: `user.settings.load` reads the user's own document, and this reads the one a repository checks in to govern the keys `user.settings.governanceKeys` lists as repo-governable. A document that fails to parse, or that sets a key a repository may not govern, is reported through `warning` while the settings that did load are still returned, so a consumer surfaces the diagnostic and continues rather than failing the session. When `repoRoot` is the user's home directory the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as repository policy. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture loadRepo(UserSettingsLoadRepoParams params) { + return caller.invoke("user.settings.loadRepo", params, UserSettingsLoadRepoResult.class); + } + + /** + * Reads a repository's settings and merges them over a supplied user layer in one step, returning the settings a consumer should act on inside that repository. Use this rather than reading the two layers separately: the merge is per setting and collection-aware, so a repository adds to the collections it is allowed to influence without replacing the user's own entries, and a whole-document overlay would get that wrong. Any diagnostic raised while reading the repository layer is returned rather than printed, so the consumer decides how to surface it; the settings that did load are merged regardless. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture loadAndMergeRepo(UserSettingsLoadAndMergeRepoParams params) { + return caller.invoke("user.settings.loadAndMergeRepo", params, UserSettingsLoadAndMergeRepoResult.class); + } + + /** + * Reports the on-disk path of the settings document `user.settings.load` and `user.settings.set` read and write. Resolved the same way those methods resolve it, so a host that shows or opens the settings file names the file the runtime actually uses, including the extensionless legacy `settings` file when that is what is present. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getPath() { + return caller.invoke("user.settings.getPath", java.util.Map.of(), UserSettingsPathResult.class); + } + + /** + * Reads the user's stored settings together with the diagnostic raised while reading them. This is `user.settings.load` plus the reason part of the document was ignored: that one answers the document alone, so a caller cannot tell a clean read from a salvaged one. Read this when the caller is about to write the file back, where accepting a partial parse would discard every value the loader could not read. The settings that did load are still reported alongside the warning, so a consumer may surface it and continue instead of failing. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture loadWithWarning() { + return caller.invoke("user.settings.loadWithWarning", java.util.Map.of(), UserSettingsLoadWithWarningResult.class); + } + + /** + * Folds a user settings layer over a managed (enterprise policy) layer and returns the merged settings. The managed layer's governance keys win, `autoTier` resolves through its overridable form, and the two per-entry control maps (`enabledPlugins`, `extraKnownMarketplaces`) union across the layers and are then stamped back from the managed layer, so each entry an administrator declares wins while the user keeps control of the rest. The parameters are named for their layers rather than being a generic base/override pair: nothing about a settings object identifies which layer produced it, so the runtime cannot detect a transposed call, and transposing one resolves the governance keys in the user's favour instead of the administrator's. Supplying only one layer returns it unchanged, and supplying neither returns an empty object. Rejects a managed `autoTier` that is neither a user-configurable tier nor a single-key overridable form, rather than silently dropping it. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture mergeManagedAndUser(UserSettingsMergeManagedAndUserParams params) { + return caller.invoke("user.settings.mergeManagedAndUser", params, UserSettingsMergeManagedAndUserResult.class); + } + + /** + * Folds a repository's settings layer into the user layer. Each repo-overridable key carries a directional policy chosen so a repository can only add restrictions and never relax the user's own. The two per-entry managed control maps are the exception those directional rules cannot express — a repository may legitimately enable plugins and declare marketplaces — so they are re-stamped afterwards from the runtime's ambient managed policy. That makes the result depend on the runtime process's managed state and not on the arguments alone: a host must call this rather than reimplement the fold, or a repository could relax a restriction the administrator imposed. Rejects when either layer is not a JSON object. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture mergeRepoValue(UserSettingsMergeRepoValueParams params) { + return caller.invoke("user.settings.mergeRepoValue", params, UserSettingsMergeRepoValueResult.class); + } + + /** + * Runs the one-time migration that moves a staff account's update channel to stable, and records that it ran. Idempotent and self-gating: it takes a lock over the global-state file, re-reads the completion stamp inside it, and returns `current` rather than migrating twice, so two hosts racing at startup cannot both migrate. Only a `migrated` status means the persisted settings changed and the caller should reload them. An account on the experimental channel is deliberately left alone and reported as `excluded-experimental`. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture migrateStaffUpdateChannelOnce(UserSettingsMigrateStaffUpdateChannelOnceParams params) { + return caller.invoke("user.settings.migrateStaffUpdateChannelOnce", params, UserSettingsMigrateStaffUpdateChannelOnceResult.class); + } + + /** + * Runs the one-time reset that clears a staff account's pinned model selection, and reports the timestamp the host should record. Idempotent and self-gating: the reset is gated on a fixed cutoff, so a caller that passes back the timestamp it recorded gets `didReset: false` rather than a second reset. It applies to staff accounts only; any other account is reported as not reset without the settings document being opened. Only `didReset: true` means the persisted settings changed, and only then are the updated settings returned for the host to adopt. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture resetStaffModelSelectionOnce(UserSettingsResetStaffModelSelectionOnceParams params) { + return caller.invoke("user.settings.resetStaffModelSelectionOnce", params, UserSettingsResetStaffModelSelectionOnceResult.class); + } + + /** + * Reports the top-level keys in the user settings document that the runtime does not recognize, phrased for display to the user. This is a separate question from the warning `user.settings.loadWithWarning` returns: that one describes parts of the document the loader had to ignore to load the rest, whereas an unknown key parses cleanly and is simply not a setting, so a host that surfaces only the load warning silently accepts a misspelled key that will never take effect. Nothing is reported when the document is absent, unreadable, or failed to load, because an unknown-key list derived from a document the runtime could not read would be misleading rather than helpful. Inspection never modifies the document. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture getUnknownKeysWarning(UserSettingsGetUnknownKeysWarningParams params) { + return caller.invoke("user.settings.getUnknownKeysWarning", params, UserSettingsUnknownKeysWarningResult.class); + } + + /** + * Resolves the effective runtime settings for a host that is about to start a session, layering the given overrides over the settings documents, the environment and the platform defaults. A host cannot assemble this itself: the precedence between a user document, a repository document, the managed layers and the environment is the runtime's own rule, and a host that re-implements it drifts from the server it is configuring. The working directory, environment and platform are taken as arguments rather than read from the server process, so a host resolving settings for a directory other than its own gets that directory's answer. Nothing is written; this only computes. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture buildRuntime(UserSettingsBuildRuntimeParams params) { + return caller.invoke("user.settings.buildRuntime", params, JsonNode.class); + } + + /** + * Runs the one-time migration that moves a staff account's log level to the current default, and records that it ran. Idempotent and self-gating: it takes a lock over the global-state file and re-reads the completion stamp inside it, so two hosts racing at startup cannot both migrate. Only `refreshed` can have changed the persisted settings, and the settings it returns are the document re-read after the write, so a host should adopt them rather than reloading separately and racing the next writer. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture migrateStaffLogLevelOnce(UserSettingsMigrateStaffLogLevelOnceParams params) { + return caller.invoke("user.settings.migrateStaffLogLevelOnce", params, UserSettingsMigrateStaffLogLevelOnceResult.class); + } + + /** + * Runs the one-time cleanup that removes obsolete CLI-owned settings and legacy rubber-duck keys from the user's settings document, and reports what it did. Idempotent and safe to call on every startup: with nothing obsolete left it reports `unchanged` and writes nothing. The cleanup preserves every key it does not recognize, so a setting written by a newer host is never dropped by an older one, and a document that fails to parse is reported `invalid` and left untouched rather than rewritten from a partial read. The cleaned document is not returned: it is written before this replies, so `user.settings.load` reads it authoritatively. A host that surfaces unrecognized keys through `user.settings.unknownKeys` wants this first, because the keys this retires would otherwise be shown to the user as if they were misspelled settings. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ + @CopilotExperimental + CompletableFuture migrateObsoleteOnDisk(UserSettingsMigrateObsoleteOnDiskParams params) { + return caller.invoke("user.settings.migrateObsoleteOnDisk", params, UserSettingsMigrateObsoleteOnDiskResult.class); + } + /** * Lists every known user setting from settings.json, each with its effective value, its default, and whether it is at the default — so settings the user has never set still appear with their default value. Does not include repository- or enterprise-managed overrides that the runtime layers on top at session time. * diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionGitHubAuthApi.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionGitHubAuthApi.java index 388576154a..f98aa7791d 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionGitHubAuthApi.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionGitHubAuthApi.java @@ -138,8 +138,8 @@ CompletableFuture switchToAuth(SessionGitHubAuthSwitchToAuthParams params) * @since 1.0.0 */ @CopilotExperimental - CompletableFuture logout() { - return caller.invoke("session.gitHubAuth.logout", java.util.Map.of("sessionId", this.sessionId), Void.class); + CompletableFuture logout() { + return caller.invoke("session.gitHubAuth.logout", java.util.Map.of("sessionId", this.sessionId), Boolean.class); } /** @@ -152,10 +152,10 @@ CompletableFuture logout() { * @since 1.0.0 */ @CopilotExperimental - CompletableFuture logoutUser(SessionGitHubAuthLogoutUserParams params) { + CompletableFuture logoutUser(SessionGitHubAuthLogoutUserParams params) { com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); _p.put("sessionId", this.sessionId); - return caller.invoke("session.gitHubAuth.logoutUser", _p, Void.class); + return caller.invoke("session.gitHubAuth.logoutUser", _p, Boolean.class); } /** diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionRpc.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionRpc.java index 21050a5317..9a56863901 100644 --- a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionRpc.java +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/SessionRpc.java @@ -280,8 +280,8 @@ public CompletableFuture interruptMainTurn(Sessi * @since 1.0.0 */ @CopilotExperimental - public CompletableFuture cancelAllBackgroundAgents() { - return caller.invoke("session.cancelAllBackgroundAgents", java.util.Map.of("sessionId", this.sessionId), Void.class); + public CompletableFuture cancelAllBackgroundAgents() { + return caller.invoke("session.cancelAllBackgroundAgents", java.util.Map.of("sessionId", this.sessionId), Long.class); } /** diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/StaffLogLevelMigrationStatus.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/StaffLogLevelMigrationStatus.java new file mode 100644 index 0000000000..1538068712 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/StaffLogLevelMigrationStatus.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * What the one-time staff log-level migration did. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum StaffLogLevelMigrationStatus { + /** The {@code ineligible} variant. */ + INELIGIBLE("ineligible"), + /** The {@code current} variant. */ + CURRENT("current"), + /** The {@code refreshed} variant. */ + REFRESHED("refreshed"); + + private final String value; + StaffLogLevelMigrationStatus(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static StaffLogLevelMigrationStatus fromValue(String value) { + for (StaffLogLevelMigrationStatus v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown StaffLogLevelMigrationStatus value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/StaffUpdateChannelMigrationStatus.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/StaffUpdateChannelMigrationStatus.java new file mode 100644 index 0000000000..a3cb8f83d7 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/StaffUpdateChannelMigrationStatus.java @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * What the one-time staff update-channel migration did. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum StaffUpdateChannelMigrationStatus { + /** The {@code ineligible} variant. */ + INELIGIBLE("ineligible"), + /** The {@code current} variant. */ + CURRENT("current"), + /** The {@code migrated} variant. */ + MIGRATED("migrated"), + /** The {@code completed} variant. */ + COMPLETED("completed"), + /** The {@code excluded-experimental} variant. */ + EXCLUDED_EXPERIMENTAL("excluded-experimental"); + + private final String value; + StaffUpdateChannelMigrationStatus(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static StaffUpdateChannelMigrationStatus fromValue(String value) { + for (StaffUpdateChannelMigrationStatus v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown StaffUpdateChannelMigrationStatus value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsBuildRuntimeParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsBuildRuntimeParams.java new file mode 100644 index 0000000000..7b95e8df04 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsBuildRuntimeParams.java @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The overrides and host context to resolve effective runtime settings from. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsBuildRuntimeParams( + /** Settings that take precedence over every document and environment layer, such as the values a host derived from its own command line. Keyed by setting name, with each value carried verbatim, so a host may pass keys this runtime does not recognize. Absent when the host contributes no overrides of its own. */ + @JsonProperty("overrides") Map overrides, + /** The directory the settings are being resolved for. This selects the repository-scoped document, so a host resolving settings for a directory other than its own process working directory must pass that directory here. */ + @JsonProperty("workingDirectory") String workingDirectory, + /** The environment to read settings-bearing variables from. Passed explicitly rather than read from the server process so a host can resolve settings for an environment it is about to create rather than the one it runs in. */ + @JsonProperty("environment") Map environment, + /** The platform to apply platform-specific defaults for, in the same spelling the host's own runtime reports. */ + @JsonProperty("platform") String platform +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetUnknownKeysWarningParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetUnknownKeysWarningParams.java new file mode 100644 index 0000000000..a90c4a6853 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsGetUnknownKeysWarningParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Selects the configuration directory whose user settings document should be inspected for unrecognized top-level keys. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsGetUnknownKeysWarningParams( + /** The configuration directory, home directory and environment to resolve the settings document from. A host that scopes a session to its own Copilot home must pass that directory here, or the server's own home is inspected instead. */ + @JsonProperty("context") UserSettingsHostContext context +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsHostContext.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsHostContext.java new file mode 100644 index 0000000000..441023ed14 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsHostContext.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The filesystem and environment facts a user-settings file is resolved from. Passed explicitly rather than read from the runtime's own process, so a host whose configuration directory differs from its process environment resolves the file it means. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsHostContext( + /** The Copilot configuration directory, when the host set one. Takes precedence over `COPILOT_HOME` and the home directory. */ + @JsonProperty("configDir") String configDir, + /** The user's home directory, used when neither a configuration directory nor `COPILOT_HOME` is set. */ + @JsonProperty("homeDirectory") String homeDirectory, + /** The host's environment variables. `COPILOT_HOME` is read from here, as are the variables a settings hook may expand. */ + @JsonProperty("environment") Map environment +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadAndMergeRepoParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadAndMergeRepoParams.java new file mode 100644 index 0000000000..56af230edf --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadAndMergeRepoParams.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * A repository to read settings from, and the user layer they are merged over. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsLoadAndMergeRepoParams( + /** Absolute path of the repository root whose settings to read. When this is the user's home directory, the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as if it were repository policy. */ + @JsonProperty("repoRoot") String repoRoot, + /** The user's own settings, keyed by setting name. The repository layer is merged over this; a repository may only add to the collection settings it is allowed to influence, so a user setting it does not name survives unchanged. */ + @JsonProperty("userSettings") Map userSettings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadAndMergeRepoResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadAndMergeRepoResult.java new file mode 100644 index 0000000000..15b319f3d9 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadAndMergeRepoResult.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The settings a consumer should act on inside a repository, together with any diagnostic raised while reading the repository layer. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsLoadAndMergeRepoResult( + /** The merged settings document, keyed by setting name. Equals the supplied user layer when the repository declares no settings. */ + @JsonProperty("settings") Map settings, + /** Why part of the repository document was ignored, as a single human-readable string joining every diagnostic with `; `. Null when it loaded cleanly. The settings that did load are still merged, so a consumer should surface this and continue rather than treat it as a failure. */ + @JsonProperty("warning") String warning +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadForConfigDirParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadForConfigDirParams.java new file mode 100644 index 0000000000..0f745e7002 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadForConfigDirParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Selects the configuration directory whose user settings to read. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsLoadForConfigDirParams( + /** Copilot configuration directory to read the settings document from, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to read the directory the server resolved for itself. */ + @JsonProperty("configDir") String configDir +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadRepoParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadRepoParams.java new file mode 100644 index 0000000000..2f809ae5b6 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadRepoParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Selects the repository whose checked-in settings to read. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsLoadRepoParams( + /** Absolute path of the repository root whose settings to read. When this is the user's home directory, the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as if it were repository policy. */ + @JsonProperty("repoRoot") String repoRoot +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadRepoResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadRepoResult.java new file mode 100644 index 0000000000..eb3f16cb85 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadRepoResult.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * A repository's settings as stored, together with any diagnostic raised while reading them. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsLoadRepoResult( + /** The repository's settings document, keyed by setting name, with each value carried verbatim. Null when the repository declares no settings. */ + @JsonProperty("settings") Map settings, + /** Why part of the document was ignored, as a single human-readable string joining every diagnostic with `; `. Null when the document loaded cleanly. The settings that did load are still reported, so a consumer should surface this and continue rather than treat it as a failure. */ + @JsonProperty("warning") String warning +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadWithWarningResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadWithWarningResult.java new file mode 100644 index 0000000000..1f9ba38d07 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsLoadWithWarningResult.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The user's stored settings, together with any diagnostic raised while reading them. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsLoadWithWarningResult( + /** The stored user settings document, keyed by setting name, with each value carried verbatim. Empty when the file could not be read at all. */ + @JsonProperty("settings") Map settings, + /** Why part of the document was ignored, phrased for display to the user. Null when the document loaded cleanly. The settings that did load are still reported, so a consumer may surface this and continue rather than treat it as a failure. */ + @JsonProperty("warning") String warning +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeManagedAndUserParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeManagedAndUserParams.java new file mode 100644 index 0000000000..740de3bc35 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeManagedAndUserParams.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The managed (enterprise policy) layer and the user layer to fold together. The field names carry the layer identity: nothing about a settings object identifies which layer produced it, so a generic base/override pair would let a caller transpose them and silently resolve the governance keys in the user's favour. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsMergeManagedAndUserParams( + /** The managed layer. Its governance keys win, and the per-entry `enabledPlugins` and `extraKnownMarketplaces` control maps are stamped back from it after the union. Omitted when the host is unmanaged. */ + @JsonProperty("managed") Object managed, + /** The user's own settings layer. Wins on every key the managed layer does not govern. Omitted when the user has no settings yet. */ + @JsonProperty("user") Object user +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeManagedAndUserResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeManagedAndUserResult.java new file mode 100644 index 0000000000..c28bbddba3 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeManagedAndUserResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The user layer folded over the managed layer. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsMergeManagedAndUserResult( + /** The merged settings. An empty object when neither layer was supplied, so an unmanaged host with no user settings governs nothing. */ + @JsonProperty("settingsJson") Object settingsJson +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeRepoValueParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeRepoValueParams.java new file mode 100644 index 0000000000..30c47590c4 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeRepoValueParams.java @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * The user layer and the repository layer to fold together. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsMergeRepoValueParams( + /** The user's settings, already resolved against any managed layer. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("userSettings") Object userSettings, + /** The repository's checked-in settings layer. */ + @JsonInclude(JsonInclude.Include.ALWAYS) + @JsonProperty("repoSettings") Object repoSettings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeRepoValueResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeRepoValueResult.java new file mode 100644 index 0000000000..136bf12f30 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMergeRepoValueResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The repository layer folded into the user layer. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsMergeRepoValueResult( + /** The merged settings, with the per-entry managed control maps re-stamped from the runtime's ambient managed policy. */ + @JsonProperty("settingsJson") Object settingsJson +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateObsoleteOnDiskParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateObsoleteOnDiskParams.java new file mode 100644 index 0000000000..8c7fce5dd4 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateObsoleteOnDiskParams.java @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Selects the configuration directory whose settings document to clean. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsMigrateObsoleteOnDiskParams( + /** The configuration directory holding the settings document to clean. A host that scopes a session to its own Copilot home passes that directory here; omit it to clean the document under the home the server resolved for itself. The home directory and environment are deliberately not caller-supplied: they decide only the settings path root and the two hook-parsing flags, and those describe the process doing the reading rather than the caller. */ + @JsonProperty("configDir") String configDir +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateObsoleteOnDiskResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateObsoleteOnDiskResult.java new file mode 100644 index 0000000000..5e894430ed --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateObsoleteOnDiskResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The outcome of the one-time obsolete-settings cleanup. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsMigrateObsoleteOnDiskResult( + /** What the cleanup did. Only `changed` rewrote the document. The cleaned settings are not returned here: the document is written before this replies, so `user.settings.load` reads it authoritatively. */ + @JsonProperty("status") UserSettingsMigrateObsoleteOnDiskStatus status +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateObsoleteOnDiskStatus.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateObsoleteOnDiskStatus.java new file mode 100644 index 0000000000..38ef9d9a42 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateObsoleteOnDiskStatus.java @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * What the one-time obsolete-settings cleanup did to the document. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +enum UserSettingsMigrateObsoleteOnDiskStatus { + /** The {@code missing} variant. */ + MISSING("missing"), + /** The {@code invalid} variant. */ + INVALID("invalid"), + /** The {@code unchanged} variant. */ + UNCHANGED("unchanged"), + /** The {@code changed} variant. */ + CHANGED("changed"); + + private final String value; + UserSettingsMigrateObsoleteOnDiskStatus(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static UserSettingsMigrateObsoleteOnDiskStatus fromValue(String value) { + for (UserSettingsMigrateObsoleteOnDiskStatus v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown UserSettingsMigrateObsoleteOnDiskStatus value: " + value); + } +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffLogLevelOnceParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffLogLevelOnceParams.java new file mode 100644 index 0000000000..24220b8882 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffLogLevelOnceParams.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Selects the configuration directory to run the one-time staff log-level migration against, and supplies the caller's record of whether it has already run. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsMigrateStaffLogLevelOnceParams( + /** The configuration directory, home directory and environment to resolve the settings and global-state documents from. A host that scopes a session to its own Copilot home must pass that directory here, or the migration is evaluated against the server's own home instead. */ + @JsonProperty("context") UserSettingsHostContext context, + /** When the caller last recorded this migration, as an ISO-8601 timestamp. Supplying it lets the runtime answer `current` without re-running the evaluation. */ + @JsonProperty("cachedCompletedAt") String cachedCompletedAt +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffLogLevelOnceResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffLogLevelOnceResult.java new file mode 100644 index 0000000000..2ffc6ba552 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffLogLevelOnceResult.java @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The outcome of the one-time staff log-level migration. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsMigrateStaffLogLevelOnceResult( + /** What the migration did. Only `refreshed` can have changed the persisted settings. */ + @JsonProperty("status") StaffLogLevelMigrationStatus status, + /** When the migration was recorded as done, as an ISO-8601 timestamp. Absent only for `ineligible`, which records nothing. */ + @JsonProperty("completedAt") String completedAt, + /** The settings document as it stands after the migration, keyed by setting name. Present only for `refreshed`, and only when the document could be re-read cleanly. */ + @JsonProperty("settings") Map settings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffUpdateChannelOnceParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffUpdateChannelOnceParams.java new file mode 100644 index 0000000000..77a3287abe --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffUpdateChannelOnceParams.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The filesystem and environment facts a user-settings file is resolved from. Passed explicitly rather than read from the runtime's own process, so a host whose configuration directory differs from its process environment resolves the file it means. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsMigrateStaffUpdateChannelOnceParams( + /** The Copilot configuration directory, when the host set one. Takes precedence over `COPILOT_HOME` and the home directory. */ + @JsonProperty("configDir") String configDir, + /** The user's home directory, used when neither a configuration directory nor `COPILOT_HOME` is set. */ + @JsonProperty("homeDirectory") String homeDirectory, + /** The host's environment variables. `COPILOT_HOME` is read from here, as are the variables a settings hook may expand. */ + @JsonProperty("environment") Map environment +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffUpdateChannelOnceResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffUpdateChannelOnceResult.java new file mode 100644 index 0000000000..8d21eca4f1 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsMigrateStaffUpdateChannelOnceResult.java @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The outcome of the one-time staff update-channel migration. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsMigrateStaffUpdateChannelOnceResult( + /** What the migration did. Only `migrated` means the persisted settings changed. */ + @JsonProperty("status") StaffUpdateChannelMigrationStatus status, + /** When the migration was recorded as done, as an ISO-8601 timestamp. Absent only for `ineligible`, which records nothing. */ + @JsonProperty("completedAt") String completedAt +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsPathResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsPathResult.java new file mode 100644 index 0000000000..5c4ac0d88e --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsPathResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The on-disk location of the user's settings document. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsPathResult( + /** Absolute path to the settings file this runtime reads and writes. Normally `settings.json` under the Copilot configuration directory; an extensionless legacy `settings` file is reported instead when it exists and `settings.json` does not. */ + @JsonProperty("path") String path +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsResetStaffModelSelectionOnceParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsResetStaffModelSelectionOnceParams.java new file mode 100644 index 0000000000..98ec0b7fb3 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsResetStaffModelSelectionOnceParams.java @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Selects the configuration directory to run the one-time staff model-selection reset against, and supplies the caller's record of whether it has already run. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsResetStaffModelSelectionOnceParams( + /** The configuration directory, home directory and environment to resolve the settings and global-state documents from. A host that scopes a session to its own Copilot home must pass that directory here, or the reset is evaluated against the server's own home instead. */ + @JsonProperty("context") UserSettingsHostContext context, + /** Whether the signed-in account is a staff account. The reset applies only to staff, so anything other than `true` returns `didReset: false` without touching the settings document. */ + @JsonProperty("staff") Boolean staff, + /** When the caller last recorded this reset, as an ISO-8601 timestamp. A timestamp at or after the cutoff means the reset already ran and is returned unchanged. */ + @JsonProperty("staffModelResetAt") String staffModelResetAt +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsResetStaffModelSelectionOnceResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsResetStaffModelSelectionOnceResult.java new file mode 100644 index 0000000000..90f9668f4f --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsResetStaffModelSelectionOnceResult.java @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; +import javax.annotation.processing.Generated; + +/** + * The outcome of the one-time staff model-selection reset. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsResetStaffModelSelectionOnceResult( + /** Whether the persisted model selection was cleared. Only `true` means the settings document changed and the host should adopt the returned settings. */ + @JsonProperty("didReset") Boolean didReset, + /** The timestamp the host should now record, as an ISO-8601 timestamp. Carries the caller's own value back unchanged when nothing was reset. */ + @JsonProperty("resetAt") String resetAt, + /** The cutoff this reset is gated on, as an ISO-8601 timestamp. A recorded timestamp at or after it means the reset is already done. */ + @JsonProperty("cutoff") String cutoff, + /** The settings document as it stands after the reset, keyed by setting name. Present only when `didReset` is true. */ + @JsonProperty("settings") Map settings +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetHookDisabledParams.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetHookDisabledParams.java new file mode 100644 index 0000000000..e8541c2841 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetHookDisabledParams.java @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * One hook to disable or re-enable. + * + * @apiNote This method is experimental and may change in a future version. + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsSetHookDisabledParams( + /** Path of the settings.json to rewrite. */ + @JsonProperty("settingsPath") String settingsPath, + /** Durable content-hash key of the hook, as `hooks.loadResources` reports it. */ + @JsonProperty("disableKey") String disableKey, + /** True adds the key to `disabledHooks`, false removes it. */ + @JsonProperty("disabled") Boolean disabled +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetHookDisabledResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetHookDisabledResult.java new file mode 100644 index 0000000000..5548816405 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsSetHookDisabledResult.java @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.copilot.CopilotExperimental; +import javax.annotation.processing.Generated; + +/** + * Outcome of rewriting the `disabledHooks` setting. + * + * @apiNote This type is experimental and may change in a future version. + * + * @since 1.0.0 + */ +@CopilotExperimental +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsSetHookDisabledResult( + /** `ok` when the setting was written, `invalid` when settings.json could not be parsed and was left alone, `error` when the write itself failed. */ + @JsonProperty("status") String status, + /** Why the write failed. Absent when the status is `ok`. */ + @JsonProperty("errorMessage") String errorMessage +) { +} diff --git a/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsUnknownKeysWarningResult.java b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsUnknownKeysWarningResult.java new file mode 100644 index 0000000000..404b8c57c0 --- /dev/null +++ b/java/sdk/src/generated/java/com/github/copilot/generated/rpc/UserSettingsUnknownKeysWarningResult.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.processing.Generated; + +/** + * The unrecognized top-level keys found in the user settings document, already phrased for display. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +record UserSettingsUnknownKeysWarningResult( + /** The warning to show the user, naming the unrecognized keys and the file they were found in. Absent when every top-level key is recognized, and also when the document is missing or could not be read, because an unknown-key list taken from a document the runtime could not load would name keys that may not be there. */ + @JsonProperty("warning") String warning +) { +} diff --git a/java/sdk/src/test/java/com/github/copilot/JsonRpcClientTest.java b/java/sdk/src/test/java/com/github/copilot/JsonRpcClientTest.java index 8db208b53f..f296aba2e5 100644 --- a/java/sdk/src/test/java/com/github/copilot/JsonRpcClientTest.java +++ b/java/sdk/src/test/java/com/github/copilot/JsonRpcClientTest.java @@ -24,6 +24,8 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.copilot.generated.rpc.ServerRpc; +import com.github.copilot.generated.rpc.SandboxProxyCaCheckRelevanceParams; class JsonRpcClientTest { @@ -104,6 +106,26 @@ private String readRpcMessage(InputStream in) throws IOException { // ---- notify() ---- + @Test + void testGeneratedProxyCaQueriesPreserveBooleanResponses() throws Exception { + try (var pair = createSocketPair()) { + var server = new ServerRpc(pair.client::invoke); + for (boolean expected : new boolean[]{true, false}) { + for (String method : new String[]{"sandbox.proxyCa.checkInstallationSupport", + "sandbox.proxyCa.checkRelevance"}) { + CompletableFuture result = method.endsWith("checkInstallationSupport") + ? server.sandbox.proxyCa.checkInstallationSupport() + : server.sandbox.proxyCa.checkRelevance(new SandboxProxyCaCheckRelevanceParams(null)); + JsonNode request = MAPPER.readTree(readRpcMessage(pair.serverSide.getInputStream())); + assertEquals(method, request.get("method").asText()); + writeRpcMessage(pair.serverSide.getOutputStream(), + "{\"jsonrpc\":\"2.0\",\"id\":" + request.get("id") + ",\"result\":" + expected + "}"); + assertEquals(expected, result.get(5, TimeUnit.SECONDS)); + } + } + } + } + @Test void testNotify() throws Exception { try (var pair = createSocketPair()) { diff --git a/nodejs/package.json b/nodejs/package.json index 70087506a9..559af6817e 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -5,7 +5,7 @@ "url": "https://github.com/github/copilot-sdk.git" }, "version": "0.0.0-dev", - "copilotCliVersion": "1.0.97-0", + "copilotCliVersion": "1.0.97-1", "description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC", "main": "./dist/cjs/index.js", "types": "./dist/index.d.ts", diff --git a/nodejs/src/cliVersion.ts b/nodejs/src/cliVersion.ts index 2bcc588cde..05901f9aee 100644 --- a/nodejs/src/cliVersion.ts +++ b/nodejs/src/cliVersion.ts @@ -1,3 +1,3 @@ -export const COPILOT_CLI_VERSION = "1.0.97-0"; +export const COPILOT_CLI_VERSION = "1.0.97-1"; export const COPILOT_CLI_USE_NPM_PACKAGE = false; diff --git a/nodejs/src/generated/rpc.ts b/nodejs/src/generated/rpc.ts index e751771174..8b029c9e77 100644 --- a/nodejs/src/generated/rpc.ts +++ b/nodejs/src/generated/rpc.ts @@ -2755,6 +2755,36 @@ export type ManagedPluginRetryStatus = | "deferred" /** The session's managed settings do not require this plugin, so nothing was done. */ | "not_required"; +/** + * Which layer disabled bypass-permissions mode. The layer matters because only a server-delivered disable is pinned to an account and can later be lifted by signing in elsewhere. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ManagedSettingsBypassDisableSource". + */ +/** @experimental */ +/** @internal */ +export type ManagedSettingsBypassDisableSource = + /** The user turned bypass mode off themselves. */ + | "user" + /** The account's server-delivered org policy disabled it. Pinned to the account named by `currentManagedIdentity`. */ + | "managed" + /** The device/MDM layer disabled it. Outranks the account, so no server answer lifts it. */ + | "mdm"; +/** + * What the managed-policy resolution said about bypass-permissions mode. `unknown` is a third answer rather than a missing one, and the caller must send it explicitly when it has no verdict. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ManagedSettingsBypassPolicyResolution". + */ +/** @experimental */ +/** @internal */ +export type ManagedSettingsBypassPolicyResolution = + /** The policy resolved and does not disable bypass mode. */ + | "allowed" + /** The policy resolved and disables bypass mode. */ + | "disabled" + /** No verdict: the fetch failed, or the service declared a policy this build may not enforce. Whatever is in force is preserved, because reverting to permissive on an unreadable policy would widen access. */ + | "unknown"; /** * A channel accepted by managedSettings.compose. * @@ -2781,6 +2811,89 @@ export type ManagedSettingsDiagnosticSeverity = | "error" /** The runtime accepts the document but ignores the flagged content. */ | "warning"; +/** + * The operation that requires a policy-helper response. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ManagedSettingsPolicyHelperReason". + */ +/** @experimental */ +/** @internal */ +export type ManagedSettingsPolicyHelperReason = + /** Resolve policy for session startup. */ + | "sessionStart" + /** Resolve policy before plugin activation. */ + | "pluginActivation"; +/** + * How an ingestion may use the on-disk server-policy cache. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ManagedSettingsServerPolicyCacheMode". + */ +/** @experimental */ +/** @internal */ +export type ManagedSettingsServerPolicyCacheMode = + /** Serve a recent cache entry before a live fetch. */ + | "preferFresh" + /** Read cached policy without a network request. */ + | "cacheOnly" + /** Serve a cached entry only as a fallback after a failed live fetch. */ + | "fallbackOnly" + /** Ignore the cache entirely and rely on the live fetch alone. */ + | "disabled"; +/** + * How the server layer of an ingestion was resolved. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ManagedSettingsServerPolicyResolution". + */ +/** @experimental */ +/** @internal */ +export type ManagedSettingsServerPolicyResolution = + /** A live fetch succeeded. */ + | "live" + /** A recent cached entry was served without a live fetch. */ + | "freshCache" + /** No cached policy or confirmed no-policy result exists. */ + | "cacheMiss" + /** A live fetch failed and a cached entry was served in its place. */ + | "fallbackCache" + /** No policy could be resolved and the host proceeds unmanaged. */ + | "failOpen" + /** No policy could be resolved and the host applies the fail-closed gates. */ + | "failClosed" + /** No fetch was attempted because no usable token was available. */ + | "skippedNoToken"; +/** + * Which channel registered the policy helper that produced a helper layer. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ManagedSettingsPolicyHelperAuthority". + */ +/** @experimental */ +/** @internal */ +export type ManagedSettingsPolicyHelperAuthority = + /** The helper was registered by the device (MDM or managed file) layer. */ + | "device" + /** The helper was registered by the account's server-delivered policy. */ + | "server"; +/** + * Severity of a diagnostic emitted while ingesting managed settings. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ManagedSettingsLogLevel". + */ +/** @experimental */ +/** @internal */ +export type ManagedSettingsLogLevel = + /** Detail useful only when diagnosing an ingestion. */ + | "debug" + /** Ordinary progress worth surfacing under a verbose flag. */ + | "info" + /** A condition the operator should see but which did not stop the ingestion. */ + | "warning" + /** A failure that changed the outcome of the ingestion. */ + | "error"; /** * UI theme preference per SEP-1865 * @@ -4560,6 +4673,36 @@ export type RemoteSessionMetadataTaskType = | "cca" /** CLI remote task. */ | "cli"; +/** + * Which repository settings file to edit. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "RepoSettingsEditScope". + */ +/** @experimental */ +/** @internal */ +export type RepoSettingsEditScope = + /** The shared repository settings file. */ + | "repo" + /** The local repository settings file. */ + | "local"; +/** + * One atomic settings mutation. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SettingsEditOperation". + */ +/** @experimental */ +/** @internal */ +export type SettingsEditOperation = + /** Set one scalar value. */ + | "set" + /** Add one string to a list, unless present. */ + | "add-item" + /** Remove one string from a list, unless absent. */ + | "remove-item" + /** Remove the setting without supplying a value. */ + | "remove"; /** * Provider-native structured output format. JSON Schema is forwarded without rewriting or validating the schema or the generated output. * @@ -5232,23 +5375,6 @@ export type SessionVisibilityStatus = | "repo" /** The session is restricted to its creator and collaborators. */ | "unshared"; -/** - * One atomic settings mutation. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SettingsEditOperation". - */ -/** @experimental */ -/** @internal */ -export type SettingsEditOperation = - /** Set one scalar value. */ - | "set" - /** Add one string to a list, unless present. */ - | "add-item" - /** Remove one string from a list, unless absent. */ - | "remove-item" - /** Remove the setting without supplying a value. */ - | "remove"; /** * Whether one atomic settings edit changed a file. * @@ -5654,6 +5780,38 @@ export type SlashCommandInvocationResult = | SlashCommandShowDialogResult | SlashCommandSetModelResult | SlashCommandSetPlanModelResult; +/** + * What the one-time staff log-level migration did. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "StaffLogLevelMigrationStatus". + */ +/** @experimental */ +export type StaffLogLevelMigrationStatus = + /** The account is not a staff account, so the migration does not apply and nothing was recorded. */ + | "ineligible" + /** The migration already ran; the stored completion timestamp is returned unchanged. */ + | "current" + /** The migration ran now. The persisted settings may have changed, so the host should adopt the returned settings when they are present. */ + | "refreshed"; +/** + * What the one-time staff update-channel migration did. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "StaffUpdateChannelMigrationStatus". + */ +/** @experimental */ +export type StaffUpdateChannelMigrationStatus = + /** The account is not a staff account, so the migration does not apply and nothing was recorded. */ + | "ineligible" + /** The migration already ran within the cutoff window; the stored completion timestamp is returned unchanged. */ + | "current" + /** The persisted update channel was changed to stable. Only this outcome requires the host to reload its configuration. */ + | "migrated" + /** The persisted channel was already stable, so nothing changed, but the migration is now recorded as done. */ + | "completed" + /** The account is on the experimental channel, which the migration deliberately leaves alone, and the migration is recorded as done. */ + | "excluded-experimental"; /** * Subagent settings to apply, or null to clear the live session override * @@ -6038,6 +6196,23 @@ export type UISessionLimitsExhaustedResponseAction = | "unset" /** Leave the limit unchanged and cancel the blocked model request. */ | "cancel"; +/** + * What the one-time obsolete-settings cleanup did to the document. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsMigrateObsoleteOnDiskStatus". + */ +/** @experimental */ +/** @internal */ +export type UserSettingsMigrateObsoleteOnDiskStatus = + /** No settings document exists, so there was nothing to clean. */ + | "missing" + /** The document could not be parsed, so it was left untouched rather than rewritten from a partial read. */ + | "invalid" + /** The document parsed and held nothing obsolete, so nothing was written. */ + | "unchanged" + /** Obsolete keys were removed and the document was rewritten. */ + | "changed"; /** * Execution-critical workflow storage operation. * @@ -6290,6 +6465,62 @@ export type WorkspacesWorkspaceDetailsHostType = | "github" /** Workspace repository is hosted on Azure DevOps. */ | "ado"; +/** + * True when this process can offer installing the sandbox credential-proxy certificate authority into OS trust. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SandboxProxyCaCheckInstallationSupportResult". + */ +/** @experimental */ +export type SandboxProxyCaCheckInstallationSupportResult = boolean; +/** + * True when the sandbox configuration uses the credential proxy and can need certificate-authority setup. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SandboxProxyCaCheckRelevanceResult". + */ +/** @experimental */ +export type SandboxProxyCaCheckRelevanceResult = boolean; +/** + * True when an OS-level sandbox can run on this host. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SandboxCheckPlatformSupportResult". + */ +/** @experimental */ +export type SandboxCheckPlatformSupportResult = boolean; +/** + * True when the sandbox on this host can reach host loopback directly. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SandboxCheckWindowsHostLoopbackSupportResult". + */ +/** @experimental */ +export type SandboxCheckWindowsHostLoopbackSupportResult = boolean; +/** + * The user-facing refusal, including the platform remedy and the documentation link. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SandboxGetUnsupportedMessageResult". + */ +/** @experimental */ +export type SandboxGetUnsupportedMessageResult = string; +/** + * The user-facing notice that a saved sandbox setting is inert for this session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SandboxGetUnsupportedSettingDisabledNoticeResult". + */ +/** @experimental */ +export type SandboxGetUnsupportedSettingDisabledNoticeResult = string; +/** + * True when the command stays available while enforcement is blocked. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SandboxCheckEnforcementCommandResult". + */ +/** @experimental */ +export type SandboxCheckEnforcementCommandResult = boolean; /** * List of all authenticated users * @@ -12298,6 +12529,62 @@ export interface FeatureFlagsResolveRequest { [k: string]: boolean | undefined; }; } +/** + * Caller population and startup inputs to resolve named online-experiment gates for. Carries no account: the runtime resolves the assignment for the authentication it already holds. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "FeatureFlagsResolveStartupGatesRequest". + */ +/** @experimental */ +/** @internal */ +export interface FeatureFlagsResolveStartupGatesRequest { + /** + * The feature flags to resolve. A name this runtime does not declare is reported as an error rather than as a disabled flag. + */ + flags: string[]; + /** + * Whether the caller is GitHub or Microsoft staff. + */ + isStaff: boolean; + /** + * Whether the caller is in an experimental population. + */ + isExperimental: boolean; + /** + * Whether the caller belongs to a team plan. + */ + isTeam: boolean; + /** + * GitHub-staff membership. Omit when it was never recorded: a legacy staff account then counts as both staff populations and keeps every staff feature. + */ + isStaffGithub?: boolean; + /** + * Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. + */ + isStaffMicrosoft?: boolean; + /** + * Environment to read flag overrides from. Defaults to this runtime process's own environment. + */ + environment?: { + [k: string]: string | undefined; + }; + /** + * User settings document whose `featureFlags` block is layered on top of the resolved set. + */ + config?: JsonValue; + /** + * Whether streamer mode is on, which withholds the populations an experiment would otherwise segment on. + */ + streamerMode: boolean; + /** + * When this installation first launched, in milliseconds since the Unix epoch. Experiments that segment on installation age read it. Omit when the first launch was never recorded. + */ + firstLaunchAtMillis?: number; + /** + * Whether the runtime may refresh the cached assignment over the network without an active session. The refresh never blocks this call: the answer comes from the cache either way, so a refresh only affects a later launch. + */ + refreshWithoutSession: boolean; +} /** * Parameters for starting fleet orchestration: an optional user prompt combined with the fleet instructions, plus the send options forwarded to the resulting turn. * @@ -12377,6 +12664,62 @@ export interface FolderTrustCheckResult { */ trusted: boolean; } +/** + * A folder to check against a persisted trusted-folders list, and the configuration directory holding that list. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "FolderTrustIsTrustedParams". + */ +/** @experimental */ +/** @internal */ +export interface FolderTrustIsTrustedParams { + /** + * Folder to check. A folder counts as trusted when it is itself listed, when an ancestor is listed, or when its git root is listed. + */ + path: string; + /** + * Configuration directory to read the trusted-folders list from. Omit it to read the default location; supply it when the host has redirected its configuration, or the check answers from a list the host is not using. + */ + configDir?: string; +} +/** + * The verdict of the `forceLoginOrgs` enterprise sign-in pin for one credential. A managed device may pin Copilot to an approved set of GitHub organizations so a developer cannot sign in with a personal — or another enterprise's — account and escape every control that keys off the signed-in identity. A host must refuse to proceed when `allowed` is false; the remaining fields explain the refusal rather than qualifying it. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ForceLoginOrgsDecision". + */ +/** @experimental */ +/** @internal */ +export interface ForceLoginOrgsDecision { + /** + * Whether the client may proceed. True whenever no pin is in force, so an unmanaged host is never blocked. + */ + allowed: boolean; + /** + * Whether a pin applies at all. Distinguishes "allowed because unmanaged" from "allowed because the account is approved", which a diagnostics surface needs and which also decides whether a bring-your-own-key provider may serve inference. + */ + enforced: boolean; + /** + * The approved organization logins, as configured. Enterprise configuration rather than user data, so it is safe to name in a message or a log line. + */ + requiredOrgs: string[]; + /** + * The approved organization the account matched, when allowed under a pin. + */ + matchedOrg?: string; + /** + * A stable kebab-case reason code when refused: `org-not-approved`, `unverifiable-credential`, `policy-undetermined`, `policy-invalid`, `not-signed-in`, or `membership-unknown`. Omitted when allowed. Treat an unrecognized code as a refusal rather than mapping it to an allow: a code this host has not been taught about still denied the credential. + */ + denial?: string; + /** + * A developer-facing explanation of the refusal. Omitted when allowed. + */ + message?: string; + /** + * Error-level detail from managed-policy discovery — which file failed to load, which field failed validation. Carried on the decision rather than left to the log because a refusal can exit the process before a log sink exists, which would discard the only actionable diagnostic a misconfigured managed device produces. + */ + policyDiagnostics: string[]; +} /** * The remote the checked-out branch tracks. * @@ -14985,6 +15328,20 @@ export interface SessionContext { */ branch?: string; } +/** + * Which stored location permissions were dropped because their directory is gone. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "LocationPermissionsCleanupResult". + */ +/** @experimental */ +/** @internal */ +export interface LocationPermissionsCleanupResult { + /** + * Location keys whose grants were removed. Empty when every stored location still exists. + */ + removedLocationKeys: string[]; +} /** * Message text, optional severity level, persistence flag, optional follow-up URL, and optional tip. * @@ -15154,6 +15511,38 @@ export interface ManagedSettingMeta { */ requested?: string; } +/** + * A user settings document and the effective managed policy whose controlled entries should be stamped onto it. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ManagedSettingsApplyControlsParams". + */ +/** @experimental */ +/** @internal */ +export interface ManagedSettingsApplyControlsParams { + /** + * The user settings document to stamp. Entries the managed layer does not name are returned exactly as supplied. + */ + settings: JsonValue; + /** + * The effective managed policy, as composed by `managedSettings.resolveEffectiveValue`. Omit it on an unmanaged host: the settings then come back unchanged. + */ + managed?: JsonValue; +} +/** + * The user settings with the managed layer's controlled entries stamped on. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ManagedSettingsApplyControlsResult". + */ +/** @experimental */ +/** @internal */ +export interface ManagedSettingsApplyControlsResult { + /** + * The resulting settings document. + */ + settingsJson: JsonValue; +} /** * One candidate channel; absent settings represents a channel that delivered no document. * @@ -15269,5336 +15658,5528 @@ export interface ManagedSettingsDiagnostic { message: string; } /** - * Validated device-managed settings discovered before a session exists. + * Inputs describing the host and account an ingestion should resolve managed policy for. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ManagedSettingsReadResult". + * via the `definition` "ManagedSettingsIngestParams". */ /** @experimental */ -export interface ManagedSettingsReadResult { +/** @internal */ +export interface ManagedSettingsIngestParams { + policyHelperReason?: ManagedSettingsPolicyHelperReason; /** - * Validated, canonical managed-settings JSON. Omitted when no managed settings were discovered or when discovered settings failed validation. + * Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. */ - settingsJson?: JsonValue; + selfFetch?: boolean; /** - * Discovery or validation error text when managed settings could not be read safely. + * The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched. */ - errorMessage?: string; -} - -/** @experimental */ -export interface ManagedSettingsResolveRequest { + authInfo?: JsonValue; /** - * Opaque account identifier returned by `account.getAllUsers`. When omitted, the current account is used, or device policy only when no account is signed in. + * The session whose credential store and working directory the policy helper should use. Omit it when no session exists yet and the process-wide store applies. */ - selectionId?: string; + sessionId?: string; /** - * GitHub token to resolve instead of the current account. The call fails when the token cannot be resolved. + * A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. */ - gitHubToken?: string; + deviceResponse?: JsonValue; /** - * Embedding client identity for server policy requests, as in session creation. Omit for the CLI identity. + * Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. + */ + hasDeviceResponse?: boolean; + /** + * Whether to ignore a cached server policy when reading, forcing the resolution to come from a live fetch. + */ + bypassCacheRead?: boolean; + serverPolicyCacheMode?: ManagedSettingsServerPolicyCacheMode; + /** + * Whether a configured platform policy helper may be run to produce an enforced helper layer. + */ + policyHelperEnabled?: boolean; + /** + * Directory the policy helper runs in when this ingestion is not owned by a registered session. A host resolving policy before its session exists must pass this, or a directory-sensitive helper judges the wrong repository. + */ + policyHelperWorkingDirectory?: string; + /** + * User agent to send with the policy fetch. + */ + userAgent: string; + /** + * Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. Omit it and the runtime reports a generic identity; the runtime version sent alongside is the gate that actually matters. */ clientName?: string; /** - * Working directory used to run an organization policy helper. When omitted, sessionless resolution does not run the helper. + * The host's environment variables, read for cache location and policy overrides. Supplied by the host rather than read from the runtime process so a command that selected its own configuration home is honored. */ - workingDirectory?: string; + environment: JsonValue; + /** + * The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. + */ + platform: string; + /** + * The host's home directory, used to resolve cache and managed-file locations. + */ + homeDirectory: string; } /** - * Effective enterprise managed settings for an account, resolved without a session. + * The managed policy layers an ingestion resolved, together with the per-layer outcome flags a host needs to decide how much to trust the result. The flags are reported rather than folded into the settings because a host must be able to distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ManagedSettingsResolveResult". + * via the `definition` "ManagedSettingsIngestResult". */ /** @experimental */ -export interface ManagedSettingsResolveResult { - permissionsContext?: ManagedPermissionsContext; +/** @internal */ +export interface ManagedSettingsIngestResult { /** - * Printable opaque identity of the account the settings were resolved for, suitable for comparison and storage, not an account selectionId. Absent when no account was available, in which case only device policy is reported. + * The effective managed settings composed from every resolved layer. Omitted when no layer set anything, so an unmanaged host locks nothing. */ - account?: string; - resolved: ManagedSettingsResolvedData; - values?: ManagedSettingsValues; - meta?: ManagedSettingsMeta; + settings?: JsonValue; /** - * Each managed-settings channel consulted, strongest first, with the validated document it delivered before merging. `resolved.settings` is the merged result. More channels may be added over time. + * The effective managed permissions layer, when the resolved policy carries one. */ - layers: ManagedSettingsLayer[]; + permissions?: JsonValue; /** - * Warnings about unavailable policy sources or a failed refresh served from cache. A cached response is not proof of a successful live fetch; `resolved.failClosed` separately describes enforcement. + * The server fetch failed and no cached entry stood in for it, so the server layer is unconfirmed and fail-closed gates apply. */ - diagnostics: ManagedSettingsDiagnostic[]; -} -/** - * The authoring JSON schema for managed settings recognized by this runtime. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ManagedSettingsSchemaResult". - */ -/** @experimental */ -export interface ManagedSettingsSchemaResult { + serverFetchFailed: boolean; /** - * JSON schema (draft 2020-12) with descriptive shared `x-composition` annotations, not a complete runtime composition contract. Model, effortLevel, and contextTier remain coupled; use `managedSettings.compose` for the runtime's effective result. + * No usable token was available, so no server fetch was attempted. */ - schema: JsonValue; + serverTokenUnavailable: boolean; /** - * Version of the runtime that owns this schema. + * The error that made the server fetch fail, when one did. */ - runtimeVersion: string; -} -/** - * A candidate managed-settings document to validate without applying it. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ManagedSettingsValidateRequest". - */ -/** @experimental */ -export interface ManagedSettingsValidateRequest { + serverFetchError?: string; + serverResolution: ManagedSettingsServerPolicyResolution; /** - * The document to validate: a JSON object, or a string containing the document's JSON text. Preview documents are limited to 1 MiB and 64 levels of nesting, a stricter resource limit than delivered-policy parsing; violations are returned as diagnostics. + * The server fetch failed in a way a later retry could succeed at, as opposed to a refusal that no retry will change. */ - content: JsonValue; + serverRetryableFailure: boolean; /** - * Channel the document is meant for (`device`, `server`, or `policyHelper`). Some keys are only honored in some channels; for example, a `policyHelper` registration is ignored in policy-helper output. When omitted, no channel-specific checks run. + * A live fetch failed but a recent cached entry was served in its place, so `serverFetchFailed` stays false. Lets a consumer distinguish a clean fetch from a cache-backed fallback. */ - layer?: string; -} -/** - * Result of validating a managed-settings document. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ManagedSettingsValidateResult". - */ -/** @experimental */ -export interface ManagedSettingsValidateResult { + serverCacheFallback: boolean; /** - * Whether the runtime would accept the document within the preview resource limits. Always equals whether `settings` is present. An invalid document is rejected as a whole. + * A server-managed policy is known to exist even though `serverResponse` is intentionally unset. Consumers should OR this with the presence of `serverResponse` when deciding whether the device is managed, so a fresh start during an outage still applies the fail-closed gates instead of treating the device as unmanaged. */ - valid: boolean; + serverSourceFound: boolean; /** - * Canonical form of the document the runtime would apply, with unrecognized keys removed. Absent when the document is invalid. + * The account's server-delivered policy, when one was resolved. */ - settings?: JsonValue; + serverResponse?: JsonValue; /** - * Errors that reject the document and warnings about content the runtime ignores. + * The sandbox object from a cached server policy that a forced refresh declined to serve in full. Folded back into the effective sandbox layer so an outage during a forced refresh still synthesizes the fail-closed sandbox floor from the administrator's known intent. */ - diagnostics: ManagedSettingsDiagnostic[]; -} -/** - * Result of registering a new marketplace. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MarketplaceAddResult". - */ -/** @experimental */ -export interface MarketplaceAddResult { + serverSandboxFloor?: JsonValue; /** - * Final name of the marketplace as resolved from its manifest + * The server fetch failed while a policy demanded a fresh confirmation, which is the strict posture an enterprise opted into rather than an ordinary transient failure. */ - name: string; + serverForcedRefreshFailure: boolean; + /** + * The server refused to deliver a policy because this client is too old to enforce it, carrying the user-facing sentence describing the refusal. No retry will help; the remedy is a client update. Gates that exist only because of managed policy should deny on this rather than falling back to their unmanaged default. + */ + serverClientUpdateRequired?: string; + /** + * Minimum client version requested by a successful response. Advisory only; the delivered policy remains active. + */ + serverClientUpdateRequested?: string; + /** + * The synthesized fail-closed permissions layer applied in place of a policy a refused client may not enforce. + */ + serverPermissionsFloor?: JsonValue; + /** + * The device layer discovered from the machine, when one exists. + */ + deviceResponse?: JsonValue; + /** + * The device layer could not be read, so it is unconfirmed rather than known-absent. + */ + deviceLoadFailed: boolean; + /** + * The sandbox floor contributed by the device layer. + */ + deviceSandboxFloor?: JsonValue; + /** + * A device-managed policy is known to exist. + */ + deviceSourceFound: boolean; + /** + * Whether the device layer's sandbox intent could not be determined, so a consumer must not read its absence as permission to run unsandboxed. + */ + deviceSandboxUndetermined: boolean; + /** + * The layer produced by the platform policy helper, when one ran. + */ + policyHelperResponse?: JsonValue; + policyHelperAuthority?: ManagedSettingsPolicyHelperAuthority; + /** + * The policy helper was configured but could not be run or its output could not be read. + */ + policyHelperLoadFailed: boolean; + /** + * A policy helper is configured for this host. + */ + policyHelperConfigured: boolean; + /** + * The policy helper's failure must be treated as fail-closed rather than ignored. + */ + policyHelperFailClosed: boolean; + /** + * Diagnostics emitted while resolving the layers, in the order they occurred. + */ + logMessages: ManagedSettingsLogMessage[]; } /** - * Plugins advertised by the marketplace. + * One diagnostic emitted while ingesting managed settings. Returned rather than logged by the runtime so the host decides where ingestion diagnostics go, which matters because an ingestion runs before a session exists to carry a log sink. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MarketplaceBrowseResult". + * via the `definition` "ManagedSettingsLogMessage". */ /** @experimental */ -export interface MarketplaceBrowseResult { +/** @internal */ +export interface ManagedSettingsLogMessage { + level: ManagedSettingsLogLevel; /** - * Plugins advertised by the marketplace + * Human-readable diagnostic text. */ - plugins: MarketplacePluginInfo[]; + message: string; } /** - * Plugin entry advertised by a marketplace. + * Inputs describing the host and account whose managed remote-control policy should be resolved. Mirrors `managedSettings.ingest`, and deliberately carries no retention decision: reading this gate never becomes this runtime process's startup policy. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MarketplacePluginInfo". + * via the `definition` "ManagedSettingsLoadRemoteControlParams". */ /** @experimental */ -export interface MarketplacePluginInfo { +/** @internal */ +export interface ManagedSettingsLoadRemoteControlParams { + policyHelperReason?: ManagedSettingsPolicyHelperReason; /** - * Plugin name as listed in the marketplace catalog + * Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. */ - name: string; + selfFetch?: boolean; /** - * Short description from the marketplace catalog, when present + * The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched. */ - description?: string; -} -/** - * Registered marketplace summary. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MarketplaceInfo". - */ -/** @experimental */ -export interface MarketplaceInfo { + authInfo?: JsonValue; /** - * Marketplace name (matches the @marketplace suffix in plugin specs) + * A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. */ - name: string; + deviceResponse?: JsonValue; /** - * Human-readable description of where the marketplace data is fetched from (e.g. "GitHub: owner/repo"). + * Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. */ - source: string; + hasDeviceResponse?: boolean; /** - * True when this is a default marketplace shipped with the runtime. Defaults are not removable. + * Whether a configured platform policy helper may be run to produce an enforced helper layer. */ - isDefault?: boolean; + policyHelperEnabled?: boolean; /** - * Whether enterprise managed settings provide and control this marketplace entry. + * User agent to send with the policy fetch. */ - managed?: boolean; + userAgent: string; /** - * Whether the managed marketplace currently resolved into the runtime marketplace registry. Set to false when the desired managed entry is retained for governance visibility after loading or reconciliation failed. + * Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. That refusal is exactly what turns into an explicit `disabled` below, so a host that omits this field forfeits the protection. */ - available?: boolean; + clientName?: string; + /** + * The host's environment variables, read for cache location and policy overrides. + */ + environment: JsonValue; + /** + * The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. + */ + platform: string; + /** + * The host's home directory, used to resolve cache and managed-file locations. + */ + homeDirectory: string; } /** - * All registered marketplaces, including built-in defaults. + * The managed remote-control policy in force for an account, if any. An absent policy means the account is unmanaged for this capability, which a host reads as allowed — so absence here is a positive statement that no policy applies, never a stand-in for a resolution that failed. A resolution that cannot be completed is rejected instead. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MarketplaceListResult". + * via the `definition` "ManagedSettingsLoadRemoteControlResult". */ /** @experimental */ -export interface MarketplaceListResult { +/** @internal */ +export interface ManagedSettingsLoadRemoteControlResult { /** - * Registered marketplaces + * The account's `remoteControl` policy document. Absent when no managed policy governs remote control for this account. Reported as an explicit disabled policy, rather than as absence, when the service refused to deliver a policy this client is too old to enforce. */ - marketplaces: MarketplaceInfo[]; + remoteControl?: JsonValue; } /** - * Per-marketplace refresh result, including marketplace name, success flag, and optional failure error. + * The client-supplied managed settings to validate and normalize. Omitting them is valid and yields no policy. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MarketplaceRefreshEntry". + * via the `definition` "ManagedSettingsParseClientValueParams". */ /** @experimental */ -export interface MarketplaceRefreshEntry { - /** - * Marketplace name that was refreshed - */ - name: string; +/** @internal */ +export interface ManagedSettingsParseClientValueParams { /** - * Whether the refresh succeeded + * The managed settings a client is supplying for a session it is about to open. Omit them when the client is imposing no policy of its own. */ - success: boolean; + settings?: JsonValue; +} +/** + * The accepted managed settings, reduced to the keys a client is allowed to set. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ManagedSettingsParseClientValueResult". + */ +/** @experimental */ +/** @internal */ +export interface ManagedSettingsParseClientValueResult { /** - * Error message (failure only) + * The normalized settings. Omitted when the client supplied none. An accepted document that sets nothing comes back as an empty object, which is distinct from omission. */ - error?: string; + settingsJson?: JsonValue; } /** - * Result of refreshing one or more marketplace catalogs. + * The device-managed settings layer, with the sandbox floor and the load outcome a host needs to compose it into an effective policy. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MarketplaceRefreshResult". + * via the `definition` "ManagedSettingsReadDeviceResult". */ /** @experimental */ -export interface MarketplaceRefreshResult { +/** @internal */ +export interface ManagedSettingsReadDeviceResult { /** - * Per-marketplace refresh results in deterministic order. + * Validated, canonical device-managed settings. Omitted when no device policy was discovered, when the discovered document failed validation, or when it validated to an empty object — an empty document carries no policy, and reporting it as present would outrank layers that do. */ - results: MarketplaceRefreshEntry[]; + settings?: JsonValue; + /** + * Sandbox floor read from the discovered document before validation, so a document that is otherwise rejected can still raise the floor it declared. + */ + sandboxFloor?: JsonValue; + /** + * Whether discovery or validation failed. A host must treat this as "policy unknown" rather than "no policy": absent settings with this set false mean the device genuinely has none. + */ + loadFailed: boolean; } /** - * Outcome of the remove attempt, including dependent-plugin info when applicable. + * Validated device-managed settings discovered before a session exists. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MarketplaceRemoveResult". + * via the `definition` "ManagedSettingsReadResult". */ /** @experimental */ -export interface MarketplaceRemoveResult { +export interface ManagedSettingsReadResult { /** - * True when the marketplace was actually removed. False when removal was skipped because the marketplace has dependent plugins and `force` was not set. + * Validated, canonical managed-settings JSON. Omitted when no managed settings were discovered or when discovered settings failed validation. */ - removed: boolean; + settingsJson?: JsonValue; /** - * Names of installed plugins that prevented removal. Populated only when `removed=false`. + * Discovery or validation error text when managed settings could not be read safely. */ - dependentPlugins?: string[]; + errorMessage?: string; } /** - * MCP server allowed by policy, with server name and optional PII-free explanatory note. + * The bypass-permissions state a host holds today, the account now signed in, and what the managed-policy resolution said. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpAllowedServer". + * via the `definition` "ManagedSettingsResolveBypassDisableTransitionParams". */ /** @experimental */ -export interface McpAllowedServer { +/** @internal */ +export interface ManagedSettingsResolveBypassDisableTransitionParams { + currentSource?: ManagedSettingsBypassDisableSource; /** - * Allowed server name + * The account a `managed` disable is pinned to. Omit it when the current source is not `managed`; it is ignored for the other sources. */ - name: string; + currentManagedIdentity?: string; /** - * PII-free note explaining why the server was allowed + * The account signed in now. A `managed` disable pinned to a different account is lifted. */ - redactedNote?: string; + activeIdentity: string; + policy: ManagedSettingsBypassPolicyResolution; } /** - * Applies exactly one previously prepared operation on its original connection. + * The bypass-permissions state a host should hold after the resolution, and what it must do to get there. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpApplyInstallRequest". + * via the `definition` "ManagedSettingsResolveBypassDisableTransitionResult". */ /** @experimental */ -export interface McpApplyInstallRequest { - contract: CatalogClientContract; +/** @internal */ +export interface ManagedSettingsResolveBypassDisableTransitionResult { + source?: ManagedSettingsBypassDisableSource; /** - * Runtime-issued ID already returned by prepareInstall, never reused or rebound. + * The account the returned `managed` source is pinned to. Store it alongside `source`; the next call needs it to decide whether an account switch lifts the disable. */ - operationId: string; + managedIdentity?: string; /** - * Same existing attached or privately borrowed session as preparation. + * The value to store in the host's own bypass-disabled flag. Omitted means leave it exactly as it is, which is not the same as being told to store `false`. */ - policySessionId: string; + setDisabledState?: boolean; + /** + * Whether a bypass-permissions session already running must be turned off. True only when this resolution newly disables bypass mode, so a host that is already compliant is not interrupted. + */ + suppressRuntimeAllowAll: boolean; } /** - * One-use application of the exact retained removal plan. + * The credential and environment to evaluate the device-channel sign-in pin against. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpApplyUninstallRequest". + * via the `definition` "ManagedSettingsResolveDeviceForceLoginOrgsGateParams". */ /** @experimental */ -export interface McpApplyUninstallRequest { - contract: CatalogClientContract; +/** @internal */ +export interface ManagedSettingsResolveDeviceForceLoginOrgsGateParams { /** - * Opaque original removal plan, consumed once. + * The authenticated identity to judge. Omitted when signed out, which is the case the device channel exists to serve: it can refuse a first sign-in before any credential exists. */ - planHandle: string; + authInfo?: JsonValue; /** - * Same existing selected session as removal preparation. + * The host's environment variables. Read for the variables that would make an identity's membership snapshot forgeable, so a credential whose provenance cannot be trusted is refused rather than accepted. */ - policySessionId: string; + environment: JsonValue; } /** - * MCP server, tool name, and arguments to invoke from an MCP App view. + * The managed-settings layers to compose into an effective policy. Every layer is optional; omitting all of them yields no effective policy. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpAppsCallToolRequest". + * via the `definition` "ManagedSettingsResolveEffectiveValueParams". */ /** @experimental */ -export interface McpAppsCallToolRequest { +/** @internal */ +export interface ManagedSettingsResolveEffectiveValueParams { /** - * MCP server hosting the tool + * The account's server-delivered org policy, as returned by a managed-settings fetch. Omitted before sign-in or when the fetch has not landed. */ - serverName: string; + server?: JsonValue; /** - * MCP tool name + * The device layer: native MDM and managed-file settings describing the machine rather than the account. */ - toolName: string; + mdm?: JsonValue; /** - * Tool arguments + * The device sandbox floor, folded into the device layer under `sandbox` before composition. */ - arguments?: { - [k: string]: JsonValue | undefined; - }; + deviceSandboxFloor?: JsonValue; /** - * **Required.** Server whose ui:// view issued the request. Per SEP-1865 ('callable by the app from this server only'), the call is rejected when this differs from `serverName`, and rejected outright when missing. + * The policy-helper layer, an enforced channel sourced from a platform policy helper process. */ - originServerName: string; + policyHelper?: JsonValue; } /** - * Capability negotiation snapshot + * The effective managed policy composed from the supplied layers. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpAppsDiagnoseCapability". + * via the `definition` "ManagedSettingsResolveEffectiveValueResult". */ /** @experimental */ -export interface McpAppsDiagnoseCapability { +/** @internal */ +export interface ManagedSettingsResolveEffectiveValueResult { /** - * Whether the session has the `mcp-apps` capability + * The composed effective managed settings. Omitted when no layer sets anything, so an unmanaged host locks nothing. Carries `sandboxAdvisoryFloorDeclined: true` when an advisory server force-on was dropped because this host cannot run the sandbox. */ - sessionHasMcpApps: boolean; + settingsJson?: JsonValue; +} + +/** @experimental */ +export interface ManagedSettingsResolveRequest { /** - * Whether the MCP_APPS feature flag (or COPILOT_MCP_APPS env override) is on + * Opaque account identifier returned by `account.getAllUsers`. When omitted, the current account is used, or device policy only when no account is signed in. */ - featureFlagEnabled: boolean; + selectionId?: string; /** - * Whether the runtime advertises `extensions.io.modelcontextprotocol/ui` to MCP servers + * GitHub token to resolve instead of the current account. The call fails when the token cannot be resolved. */ - advertised: boolean; -} -/** - * MCP server to diagnose MCP Apps wiring for. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpAppsDiagnoseRequest". - */ -/** @experimental */ -export interface McpAppsDiagnoseRequest { + gitHubToken?: string; /** - * MCP server to probe + * Embedding client identity for server policy requests, as in session creation. Omit for the CLI identity. */ - serverName: string; + clientName?: string; + /** + * Working directory used to run an organization policy helper. When omitted, sessionless resolution does not run the helper. + */ + workingDirectory?: string; } /** - * Diagnostic snapshot of MCP Apps wiring for the named server. + * Effective enterprise managed settings for an account, resolved without a session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpAppsDiagnoseResult". + * via the `definition` "ManagedSettingsResolveResult". */ /** @experimental */ -export interface McpAppsDiagnoseResult { - capability: McpAppsDiagnoseCapability; - server: McpAppsDiagnoseServer; +export interface ManagedSettingsResolveResult { + permissionsContext?: ManagedPermissionsContext; + /** + * Printable opaque identity of the account the settings were resolved for, suitable for comparison and storage, not an account selectionId. Absent when no account was available, in which case only device policy is reported. + */ + account?: string; + resolved: ManagedSettingsResolvedData; + values?: ManagedSettingsValues; + meta?: ManagedSettingsMeta; + /** + * Each managed-settings channel consulted, strongest first, with the validated document it delivered before merging. `resolved.settings` is the merged result. More channels may be added over time. + */ + layers: ManagedSettingsLayer[]; + /** + * Warnings about unavailable policy sources or a failed refresh served from cache. A cached response is not proof of a successful live fetch; `resolved.failClosed` separately describes enforcement. + */ + diagnostics: ManagedSettingsDiagnostic[]; } /** - * What the server returned for this session + * Inputs describing the host and account a startup policy resolution should run for. Mirrors `managedSettings.ingest`, and adds the decision of whether the resolved policy is retained for this runtime process. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpAppsDiagnoseServer". + * via the `definition` "ManagedSettingsResolveStartupPolicyParams". */ /** @experimental */ -export interface McpAppsDiagnoseServer { +/** @internal */ +export interface ManagedSettingsResolveStartupPolicyParams { + policyHelperReason?: ManagedSettingsPolicyHelperReason; /** - * Whether the named server is currently connected + * Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. */ - connected: boolean; + selfFetch?: boolean; /** - * Total tools returned by the server's tools/list + * The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched and the sign-in pin is evaluated against no credential. */ - toolCount: number; + authInfo?: JsonValue; /** - * Tools whose `_meta.ui` is populated (resourceUri and/or visibility set) + * The session whose credential store, working directory and client kind the resolution should use. Omit it when no session exists yet and the process-wide store applies. A resolution whose session names a credential other than `authInfo` is returned but not retained, so a stale sign-in cannot apply policy for an account that has already been switched away from. */ - toolsWithUiMeta: number; + sessionId?: string; /** - * Up to 5 tool names with `_meta.ui` for quick inspection + * A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. */ - sampleToolNames: string[]; + deviceResponse?: JsonValue; + /** + * Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. + */ + hasDeviceResponse?: boolean; + /** + * Whether to ignore a cached server policy when reading, forcing the resolution to come from a live fetch. + */ + bypassCacheRead?: boolean; + serverPolicyCacheMode?: ManagedSettingsServerPolicyCacheMode; + /** + * Whether a configured platform policy helper may be run to produce an enforced helper layer. + */ + policyHelperEnabled?: boolean; + /** + * Directory the policy helper runs in when this resolution is not owned by a registered session. A host resolving policy before its session exists must pass this, or a directory-sensitive helper judges the wrong repository. + */ + policyHelperWorkingDirectory?: string; + /** + * User agent to send with the policy fetch. + */ + userAgent: string; + /** + * Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. + */ + clientName?: string; + /** + * The host's environment variables, read for cache location, policy overrides, and the variables that would make a membership snapshot forgeable. + */ + environment: JsonValue; + /** + * The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. + */ + platform: string; + /** + * The host's home directory, used to resolve cache and managed-file locations. + */ + homeDirectory: string; + /** + * Whether to retain the resolved policy as this runtime process's startup policy, so later work in the process enforces it. Set false to resolve without side effects, which is what a protocol host wants before session creation: its sessions apply the complete policy through the normal lifecycle, and retaining here would let a readiness credential affect unrelated sessions. The returned verdict is identical either way — this decides only whether the process keeps it. + */ + retainAndApply: boolean; } /** - * Current host context advertised to MCP App guests. + * The startup policy a resolution composed, the per-layer outcome flags a host needs to decide how much to trust it, and the enterprise sign-in verdict for the credential it ran against. The flags are reported rather than folded into the settings because a host must distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpAppsHostContext". + * via the `definition` "ManagedSettingsResolveStartupPolicyResult". */ /** @experimental */ -export interface McpAppsHostContext { - context: McpAppsHostContextDetails; +/** @internal */ +export interface ManagedSettingsResolveStartupPolicyResult { + serverResolution: ManagedSettingsServerPolicyResolution; + /** + * Advisory minimum client version from a successful server response. + */ + clientUpdateRequested?: string; + /** + * The account's server-delivered policy, when one was resolved. + */ + serverResponse?: JsonValue; + /** + * The device layer discovered from the machine, when one exists. + */ + deviceResponse?: JsonValue; + /** + * The sandbox floor contributed by the device layer. + */ + deviceSandboxFloor?: JsonValue; + /** + * The layer produced by the platform policy helper, when one ran. + */ + policyHelperResponse?: JsonValue; + /** + * The server fetch failed and no cached entry stood in for it, so the server layer is unconfirmed and fail-closed gates apply. + */ + serverFetchFailed: boolean; + /** + * The device layer could not be read, so it is unconfirmed rather than known-absent. + */ + deviceLoadFailed: boolean; + /** + * The policy helper was configured but could not be run, or its output could not be read. + */ + policyHelperLoadFailed: boolean; + /** + * Telemetry describing which layers answered and how, for the host to report alongside its own startup events. + */ + telemetry: JsonValue; + /** + * The effective sandbox floor composed across every layer, which a host must apply rather than its own default. + */ + sandboxFloor?: JsonValue; + /** + * Some layer of the policy could not be confirmed, so its absence must not be read as permission. Folds in a failed server fetch as well as an unreadable device layer. + */ + policyUndetermined: boolean; + /** + * The permissions layer specifically could not be confirmed, so permission gates apply their fail-closed posture. + */ + permissionPolicyUndetermined: boolean; + /** + * A managed policy is known to apply to this host, from a discovered source or a resolved document. + */ + managedPolicyPresent: boolean; + /** + * The sandbox was enabled because policy could not be confirmed rather than because an administrator asked for it. Lets a host explain a sandbox the user did not configure. + */ + sandboxEnabledByUndeterminedPolicy: boolean; + forceLoginOrgs: ForceLoginOrgsDecision; + /** + * The server refused to deliver a policy because this client is too old to enforce it, carrying the user-facing sentence describing the refusal. No retry will help; the remedy is a client update. + */ + clientUpdateRequired?: string; + /** + * Warnings raised while resolving, in the order they occurred. + */ + warnings: string[]; } /** - * Current host context + * The managed layers to retain as this process's startup policy, with the outcome of fetching each one. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpAppsHostContextDetails". + * via the `definition` "ManagedSettingsRetainPolicyParams". */ /** @experimental */ -export interface McpAppsHostContextDetails { - theme?: McpAppsHostContextDetailsTheme; +/** @internal */ +export interface ManagedSettingsRetainPolicyParams { /** - * BCP-47 locale, e.g. 'en-US' + * The resolved server policy. A known source can lack a response after a forced-refresh failure. */ - locale?: string; + serverResponse?: JsonValue; /** - * IANA timezone, e.g. 'America/New_York' + * The device/MDM policy layer. */ - timeZone?: string; - displayMode?: McpAppsHostContextDetailsDisplayMode; + deviceResponse?: JsonValue; /** - * Display modes the host supports + * Sandbox floor declared by the device layer, carried separately so a document that failed validation can still raise the floor. */ - availableDisplayModes?: McpAppsHostContextDetailsAvailableDisplayMode[]; - platform?: McpAppsHostContextDetailsPlatform; + deviceSandboxFloor?: JsonValue; /** - * Host application identifier + * Whether a device policy source demonstrably exists. This, not a read error, is the evidence a device is managed, so a fail-closed policy gates on it. */ - userAgent?: string; - [k: string]: unknown | undefined; + deviceSourceFound: boolean; + /** + * Whether any managed policy source exists, independently of fetch failures. + */ + managedPolicyPresent: boolean; + /** + * Whether the server policy source exists, even when its response is unavailable. + */ + serverSourceFound: boolean; + /** + * Whether a required fresh server-policy confirmation failed. + */ + serverForcedRefreshFailure: boolean; + /** + * Preserve the retained server layer during a device-only resolution. + */ + preserveServerState: boolean; + /** + * Whether the device sandbox intent is unreadable independently of its other settings. + */ + deviceSandboxUndetermined: boolean; + /** + * Whether the shared sandbox policy is undetermined. Diagnostic errors alone do not imply this flag. + */ + sandboxFloorUndetermined: boolean; + /** + * Whether permission policy is undetermined. Sandbox-only uncertainty does not imply this flag. + */ + permissionPolicyUndetermined: boolean; + /** + * Whether uncertainty alone enabled the shared sandbox floor. + */ + sandboxEnabledByUndeterminedPolicy: boolean; + /** + * Shared server/device sandbox floor, excluding session-local helper policy. + */ + sharedSandboxFloor?: JsonValue; + /** + * Whether the server fetch failed. Report it honestly: true keeps the already-retained server layer rather than replacing it with an absent one. + */ + serverFetchFailed: boolean; + /** + * Whether the device load failed. Report it honestly, for the same reason as `serverFetchFailed`. + */ + deviceLoadFailed: boolean; + /** + * The policy helper's response: the third managed layer that a process owning its startup policy resolves. It is retained with the other two so that every ambient read in this process, including the mutation guards and the governed marketplace allowlist that the `plugins.*` handlers derive, sees the whole policy the process fetched. A session-owning process omits it, because it resolves a helper per session against that session's working directory. + */ + policyHelperResponse?: JsonValue; } /** - * MCP server to list app-callable tools for. + * The authoring JSON schema for managed settings recognized by this runtime. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpAppsListToolsRequest". + * via the `definition` "ManagedSettingsSchemaResult". */ /** @experimental */ -export interface McpAppsListToolsRequest { +export interface ManagedSettingsSchemaResult { /** - * MCP server hosting the app + * JSON schema (draft 2020-12) with descriptive shared `x-composition` annotations, not a complete runtime composition contract. Model, effortLevel, and contextTier remain coupled; use `managedSettings.compose` for the runtime's effective result. */ - serverName: string; + schema: JsonValue; /** - * **Required.** Server whose ui:// view issued the request. Per SEP-1865 ('callable by the app from this server only'), the call is rejected when this differs from `serverName`, and rejected outright when missing. + * Version of the runtime that owns this schema. */ - originServerName: string; + runtimeVersion: string; } /** - * App-callable tools from the named MCP server. + * A candidate managed-settings document to validate without applying it. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpAppsListToolsResult". + * via the `definition` "ManagedSettingsValidateRequest". */ /** @experimental */ -export interface McpAppsListToolsResult { +export interface ManagedSettingsValidateRequest { /** - * App-callable tools from the server + * The document to validate: a JSON object, or a string containing the document's JSON text. Preview documents are limited to 1 MiB and 64 levels of nesting, a stricter resource limit than delivered-policy parsing; violations are returned as diagnostics. */ - tools: { - [k: string]: JsonValue | undefined; - }[]; + content: JsonValue; + /** + * Channel the document is meant for (`device`, `server`, or `policyHelper`). Some keys are only honored in some channels; for example, a `policyHelper` registration is ignored in policy-helper output. When omitted, no channel-specific checks run. + */ + layer?: string; } /** - * MCP server and resource URI to fetch. + * Result of validating a managed-settings document. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpAppsReadResourceRequest". + * via the `definition` "ManagedSettingsValidateResult". */ /** @experimental */ -export interface McpAppsReadResourceRequest { +export interface ManagedSettingsValidateResult { /** - * Name of the MCP server hosting the resource + * Whether the runtime would accept the document within the preview resource limits. Always equals whether `settings` is present. An invalid document is rejected as a whole. */ - serverName: string; + valid: boolean; /** - * Resource URI (typically ui://...) + * Canonical form of the document the runtime would apply, with unrecognized keys removed. Absent when the document is invalid. */ - uri: string; + settings?: JsonValue; + /** + * Errors that reject the document and warnings about content the runtime ignores. + */ + diagnostics: ManagedSettingsDiagnostic[]; } /** - * Resource contents returned by the MCP server. + * Result of registering a new marketplace. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpAppsReadResourceResult". + * via the `definition` "MarketplaceAddResult". */ /** @experimental */ -export interface McpAppsReadResourceResult { +export interface MarketplaceAddResult { /** - * Resource contents returned by the server + * Final name of the marketplace as resolved from its manifest */ - contents: McpAppsResourceContent[]; + name: string; } /** - * MCP Apps resource content with URI, optional MIME type, text or base64 blob, and resource metadata. + * Plugins advertised by the marketplace. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpAppsResourceContent". + * via the `definition` "MarketplaceBrowseResult". */ /** @experimental */ -export interface McpAppsResourceContent { - /** - * The resource URI (typically ui://...) - */ - uri: string; - /** - * MIME type of the content - */ - mimeType?: string; +export interface MarketplaceBrowseResult { /** - * Text content (e.g. HTML) + * Plugins advertised by the marketplace */ - text?: string; - /** - * Base64-encoded binary content + plugins: MarketplacePluginInfo[]; +} +/** + * Plugin entry advertised by a marketplace. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "MarketplacePluginInfo". + */ +/** @experimental */ +export interface MarketplacePluginInfo { + /** + * Plugin name as listed in the marketplace catalog */ - blob?: string; + name: string; /** - * Resource-level metadata (CSP, permissions, etc.) + * Short description from the marketplace catalog, when present */ - _meta?: { - [k: string]: JsonValue | undefined; - }; + description?: string; } /** - * Host context advertised to MCP App guests + * Registered marketplace summary. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpAppsSetHostContextDetails". + * via the `definition` "MarketplaceInfo". */ /** @experimental */ -export interface McpAppsSetHostContextDetails { - theme?: McpAppsSetHostContextDetailsTheme; +export interface MarketplaceInfo { /** - * BCP-47 locale, e.g. 'en-US' + * Marketplace name (matches the @marketplace suffix in plugin specs) */ - locale?: string; + name: string; /** - * IANA timezone, e.g. 'America/New_York' + * Human-readable description of where the marketplace data is fetched from (e.g. "GitHub: owner/repo"). */ - timeZone?: string; - displayMode?: McpAppsSetHostContextDetailsDisplayMode; + source: string; /** - * Display modes the host supports + * True when this is a default marketplace shipped with the runtime. Defaults are not removable. */ - availableDisplayModes?: McpAppsSetHostContextDetailsAvailableDisplayMode[]; - platform?: McpAppsSetHostContextDetailsPlatform; + isDefault?: boolean; /** - * Host application identifier + * Whether enterprise managed settings provide and control this marketplace entry. */ - userAgent?: string; - [k: string]: unknown | undefined; + managed?: boolean; + /** + * Whether the managed marketplace currently resolved into the runtime marketplace registry. Set to false when the desired managed entry is retained for governance visibility after loading or reconciliation failed. + */ + available?: boolean; } /** - * Host context to advertise to MCP App guests. + * All registered marketplaces, including built-in defaults. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpAppsSetHostContextRequest". + * via the `definition` "MarketplaceListResult". */ /** @experimental */ -export interface McpAppsSetHostContextRequest { - context: McpAppsSetHostContextDetails; +export interface MarketplaceListResult { + /** + * Registered marketplaces + */ + marketplaces: MarketplaceInfo[]; } /** - * The requestId previously passed to executeSampling that should be cancelled. + * Per-marketplace refresh result, including marketplace name, success flag, and optional failure error. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpCancelSamplingExecutionParams". + * via the `definition` "MarketplaceRefreshEntry". */ /** @experimental */ -export interface McpCancelSamplingExecutionParams { +export interface MarketplaceRefreshEntry { /** - * The requestId previously passed to executeSampling that should be cancelled + * Marketplace name that was refreshed */ - requestId: string; + name: string; + /** + * Whether the refresh succeeded + */ + success: boolean; + /** + * Error message (failure only) + */ + error?: string; } /** - * Indicates whether an in-flight sampling execution with the given requestId was found and cancelled. + * Result of refreshing one or more marketplace catalogs. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpCancelSamplingExecutionResult". + * via the `definition` "MarketplaceRefreshResult". */ /** @experimental */ -export interface McpCancelSamplingExecutionResult { +export interface MarketplaceRefreshResult { /** - * True if an in-flight execution with the given requestId was found and signalled to cancel. False when no such execution is in flight (already completed, never started, or cancelled by another caller). + * Per-marketplace refresh results in deterministic order. */ - cancelled: boolean; + results: MarketplaceRefreshEntry[]; } /** - * MCP server name and configuration to add to user configuration. + * Outcome of the remove attempt, including dependent-plugin info when applicable. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpConfigAddRequest". + * via the `definition` "MarketplaceRemoveResult". */ /** @experimental */ -export interface McpConfigAddRequest { +export interface MarketplaceRemoveResult { /** - * Unique name for the MCP server + * True when the marketplace was actually removed. False when removal was skipped because the marketplace has dependent plugins and `force` was not set. */ - name: string; - config: McpSerializableServerConfig; + removed: boolean; + /** + * Names of installed plugins that prevented removal. Populated only when `removed=false`. + */ + dependentPlugins?: string[]; } /** - * Stdio MCP server configuration launched as a child process. + * MCP server allowed by policy, with server name and optional PII-free explanatory note. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpServerConfigStdio". + * via the `definition` "McpAllowedServer". */ /** @experimental */ -export interface McpServerConfigStdio { - /** - * Optional human-readable server name. - */ - displayName?: string; - safeForTelemetry?: McpSafeForTelemetry; - /** - * Tools to include. Defaults to all tools if not specified. - */ - tools?: string[]; - /** - * Whether this server is a built-in fallback used when the user has not configured their own server. - */ - isDefaultServer?: boolean; - filterMapping?: FilterMapping; - /** - * Timeout in milliseconds for tool discovery and tool calls. - */ - timeout?: number; - /** - * Milliseconds this server may spend connecting before the CLI warns that it is taking longer than expected. Presentation only: it does not change how long the connection is allowed to take. - */ - slowConnectionThresholdMs?: number; - oidc?: McpServerAuthConfig; - auth?: McpServerAuthConfig; - deferTools?: McpServerConfigDeferTools; - /** - * Set to true to disable persisted MCP tool snapshots for this server. Live tool discovery is unaffected. - */ - disableToolCache?: boolean; - /** - * Whether secret masking is disabled for calls to this server. - */ - disableSecretMasking?: boolean; - /** - * Tool names excluded after the include filter is applied. - */ - excludeTools?: string[]; - /** - * Event types this server receives as Copilot notifications. - */ - events?: string[]; +export interface McpAllowedServer { /** - * Copilot notification types this server may send to the host. + * Allowed server name */ - notifications?: string[]; - source?: McpServerSource; + name: string; /** - * Plugin that provided this server. + * PII-free note explaining why the server was allowed */ - sourcePlugin?: string; + redactedNote?: string; +} +/** + * Applies exactly one previously prepared operation on its original connection. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpApplyInstallRequest". + */ +/** @experimental */ +export interface McpApplyInstallRequest { + contract: CatalogClientContract; /** - * Version of the plugin that provided this server. + * Runtime-issued ID already returned by prepareInstall, never reused or rebound. */ - sourcePluginVersion?: string; + operationId: string; /** - * Whether the providing plugin uses the Open Plugin Spec. + * Same existing attached or privately borrowed session as preparation. */ - sourcePluginSpec?: boolean; + policySessionId: string; +} +/** + * One-use application of the exact retained removal plan. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpApplyUninstallRequest". + */ +/** @experimental */ +export interface McpApplyUninstallRequest { + contract: CatalogClientContract; /** - * Source file path recorded while loading the config. + * Opaque original removal plan, consumed once. */ - sourcePath?: string; + planHandle: string; /** - * Configuration warnings recorded while loading the server. + * Same existing selected session as removal preparation. */ - configWarnings?: string[]; + policySessionId: string; +} +/** + * MCP server, tool name, and arguments to invoke from an MCP App view. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpAppsCallToolRequest". + */ +/** @experimental */ +export interface McpAppsCallToolRequest { /** - * Executable command used to start the Stdio MCP server process. + * MCP server hosting the tool */ - command: string; + serverName: string; /** - * Command-line arguments passed to the Stdio MCP server process. + * MCP tool name */ - args?: string[]; + toolName: string; /** - * Working directory for the Stdio MCP server process. + * Tool arguments */ - cwd?: string; + arguments?: { + [k: string]: JsonValue | undefined; + }; /** - * Environment variables to pass to the Stdio MCP server process. + * **Required.** Server whose ui:// view issued the request. Per SEP-1865 ('callable by the app from this server only'), the call is rejected when this differs from `serverName`, and rejected outright when missing. */ - env?: { - [k: string]: string | undefined; - }; - type?: McpServerConfigStdioType; + originServerName: string; } /** - * Per-field MCP telemetry-obfuscation policy. + * Capability negotiation snapshot * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpSafeForTelemetryFields". + * via the `definition` "McpAppsDiagnoseCapability". */ /** @experimental */ -export interface McpSafeForTelemetryFields { +export interface McpAppsDiagnoseCapability { /** - * Whether the MCP tool name may be included in telemetry without obfuscation. + * Whether the session has the `mcp-apps` capability */ - name: boolean; + sessionHasMcpApps: boolean; /** - * Whether MCP tool input names may be included in telemetry without obfuscation. + * Whether the MCP_APPS feature flag (or COPILOT_MCP_APPS env override) is on */ - inputsNames: boolean; + featureFlagEnabled: boolean; + /** + * Whether the runtime advertises `extensions.io.modelcontextprotocol/ui` to MCP servers + */ + advertised: boolean; } /** - * Authentication settings with optional redirect port configuration. + * MCP server to diagnose MCP Apps wiring for. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpServerAuthConfigRedirectPort". + * via the `definition` "McpAppsDiagnoseRequest". */ /** @experimental */ -export interface McpServerAuthConfigRedirectPort { +export interface McpAppsDiagnoseRequest { /** - * Fixed port for the OAuth redirect callback server. + * MCP server to probe */ - redirectPort?: number; + serverName: string; } /** - * Remote MCP server configuration accessed over HTTP or SSE. + * Diagnostic snapshot of MCP Apps wiring for the named server. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpServerConfigHttp". + * via the `definition` "McpAppsDiagnoseResult". */ /** @experimental */ -export interface McpServerConfigHttp { - /** - * Optional human-readable server name. - */ - displayName?: string; - safeForTelemetry?: McpSafeForTelemetry; - /** - * Tools to include. Defaults to all tools if not specified. - */ - tools?: string[]; - type?: McpServerConfigHttpType; - /** - * Whether this server is a built-in fallback used when the user has not configured their own server. - */ - isDefaultServer?: boolean; - filterMapping?: FilterMapping; - /** - * Timeout in milliseconds for tool discovery and tool calls. - */ - timeout?: number; - /** - * Milliseconds this server may spend connecting before the CLI warns that it is taking longer than expected. Presentation only: it does not change how long the connection is allowed to take. - */ - slowConnectionThresholdMs?: number; - oidc?: McpServerAuthConfig; - auth?: McpServerAuthConfig; - deferTools?: McpServerConfigDeferTools; - /** - * Set to true to disable persisted MCP tool snapshots for this server. Live tool discovery is unaffected. - */ - disableToolCache?: boolean; - /** - * Whether secret masking is disabled for calls to this server. - */ - disableSecretMasking?: boolean; - /** - * Tool names excluded after the include filter is applied. - */ - excludeTools?: string[]; - /** - * Event types this server receives as Copilot notifications. - */ - events?: string[]; - /** - * Copilot notification types this server may send to the host. - */ - notifications?: string[]; - source?: McpServerSource; - /** - * Plugin that provided this server. - */ - sourcePlugin?: string; - /** - * Version of the plugin that provided this server. - */ - sourcePluginVersion?: string; - /** - * Whether the providing plugin uses the Open Plugin Spec. - */ - sourcePluginSpec?: boolean; +export interface McpAppsDiagnoseResult { + capability: McpAppsDiagnoseCapability; + server: McpAppsDiagnoseServer; +} +/** + * What the server returned for this session + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpAppsDiagnoseServer". + */ +/** @experimental */ +export interface McpAppsDiagnoseServer { /** - * Source file path recorded while loading the config. + * Whether the named server is currently connected */ - sourcePath?: string; + connected: boolean; /** - * Configuration warnings recorded while loading the server. + * Total tools returned by the server's tools/list */ - configWarnings?: string[]; + toolCount: number; /** - * URL of the remote MCP server endpoint. + * Tools whose `_meta.ui` is populated (resourceUri and/or visibility set) */ - url: string; + toolsWithUiMeta: number; /** - * HTTP headers to include in requests to the remote MCP server. + * Up to 5 tool names with `_meta.ui` for quick inspection */ - headers?: { - [k: string]: string | undefined; - }; + sampleToolNames: string[]; +} +/** + * Current host context advertised to MCP App guests. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpAppsHostContext". + */ +/** @experimental */ +export interface McpAppsHostContext { + context: McpAppsHostContextDetails; +} +/** + * Current host context + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpAppsHostContextDetails". + */ +/** @experimental */ +export interface McpAppsHostContextDetails { + theme?: McpAppsHostContextDetailsTheme; /** - * Dynamic-header refresh cache lifetime in milliseconds. + * BCP-47 locale, e.g. 'en-US' */ - headersRefreshTtlMs?: number; + locale?: string; /** - * OAuth client ID for a pre-registered remote MCP OAuth client. + * IANA timezone, e.g. 'America/New_York' */ - oauthClientId?: string; + timeZone?: string; + displayMode?: McpAppsHostContextDetailsDisplayMode; /** - * Non-empty array of valid RFC 6749 scope-token strings to request for the statically configured OAuth client when the server challenge omits scope or provides an empty scope. Requires a non-empty oauthClientId. These scopes take precedence over protected-resource metadata. + * Display modes the host supports */ - oauthScopes?: string[]; + availableDisplayModes?: McpAppsHostContextDetailsAvailableDisplayMode[]; + platform?: McpAppsHostContextDetailsPlatform; /** - * Whether the configured OAuth client is public and does not require a client secret. + * Host application identifier */ - oauthPublicClient?: boolean; - oauthGrantType?: McpServerConfigHttpOauthGrantType; + userAgent?: string; + [k: string]: unknown | undefined; } /** - * MCP server names to disable for new sessions. + * MCP server to list app-callable tools for. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpConfigDisableRequest". + * via the `definition` "McpAppsListToolsRequest". */ /** @experimental */ -export interface McpConfigDisableRequest { +export interface McpAppsListToolsRequest { /** - * Names of MCP servers to disable. Each server is added to the persisted disabled list so new sessions skip it. Already-disabled names are ignored. Active sessions keep their current connections until they end. + * MCP server hosting the app */ - names: string[]; -} -/** - * MCP server names to enable for new sessions. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpConfigEnableRequest". - */ -/** @experimental */ -export interface McpConfigEnableRequest { + serverName: string; /** - * Names of MCP servers to enable. Each server is removed from the persisted disabled list so new sessions spawn it. Unknown or already-enabled names are ignored. + * **Required.** Server whose ui:// view issued the request. Per SEP-1865 ('callable by the app from this server only'), the call is rejected when this differs from `serverName`, and rejected outright when missing. */ - names: string[]; + originServerName: string; } /** - * User-configured MCP servers, keyed by server name. + * App-callable tools from the named MCP server. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpConfigList". + * via the `definition` "McpAppsListToolsResult". */ /** @experimental */ -export interface McpConfigList { +export interface McpAppsListToolsResult { /** - * All MCP servers from user config, keyed by name + * App-callable tools from the server */ - servers: { - [k: string]: McpSerializableServerConfig; - }; + tools: { + [k: string]: JsonValue | undefined; + }[]; } /** - * MCP server name to remove from user configuration. + * MCP server and resource URI to fetch. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpConfigRemoveRequest". + * via the `definition` "McpAppsReadResourceRequest". */ /** @experimental */ -export interface McpConfigRemoveRequest { +export interface McpAppsReadResourceRequest { /** - * Name of the MCP server to remove + * Name of the MCP server hosting the resource */ - name: string; + serverName: string; /** - * OAuth Client ID Metadata Document URL whose persisted credentials should also be removed. + * Resource URI (typically ui://...) */ - authClientIdMetadataUrl?: string; + uri: string; } /** - * MCP server name and replacement configuration to write to user configuration. + * Resource contents returned by the MCP server. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpConfigUpdateRequest". + * via the `definition` "McpAppsReadResourceResult". */ /** @experimental */ -export interface McpConfigUpdateRequest { +export interface McpAppsReadResourceResult { /** - * Name of the MCP server to update + * Resource contents returned by the server */ - name: string; - config: McpSerializableServerConfig; + contents: McpAppsResourceContent[]; } /** - * Effective MCP configuration entry. Configuration enablement is distinct from the optional live observation. + * MCP Apps resource content with URI, optional MIME type, text or base64 blob, and resource metadata. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpConfiguredServer". + * via the `definition` "McpAppsResourceContent". */ /** @experimental */ -export interface McpConfiguredServer { +export interface McpAppsResourceContent { /** - * Server name (config key) + * The resource URI (typically ui://...) */ - name: string; + uri: string; /** - * Whether this configured server is enabled after session configuration and policy filtering. + * MIME type of the content */ - enabled: boolean; - source?: McpServerSource; + mimeType?: string; /** - * Plugin name that provided this server, when source is plugin. + * Text content (e.g. HTML) */ - sourcePlugin?: string; + text?: string; /** - * Plugin version that provided this server, when source is plugin. + * Base64-encoded binary content */ - sourcePluginVersion?: string; + blob?: string; /** - * Human-readable display name supplied by configuration. + * Resource-level metadata (CSP, permissions, etc.) */ - displayName?: string; - live: McpConfiguredServerState; + _meta?: { + [k: string]: JsonValue | undefined; + }; } /** - * Observational state for a matching already materialized MCP server. + * Host context advertised to MCP App guests * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpConfiguredServerState". + * via the `definition` "McpAppsSetHostContextDetails". */ /** @experimental */ -export interface McpConfiguredServerState { - status: McpServerStatus; +export interface McpAppsSetHostContextDetails { + theme?: McpAppsSetHostContextDetailsTheme; /** - * Observed connection error, when the materialized server failed. + * BCP-47 locale, e.g. 'en-US' */ - error?: string; + locale?: string; + /** + * IANA timezone, e.g. 'America/New_York' + */ + timeZone?: string; + displayMode?: McpAppsSetHostContextDetailsDisplayMode; + /** + * Display modes the host supports + */ + availableDisplayModes?: McpAppsSetHostContextDetailsAvailableDisplayMode[]; + platform?: McpAppsSetHostContextDetailsPlatform; + /** + * Host application identifier + */ + userAgent?: string; + [k: string]: unknown | undefined; } /** - * Effective MCP configuration with optional live observations from matching already materialized servers. + * Host context to advertise to MCP App guests. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpConfiguredServerList". + * via the `definition` "McpAppsSetHostContextRequest". */ /** @experimental */ -export interface McpConfiguredServerList { - /** - * Effective configured MCP servers. - */ - servers: McpConfiguredServer[]; +export interface McpAppsSetHostContextRequest { + context: McpAppsSetHostContextDetails; } /** - * Credential-free authentication identity used to configure GitHub MCP. + * The requestId previously passed to executeSampling that should be cancelled. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpConfigureGitHubRequest". + * via the `definition` "McpCancelSamplingExecutionParams". */ /** @experimental */ -/** @internal */ -export interface McpConfigureGitHubRequest { +export interface McpCancelSamplingExecutionParams { /** - * Opaque runtime auth info for GitHub MCP configuration. Marked internal: an in-process runtime shape (configureGitHubMcp is a no-op over the wire). - * - * @internal + * The requestId previously passed to executeSampling that should be cancelled */ - authInfo: OpaqueInProcessValue; + requestId: string; } /** - * Result of configuring GitHub MCP. + * Indicates whether an in-flight sampling execution with the given requestId was found and cancelled. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpConfigureGitHubResult". + * via the `definition` "McpCancelSamplingExecutionResult". */ /** @experimental */ -export interface McpConfigureGitHubResult { +export interface McpCancelSamplingExecutionResult { /** - * Whether GitHub MCP configuration changed. + * True if an in-flight execution with the given requestId was found and signalled to cancel. False when no such execution is in flight (already completed, never started, or cancelled by another caller). */ - changed: boolean; + cancelled: boolean; } /** - * Name of the MCP server to disable for the session. + * MCP server name and configuration to add to user configuration. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpDisableRequest". + * via the `definition` "McpConfigAddRequest". */ /** @experimental */ -export interface McpDisableRequest { - /** - * Required for an owned installation; omission preserves only manual-server behaviour. - */ - expectedInstallationId?: string; +export interface McpConfigAddRequest { /** - * Name of the MCP server to disable + * Unique name for the MCP server */ - serverName: string; + name: string; + config: McpSerializableServerConfig; } /** - * Optional working directory used as context for MCP server discovery. + * Stdio MCP server configuration launched as a child process. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpDiscoverRequest". + * via the `definition` "McpServerConfigStdio". */ /** @experimental */ -export interface McpDiscoverRequest { +export interface McpServerConfigStdio { /** - * Working directory used as context for discovery (e.g., plugin resolution) + * Optional human-readable server name. */ - workingDirectory?: string; + displayName?: string; + safeForTelemetry?: McpSafeForTelemetry; /** - * Whether to include canonical effectiveSource metadata for each discovered server. Callers must opt in so protocol-3 clients retain the legacy closed response shape. + * Tools to include. Defaults to all tools if not specified. */ - includeEffectiveSource?: boolean; -} -/** - * MCP servers discovered from user, workspace, plugin, and built-in sources. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpDiscoverResult". - */ -/** @experimental */ -export interface McpDiscoverResult { + tools?: string[]; /** - * MCP servers discovered from all sources + * Whether this server is a built-in fallback used when the user has not configured their own server. */ - servers: DiscoveredMcpServer[]; -} -/** - * Name of the MCP server to enable for the session. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpEnableRequest". - */ -/** @experimental */ -export interface McpEnableRequest { + isDefaultServer?: boolean; + filterMapping?: FilterMapping; /** - * Exact receipt identity for explicit owned activation in this session. + * Timeout in milliseconds for tool discovery and tool calls. */ - expectedInstallationId?: string; + timeout?: number; /** - * Name of the MCP server to enable + * Milliseconds this server may spend connecting before the CLI warns that it is taking longer than expected. Presentation only: it does not change how long the connection is allowed to take. */ - serverName: string; -} -/** - * Identifiers and raw MCP CreateMessageRequest params used to run a sampling inference. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpExecuteSamplingParams". - */ -/** @experimental */ -export interface McpExecuteSamplingParams { + slowConnectionThresholdMs?: number; + oidc?: McpServerAuthConfig; + auth?: McpServerAuthConfig; + deferTools?: McpServerConfigDeferTools; /** - * Caller-provided unique identifier for this sampling execution. Use this same ID with cancelSamplingExecution to cancel the in-flight call. Must be unique within the session for the lifetime of the call. + * Set to true to disable persisted MCP tool snapshots for this server. Live tool discovery is unaffected. */ - requestId: string; + disableToolCache?: boolean; /** - * Name of the MCP server that initiated the sampling request + * Whether secret masking is disabled for calls to this server. */ - serverName: string; + disableSecretMasking?: boolean; /** - * The original MCP JSON-RPC request ID (string or number). Used by the runtime to correlate the inference with the originating MCP request for telemetry; this is distinct from `requestId` (which is the schema-level cancellation handle). + * Tool names excluded after the include filter is applied. */ - mcpRequestId: JsonValue; - request: McpExecuteSamplingRequest; -} -/** - * Raw MCP CreateMessageRequest params, as received in the `sampling.requested` event. Treated as opaque at the schema layer; the runtime converts the embedded MCP messages into the OpenAI chat-completion shape internally. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpExecuteSamplingRequest". - */ -/** @experimental */ -export interface McpExecuteSamplingRequest { - [k: string]: unknown | undefined; -} -/** - * MCP CreateMessageResult payload (with optional 'tools' extension), present when action='success'. Treated as opaque at the schema layer; consumers should construct/consume it per the MCP CreateMessageResult shape. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpExecuteSamplingResult". - */ -/** @experimental */ -export interface McpExecuteSamplingResult { - [k: string]: unknown | undefined; -} -/** - * MCP server whose connection attempt failed. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpFailedServer". - */ -/** @experimental */ -export interface McpFailedServer { + excludeTools?: string[]; /** - * The config key of the server that failed to connect. + * Event types this server receives as Copilot notifications. */ - name: string; + events?: string[]; /** - * The captured connection failure detail. + * Copilot notification types this server may send to the host. */ - error?: string; -} -/** - * MCP server filtered by policy, with name, reason, and optional redacted reason. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpFilteredServer". - */ -/** @experimental */ -export interface McpFilteredServer { + notifications?: string[]; + source?: McpServerSource; /** - * Filtered server name + * Plugin that provided this server. */ - name: string; + sourcePlugin?: string; /** - * Human-readable filter reason + * Version of the plugin that provided this server. */ - reason: string; + sourcePluginVersion?: string; /** - * PII-free filter reason + * Whether the providing plugin uses the Open Plugin Spec. */ - redactedReason?: string; + sourcePluginSpec?: boolean; /** - * @deprecated - * Deprecated. This field is no longer populated. + * Source file path recorded while loading the config. */ - enterpriseName?: string; + sourcePath?: string; + /** + * Configuration warnings recorded while loading the server. + */ + configWarnings?: string[]; + /** + * Executable command used to start the Stdio MCP server process. + */ + command: string; + /** + * Command-line arguments passed to the Stdio MCP server process. + */ + args?: string[]; + /** + * Working directory for the Stdio MCP server process. + */ + cwd?: string; + /** + * Environment variables to pass to the Stdio MCP server process. + */ + env?: { + [k: string]: string | undefined; + }; + type?: McpServerConfigStdioType; } /** - * MCP headers refresh request id and the host response. + * Per-field MCP telemetry-obfuscation policy. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpHeadersHandlePendingHeadersRefreshRequestRequest". + * via the `definition` "McpSafeForTelemetryFields". */ /** @experimental */ -export interface McpHeadersHandlePendingHeadersRefreshRequestRequest { +export interface McpSafeForTelemetryFields { /** - * Headers refresh request identifier from mcp.headers_refresh_required + * Whether the MCP tool name may be included in telemetry without obfuscation. */ - requestId: string; - result: McpHeadersHandlePendingHeadersRefreshRequest; + name: boolean; + /** + * Whether MCP tool input names may be included in telemetry without obfuscation. + */ + inputsNames: boolean; } /** - * Indicates whether the pending MCP headers refresh response was accepted. + * Authentication settings with optional redirect port configuration. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpHeadersHandlePendingHeadersRefreshRequestResult". + * via the `definition` "McpServerAuthConfigRedirectPort". */ /** @experimental */ -export interface McpHeadersHandlePendingHeadersRefreshRequestResult { +export interface McpServerAuthConfigRedirectPort { /** - * Whether the response was accepted. False if the request was unknown, timed out, or already resolved. + * Fixed port for the OAuth redirect callback server. */ - success: boolean; + redirectPort?: number; } /** - * Host-level state, omitted when no MCP host is initialized. + * Remote MCP server configuration accessed over HTTP or SSE. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpHostState". + * via the `definition` "McpServerConfigHttp". */ /** @experimental */ -export interface McpHostState { +export interface McpServerConfigHttp { /** - * Whether third-party MCP servers are policy-enabled for this session. + * Optional human-readable server name. */ - mcp3pEnabled: boolean; + displayName?: string; + safeForTelemetry?: McpSafeForTelemetry; /** - * Configured servers that are explicitly disabled. + * Tools to include. Defaults to all tools if not specified. */ - disabledServers: string[]; + tools?: string[]; + type?: McpServerConfigHttpType; /** - * Configured servers filtered out by MCP server policy. + * Whether this server is a built-in fallback used when the user has not configured their own server. */ - filteredServers: string[]; + isDefaultServer?: boolean; + filterMapping?: FilterMapping; /** - * Names of currently-connected MCP clients. + * Timeout in milliseconds for tool discovery and tool calls. */ - clients: string[]; + timeout?: number; /** - * Names of servers with in-flight connection attempts. + * Milliseconds this server may spend connecting before the CLI warns that it is taking longer than expected. Presentation only: it does not change how long the connection is allowed to take. */ - pendingConnections: string[]; - /** - * Map of server name to recorded connection failure. - */ - failedServers: { - [k: string]: McpServerFailureInfo | undefined; - }; + slowConnectionThresholdMs?: number; + oidc?: McpServerAuthConfig; + auth?: McpServerAuthConfig; + deferTools?: McpServerConfigDeferTools; /** - * Map of server name to recorded pending-auth state. + * Set to true to disable persisted MCP tool snapshots for this server. Live tool discovery is unaffected. */ - needsAuthServers: { - [k: string]: McpServerNeedsAuthInfo | undefined; - }; -} -/** - * Recorded MCP server connection failure. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpServerFailureInfo". - */ -/** @experimental */ -export interface McpServerFailureInfo { + disableToolCache?: boolean; /** - * Failure message produced when the MCP server connection failed. + * Whether secret masking is disabled for calls to this server. */ - message: string; + disableSecretMasking?: boolean; /** - * epoch-ms timestamp at which the failure was recorded. + * Tool names excluded after the include filter is applied. */ - timestamp: number; -} -/** - * Recorded MCP server pending-auth state. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpServerNeedsAuthInfo". - */ -/** @experimental */ -export interface McpServerNeedsAuthInfo { + excludeTools?: string[]; /** - * epoch-ms timestamp at which the server signalled it needs authentication. + * Event types this server receives as Copilot notifications. */ - timestamp: number; -} -/** - * Inert, runtime-owned admission. The operation ID is known before confirmation or effects. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpPreparedInstall". - */ -/** @experimental */ -export interface McpPreparedInstall { + events?: string[]; /** - * Original connection-owned operation, known before the first confirmation callback. + * Copilot notification types this server may send to the host. */ - operationId: string; + notifications?: string[]; + source?: McpServerSource; /** - * Original plan expiry in Unix epoch milliseconds; preparation does not extend it. + * Plugin that provided this server. */ - expiresAtEpochMs: number; -} -/** - * Durable configuration ownership is distinct from session-specific usability. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpInstallationSummary". - */ -/** @experimental */ -export interface McpInstallationSummary { + sourcePlugin?: string; /** - * Exact durable installation receipt identity. + * Version of the plugin that provided this server. */ - installationId: string; + sourcePluginVersion?: string; /** - * Original installing operation, not a fresh management operation. + * Whether the providing plugin uses the Open Plugin Spec. */ - operationId: string; - identity: McpPlanResourceIdentity; + sourcePluginSpec?: boolean; /** - * Exact alternative retained in the installing receipt. + * Source file path recorded while loading the config. */ - choiceId: string; - state: McpInstallationState; - catalogue?: InstallationCatalogueIdentity; + sourcePath?: string; /** - * ISO 8601 wall-clock installation time when available. + * Configuration warnings recorded while loading the server. */ - installedAt?: string; -} -/** - * Exact inert removal plan. No configuration or credentials have changed. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpUninstallPlan". - */ -/** @experimental */ -export interface McpUninstallPlan { + configWarnings?: string[]; /** - * One-use original connection and authority-bound plan handle. + * URL of the remote MCP server endpoint. */ - planHandle: string; + url: string; /** - * The original operation, inspectable and cancellable on this same connection. + * HTTP headers to include in requests to the remote MCP server. */ - operationId: string; + headers?: { + [k: string]: string | undefined; + }; /** - * Original wall-clock expiry in milliseconds. Applying never renews it. + * Dynamic-header refresh cache lifetime in milliseconds. */ - expiresAtEpochMs: number; - installation: McpInstallationSummary; + headersRefreshTtlMs?: number; /** - * Whether removal restores a protected earlier configuration. + * OAuth client ID for a pre-registered remote MCP OAuth client. */ - restoresPreviousConfiguration: boolean; + oauthClientId?: string; /** - * Exact configured input slots owned by this installation, never shared OAuth tokens. + * Non-empty array of valid RFC 6749 scope-token strings to request for the statically configured OAuth client when the server challenge omits scope or provides an empty scope. Requires a non-empty oauthClientId. These scopes take precedence over protected-resource metadata. */ - ownedSecretCount: number; + oauthScopes?: string[]; /** - * Shared authentication is deliberately retained; revocation is a separate action. + * Whether the configured OAuth client is public and does not require a client secret. */ - preservesSharedAuthentication: boolean; + oauthPublicClient?: boolean; + oauthGrantType?: McpServerConfigHttpOauthGrantType; } /** - * Existing-operation control. A new session selector is deliberately not accepted. + * MCP server names to disable for new sessions. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpInstallationOperationRequest". + * via the `definition` "McpConfigDisableRequest". */ /** @experimental */ -export interface McpInstallationOperationRequest { - contract: CatalogClientContract; +export interface McpConfigDisableRequest { /** - * Exact runtime-issued operation ID on the original connection. + * Names of MCP servers to disable. Each server is added to the persisted disabled list so new sessions skip it. Already-disabled names are ignored. Active sessions keep their current connections until they end. */ - operationId: string; + names: string[]; } /** - * A request-local value for one exact reviewed placeholder. Never logged or persisted in a plan. + * MCP server names to enable for new sessions. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpInstallationSecret". + * via the `definition` "McpConfigEnableRequest". */ /** @experimental */ -export interface McpInstallationSecret { - placeholder: McpPlanSecretReference; +export interface McpConfigEnableRequest { /** - * Fresh explicit secret value. It is omitted from confirmation reviews and telemetry. + * Names of MCP servers to enable. Each server is removed from the persisted disabled list so new sessions spawn it. Unknown or already-enabled names are ignored. */ - value: string; + names: string[]; } /** - * New-work inventory or recovery request under an explicitly selected existing session. + * User-configured MCP servers, keyed by server name. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpInstallationsRequest". + * via the `definition` "McpConfigList". */ /** @experimental */ -export interface McpInstallationsRequest { - contract: CatalogClientContract; +export interface McpConfigList { /** - * Existing selected local session on this connection. + * All MCP servers from user config, keyed by name */ - policySessionId: string; + servers: { + [k: string]: McpSerializableServerConfig; + }; } /** - * A normalised, inert description of what installing an MCP server would involve. Carries no raw card, no install specification, and no secret value. + * MCP server name to remove from user configuration. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpInstallPlan". + * via the `definition` "McpConfigRemoveRequest". */ /** @experimental */ -export interface McpInstallPlan { +export interface McpConfigRemoveRequest { /** - * Opaque, runtime-instance scoped, TTL-bound, single-use handle for this plan. Rejected when stale, replayed, or presented to a different runtime instance. Never logged. + * Name of the MCP server to remove */ - planHandle: string; + name: string; /** - * ISO 8601 timestamp after which the plan handle is stale and will be rejected. Abandoning a plan needs no call: an unused handle simply expires, so cancellation before commit is side-effect free. + * OAuth Client ID Metadata Document URL whose persisted credentials should also be removed. */ - planHandleExpiresAt: string; - identity: McpPlanResourceIdentity; - provenance: McpPlanProvenance; + authClientIdMetadataUrl?: string; +} +/** + * MCP server name and replacement configuration to write to user configuration. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpConfigUpdateRequest". + */ +/** @experimental */ +export interface McpConfigUpdateRequest { /** - * Every eligible transport, so a host can present an explicit choice. A completed plan always has at least one; when none is eligible, planning returns `CatalogUnavailableTransportError` instead. - * - * @minItems 1 - * @maxItems 50 + * Name of the MCP server to update */ - transportChoices: [McpPlanTransportChoice, ...McpPlanTransportChoice[]]; + name: string; + config: McpSerializableServerConfig; +} +/** + * Effective MCP configuration entry. Configuration enablement is distinct from the optional live observation. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpConfiguredServer". + */ +/** @experimental */ +export interface McpConfiguredServer { /** - * Identifier of the choice the runtime would pick by default. Omitted when there is no eligible transport, or when the runtime expresses no preference. + * Server name (config key) */ - recommendedTransportChoiceId?: string; - target: McpPlanTarget; - policy: McpPlanPolicyResult; + name: string; /** - * Alternative configuration changes, with exactly one entry for each transportChoices entry in the same order. Only the entry for the subsequently selected transport applies; these are not cumulative writes. Payloads remain behind the runtime boundary. + * Whether this configured server is enabled after session configuration and policy filtering. */ - configurationChanges: McpPlanConfigurationChange[]; + enabled: boolean; + source?: McpServerSource; /** - * Whether applying this plan would require an MCP reload to take effect. Planning itself never reloads. + * Plugin name that provided this server, when source is plugin. */ - reloadRequired: boolean; + sourcePlugin?: string; /** - * True only when every eligible transport choice needs additional values or secrets. False means at least one choice needs no additional configuration, not that every choice is ready. A later apply operation must validate the selected choice's own inputs, secrets and policy after explicit confirmation. + * Plugin version that provided this server, when source is plugin. */ - requiresInteractiveConfiguration: boolean; + sourcePluginVersion?: string; + /** + * Human-readable display name supplied by configuration. + */ + displayName?: string; + live: McpConfiguredServerState; } /** - * Server name to check running status for. + * Observational state for a matching already materialized MCP server. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpIsServerRunningRequest". + * via the `definition` "McpConfiguredServerState". */ /** @experimental */ -export interface McpIsServerRunningRequest { +export interface McpConfiguredServerState { + status: McpServerStatus; /** - * Name of the MCP server to check + * Observed connection error, when the materialized server failed. */ - serverName: string; + error?: string; } /** - * Whether the named MCP server is running. + * Effective MCP configuration with optional live observations from matching already materialized servers. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpIsServerRunningResult". + * via the `definition` "McpConfiguredServerList". */ /** @experimental */ -export interface McpIsServerRunningResult { +export interface McpConfiguredServerList { /** - * True if the server has an active client and transport. + * Effective configured MCP servers. */ - running: boolean; + servers: McpConfiguredServer[]; } /** - * Names of the MCP servers the runtime supplies itself. + * Credential-free authentication identity used to configure GitHub MCP. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpListBuiltinServerNamesResult". + * via the `definition` "McpConfigureGitHubRequest". */ /** @experimental */ /** @internal */ -export interface McpListBuiltinServerNamesResult { +export interface McpConfigureGitHubRequest { /** - * Every built-in server name. A host disabling the built-ins wholesale suppresses exactly this set. + * Opaque runtime auth info for GitHub MCP configuration. Marked internal: an in-process runtime shape (configureGitHubMcp is a no-op over the wire). + * + * @internal */ - names: string[]; + authInfo: OpaqueInProcessValue; } /** - * Server name whose tool list should be returned. + * Result of configuring GitHub MCP. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpListToolsRequest". + * via the `definition` "McpConfigureGitHubResult". */ /** @experimental */ -export interface McpListToolsRequest { +export interface McpConfigureGitHubResult { /** - * Name of the connected MCP server whose tools to list. + * Whether GitHub MCP configuration changed. */ - serverName: string; + changed: boolean; } /** - * Tools exposed by the connected MCP server. Throws when the server is not connected. + * Name of the MCP server to disable for the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpListToolsResult". + * via the `definition` "McpDisableRequest". */ /** @experimental */ -export interface McpListToolsResult { +export interface McpDisableRequest { /** - * Tools exposed by the server. + * Required for an owned installation; omission preserves only manual-server behaviour. */ - tools: McpTools[]; + expectedInstallationId?: string; + /** + * Name of the MCP server to disable + */ + serverName: string; } /** - * MCP tool metadata with tool name, optional description, and normalized MCP Apps discovery metadata. + * Optional working directory used as context for MCP server discovery. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpTools". + * via the `definition` "McpDiscoverRequest". */ /** @experimental */ -export interface McpTools { +export interface McpDiscoverRequest { /** - * Tool name. + * Working directory used as context for discovery (e.g., plugin resolution) */ - name: string; + workingDirectory?: string; /** - * Tool description, when provided. + * Whether to include canonical effectiveSource metadata for each discovered server. Callers must opt in so protocol-3 clients retain the legacy closed response shape. */ - description?: string; - ui?: McpToolUi; + includeEffectiveSource?: boolean; } /** - * Normalized MCP Apps discovery metadata from a tool's `_meta.ui` block. + * MCP servers discovered from user, workspace, plugin, and built-in sources. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpToolUi". + * via the `definition` "McpDiscoverResult". */ /** @experimental */ -export interface McpToolUi { - /** - * URI of the tool's MCP App resource, typically a `ui://` resource identifier. Use `session.mcp.resources.read` to fetch its HTML and resource metadata. - */ - resourceUri?: string; +export interface McpDiscoverResult { /** - * Tool visibility advertised by the server. When absent, MCP Apps defaults apply. + * MCP servers discovered from all sources */ - visibility?: McpToolUiVisibility[]; + servers: DiscoveredMcpServer[]; } /** - * Identifies the MCP server whose persisted OAuth credentials were updated. + * Name of the MCP server to enable for the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpOauthAuthenticationStateChangedRequest". + * via the `definition` "McpEnableRequest". */ /** @experimental */ -export interface McpOauthAuthenticationStateChangedRequest { +export interface McpEnableRequest { /** - * Name of the MCP server whose OAuth credentials were updated. Omit only when the host cannot identify the server. + * Exact receipt identity for explicit owned activation in this session. */ - serverName?: string; + expectedInstallationId?: string; /** - * Whether the target session must mint a session-scoped access token instead of reusing a shared access token persisted by another session. + * Name of the MCP server to enable */ - refreshSessionToken?: boolean; + serverName: string; } /** - * Targets only the original prepared/applying owned login on this exact session requester. + * Identifiers and raw MCP CreateMessageRequest params used to run a sampling inference. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpOauthCancelLoginRequest". + * via the `definition` "McpExecuteSamplingParams". */ /** @experimental */ -export interface McpOauthCancelLoginRequest { +export interface McpExecuteSamplingParams { /** - * The same authoritative installation identity supplied during preparation. + * Caller-provided unique identifier for this sampling execution. Use this same ID with cancelSamplingExecution to cancel the in-flight call. Must be unique within the session for the lifetime of the call. */ - expectedInstallationId: string; + requestId: string; /** - * Runtime-issued login handle known before the effectful login request begins. + * Name of the MCP server that initiated the sampling request */ - loginId: string; + serverName: string; + /** + * The original MCP JSON-RPC request ID (string or number). Used by the runtime to correlate the inference with the originating MCP request for telemetry; this is distinct from `requestId` (which is the schema-level cancellation handle). + */ + mcpRequestId: JsonValue; + request: McpExecuteSamplingRequest; } /** - * Honest terminal cancellation result; persistence or recovery failures remain RPC errors. + * Raw MCP CreateMessageRequest params, as received in the `sampling.requested` event. Treated as opaque at the schema layer; the runtime converts the embedded MCP messages into the OpenAI chat-completion shape internally. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpOauthCancelLoginResult". + * via the `definition` "McpExecuteSamplingRequest". */ /** @experimental */ -export interface McpOauthCancelLoginResult { +export interface McpExecuteSamplingRequest { + [k: string]: unknown | undefined; +} +/** + * MCP CreateMessageResult payload (with optional 'tools' extension), present when action='success'. Treated as opaque at the schema layer; consumers should construct/consume it per the MCP CreateMessageResult shape. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpExecuteSamplingResult". + */ +/** @experimental */ +export interface McpExecuteSamplingResult { + [k: string]: unknown | undefined; +} +/** + * MCP server whose connection attempt failed. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpFailedServer". + */ +/** @experimental */ +export interface McpFailedServer { /** - * True after cancellation settles, false when the original login already connected successfully. + * The config key of the server that failed to connect. */ - cancelled: boolean; + name: string; + /** + * The captured connection failure detail. + */ + error?: string; } /** - * Host-delivered callback for a runtime-managed MCP OAuth login. + * MCP server filtered by policy, with name, reason, and optional redacted reason. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpOauthCompleteRequest". + * via the `definition` "McpFilteredServer". */ /** @experimental */ -export interface McpOauthCompleteRequest { +export interface McpFilteredServer { /** - * Opaque identifier returned by session.mcp.oauth.login for the pending external callback. + * Filtered server name */ - authorizationId: string; + name: string; /** - * Full externally visible HTTPS callback URL received by the host, including the authorization response query parameters. Applications behind a reverse proxy must reconstruct the public URL rather than passing an internal proxy URL. + * Human-readable filter reason */ - callbackUrl: string; + reason: string; + /** + * PII-free filter reason + */ + redactedReason?: string; + /** + * @deprecated + * Deprecated. This field is no longer populated. + */ + enterpriseName?: string; } /** - * Pending MCP OAuth request ID and host-provided token or cancellation response. + * MCP headers refresh request id and the host response. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpOauthHandlePendingRequest". + * via the `definition` "McpHeadersHandlePendingHeadersRefreshRequestRequest". */ /** @experimental */ -export interface McpOauthHandlePendingRequest { +export interface McpHeadersHandlePendingHeadersRefreshRequestRequest { /** - * OAuth request identifier from the mcp.oauth_required event + * Headers refresh request identifier from mcp.headers_refresh_required */ requestId: string; - result: McpOauthPendingRequestResponse; + result: McpHeadersHandlePendingHeadersRefreshRequest; } /** - * Indicates whether the pending MCP OAuth response was accepted. + * Indicates whether the pending MCP headers refresh response was accepted. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpOauthHandlePendingResult". + * via the `definition` "McpHeadersHandlePendingHeadersRefreshRequestResult". */ /** @experimental */ -export interface McpOauthHandlePendingResult { +export interface McpHeadersHandlePendingHeadersRefreshRequestResult { /** * Whether the response was accepted. False if the request was unknown, timed out, or already resolved. */ success: boolean; } /** - * Remote MCP server name and optional overrides controlling reauthentication, OAuth client display name, callback handling, and static OAuth client selection. + * Host-level state, omitted when no MCP host is initialized. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpOauthLoginRequest". + * via the `definition` "McpHostState". */ /** @experimental */ -export interface McpOauthLoginRequest { - /** - * Name of the remote MCP server to authenticate - */ - serverName: string; - /** - * When true, clears any cached OAuth token for the server and runs a full new authorization. Use when the user explicitly wants to switch accounts or believes their session is stuck. - */ - forceReauth?: boolean; - /** - * Optional override for the OAuth client display name shown on the consent screen. Applies to newly registered dynamic clients only — existing registrations keep the name they were created with. When omitted, the runtime applies a neutral fallback; callers driving interactive auth should pass their own surface-specific label so the consent screen matches the product the user sees. - */ - clientName?: string; +export interface McpHostState { /** - * Optional override for the body text shown on the OAuth loopback callback success page. When omitted, the runtime applies a neutral fallback; callers driving interactive auth should pass surface-specific copy telling the user where to return. + * Whether third-party MCP servers are policy-enabled for this session. */ - callbackSuccessMessage?: string; + mcp3pEnabled: boolean; /** - * Optional OAuth client ID override for this login. When set, the runtime uses this pre-registered static client instead of dynamic client registration. + * Configured servers that are explicitly disabled. */ - clientId?: string; + disabledServers: string[]; /** - * Optional OAuth client secret override for this login. The runtime treats this as an ephemeral host-owned secret, uses it for this authentication attempt and does not persist it. + * Configured servers filtered out by MCP server policy. */ - clientSecret?: string; + filteredServers: string[]; /** - * Optional override indicating whether the static OAuth client is public. When false, the runtime treats it as confidential and uses the per-login clientSecret if provided, otherwise retrieving the client secret from the MCP OAuth secret store. + * Names of currently-connected MCP clients. */ - publicClient?: boolean; - grantType?: McpOauthLoginGrantType; + clients: string[]; /** - * Optional externally visible HTTPS redirect URI for a host-managed callback endpoint. When supplied, the runtime still owns discovery, PKCE, token exchange, persistence, and reconnect, but does not bind a loopback listener or terminate HTTPS. The URI must not contain query parameters or a fragment and must be registered for the selected CIMD, DCR, or static OAuth client. + * Names of servers with in-flight connection attempts. */ - redirectUri?: string; + pendingConnections: string[]; /** - * Required for owned login. Consumes the exact prepareLogin handle once. - * Set forceReauth and display options during preparation, not consumption. + * Map of server name to recorded connection failure. */ - loginId?: string; + failedServers: { + [k: string]: McpServerFailureInfo | undefined; + }; /** - * Exact owned receipt identity. Owned login never uses an implicit helper session. + * Map of server name to recorded pending-auth state. */ - expectedInstallationId?: string; + needsAuthServers: { + [k: string]: McpServerNeedsAuthInfo | undefined; + }; } /** - * OAuth authorization URL the caller should open, or empty when cached tokens already authenticated the server. + * Recorded MCP server connection failure. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpOauthLoginResult". + * via the `definition` "McpServerFailureInfo". */ /** @experimental */ -export interface McpOauthLoginResult { +export interface McpServerFailureInfo { /** - * Runtime-issued owned flow identity; never a server name or installation operation ID. + * Failure message produced when the MCP server connection failed. */ - loginId?: string; - status?: McpOwnedOauthLoginStatus; + message: string; /** - * URL the caller should open in a browser to complete OAuth. Omitted when cached tokens were still valid and no browser interaction was needed — the server is already reconnected in that case. For the default loopback flow, the runtime starts its listener before returning. With redirectUri, the host receives the callback and completes it through session.mcp.oauth.complete. The runtime continues the flow in the background and signals completion via session.mcp_server_status_changed. + * epoch-ms timestamp at which the failure was recorded. */ - authorizationUrl?: string; + timestamp: number; +} +/** + * Recorded MCP server pending-auth state. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpServerNeedsAuthInfo". + */ +/** @experimental */ +export interface McpServerNeedsAuthInfo { /** - * Opaque authorization identifier returned only for a host-managed redirect URI. The runtime also sends it as the OAuth state value, so the callback endpoint can read state and pass it with the full callback URL to session.mcp.oauth.complete. + * epoch-ms timestamp at which the server signalled it needs authentication. */ - authorizationId?: string; + timestamp: number; } /** - * Effect-free preparation bound to the existing local session, requester and installation, with frozen options. + * Inert, runtime-owned admission. The operation ID is known before confirmation or effects. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpOauthPrepareLoginRequest". + * via the `definition` "McpPreparedInstall". */ /** @experimental */ -export interface McpOauthPrepareLoginRequest { +export interface McpPreparedInstall { /** - * Name recorded by the authoritative owned installation receipt. + * Original connection-owned operation, known before the first confirmation callback. */ - serverName: string; + operationId: string; /** - * Exact installation identity from owned inventory, never a server-name alias. + * Original plan expiry in Unix epoch milliseconds; preparation does not extend it. */ - expectedInstallationId: string; + expiresAtEpochMs: number; +} +/** + * Durable configuration ownership is distinct from session-specific usability. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpInstallationSummary". + */ +/** @experimental */ +export interface McpInstallationSummary { /** - * Request a new authorisation rather than accepting a usable cached grant. + * Exact durable installation receipt identity. */ - forceReauth?: boolean; + installationId: string; /** - * Display name used by the incumbent OAuth client-registration flow. + * Original installing operation, not a fresh management operation. */ - clientName?: string; + operationId: string; + identity: McpPlanResourceIdentity; /** - * Text shown on the loopback callback page after successful authorisation. + * Exact alternative retained in the installing receipt. */ - callbackSuccessMessage?: string; + choiceId: string; + state: McpInstallationState; + catalogue?: InstallationCatalogueIdentity; + /** + * ISO 8601 wall-clock installation time when available. + */ + installedAt?: string; } /** - * An inert runtime-issued login handle. Preparation alone performs no activation or OAuth work. + * Exact inert removal plan. No configuration or credentials have changed. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpOauthPrepareLoginResult". + * via the `definition` "McpUninstallPlan". */ /** @experimental */ -export interface McpOauthPrepareLoginResult { +export interface McpUninstallPlan { /** - * Retain with the original requester and use for one login or cancellation. + * One-use original connection and authority-bound plan handle. */ - loginId: string; + planHandle: string; /** - * Original expiry, not extended by consumption, retries or cancellation. + * The original operation, inspectable and cancellable on this same connection. */ - expiresAt: string; + operationId: string; + /** + * Original wall-clock expiry in milliseconds. Applying never renews it. + */ + expiresAtEpochMs: number; + installation: McpInstallationSummary; + /** + * Whether removal restores a protected earlier configuration. + */ + restoresPreviousConfiguration: boolean; + /** + * Exact configured input slots owned by this installation, never shared OAuth tokens. + */ + ownedSecretCount: number; + /** + * Shared authentication is deliberately retained; revocation is a separate action. + */ + preservesSharedAuthentication: boolean; } /** - * Remote MCP server name for a passive OAuth status probe. + * Existing-operation control. A new session selector is deliberately not accepted. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpOauthProbeRequest". + * via the `definition` "McpInstallationOperationRequest". */ /** @experimental */ -export interface McpOauthProbeRequest { - /** - * Exact owned receipt identity; probing never activates a dormant installation. - */ - expectedInstallationId?: string; +export interface McpInstallationOperationRequest { + contract: CatalogClientContract; /** - * Name of the configured remote MCP server to probe. + * Exact runtime-issued operation ID on the original connection. */ - serverName: string; + operationId: string; } /** - * Pending MCP OAuth request id to respond to. + * A request-local value for one exact reviewed placeholder. Never logged or persisted in a plan. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpOauthRespondRequest". + * via the `definition` "McpInstallationSecret". */ /** @experimental */ -export interface McpOauthRespondRequest { +export interface McpInstallationSecret { + placeholder: McpPlanSecretReference; /** - * OAuth request identifier from the mcp.oauth_required event + * Fresh explicit secret value. It is omitted from confirmation reviews and telemetry. */ - requestId: string; + value: string; } /** - * Indicates whether the pending MCP OAuth response was accepted. + * New-work inventory or recovery request under an explicitly selected existing session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpOauthRespondResult". + * via the `definition` "McpInstallationsRequest". */ /** @experimental */ -export interface McpOauthRespondResult { +export interface McpInstallationsRequest { + contract: CatalogClientContract; /** - * Whether the response was accepted. False if the request was unknown, timed out, or already resolved. + * Existing selected local session on this connection. */ - success: boolean; + policySessionId: string; } /** - * A computed MCP install plan. Nothing has been applied: the plan describes what installing would change, and the plan handle is what a later apply operation would consume. + * A normalised, inert description of what installing an MCP server would involve. Carries no raw card, no install specification, and no secret value. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpPlanInstallPlanned". + * via the `definition` "McpInstallPlan". */ /** @experimental */ -export interface McpPlanInstallPlanned { +export interface McpInstallPlan { /** - * Discriminator: a plan was computed and nothing was changed + * Opaque, runtime-instance scoped, TTL-bound, single-use handle for this plan. Rejected when stale, replayed, or presented to a different runtime instance. Never logged. */ - kind: "planned"; - plan: McpInstallPlan; - negotiated: CatalogNegotiatedContract; + planHandle: string; + /** + * ISO 8601 timestamp after which the plan handle is stale and will be rejected. Abandoning a plan needs no call: an unused handle simply expires, so cancellation before commit is side-effect free. + */ + planHandleExpiresAt: string; + identity: McpPlanResourceIdentity; + provenance: McpPlanProvenance; + /** + * Every eligible transport, so a host can present an explicit choice. A completed plan always has at least one; when none is eligible, planning returns `CatalogUnavailableTransportError` instead. + * + * @minItems 1 + * @maxItems 50 + */ + transportChoices: [McpPlanTransportChoice, ...McpPlanTransportChoice[]]; + /** + * Identifier of the choice the runtime would pick by default. Omitted when there is no eligible transport, or when the runtime expresses no preference. + */ + recommendedTransportChoiceId?: string; + target: McpPlanTarget; + policy: McpPlanPolicyResult; + /** + * Alternative configuration changes, with exactly one entry for each transportChoices entry in the same order. Only the entry for the subsequently selected transport applies; these are not cumulative writes. Payloads remain behind the runtime boundary. + */ + configurationChanges: McpPlanConfigurationChange[]; + /** + * Whether applying this plan would require an MCP reload to take effect. Planning itself never reloads. + */ + reloadRequired: boolean; + /** + * True only when every eligible transport choice needs additional values or secrets. False means at least one choice needs no additional configuration, not that every choice is ready. A later apply operation must validate the selected choice's own inputs, secrets and policy after explicit confirmation. + */ + requiresInteractiveConfiguration: boolean; } /** - * A side-effect-free request for an MCP install plan. Computing a plan never writes configuration, stores a secret, or reloads MCP servers. + * Server name to check running status for. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpPlanInstallRequest". + * via the `definition` "McpIsServerRunningRequest". */ /** @experimental */ -export interface McpPlanInstallRequest { - contract: CatalogClientContract; - source: McpPlanInstallSource; - scope?: McpPlanScope; +export interface McpIsServerRunningRequest { /** - * The same existing attached session that owns the original catalogue candidate. + * Name of the MCP server to check */ - policySessionId?: string; + serverName: string; } /** - * Plan from a candidate returned by a previous catalog search. + * Whether the named MCP server is running. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpPlanInstallSourceCandidate". + * via the `definition` "McpIsServerRunningResult". */ /** @experimental */ -export interface McpPlanInstallSourceCandidate { - kind: McpPlanInstallSourceCandidateKind; - /** - * Single-use candidate handle. Consumed by this call, so a replay of the same handle is rejected. - */ - candidateHandle: string; +export interface McpIsServerRunningResult { /** - * The runtime- or authority-minted `searchId` returned with the search that produced this candidate. Planning verifies the private correlation and atomically consumes a matching candidate before downstream work, including attempts that subsequently fail or report unavailable. A mismatched search does not consume the candidate. It identifies a search rather than a person and must never be joined with user identity to re-identify anyone. + * True if the server has an active client and transport. */ - searchId: string; + running: boolean; } /** - * Plan from a card supplied directly by the caller, without a preceding search. + * Names of the MCP servers the runtime supplies itself. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpPlanInstallSourceCard". + * via the `definition` "McpListBuiltinServerNamesResult". */ /** @experimental */ -export interface McpPlanInstallSourceCard { - kind: McpPlanInstallSourceCardKind; - card: McpServerCardReference; +/** @internal */ +export interface McpListBuiltinServerNamesResult { + /** + * Every built-in server name. A host disabling the built-ins wholesale suppresses exactly this set. + */ + names: string[]; } /** - * An MCP server card to be retrieved from a URL through the runtime's hardened fetch boundary. + * Server name whose tool list should be returned. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpServerCardUrl". + * via the `definition` "McpListToolsRequest". */ /** @experimental */ -export interface McpServerCardUrl { - kind: McpServerCardUrlKind; - mediaType: McpServerCardMediaType; +export interface McpListToolsRequest { /** - * Card URL. Retrieved only through the runtime's hardened boundary, with scheme, credential, address-range, redirect, timeout, and response-size controls applied. Never logged. + * Name of the connected MCP server whose tools to list. */ - url: string; + serverName: string; } /** - * An MCP server card supplied inline as an inert document. + * Tools exposed by the connected MCP server. Throws when the server is not connected. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpServerCardEmbedded". + * via the `definition` "McpListToolsResult". */ /** @experimental */ -export interface McpServerCardEmbedded { - kind: McpServerCardEmbeddedKind; - mediaType: McpServerCardMediaType; +export interface McpListToolsResult { /** - * The card document verbatim, treated as inert untrusted bytes. The runtime parses and validates it; the host is not expected to interpret it. Never logged. + * Tools exposed by the server. */ - data: string; + tools: McpTools[]; } /** - * Read-only preparation of one owned removal under fresh selected-session authority. + * MCP tool metadata with tool name, optional description, and normalized MCP Apps discovery metadata. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpPlanUninstallRequest". + * via the `definition` "McpTools". */ /** @experimental */ -export interface McpPlanUninstallRequest { - contract: CatalogClientContract; +export interface McpTools { /** - * Exact receipt to inspect, not a server-name guess. + * Tool name. */ - installationId: string; + name: string; /** - * Existing selected session on the original connection. + * Tool description, when provided. */ - policySessionId: string; + description?: string; + ui?: McpToolUi; } /** - * Side-effect-free preparation of one original bound remote MCP choice. + * Normalized MCP Apps discovery metadata from a tool's `_meta.ui` block. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpPrepareInstallRequest". + * via the `definition` "McpToolUi". */ /** @experimental */ -export interface McpPrepareInstallRequest { - contract: CatalogClientContract; +export interface McpToolUi { /** - * Original single-use bound plan, never a client-authored configuration. + * URI of the tool's MCP App resource, typically a `ui://` resource identifier. Use `session.mcp.resources.read` to fetch its HTML and resource metadata. */ - planHandle: string; + resourceUri?: string; /** - * Exact selected alternative from that plan. + * Tool visibility advertised by the server. When absent, MCP Apps defaults apply. */ - choiceId: string; + visibility?: McpToolUiVisibility[]; +} +/** + * Identifies the MCP server whose persisted OAuth credentials were updated. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpOauthAuthenticationStateChangedRequest". + */ +/** @experimental */ +export interface McpOauthAuthenticationStateChangedRequest { /** - * An existing local session attached to this connection, not permission to attach one. + * Name of the MCP server whose OAuth credentials were updated. Omit only when the host cannot identify the server. */ - policySessionId: string; + serverName?: string; /** - * Declared non-secret values. Non-empty only when the caller requires - * `mcp-configured-remote-installation`; omitted values use the card default. + * Whether the target session must mint a session-scoped access token instead of reusing a shared access token persisted by another session. */ - inputs: McpInstallationInput[]; - /** - * One entry per declared secret placeholder of the selected choice. Non-empty - * only when the caller requires `mcp-configured-remote-installation`. - */ - secrets: McpInstallationSecret[]; - source: McpServerCardReference; - secretStorage: McpInstallationSecretStorage; + refreshSessionToken?: boolean; } /** - * An MCP prompt descriptor. Server-provided non-standard fields are exposed under `additionalProperties`. + * Targets only the original prepared/applying owned login on this exact session requester. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpPrompt". + * via the `definition` "McpOauthCancelLoginRequest". */ /** @experimental */ -export interface McpPrompt { +export interface McpOauthCancelLoginRequest { /** - * The programmatic name of the prompt + * The same authoritative installation identity supplied during preparation. */ - name: string; + expectedInstallationId: string; /** - * Human-readable display title + * Runtime-issued login handle known before the effectful login request begins. */ - title?: string; + loginId: string; +} +/** + * Honest terminal cancellation result; persistence or recovery failures remain RPC errors. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpOauthCancelLoginResult". + */ +/** @experimental */ +export interface McpOauthCancelLoginResult { /** - * Description of what this prompt provides + * True after cancellation settles, false when the original login already connected successfully. */ - description?: string; + cancelled: boolean; +} +/** + * Host-delivered callback for a runtime-managed MCP OAuth login. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpOauthCompleteRequest". + */ +/** @experimental */ +export interface McpOauthCompleteRequest { /** - * Arguments accepted by the prompt + * Opaque identifier returned by session.mcp.oauth.login for the pending external callback. */ - arguments?: McpPromptArgument[]; + authorizationId: string; /** - * Icons associated with this prompt + * Full externally visible HTTPS callback URL received by the host, including the authorization response query parameters. Applications behind a reverse proxy must reconstruct the public URL rather than passing an internal proxy URL. */ - icons?: McpPromptIcon[]; + callbackUrl: string; +} +/** + * Pending MCP OAuth request ID and host-provided token or cancellation response. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpOauthHandlePendingRequest". + */ +/** @experimental */ +export interface McpOauthHandlePendingRequest { /** - * Prompt-level metadata + * OAuth request identifier from the mcp.oauth_required event */ - _meta?: { - [k: string]: JsonValue | undefined; - }; + requestId: string; + result: McpOauthPendingRequestResponse; +} +/** + * Indicates whether the pending MCP OAuth response was accepted. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpOauthHandlePendingResult". + */ +/** @experimental */ +export interface McpOauthHandlePendingResult { /** - * Server-provided non-standard descriptor fields + * Whether the response was accepted. False if the request was unknown, timed out, or already resolved. */ - additionalProperties?: { - [k: string]: JsonValue | undefined; - }; + success: boolean; } /** - * An argument accepted by an MCP prompt. + * Remote MCP server name and optional overrides controlling reauthentication, OAuth client display name, callback handling, and static OAuth client selection. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpPromptArgument". + * via the `definition` "McpOauthLoginRequest". */ /** @experimental */ -export interface McpPromptArgument { +export interface McpOauthLoginRequest { /** - * Name of the argument + * Name of the remote MCP server to authenticate */ - name: string; + serverName: string; /** - * Description of the argument + * When true, clears any cached OAuth token for the server and runs a full new authorization. Use when the user explicitly wants to switch accounts or believes their session is stuck. */ - description?: string; + forceReauth?: boolean; /** - * Whether the argument is required; omission is distinct from false + * Optional override for the OAuth client display name shown on the consent screen. Applies to newly registered dynamic clients only — existing registrations keep the name they were created with. When omitted, the runtime applies a neutral fallback; callers driving interactive auth should pass their own surface-specific label so the consent screen matches the product the user sees. */ - required?: boolean; + clientName?: string; /** - * Argument-level metadata + * Optional override for the body text shown on the OAuth loopback callback success page. When omitted, the runtime applies a neutral fallback; callers driving interactive auth should pass surface-specific copy telling the user where to return. */ - _meta?: { - [k: string]: JsonValue | undefined; - }; + callbackSuccessMessage?: string; /** - * Server-provided non-standard argument fields + * Optional OAuth client ID override for this login. When set, the runtime uses this pre-registered static client instead of dynamic client registration. */ - additionalProperties?: { - [k: string]: JsonValue | undefined; - }; -} -/** - * An MCP prompt icon with standard size hints and preserved non-standard fields. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpPromptIcon". - */ -/** @experimental */ -export interface McpPromptIcon { + clientId?: string; /** - * Icon URI + * Optional OAuth client secret override for this login. The runtime treats this as an ephemeral host-owned secret, uses it for this authentication attempt and does not persist it. */ - src: string; + clientSecret?: string; /** - * Icon MIME type, when known + * Optional override indicating whether the static OAuth client is public. When false, the runtime treats it as confidential and uses the per-login clientSecret if provided, otherwise retrieving the client secret from the MCP OAuth secret store. */ - mimeType?: string; + publicClient?: boolean; + grantType?: McpOauthLoginGrantType; /** - * Icon sizes, such as `48x48` or `any` + * Optional externally visible HTTPS redirect URI for a host-managed callback endpoint. When supplied, the runtime still owns discovery, PKCE, token exchange, persistence, and reconnect, but does not bind a loopback listener or terminate HTTPS. The URI must not contain query parameters or a fragment and must be registered for the selected CIMD, DCR, or static OAuth client. */ - sizes?: string[]; + redirectUri?: string; /** - * Theme hint for this icon + * Required for owned login. Consumes the exact prepareLogin handle once. + * Set forceReauth and display options during preparation, not consumption. */ - theme?: string; + loginId?: string; /** - * Server-provided non-standard icon fields + * Exact owned receipt identity. Owned login never uses an implicit helper session. */ - additionalProperties?: { - [k: string]: JsonValue | undefined; - }; + expectedInstallationId?: string; } /** - * An MCP prompt message with opaque JSON content preserved without flattening or content-type filtering. + * OAuth authorization URL the caller should open, or empty when cached tokens already authenticated the server. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpPromptMessage". + * via the `definition` "McpOauthLoginResult". */ /** @experimental */ -export interface McpPromptMessage { - role: McpPromptRole; +export interface McpOauthLoginResult { /** - * The original MCP content block, including nested metadata and unfamiliar content types + * Runtime-issued owned flow identity; never a server name or installation operation ID. */ - content: JsonValue; + loginId?: string; + status?: McpOwnedOauthLoginStatus; /** - * Message-level metadata + * URL the caller should open in a browser to complete OAuth. Omitted when cached tokens were still valid and no browser interaction was needed — the server is already reconnected in that case. For the default loopback flow, the runtime starts its listener before returning. With redirectUri, the host receives the callback and completes it through session.mcp.oauth.complete. The runtime continues the flow in the background and signals completion via session.mcp_server_status_changed. */ - _meta?: { - [k: string]: JsonValue | undefined; - }; + authorizationUrl?: string; /** - * Server-provided non-standard message fields + * Opaque authorization identifier returned only for a host-managed redirect URI. The runtime also sends it as the OAuth state value, so the callback endpoint can read state and pass it with the full callback URL to session.mcp.oauth.complete. */ - additionalProperties?: { - [k: string]: JsonValue | undefined; - }; + authorizationId?: string; } /** - * MCP server, prompt name, and optional string-valued arguments. + * Effect-free preparation bound to the existing local session, requester and installation, with frozen options. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpPromptsGetRequest". + * via the `definition` "McpOauthPrepareLoginRequest". */ /** @experimental */ -export interface McpPromptsGetRequest { +export interface McpOauthPrepareLoginRequest { /** - * Name of the MCP server hosting the prompt + * Name recorded by the authoritative owned installation receipt. */ serverName: string; /** - * The programmatic name of the prompt + * Exact installation identity from owned inventory, never a server-name alias. */ - promptName: string; + expectedInstallationId: string; /** - * String-valued arguments to pass to the prompt + * Request a new authorisation rather than accepting a usable cached grant. */ - arguments?: { - [k: string]: string | undefined; - }; + forceReauth?: boolean; + /** + * Display name used by the incumbent OAuth client-registration flow. + */ + clientName?: string; + /** + * Text shown on the loopback callback page after successful authorisation. + */ + callbackSuccessMessage?: string; } /** - * Prompt messages returned by the MCP server without sending them to the model. + * An inert runtime-issued login handle. Preparation alone performs no activation or OAuth work. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpPromptsGetResult". + * via the `definition` "McpOauthPrepareLoginResult". */ /** @experimental */ -export interface McpPromptsGetResult { +export interface McpOauthPrepareLoginResult { /** - * Description of the prompt + * Retain with the original requester and use for one login or cancellation. */ - description?: string; + loginId: string; /** - * Ordered prompt messages + * Original expiry, not extended by consumption, retries or cancellation. */ - messages: McpPromptMessage[]; + expiresAt: string; +} +/** + * Remote MCP server name for a passive OAuth status probe. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpOauthProbeRequest". + */ +/** @experimental */ +export interface McpOauthProbeRequest { /** - * MCP result metadata + * Exact owned receipt identity; probing never activates a dormant installation. */ - _meta?: { - [k: string]: JsonValue | undefined; - }; + expectedInstallationId?: string; /** - * Server-provided non-standard result fields + * Name of the configured remote MCP server to probe. */ - additionalProperties?: { - [k: string]: JsonValue | undefined; - }; + serverName: string; } /** - * MCP server whose prompts to enumerate. + * Pending MCP OAuth request id to respond to. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpPromptsListRequest". + * via the `definition` "McpOauthRespondRequest". */ /** @experimental */ -export interface McpPromptsListRequest { - /** - * Name of the MCP server whose prompts to enumerate - */ - serverName: string; +export interface McpOauthRespondRequest { /** - * Opaque MCP pagination cursor from a prior `nextCursor` value + * OAuth request identifier from the mcp.oauth_required event */ - cursor?: string; + requestId: string; } /** - * One page of prompts advertised by the named MCP server. + * Indicates whether the pending MCP OAuth response was accepted. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpPromptsListResult". + * via the `definition` "McpOauthRespondResult". */ /** @experimental */ -export interface McpPromptsListResult { +export interface McpOauthRespondResult { /** - * Prompts advertised by the server + * Whether the response was accepted. False if the request was unknown, timed out, or already resolved. */ - prompts: McpPrompt[]; - /** - * Opaque cursor for the next page, if the server has more prompts - */ - nextCursor?: string; - /** - * MCP result metadata - */ - _meta?: { - [k: string]: JsonValue | undefined; - }; - /** - * Server-provided non-standard result fields - */ - additionalProperties?: { - [k: string]: JsonValue | undefined; - }; + success: boolean; } /** - * Registration parameters for an external MCP client. + * A computed MCP install plan. Nothing has been applied: the plan describes what installing would change, and the plan handle is what a later apply operation would consume. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpRegisterExternalClientRequest". + * via the `definition` "McpPlanInstallPlanned". */ /** @experimental */ -/** @internal */ -export interface McpRegisterExternalClientRequest { - /** - * Logical server name for the external client - */ - serverName: string; - /** - * In-process MCP Client instance. Marked internal: cannot be serialized across the JSON-RPC boundary. - * - * @internal - */ - client: OpaqueInProcessValue; - /** - * In-process MCP Transport instance. Marked internal: cannot be serialized across the JSON-RPC boundary. - * - * @internal - */ - transport: OpaqueInProcessValue; +export interface McpPlanInstallPlanned { /** - * In-process server config (MCPServerConfig) paired with the in-process client/transport. Marked internal alongside its companions. - * - * @internal + * Discriminator: a plan was computed and nothing was changed */ - config: OpaqueInProcessValue; + kind: "planned"; + plan: McpInstallPlan; + negotiated: CatalogNegotiatedContract; } /** - * Registry search to abandon. + * A side-effect-free request for an MCP install plan. Computing a plan never writes configuration, stores a secret, or reloads MCP servers. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpRegistryCancelRequest". + * via the `definition` "McpPlanInstallRequest". */ /** @experimental */ -/** @internal */ -export interface McpRegistryCancelRequest { +export interface McpPlanInstallRequest { + contract: CatalogClientContract; + source: McpPlanInstallSource; + scope?: McpPlanScope; /** - * Request ID from `mcp.registry.allocateRequestId` that the search uses. + * The same existing attached session that owns the original catalogue candidate. */ - requestId: number; + policySessionId?: string; } /** - * Whether the cancel reached a live search. + * Plan from a candidate returned by a previous catalog search. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpRegistryCancelResult". + * via the `definition` "McpPlanInstallSourceCandidate". */ /** @experimental */ -/** @internal */ -export interface McpRegistryCancelResult { +export interface McpPlanInstallSourceCandidate { + kind: McpPlanInstallSourceCandidateKind; /** - * True when the cancel stopped a running search. False for unknown or reclaimed IDs, completed or canceled searches, and unused reservations. The cancel releases an unused reservation. + * Single-use candidate handle. Consumed by this call, so a replay of the same handle is rejected. */ - canceled: boolean; -} -/** - * Request id naming a cancellable registry search. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpRegistryRequestIdResult". - */ -/** @experimental */ -/** @internal */ -export interface McpRegistryRequestIdResult { + candidateHandle: string; /** - * Request ID for `mcp.registry.search` and `mcp.registry.cancel`. It serves one search. Allocation can reclaim unused IDs at the 1,024-ID reservation limit. + * The runtime- or authority-minted `searchId` returned with the search that produced this candidate. Planning verifies the private correlation and atomically consumes a matching candidate before downstream work, including attempts that subsequently fail or report unavailable. A mismatched search does not consume the candidate. It identifies a search rather than a person and must never be joined with user identity to re-identify anyone. */ - requestId: number; + searchId: string; } /** - * Registry search terms, the credential to search under, and the request id that makes the search cancellable. + * Plan from a card supplied directly by the caller, without a preceding search. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpRegistrySearchRequest". + * via the `definition` "McpPlanInstallSourceCard". */ /** @experimental */ -/** @internal */ -export interface McpRegistrySearchRequest { - /** - * Request ID from `mcp.registry.allocateRequestId`. The search refuses unknown, reclaimed, or canceled IDs and IDs that another search or request already uses. - */ - requestId: number; - /** - * The credential the search runs under, carried opaquely. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. - */ - authInfo: JsonValue; - /** - * Free-text query. Omitted or empty asks the registry for its top servers rather than searching. A value that is not a string is refused. - */ - query?: string; - /** - * Repository used for the policy lookup, as `owner/name`. The policy selects the registry URL and whether the user token goes to the registry. The registry receives this repository only when the policy entry lists it as required context. A value that is not a string is refused. - */ - repository?: string; - /** - * Maximum number of servers to return. - */ - limit: number; +export interface McpPlanInstallSourceCard { + kind: McpPlanInstallSourceCardKind; + card: McpServerCardReference; } /** - * Servers selected from the registry response. + * An MCP server card to be retrieved from a URL through the runtime's hardened fetch boundary. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpRegistrySearchResult". + * via the `definition` "McpServerCardUrl". */ /** @experimental */ -/** @internal */ -export interface McpRegistrySearchResult { +export interface McpServerCardUrl { + kind: McpServerCardUrlKind; + mediaType: McpServerCardMediaType; /** - * The server objects, carried opaquely. The runtime follows pages, keeps the newest entry per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub stars. Each server object remains unchanged because the registry owns that shape. + * Card URL. Retrieved only through the runtime's hardened boundary, with scheme, credential, address-range, redirect, timeout, and response-size controls applied. Never logged. */ - servers: JsonValue; + url: string; } /** - * In-process MCP reload configuration. + * An MCP server card supplied inline as an inert document. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpReloadConfig". + * via the `definition` "McpServerCardEmbedded". */ /** @experimental */ -/** @internal */ -export interface McpReloadConfig { - mcpServers: { - [k: string]: McpServerConfig | undefined; - }; - disabledServers?: string[]; - enabledServers?: string[]; +export interface McpServerCardEmbedded { + kind: McpServerCardEmbeddedKind; + mediaType: McpServerCardMediaType; /** - * Server names the CLI enabled for this session via `--enable-mcp-server`. + * The card document verbatim, treated as inert untrusted bytes. The runtime parses and validates it; the host is not expected to interpret it. Never logged. */ - cliEnabledServers?: string[]; - mcp3pEnabled?: boolean; - includeWorkspaceSources?: boolean; - configFilter?: OpaqueInProcessValue; - githubMcpToolOptions?: OpaqueInProcessValue; - githubMcpUserOverride?: boolean; - secretStore?: OpaqueInProcessValue; - activeGitHubToken?: string; - useCachedToolSnapshots?: boolean; - forceRestart?: boolean; + data: string; } /** - * Opaque MCP reload configuration. + * Read-only preparation of one owned removal under fresh selected-session authority. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpReloadWithConfigRequest". + * via the `definition` "McpPlanUninstallRequest". */ /** @experimental */ -/** @internal */ -export interface McpReloadWithConfigRequest { - config: unknown; +export interface McpPlanUninstallRequest { + contract: CatalogClientContract; + /** + * Exact receipt to inspect, not a server-name guess. + */ + installationId: string; + /** + * Existing selected session on the original connection. + */ + policySessionId: string; } /** - * Indicates whether the auto-managed `github` MCP server was removed (false when nothing to remove). + * Side-effect-free preparation of one original bound remote MCP choice. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpRemoveGitHubResult". + * via the `definition` "McpPrepareInstallRequest". */ /** @experimental */ -export interface McpRemoveGitHubResult { +export interface McpPrepareInstallRequest { + contract: CatalogClientContract; /** - * True when the auto-managed `github` MCP server was removed; false when no removal happened (e.g. user has explicitly configured a `github` server, or the server was not registered). + * Original single-use bound plan, never a client-authored configuration. */ - removed: boolean; + planHandle: string; + /** + * Exact selected alternative from that plan. + */ + choiceId: string; + /** + * An existing local session attached to this connection, not permission to attach one. + */ + policySessionId: string; + /** + * Declared non-secret values. Non-empty only when the caller requires + * `mcp-configured-remote-installation`; omitted values use the card default. + */ + inputs: McpInstallationInput[]; + /** + * One entry per declared secret placeholder of the selected choice. Non-empty + * only when the caller requires `mcp-configured-remote-installation`. + */ + secrets: McpInstallationSecret[]; + source: McpServerCardReference; + secretStorage: McpInstallationSecretStorage; } /** - * An MCP resource descriptor (spec `Resource`): URI, name, and optional title, description, MIME type, size, icons, annotations, and metadata. Server-provided fields outside the standard descriptor shape are exposed under `additionalProperties`. + * An MCP prompt descriptor. Server-provided non-standard fields are exposed under `additionalProperties`. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpResource". + * via the `definition` "McpPrompt". */ /** @experimental */ -export interface McpResource { - /** - * The resource URI (e.g. ui://... or file:///...) - */ - uri: string; +export interface McpPrompt { /** - * The programmatic name of the resource + * The programmatic name of the prompt */ name: string; /** - * Optional human-readable display title + * Human-readable display title */ title?: string; /** - * Optional description of what this resource represents + * Description of what this prompt provides */ description?: string; /** - * MIME type of the resource, if known - */ - mimeType?: string; - /** - * Resource size in bytes, when known + * Arguments accepted by the prompt */ - size?: number; + arguments?: McpPromptArgument[]; /** - * Icons associated with this resource + * Icons associated with this prompt */ - icons?: McpResourceIcon[]; - annotations?: McpResourceAnnotations; + icons?: McpPromptIcon[]; /** - * Resource-level metadata + * Prompt-level metadata */ _meta?: { [k: string]: JsonValue | undefined; }; /** - * Server-provided non-standard descriptor fields preserved from the MCP response + * Server-provided non-standard descriptor fields */ additionalProperties?: { [k: string]: JsonValue | undefined; }; } /** - * A resource icon descriptor plus preserved non-standard icon fields. + * An argument accepted by an MCP prompt. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpResourceIcon". + * via the `definition` "McpPromptArgument". */ /** @experimental */ -export interface McpResourceIcon { +export interface McpPromptArgument { /** - * Icon URI + * Name of the argument */ - src: string; + name: string; /** - * Icon MIME type, when known + * Description of the argument */ - mimeType?: string; + description?: string; /** - * Icon sizes hint + * Whether the argument is required; omission is distinct from false */ - sizes?: string; + required?: boolean; /** - * Theme hint for this icon + * Argument-level metadata */ - theme?: string; + _meta?: { + [k: string]: JsonValue | undefined; + }; /** - * Server-provided non-standard icon fields preserved from the MCP response + * Server-provided non-standard argument fields */ additionalProperties?: { [k: string]: JsonValue | undefined; }; } /** - * Standard MCP resource annotations plus preserved non-standard annotation fields. + * An MCP prompt icon with standard size hints and preserved non-standard fields. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpResourceAnnotations". + * via the `definition` "McpPromptIcon". */ /** @experimental */ -export interface McpResourceAnnotations { +export interface McpPromptIcon { /** - * Intended audience roles for this resource + * Icon URI */ - audience?: string[]; + src: string; /** - * Priority hint for model/client use + * Icon MIME type, when known */ - priority?: number; + mimeType?: string; /** - * Last-modified timestamp hint + * Icon sizes, such as `48x48` or `any` */ - lastModified?: string; + sizes?: string[]; /** - * Server-provided non-standard annotation fields preserved from the MCP response + * Theme hint for this icon + */ + theme?: string; + /** + * Server-provided non-standard icon fields */ additionalProperties?: { [k: string]: JsonValue | undefined; }; } /** - * MCP resource content with URI, optional MIME type, text or base64 blob, and resource metadata. + * An MCP prompt message with opaque JSON content preserved without flattening or content-type filtering. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpResourceContent". + * via the `definition` "McpPromptMessage". */ /** @experimental */ -export interface McpResourceContent { - /** - * The resource URI - */ - uri: string; - /** - * MIME type of the content - */ - mimeType?: string; +export interface McpPromptMessage { + role: McpPromptRole; /** - * Text content (e.g. HTML) + * The original MCP content block, including nested metadata and unfamiliar content types */ - text?: string; + content: JsonValue; /** - * Base64-encoded binary content + * Message-level metadata */ - blob?: string; + _meta?: { + [k: string]: JsonValue | undefined; + }; /** - * Resource-level metadata (CSP, permissions, etc.) + * Server-provided non-standard message fields */ - _meta?: { + additionalProperties?: { [k: string]: JsonValue | undefined; }; } /** - * MCP server whose resources to enumerate. + * MCP server, prompt name, and optional string-valued arguments. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpResourcesListRequest". + * via the `definition` "McpPromptsGetRequest". */ /** @experimental */ -export interface McpResourcesListRequest { +export interface McpPromptsGetRequest { /** - * Name of the MCP server whose resources to enumerate + * Name of the MCP server hosting the prompt */ serverName: string; /** - * Opaque MCP pagination cursor from a prior `nextCursor` value + * The programmatic name of the prompt */ - cursor?: string; + promptName: string; + /** + * String-valued arguments to pass to the prompt + */ + arguments?: { + [k: string]: string | undefined; + }; } /** - * One page of resources advertised by the named MCP server. + * Prompt messages returned by the MCP server without sending them to the model. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpResourcesListResult". + * via the `definition` "McpPromptsGetResult". */ /** @experimental */ -export interface McpResourcesListResult { +export interface McpPromptsGetResult { /** - * Resources advertised by the server (proxied MCP `resources/list`) + * Description of the prompt */ - resources: McpResource[]; + description?: string; /** - * Opaque cursor for the next page, if the server has more resources + * Ordered prompt messages */ - nextCursor?: string; -} -/** - * MCP server whose resource templates to enumerate. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpResourcesListTemplatesRequest". - */ -/** @experimental */ -export interface McpResourcesListTemplatesRequest { + messages: McpPromptMessage[]; /** - * Name of the MCP server whose resource templates to enumerate + * MCP result metadata */ - serverName: string; + _meta?: { + [k: string]: JsonValue | undefined; + }; /** - * Opaque MCP pagination cursor from a prior `nextCursor` value + * Server-provided non-standard result fields */ - cursor?: string; + additionalProperties?: { + [k: string]: JsonValue | undefined; + }; } /** - * One page of resource templates advertised by the named MCP server. + * MCP server whose prompts to enumerate. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpResourcesListTemplatesResult". + * via the `definition` "McpPromptsListRequest". */ /** @experimental */ -export interface McpResourcesListTemplatesResult { +export interface McpPromptsListRequest { /** - * Resource templates advertised by the server (proxied MCP `resources/templates/list`) + * Name of the MCP server whose prompts to enumerate */ - resourceTemplates: McpResourceTemplate[]; + serverName: string; /** - * Opaque cursor for the next page, if the server has more resource templates + * Opaque MCP pagination cursor from a prior `nextCursor` value */ - nextCursor?: string; + cursor?: string; } /** - * An MCP resource template descriptor (spec `ResourceTemplate`): an RFC 6570 URI template, name, and optional title, description, MIME type, icons, annotations, and metadata. Server-provided fields outside the standard descriptor shape are exposed under `additionalProperties`. + * One page of prompts advertised by the named MCP server. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpResourceTemplate". + * via the `definition` "McpPromptsListResult". */ /** @experimental */ -export interface McpResourceTemplate { - /** - * An RFC 6570 URI template for constructing resource URIs - */ - uriTemplate: string; - /** - * The programmatic name of the resource template - */ - name: string; - /** - * Optional human-readable display title - */ - title?: string; - /** - * Optional description of what this template is for - */ - description?: string; +export interface McpPromptsListResult { /** - * MIME type for resources matching this template, if uniform + * Prompts advertised by the server */ - mimeType?: string; + prompts: McpPrompt[]; /** - * Icons associated with resources matching this template + * Opaque cursor for the next page, if the server has more prompts */ - icons?: McpResourceIcon[]; - annotations?: McpResourceAnnotations; + nextCursor?: string; /** - * Resource-template-level metadata + * MCP result metadata */ _meta?: { [k: string]: JsonValue | undefined; }; /** - * Server-provided non-standard descriptor fields preserved from the MCP response + * Server-provided non-standard result fields */ additionalProperties?: { [k: string]: JsonValue | undefined; }; } /** - * MCP server and resource URI to fetch. + * Registration parameters for an external MCP client. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpResourcesReadRequest". + * via the `definition` "McpRegisterExternalClientRequest". */ /** @experimental */ -export interface McpResourcesReadRequest { +/** @internal */ +export interface McpRegisterExternalClientRequest { /** - * Name of the MCP server hosting the resource + * Logical server name for the external client */ serverName: string; /** - * Resource URI + * In-process MCP Client instance. Marked internal: cannot be serialized across the JSON-RPC boundary. + * + * @internal */ - uri: string; + client: OpaqueInProcessValue; + /** + * In-process MCP Transport instance. Marked internal: cannot be serialized across the JSON-RPC boundary. + * + * @internal + */ + transport: OpaqueInProcessValue; + /** + * In-process server config (MCPServerConfig) paired with the in-process client/transport. Marked internal alongside its companions. + * + * @internal + */ + config: OpaqueInProcessValue; } /** - * Resource contents returned by the MCP server. + * Registry search to abandon. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpResourcesReadResult". + * via the `definition` "McpRegistryCancelRequest". */ /** @experimental */ -export interface McpResourcesReadResult { +/** @internal */ +export interface McpRegistryCancelRequest { /** - * Resource contents returned by the server + * Request ID from `mcp.registry.allocateRequestId` that the search uses. */ - contents: McpResourceContent[]; + requestId: number; } /** - * Server name and optional replacement configuration for an individual MCP server restart. Omit `config` for a config-free restart-by-name of an already-configured server. + * Whether the cancel reached a live search. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpRestartServerRequest". + * via the `definition` "McpRegistryCancelResult". */ /** @experimental */ -export interface McpRestartServerRequest { - /** - * Name of the MCP server to restart - */ - serverName: string; - config?: McpSerializableServerConfig; +/** @internal */ +export interface McpRegistryCancelResult { /** - * Exact receipt identity for an explicit owned restart; configuration overrides are refused. + * True when the cancel stopped a running search. False for unknown or reclaimed IDs, completed or canceled searches, and unused reservations. The cancel releases an unused reservation. */ - expectedInstallationId?: string; + canceled: boolean; } /** - * Outcome of an MCP sampling execution: success result, failure error, or cancellation. + * Request id naming a cancellable registry search. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpSamplingExecutionResult". + * via the `definition` "McpRegistryRequestIdResult". */ /** @experimental */ -export interface McpSamplingExecutionResult { - action: McpSamplingExecutionAction; - result?: McpExecuteSamplingResult; +/** @internal */ +export interface McpRegistryRequestIdResult { /** - * Error description, present when action='failure'. + * Request ID for `mcp.registry.search` and `mcp.registry.cancel`. It serves one search. Allocation can reclaim unused IDs at the 1,024-ID reservation limit. */ - error?: string; + requestId: number; } /** - * MCP server status entry, including config source/plugin source and any connection error. + * Registry search terms, the credential to search under, and the request id that makes the search cancellable. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpServer". + * via the `definition` "McpRegistrySearchRequest". */ /** @experimental */ -export interface McpServer { +/** @internal */ +export interface McpRegistrySearchRequest { /** - * Server name (config key) + * Request ID from `mcp.registry.allocateRequestId`. The search refuses unknown, reclaimed, or canceled IDs and IDs that another search or request already uses. */ - name: string; - status: McpServerStatus; - source?: McpServerSource; + requestId: number; /** - * Configured URL for an HTTP/SSE server, regardless of configuration source. Omitted for local and in-memory servers. + * The credential the search runs under, carried opaquely. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. */ - url?: string; + authInfo: JsonValue; /** - * Plugin name that provided this server, when source is plugin. + * Free-text query. Omitted or empty asks the registry for its top servers rather than searching. A value that is not a string is refused. */ - sourcePlugin?: string; + query?: string; /** - * Plugin version that provided this server, when source is plugin. + * Repository used for the policy lookup, as `owner/name`. The policy selects the registry URL and whether the user token goes to the registry. The registry receives this repository only when the policy entry lists it as required context. A value that is not a string is refused. */ - sourcePluginVersion?: string; + repository?: string; /** - * Human-readable display name supplied by a managed server catalog. + * Maximum number of servers to return. */ - displayName?: string; - /** - * Error message if the server failed to connect - */ - error?: string; - serverMetadata?: McpServerMetadata; - owned?: McpServerOwnership; + limit: number; } /** - * Owned installation that a listed MCP server's live configuration came from. + * Servers selected from the registry response. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpServerOwnership". + * via the `definition` "McpRegistrySearchResult". */ /** @experimental */ -export interface McpServerOwnership { +/** @internal */ +export interface McpRegistrySearchResult { /** - * Stable installation identifier from the owned installation receipt. + * The server objects, carried opaquely. The runtime follows pages, keeps the newest entry per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub stars. Each server object remains unchanged because the registry owns that shape. */ - installationId: string; + servers: JsonValue; } /** - * In-process MCP server configuration used by embedded SDK clients. + * In-process MCP reload configuration. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpServerConfigMemory". + * via the `definition` "McpReloadConfig". */ /** @experimental */ /** @internal */ -export interface McpServerConfigMemory { - type: McpServerConfigMemoryType; +export interface McpReloadConfig { + mcpServers: { + [k: string]: McpServerConfig | undefined; + }; + disabledServers?: string[]; + enabledServers?: string[]; /** - * In-process MCP server instance. This value cannot cross a JSON-RPC boundary. - * - * @internal + * Server names the CLI enabled for this session via `--enable-mcp-server`. */ - serverInstance: OpaqueInProcessValue; + cliEnabledServers?: string[]; + mcp3pEnabled?: boolean; + includeWorkspaceSources?: boolean; + configFilter?: OpaqueInProcessValue; + githubMcpToolOptions?: OpaqueInProcessValue; + githubMcpUserOverride?: boolean; + secretStore?: OpaqueInProcessValue; + activeGitHubToken?: string; + useCachedToolSnapshots?: boolean; + forceRestart?: boolean; +} +/** + * Opaque MCP reload configuration. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpReloadWithConfigRequest". + */ +/** @experimental */ +/** @internal */ +export interface McpReloadWithConfigRequest { + config: unknown; +} +/** + * Indicates whether the auto-managed `github` MCP server was removed (false when nothing to remove). + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpRemoveGitHubResult". + */ +/** @experimental */ +export interface McpRemoveGitHubResult { /** - * Tools to include. Defaults to all tools if not specified. + * True when the auto-managed `github` MCP server was removed; false when no removal happened (e.g. user has explicitly configured a `github` server, or the server was not registered). */ - tools?: string[]; + removed: boolean; +} +/** + * An MCP resource descriptor (spec `Resource`): URI, name, and optional title, description, MIME type, size, icons, annotations, and metadata. Server-provided fields outside the standard descriptor shape are exposed under `additionalProperties`. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpResource". + */ +/** @experimental */ +export interface McpResource { /** - * Optional human-readable server name. + * The resource URI (e.g. ui://... or file:///...) */ - displayName?: string; + uri: string; /** - * Whether this server is a built-in fallback. + * The programmatic name of the resource */ - isDefaultServer?: boolean; - filterMapping?: FilterMapping; - safeForTelemetry?: McpSafeForTelemetry; + name: string; /** - * Timeout in milliseconds for tool discovery and tool calls. + * Optional human-readable display title */ - timeout?: number; + title?: string; /** - * Milliseconds this server may spend connecting before the CLI warns that it is taking longer than expected. Presentation only: it does not change how long the connection is allowed to take. + * Optional description of what this resource represents */ - slowConnectionThresholdMs?: number; - oidc?: McpServerAuthConfig; - deferTools?: McpServerConfigDeferTools; + description?: string; /** - * Whether persisted tool snapshots are disabled. + * MIME type of the resource, if known */ - disableToolCache?: boolean; + mimeType?: string; /** - * Whether secret masking is disabled for calls to this server. + * Resource size in bytes, when known */ - disableSecretMasking?: boolean; + size?: number; /** - * Tool names excluded after the include filter is applied. + * Icons associated with this resource */ - excludeTools?: string[]; + icons?: McpResourceIcon[]; + annotations?: McpResourceAnnotations; /** - * Event types this server receives as Copilot notifications. + * Resource-level metadata */ - events?: string[]; + _meta?: { + [k: string]: JsonValue | undefined; + }; /** - * Copilot notification types this server may send to the host. + * Server-provided non-standard descriptor fields preserved from the MCP response */ - notifications?: string[]; - source?: McpServerSource; + additionalProperties?: { + [k: string]: JsonValue | undefined; + }; +} +/** + * A resource icon descriptor plus preserved non-standard icon fields. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpResourceIcon". + */ +/** @experimental */ +export interface McpResourceIcon { /** - * Plugin that provided this server. + * Icon URI */ - sourcePlugin?: string; + src: string; /** - * Version of the plugin that provided this server. + * Icon MIME type, when known */ - sourcePluginVersion?: string; + mimeType?: string; /** - * Whether the providing plugin uses the Open Plugin Spec. + * Icon sizes hint */ - sourcePluginSpec?: boolean; + sizes?: string; /** - * Source file path recorded while loading the config. + * Theme hint for this icon */ - sourcePath?: string; + theme?: string; /** - * Configuration warnings recorded while loading the server. + * Server-provided non-standard icon fields preserved from the MCP response */ - configWarnings?: string[]; + additionalProperties?: { + [k: string]: JsonValue | undefined; + }; } /** - * MCP servers configured for the session, with their connection status and host-level state. + * Standard MCP resource annotations plus preserved non-standard annotation fields. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpServerList". + * via the `definition` "McpResourceAnnotations". */ /** @experimental */ -export interface McpServerList { +export interface McpResourceAnnotations { /** - * Configured MCP servers + * Intended audience roles for this resource */ - servers: McpServer[]; - host?: McpHostState; -} -/** - * Mode controlling how MCP server env values are resolved (`direct` or `indirect`). - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpSetEnvValueModeParams". - */ -/** @experimental */ -export interface McpSetEnvValueModeParams { - mode: McpSetEnvValueModeDetails; -} -/** - * Env-value mode recorded on the session after the update. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpSetEnvValueModeResult". - */ -/** @experimental */ -export interface McpSetEnvValueModeResult { - mode: McpSetEnvValueModeDetails; -} -/** - * The session tool filters that decide whether the session still has a shell to run `gh` with. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpShouldExcludeGitHubToolsRequest". - */ -/** @experimental */ -/** @internal */ -export interface McpShouldExcludeGitHubToolsRequest { + audience?: string[]; /** - * The session's tool allowlist, when it set one. Omitted means the session constrains nothing this way. + * Priority hint for model/client use */ - availableTools?: string[]; + priority?: number; /** - * The session's tool denylist, when it set one. Omitted means the session constrains nothing this way. + * Last-modified timestamp hint */ - excludedTools?: string[]; + lastModified?: string; /** - * How the allowlist and denylist combine when both are set. Omitted means the default every session gets, so a caller that never chose a precedence is answered as its sessions behave. + * Server-provided non-standard annotation fields preserved from the MCP response */ - toolFilterPrecedence?: OptionsUpdateToolFilterPrecedence | null; + additionalProperties?: { + [k: string]: JsonValue | undefined; + }; } /** - * Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by the request. + * MCP resource content with URI, optional MIME type, text or base64 blob, and resource metadata. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpShouldExcludeGitHubToolsResult". + * via the `definition` "McpResourceContent". */ /** @experimental */ -/** @internal */ -export interface McpShouldExcludeGitHubToolsResult { +export interface McpResourceContent { /** - * True only when both halves hold: the session's filters still reach the platform shell tool, and the host actually has the `gh` those tools would be replaced by. Feed it straight back as the `excludeGhReplaceableTools` build option. + * The resource URI */ - excludeGhReplaceableTools: boolean; + uri: string; + /** + * MIME type of the content + */ + mimeType?: string; + /** + * Text content (e.g. HTML) + */ + text?: string; + /** + * Base64-encoded binary content + */ + blob?: string; + /** + * Resource-level metadata (CSP, permissions, etc.) + */ + _meta?: { + [k: string]: JsonValue | undefined; + }; } /** - * Server name and optional configuration for an individual MCP server start. Omit `config` for a config-free start-by-name of an already-configured server. + * MCP server whose resources to enumerate. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpStartServerRequest". + * via the `definition` "McpResourcesListRequest". */ /** @experimental */ -export interface McpStartServerRequest { +export interface McpResourcesListRequest { /** - * Name of the MCP server to start + * Name of the MCP server whose resources to enumerate */ serverName: string; - config?: McpSerializableServerConfig; /** - * Exact receipt identity for explicit owned activation in this session. + * Opaque MCP pagination cursor from a prior `nextCursor` value */ - expectedInstallationId?: string; + cursor?: string; } /** - * MCP server startup filtering result. + * One page of resources advertised by the named MCP server. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpStartServersResult". + * via the `definition` "McpResourcesListResult". */ /** @experimental */ -export interface McpStartServersResult { - /** - * Servers filtered out before startup - */ - filteredServers: McpFilteredServer[]; +export interface McpResourcesListResult { /** - * Non-default servers allowed by policy + * Resources advertised by the server (proxied MCP `resources/list`) */ - allowedServers?: McpAllowedServer[]; + resources: McpResource[]; /** - * Servers whose connection attempt failed. + * Opaque cursor for the next page, if the server has more resources */ - failedServers?: McpFailedServer[]; + nextCursor?: string; } /** - * Server name for an individual MCP server stop. + * MCP server whose resource templates to enumerate. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpStopServerRequest". + * via the `definition` "McpResourcesListTemplatesRequest". */ /** @experimental */ -export interface McpStopServerRequest { - /** - * Exact owned receipt identity. Stop also forgets this session's durable activation. - */ - expectedInstallationId?: string; +export interface McpResourcesListTemplatesRequest { /** - * Name of the MCP server to stop + * Name of the MCP server whose resource templates to enumerate */ serverName: string; -} -/** - * Metadata controlling an MCP task's lifetime. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpTaskMetadata". - */ -/** @experimental */ -export interface McpTaskMetadata { /** - * Task time-to-live. + * Opaque MCP pagination cursor from a prior `nextCursor` value */ - ttl?: number; + cursor?: string; } /** - * Server name identifying the external client to remove. + * One page of resource templates advertised by the named MCP server. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpUnregisterExternalClientRequest". + * via the `definition` "McpResourcesListTemplatesResult". */ /** @experimental */ -/** @internal */ -export interface McpUnregisterExternalClientRequest { +export interface McpResourcesListTemplatesResult { /** - * Server name of the external client to unregister + * Resource templates advertised by the server (proxied MCP `resources/templates/list`) */ - serverName: string; -} -/** - * Memory configuration for this session. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MemoryConfiguration". - */ -/** @experimental */ -export interface MemoryConfiguration { + resourceTemplates: McpResourceTemplate[]; /** - * Whether memory is enabled for the session. + * Opaque cursor for the next page, if the server has more resource templates */ - enabled: boolean; + nextCursor?: string; } /** - * Per-source attribution breakdown for the session's current context window, or null if uninitialized. + * An MCP resource template descriptor (spec `ResourceTemplate`): an RFC 6570 URI template, name, and optional title, description, MIME type, icons, annotations, and metadata. Server-provided fields outside the standard descriptor shape are exposed under `additionalProperties`. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataContextAttributionResult". + * via the `definition` "McpResourceTemplate". */ /** @experimental */ -export interface MetadataContextAttributionResult { +export interface McpResourceTemplate { /** - * Per-source context-window attribution, or null if the session has not yet been initialized (no system prompt or tool metadata cached). + * An RFC 6570 URI template for constructing resource URIs */ - contextAttribution?: SessionContextAttribution | null; -} -/** - * Parameters for the heaviest-messages query. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataContextHeaviestMessagesRequest". - */ -/** @experimental */ -export interface MetadataContextHeaviestMessagesRequest { + uriTemplate: string; /** - * Maximum number of messages to return, most-expensive first. Omit for the server default. + * The programmatic name of the resource template */ - limit?: number; -} -/** - * The heaviest individual messages in the session's context window, most-expensive first. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataContextHeaviestMessagesResult". - */ -/** @experimental */ -export interface MetadataContextHeaviestMessagesResult { + name: string; /** - * Total token count of the current context window, so callers can compute each message's share without a second call. + * Optional human-readable display title */ - totalTokens: number; + title?: string; /** - * Heaviest messages, most-expensive first. + * Optional description of what this template is for */ - messages: ContextHeaviestMessage[]; -} -/** - * Model identifier and token limits used to compute the context-info breakdown. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataContextInfoRequest". - */ -/** @experimental */ -export interface MetadataContextInfoRequest { + description?: string; /** - * Advertised prompt allowance. Pass 0 to resolve the selected model and context tier from the session. + * MIME type for resources matching this template, if uniform */ - promptTokenLimit: number; + mimeType?: string; /** - * Requested output allowance to reserve against the combined context ceiling. Pass 0 to resolve the session's request cap, falling back to the model's advertised output limit. + * Icons associated with resources matching this template */ - outputTokenLimit: number; + icons?: McpResourceIcon[]; + annotations?: McpResourceAnnotations; /** - * Model identifier used for tokenization. Omit to use the session default. Used both for token counting and to compute display values. + * Resource-template-level metadata */ - selectedModel?: string; + _meta?: { + [k: string]: JsonValue | undefined; + }; /** - * Provider owning selectedModel. Omit to use the current provider for the current model, or deterministic legacy lookup for a different model. + * Server-provided non-standard descriptor fields preserved from the MCP response */ - providerId?: string; + additionalProperties?: { + [k: string]: JsonValue | undefined; + }; } /** - * Token breakdown for the session's current context window, or null if uninitialized. + * MCP server and resource URI to fetch. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataContextInfoResult". + * via the `definition` "McpResourcesReadRequest". */ /** @experimental */ -export interface MetadataContextInfoResult { +export interface McpResourcesReadRequest { /** - * Token breakdown for the current context window, or null if the session has not yet been initialized (no system prompt or tool metadata cached). + * Name of the MCP server hosting the resource */ - contextInfo?: SessionContextInfo | null; -} -/** - * Indicates whether the local session is currently processing a turn or background continuation. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataIsProcessingResult". - */ -/** @experimental */ -export interface MetadataIsProcessingResult { + serverName: string; /** - * Whether the session is currently processing user/agent messages. False for non-local sessions (which don't run a local agentic loop). Reflects an in-flight turn or background continuation. + * Resource URI */ - processing: boolean; + uri: string; } /** - * Model identifier to use when re-tokenizing the session's existing messages. + * Resource contents returned by the MCP server. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataRecomputeContextTokensRequest". + * via the `definition` "McpResourcesReadResult". */ /** @experimental */ -export interface MetadataRecomputeContextTokensRequest { +export interface McpResourcesReadResult { /** - * Model identifier used for tokenization. The runtime token-counts both chat-context and system-context messages against this model. + * Resource contents returned by the server */ - modelId: string; + contents: McpResourceContent[]; } /** - * Re-tokenize the session's existing messages against `modelId` and return the token totals. Useful for hosts that want an initial estimate of context usage on session resume, before the next agent turn fires `session.context_info_changed` events. Returns zeros for an empty session. + * Server name and optional replacement configuration for an individual MCP server restart. Omit `config` for a config-free restart-by-name of an already-configured server. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataRecomputeContextTokensResult". + * via the `definition` "McpRestartServerRequest". */ /** @experimental */ -export interface MetadataRecomputeContextTokensResult { - /** - * Sum of tokens across chat-context and system-context messages currently held by the session. - */ - totalTokens: number; +export interface McpRestartServerRequest { /** - * Tokens contributed by user/assistant/tool messages (excludes system/developer prompts). + * Name of the MCP server to restart */ - messagesTokenCount: number; + serverName: string; + config?: McpSerializableServerConfig; /** - * Tokens contributed by system/developer prompt snapshots. + * Exact receipt identity for an explicit owned restart; configuration overrides are refused. */ - systemTokenCount: number; + expectedInstallationId?: string; } /** - * Updated working-directory/git context to record on the session. + * Outcome of an MCP sampling execution: success result, failure error, or cancellation. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataRecordContextChangeRequest". + * via the `definition` "McpSamplingExecutionResult". */ /** @experimental */ -export interface MetadataRecordContextChangeRequest { - context: SessionWorkingDirectoryContext; +export interface McpSamplingExecutionResult { + action: McpSamplingExecutionAction; + result?: McpExecuteSamplingResult; + /** + * Error description, present when action='failure'. + */ + error?: string; } /** - * Updated working directory and git context. Emitted as the new payload of `session.context_changed`. + * MCP server status entry, including config source/plugin source and any connection error. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionWorkingDirectoryContext". + * via the `definition` "McpServer". */ /** @experimental */ -export interface SessionWorkingDirectoryContext { - /** - * Current working directory path - */ - cwd: string; +export interface McpServer { /** - * Root directory of the git repository, resolved via git rev-parse + * Server name (config key) */ - gitRoot?: string; + name: string; + status: McpServerStatus; + source?: McpServerSource; /** - * Repository identifier derived from the git remote URL ("owner/name" for GitHub, "org/project/repo" for Azure DevOps) + * Configured URL for an HTTP/SSE server, regardless of configuration source. Omitted for local and in-memory servers. */ - repository?: string; - hostType?: SessionWorkingDirectoryContextHostType; + url?: string; /** - * Raw host string from the git remote URL (e.g. "github.com", "dev.azure.com") + * Plugin name that provided this server, when source is plugin. */ - repositoryHost?: string; + sourcePlugin?: string; /** - * Current git branch name + * Plugin version that provided this server, when source is plugin. */ - branch?: string; + sourcePluginVersion?: string; /** - * Head commit of the current git branch + * Human-readable display name supplied by a managed server catalog. */ - headCommit?: string; + displayName?: string; /** - * Merge-base commit SHA (fork point from the remote default branch) + * Error message if the server failed to connect */ - baseCommit?: string; + error?: string; + serverMetadata?: McpServerMetadata; + owned?: McpServerOwnership; } /** - * Notify the session that its working directory context has changed. Emits a `session.context_changed` event so consumers (telemetry, OTel tracker, ACP, the timeline UI) can react. Use this when the host has detected a cwd/branch/repo change outside the session's normal lifecycle (e.g., after a shell command in interactive mode). For a local session, a report whose `cwd` diverges from the session's current working directory is ignored (the call still succeeds but records nothing and emits no event); move a local session's working directory via `metadata.setWorkingDirectory` instead. + * Owned installation that a listed MCP server's live configuration came from. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataRecordContextChangeResult". + * via the `definition` "McpServerOwnership". */ /** @experimental */ -export interface MetadataRecordContextChangeResult {} +export interface McpServerOwnership { + /** + * Stable installation identifier from the owned installation receipt. + */ + installationId: string; +} /** - * Absolute path to set as the session's new working directory. For local sessions the path must be absolute and exist on disk: it is validated before any session state changes, and a failing validation rejects the call with nothing mutated, persisted, or emitted. Remote sessions record the path as-is. + * In-process MCP server configuration used by embedded SDK clients. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataSetWorkingDirectoryRequest". + * via the `definition` "McpServerConfigMemory". */ /** @experimental */ -export interface MetadataSetWorkingDirectoryRequest { +/** @internal */ +export interface McpServerConfigMemory { + type: McpServerConfigMemoryType; /** - * Absolute path to set as the session's working directory. The runtime updates the session's recorded cwd so subsequent operations (shell tools, file lookups, telemetry) anchor to it. + * In-process MCP server instance. This value cannot cross a JSON-RPC boundary. + * + * @internal */ - workingDirectory: string; + serverInstance: OpaqueInProcessValue; + /** + * Tools to include. Defaults to all tools if not specified. + */ + tools?: string[]; + /** + * Optional human-readable server name. + */ + displayName?: string; + /** + * Whether this server is a built-in fallback. + */ + isDefaultServer?: boolean; + filterMapping?: FilterMapping; + safeForTelemetry?: McpSafeForTelemetry; + /** + * Timeout in milliseconds for tool discovery and tool calls. + */ + timeout?: number; + /** + * Milliseconds this server may spend connecting before the CLI warns that it is taking longer than expected. Presentation only: it does not change how long the connection is allowed to take. + */ + slowConnectionThresholdMs?: number; + oidc?: McpServerAuthConfig; + deferTools?: McpServerConfigDeferTools; + /** + * Whether persisted tool snapshots are disabled. + */ + disableToolCache?: boolean; + /** + * Whether secret masking is disabled for calls to this server. + */ + disableSecretMasking?: boolean; + /** + * Tool names excluded after the include filter is applied. + */ + excludeTools?: string[]; + /** + * Event types this server receives as Copilot notifications. + */ + events?: string[]; + /** + * Copilot notification types this server may send to the host. + */ + notifications?: string[]; + source?: McpServerSource; + /** + * Plugin that provided this server. + */ + sourcePlugin?: string; + /** + * Version of the plugin that provided this server. + */ + sourcePluginVersion?: string; + /** + * Whether the providing plugin uses the Open Plugin Spec. + */ + sourcePluginSpec?: boolean; + /** + * Source file path recorded while loading the config. + */ + sourcePath?: string; + /** + * Configuration warnings recorded while loading the server. + */ + configWarnings?: string[]; } /** - * Update the session's working directory. Used by the host when the user explicitly changes cwd (e.g., the `/cd` slash command). The host is responsible for any related side-effects (file index, etc.); it does NOT change the process working directory (a session's cwd is per-session, not process-global). For local sessions the runtime validates the target first (an absolute path that exists on disk) and re-bases the permission primary directory; a rejected validation fails the call before anything is mutated, persisted, or emitted. Location-scoped permission rules are then re-keyed to the new directory (best-effort). Remote sessions only record the path. + * MCP servers configured for the session, with their connection status and host-level state. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataSetWorkingDirectoryResult". + * via the `definition` "McpServerList". */ /** @experimental */ -export interface MetadataSetWorkingDirectoryResult { +export interface McpServerList { /** - * Working directory after the update + * Configured MCP servers */ - workingDirectory: string; + servers: McpServer[]; + host?: McpHostState; } /** - * Remote-session-specific metadata. Populated only when `isRemote` is true. Fields are immutable for the lifetime of the session. + * Mode controlling how MCP server env values are resolved (`direct` or `indirect`). * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataSnapshotRemoteMetadata". + * via the `definition` "McpSetEnvValueModeParams". */ /** @experimental */ -export interface MetadataSnapshotRemoteMetadata { - /** - * The original resource identifier (task ID or PR node ID), preserved across event-replay reconstructions. Falls back to `sessionId` when absent. - */ - resourceId?: string; - repository: MetadataSnapshotRemoteMetadataRepository; - /** - * The pull request number the remote session is associated with, if any. - */ - pullRequestNumber?: number; - taskType?: MetadataSnapshotRemoteMetadataTaskType; +export interface McpSetEnvValueModeParams { + mode: McpSetEnvValueModeDetails; } /** - * The repository the remote session targets. + * Env-value mode recorded on the session after the update. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataSnapshotRemoteMetadataRepository". + * via the `definition` "McpSetEnvValueModeResult". */ /** @experimental */ -export interface MetadataSnapshotRemoteMetadataRepository { - /** - * The GitHub owner (user or organization) of the target repository. - */ - owner: string; - /** - * The GitHub repository name (without owner). - */ - name: string; - /** - * The branch the remote session is operating on. - */ - branch: string; +export interface McpSetEnvValueModeResult { + mode: McpSetEnvValueModeDetails; } /** - * Atomic patch for client-owned session metadata. Operations apply in clear, remove, then set order. The resulting bag must satisfy the ClientMetadata entry and serialized-size limits. Local storage coordinates concurrent runtime processes; custom SessionFs providers must serialize writers that access the same session from multiple processes. + * The session tool filters that decide whether the session still has a shell to run `gh` with. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MetadataUpdateClientMetadataRequest". + * via the `definition` "McpShouldExcludeGitHubToolsRequest". */ /** @experimental */ -export interface MetadataUpdateClientMetadataRequest { +/** @internal */ +export interface McpShouldExcludeGitHubToolsRequest { /** - * Remove every existing client metadata entry before applying remove and set. Defaults to false. + * The session's tool allowlist, when it set one. Omitted means the session constrains nothing this way. */ - clear?: boolean; + availableTools?: string[]; /** - * Case-sensitive keys to remove. Missing keys are ignored. Each key must be non-empty, at most 256 UTF-8 bytes, and outside the reserved `copilot/` and `github/` namespaces. - * - * @maxItems 128 + * The session's tool denylist, when it set one. Omitted means the session constrains nothing this way. */ - remove?: string[]; + excludedTools?: string[]; /** - * String entries to add or replace. Set wins when a key also appears in remove. Each key must be non-empty, at most 256 UTF-8 bytes, and outside the reserved `copilot/` and `github/` namespaces. Each value may contain at most 16 KiB of UTF-8 data. + * How the allowlist and denylist combine when both are set. Omitted means the default every session gets, so a caller that never chose a precedence is answered as its sessions behave. */ - set?: { - [k: string]: string | undefined; - }; + toolFilterPrecedence?: OptionsUpdateToolFilterPrecedence | null; } /** - * Copilot model metadata, including identifier, display name, capabilities, policy, billing, reasoning efforts, and picker categories. + * Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by the request. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "Model". + * via the `definition` "McpShouldExcludeGitHubToolsResult". */ /** @experimental */ -export interface Model { - /** - * Model identifier (e.g., "claude-sonnet-4.5") - */ - id: string; +/** @internal */ +export interface McpShouldExcludeGitHubToolsResult { /** - * Display name + * True only when both halves hold: the session's filters still reach the platform shell tool, and the host actually has the `gh` those tools would be replaced by. Feed it straight back as the `excludeGhReplaceableTools` build option. */ - name: string; - capabilities: ModelCapabilities; + excludeGhReplaceableTools: boolean; +} +/** + * Server name and optional configuration for an individual MCP server start. Omit `config` for a config-free start-by-name of an already-configured server. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpStartServerRequest". + */ +/** @experimental */ +export interface McpStartServerRequest { /** - * Provider-supplied model metadata. Keys and JSON-compatible values are preserved unchanged. This is factual metadata published by the model provider; it carries no picker or UX semantics. + * Name of the MCP server to start */ - metadata?: { - [k: string]: JsonValue | undefined; - }; + serverName: string; + config?: McpSerializableServerConfig; /** - * Model vendor as the Copilot API reports it, for example "Anthropic" or "Azure OpenAI". Open vocabulary, passed through unchanged. It can name the vendor that serves the model instead of the one that built it, or a label that is not a vendor, such as "Experimental". Absent when the Copilot API reports no vendor. + * Exact receipt identity for explicit owned activation in this session. */ - vendor?: string; - policy?: ModelPolicy; - billing?: ModelBilling; + expectedInstallationId?: string; +} +/** + * MCP server startup filtering result. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpStartServersResult". + */ +/** @experimental */ +export interface McpStartServersResult { /** - * Supported reasoning effort levels (only present if model supports reasoning effort) + * Servers filtered out before startup */ - supportedReasoningEfforts?: string[]; + filteredServers: McpFilteredServer[]; /** - * Default reasoning effort level (only present if model supports reasoning effort) + * Non-default servers allowed by policy */ - defaultReasoningEffort?: string; + allowedServers?: McpAllowedServer[]; /** - * Context-window tiers this model offers, when the provider advertises them independently of tiered token pricing. Copilot models carry their tiers in `billing.tokenPrices`; a provider that has no pricing to publish (an agent host reached over AHP, for example) declares them here instead, so the model picker can still offer the tier toggle. + * Servers whose connection attempt failed. */ - supportedContextTiers?: string[]; - modelPickerCategory?: ModelPickerCategory; - modelPickerPriceCategory?: ModelPickerPriceCategory; - warningText?: ModelWarningText; + failedServers?: McpFailedServer[]; +} +/** + * Server name for an individual MCP server stop. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "McpStopServerRequest". + */ +/** @experimental */ +export interface McpStopServerRequest { /** - * Informational notices the service published for this model, such as an upcoming change or a recommended alternative. Present only when the service published at least one notice. Hosts should surface these without implying anything is wrong with the model. + * Exact owned receipt identity. Stop also forgets this session's durable activation. */ - infoMessages?: ModelMessage[]; + expectedInstallationId?: string; /** - * Warnings the service published for this model, such as a deprecated client version. Present only when the service published at least one warning. The model remains usable; hosts should surface these as advisory rather than blocking. + * Name of the MCP server to stop */ - warningMessages?: ModelMessage[]; - provider?: ModelProviderRef; + serverName: string; } /** - * Policy state (if applicable) + * Metadata controlling an MCP task's lifetime. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelPolicy". + * via the `definition` "McpTaskMetadata". */ /** @experimental */ -export interface ModelPolicy { - state: ModelPolicyState; +export interface McpTaskMetadata { /** - * Usage terms or conditions for this model + * Task time-to-live. */ - terms?: string; + ttl?: number; } /** - * Billing information + * Server name identifying the external client to remove. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelBilling". + * via the `definition` "McpUnregisterExternalClientRequest". */ /** @experimental */ -export interface ModelBilling { - /** - * Billing cost multiplier relative to the base rate - */ - multiplier?: number; - tokenPrices?: ModelBillingTokenPrices; +/** @internal */ +export interface McpUnregisterExternalClientRequest { /** - * Whole-number percentage discount (0-100) applied to usage billed through this model. Populated for the synthetic `auto` model, where requests routed by auto-mode are billed at a reduced rate; absent for concrete models. + * Server name of the external client to unregister */ - discountPercent?: number; - promo?: ModelBillingPromo; + serverName: string; } /** - * Token-level pricing information for this model + * Memory configuration for this session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelBillingTokenPrices". + * via the `definition` "MemoryConfiguration". */ /** @experimental */ -export interface ModelBillingTokenPrices { +export interface MemoryConfiguration { /** - * AI Credits cost per billing batch of input tokens - */ - inputPrice?: number; - /** - * AI Credits cost per billing batch of output tokens - */ - outputPrice?: number; - /** - * @deprecated - * Use cacheReadPrice instead. AI Credits cost per billing batch of cached tokens - */ - cachePrice?: number; - /** - * AI Credits cost per billing batch of cached (read) tokens - */ - cacheReadPrice?: number; - /** - * AI Credits cost per billing batch of cache-write (cache creation) tokens. - */ - cacheWritePrice?: number; - /** - * AI Credits cost per billing batch of 1-hour cache-write (cache creation) tokens. - */ - cacheWrite1hPrice?: number; - /** - * Number of tokens per standard billing batch - */ - batchSize?: number; - /** - * @deprecated - * Use maxPromptTokens instead. Prompt token budget for the default tier. The total context window is this value plus the model's max_output_tokens. - */ - contextMax?: number; - /** - * Prompt token budget for the default tier. The total context window is this value plus the model's max_output_tokens. + * Whether memory is enabled for the session. */ - maxPromptTokens?: number; - longContext?: ModelBillingTokenPricesLongContext; + enabled: boolean; } /** - * Long context tier pricing (available for models with extended context windows) + * Per-source attribution breakdown for the session's current context window, or null if uninitialized. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelBillingTokenPricesLongContext". + * via the `definition` "MetadataContextAttributionResult". */ /** @experimental */ -export interface ModelBillingTokenPricesLongContext { - /** - * AI Credits cost per billing batch of input tokens - */ - inputPrice?: number; - /** - * AI Credits cost per billing batch of output tokens - */ - outputPrice?: number; - /** - * @deprecated - * Use cacheReadPrice instead. AI Credits cost per billing batch of cached tokens - */ - cachePrice?: number; - /** - * AI Credits cost per billing batch of cached (read) tokens - */ - cacheReadPrice?: number; +export interface MetadataContextAttributionResult { /** - * AI Credits cost per billing batch of cache-write (cache creation) tokens. + * Per-source context-window attribution, or null if the session has not yet been initialized (no system prompt or tool metadata cached). */ - cacheWritePrice?: number; + contextAttribution?: SessionContextAttribution | null; +} +/** + * Parameters for the heaviest-messages query. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "MetadataContextHeaviestMessagesRequest". + */ +/** @experimental */ +export interface MetadataContextHeaviestMessagesRequest { /** - * AI Credits cost per billing batch of 1-hour cache-write (cache creation) tokens. + * Maximum number of messages to return, most-expensive first. Omit for the server default. */ - cacheWrite1hPrice?: number; + limit?: number; +} +/** + * The heaviest individual messages in the session's context window, most-expensive first. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "MetadataContextHeaviestMessagesResult". + */ +/** @experimental */ +export interface MetadataContextHeaviestMessagesResult { /** - * @deprecated - * Use maxPromptTokens instead. Prompt token budget for the long context tier. The total context window is this value plus the model's max_output_tokens. + * Total token count of the current context window, so callers can compute each message's share without a second call. */ - contextMax?: number; + totalTokens: number; /** - * Prompt token budget for the long context tier. The total context window is this value plus the model's max_output_tokens. + * Heaviest messages, most-expensive first. */ - maxPromptTokens?: number; + messages: ContextHeaviestMessage[]; } /** - * Active server-driven promotion for a model, including its discount and optional expiry. + * Model identifier and token limits used to compute the context-info breakdown. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelBillingPromo". + * via the `definition` "MetadataContextInfoRequest". */ /** @experimental */ -export interface ModelBillingPromo { - /** - * Stable identifier for the promotion campaign. - */ - id?: string; +export interface MetadataContextInfoRequest { /** - * Percentage discount (0-100) applied while the promotion is active. May be fractional. + * Advertised prompt allowance. Pass 0 to resolve the selected model and context tier from the session. */ - discountPercent?: number; + promptTokenLimit: number; /** - * UTC ISO 8601 timestamp marking when the promotion ends. Optional: an open-ended promotion omits this field. When present, the API only surfaces a promo whose expiry parses and is in the future, so consumers should treat a past value as expired. + * Requested output allowance to reserve against the combined context ceiling. Pass 0 to resolve the session's request cap, falling back to the model's advertised output limit. */ - endsAt?: string; + outputTokenLimit: number; /** - * Human-readable promotion message. Does not include the expiry timestamp; consumers may format endsAt and append it when present. + * Model identifier used for tokenization. Omit to use the session default. Used both for token counting and to compute display values. */ - message?: string; + selectedModel?: string; /** - * Whether the service asked hosts to give this promotion a prominent surface, such as a dedicated banner, in addition to listing it with the model. `true` requests that surface and `false` asks for the model list only. Absent means the service expressed no preference — for example a response that predates the field — so hosts should apply their own default rather than read it as `false`. + * Provider owning selectedModel. Omit to use the current provider for the current model, or deterministic legacy lookup for a different model. */ - showBanner?: boolean; + providerId?: string; } /** - * Service-published warning text that hosts should display when presenting a model. + * Token breakdown for the session's current context window, or null if uninitialized. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelWarningText". + * via the `definition` "MetadataContextInfoResult". */ /** @experimental */ -export interface ModelWarningText { +export interface MetadataContextInfoResult { /** - * Data-retention warning for the model. The text may contain Markdown links and should be rendered as Markdown when supported. + * Token breakdown for the current context window, or null if the session has not yet been initialized (no system prompt or tool metadata cached). */ - dataRetention?: string; + contextInfo?: SessionContextInfo | null; } /** - * A service-published message about a model, carrying a stable machine-readable code alongside human-readable text. + * Indicates whether the local session is currently processing a turn or background continuation. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelMessage". + * via the `definition` "MetadataIsProcessingResult". */ /** @experimental */ -export interface ModelMessage { - /** - * Stable machine-readable identifier for the message, such as `client_version_deprecated`. Hosts can key custom presentation off this; unrecognized codes should fall back to displaying `message`. - */ - code: string; +export interface MetadataIsProcessingResult { /** - * Human-readable message text intended for display to the user. + * Whether the session is currently processing user/agent messages. False for non-local sessions (which don't run a local agentic loop). Reflects an in-flight turn or background continuation. */ - message: string; + processing: boolean; } /** - * Managed, repository, and CLI model overrides to overlay onto the session at startup. + * Model identifier to use when re-tokenizing the session's existing messages. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelApplyStartupOverlayRequest". + * via the `definition` "MetadataRecomputeContextTokensRequest". */ /** @experimental */ -export interface ModelApplyStartupOverlayRequest { - /** - * Model required by device-managed policy, when configured. - */ - deviceManagedModel?: string; +export interface MetadataRecomputeContextTokensRequest { /** - * Model required by server-managed policy, when configured. + * Model identifier used for tokenization. The runtime token-counts both chat-context and system-context messages against this model. */ - serverManagedModel?: string; + modelId: string; +} +/** + * Re-tokenize the session's existing messages against `modelId` and return the token totals. Useful for hosts that want an initial estimate of context usage on session resume, before the next agent turn fires `session.context_info_changed` events. Returns zeros for an empty session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "MetadataRecomputeContextTokensResult". + */ +/** @experimental */ +export interface MetadataRecomputeContextTokensResult { /** - * Startup default model from the enterprise policy helper, when configured. Weakest of the managed sources: it applies only when neither device nor server policy names a model, and an explicit user selection still wins. + * Sum of tokens across chat-context and system-context messages currently held by the session. */ - policyHelperModel?: string; - autoTier?: AutoTier; + totalTokens: number; /** - * Model selected by repository settings, when configured. + * Tokens contributed by user/assistant/tool messages (excludes system/developer prompts). */ - repoModel?: string; + messagesTokenCount: number; /** - * Provider owning the repository-selected model. Omitted repository provider identity retains legacy bare-model behavior. + * Tokens contributed by system/developer prompt snapshots. */ - repoModelProviderId?: string; + systemTokenCount: number; +} +/** + * Updated working-directory/git context to record on the session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "MetadataRecordContextChangeRequest". + */ +/** @experimental */ +export interface MetadataRecordContextChangeRequest { + context: SessionWorkingDirectoryContext; +} +/** + * Updated working directory and git context. Emitted as the new payload of `session.context_changed`. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionWorkingDirectoryContext". + */ +/** @experimental */ +export interface SessionWorkingDirectoryContext { /** - * Reasoning effort selected by repository settings, when configured. + * Current working directory path */ - repoReasoningEffort?: string; + cwd: string; /** - * Context tier selected by repository settings, when configured. + * Root directory of the git repository, resolved via git rev-parse */ - repoContextTier?: string; + gitRoot?: string; /** - * Auto routing preference selected by repository settings, when configured. Applied only when the overlay selects the Auto model; beside a concrete model it stays dormant. + * Repository identifier derived from the git remote URL ("owner/name" for GitHub, "org/project/repo" for Azure DevOps) */ - repoAutoTier?: string; + repository?: string; + hostType?: SessionWorkingDirectoryContextHostType; /** - * Model explicitly selected by the CLI, when provided. + * Raw host string from the git remote URL (e.g. "github.com", "dev.azure.com") */ - cliModel?: string; + repositoryHost?: string; /** - * Whether the overlay is being applied while resuming a deferred session. + * Current git branch name */ - deferredResume?: boolean; + branch?: string; /** - * Reasoning effort paired with the effective organization-managed model. Applies only when that concrete managed model is selected; it is ignored for Auto and for CLI, resume, or user overrides. + * Head commit of the current git branch */ - managedReasoningEffort?: string; + headCommit?: string; /** - * Context tier paired with the effective organization-managed model. Applies only when that concrete managed model is selected; it is ignored for Auto and for CLI, resume, or user overrides. + * Merge-base commit SHA (fork point from the remote default branch) */ - managedContextTier?: string; + baseCommit?: string; } /** - * Optional capability overrides (vision, tool_calls, reasoning, etc.). + * Notify the session that its working directory context has changed. Emits a `session.context_changed` event so consumers (telemetry, OTel tracker, ACP, the timeline UI) can react. Use this when the host has detected a cwd/branch/repo change outside the session's normal lifecycle (e.g., after a shell command in interactive mode). For a local session, a report whose `cwd` diverges from the session's current working directory is ignored (the call still succeeds but records nothing and emits no event); move a local session's working directory via `metadata.setWorkingDirectory` instead. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelCapabilitiesOverride". + * via the `definition` "MetadataRecordContextChangeResult". */ /** @experimental */ -export interface ModelCapabilitiesOverride { - supports?: ModelCapabilitiesOverrideSupports; - limits?: ModelCapabilitiesOverrideLimits; -} +export interface MetadataRecordContextChangeResult {} /** - * Feature flags indicating what the model supports + * Absolute path to set as the session's new working directory. For local sessions the path must be absolute and exist on disk: it is validated before any session state changes, and a failing validation rejects the call with nothing mutated, persisted, or emitted. Remote sessions record the path as-is. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelCapabilitiesOverrideSupports". + * via the `definition` "MetadataSetWorkingDirectoryRequest". */ /** @experimental */ -export interface ModelCapabilitiesOverrideSupports { - /** - * Whether this model supports vision/image input - */ - vision?: boolean; - /** - * Whether this model supports canonical tool calling - */ - toolCalls?: boolean; +export interface MetadataSetWorkingDirectoryRequest { /** - * Whether this model supports reasoning effort configuration + * Absolute path to set as the session's working directory. The runtime updates the session's recorded cwd so subsequent operations (shell tools, file lookups, telemetry) anchor to it. */ - reasoningEffort?: boolean; - adaptive_thinking?: AdaptiveThinkingSupport; + workingDirectory: string; } /** - * Token limits for prompts, outputs, and context window + * Update the session's working directory. Used by the host when the user explicitly changes cwd (e.g., the `/cd` slash command). The host is responsible for any related side-effects (file index, etc.); it does NOT change the process working directory (a session's cwd is per-session, not process-global). For local sessions the runtime validates the target first (an absolute path that exists on disk) and re-bases the permission primary directory; a rejected validation fails the call before anything is mutated, persisted, or emitted. Location-scoped permission rules are then re-keyed to the new directory (best-effort). Remote sessions only record the path. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelCapabilitiesOverrideLimits". + * via the `definition` "MetadataSetWorkingDirectoryResult". */ /** @experimental */ -export interface ModelCapabilitiesOverrideLimits { +export interface MetadataSetWorkingDirectoryResult { /** - * Maximum number of prompt/input tokens + * Working directory after the update */ - max_prompt_tokens?: number; + workingDirectory: string; +} +/** + * Remote-session-specific metadata. Populated only when `isRemote` is true. Fields are immutable for the lifetime of the session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "MetadataSnapshotRemoteMetadata". + */ +/** @experimental */ +export interface MetadataSnapshotRemoteMetadata { /** - * Maximum number of output/completion tokens + * The original resource identifier (task ID or PR node ID), preserved across event-replay reconstructions. Falls back to `sessionId` when absent. */ - max_output_tokens?: number; + resourceId?: string; + repository: MetadataSnapshotRemoteMetadataRepository; /** - * Maximum total context window size in tokens + * The pull request number the remote session is associated with, if any. */ - max_context_window_tokens?: number; - vision?: ModelCapabilitiesOverrideLimitsVision; + pullRequestNumber?: number; + taskType?: MetadataSnapshotRemoteMetadataTaskType; } /** - * Vision-specific limits + * The repository the remote session targets. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelCapabilitiesOverrideLimitsVision". + * via the `definition` "MetadataSnapshotRemoteMetadataRepository". */ /** @experimental */ -export interface ModelCapabilitiesOverrideLimitsVision { - /** - * MIME types the model accepts - */ - supported_media_types?: string[]; +export interface MetadataSnapshotRemoteMetadataRepository { /** - * Maximum number of images per prompt + * The GitHub owner (user or organization) of the target repository. */ - max_prompt_images?: number; + owner: string; /** - * Maximum image size in bytes + * The GitHub repository name (without owner). */ - max_prompt_image_size?: number; -} - -/** @experimental */ -/** @internal */ -export interface ModelClearStartupSeedRequest { - expectedModel: string; + name: string; /** - * Provider captured with the startup seed; omission matches only an unqualified seed. + * The branch the remote session is operating on. */ - expectedProviderId?: string; -} - -/** @experimental */ -/** @internal */ -export interface ModelClearStartupSeedResult { - cleared: boolean; + branch: string; } /** - * Host presentation state the reasoning-summaries policy depends on. + * Atomic patch for client-owned session metadata. Operations apply in clear, remove, then set order. The resulting bag must satisfy the ClientMetadata entry and serialized-size limits. Local storage coordinates concurrent runtime processes; custom SessionFs providers must serialize writers that access the same session from multiple processes. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelGetReasoningSummariesRequest". + * via the `definition` "MetadataUpdateClientMetadataRequest". */ /** @experimental */ -export interface ModelGetReasoningSummariesRequest { +export interface MetadataUpdateClientMetadataRequest { /** - * The host's persisted `showReasoning` user setting, omitted when unset. + * Remove every existing client metadata entry before applying remove and set. Defaults to false. */ - persistedShowReasoning?: boolean; + clear?: boolean; /** - * Whether the host is currently showing reasoning summaries. Defaults to false. + * Case-sensitive keys to remove. Missing keys are ignored. Each key must be non-empty, at most 256 UTF-8 bytes, and outside the reserved `copilot/` and `github/` namespaces. + * + * @maxItems 128 */ - summariesVisible?: boolean; + remove?: string[]; + /** + * String entries to add or replace. Set wins when a key also appears in remove. Each key must be non-empty, at most 256 UTF-8 bytes, and outside the reserved `copilot/` and `github/` namespaces. Each value may contain at most 16 KiB of UTF-8 data. + */ + set?: { + [k: string]: string | undefined; + }; } /** - * Reasoning-summaries presentation policy for the session's current model. + * Copilot model metadata, including identifier, display name, capabilities, policy, billing, reasoning efforts, and picker categories. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelGetReasoningSummariesResult". + * via the `definition` "Model". */ /** @experimental */ -export interface ModelGetReasoningSummariesResult { +export interface Model { /** - * False until the session has a model catalog and a selected model. This read never resolves the catalog itself, and the runtime emits no readiness notification, so repeating this call alone leaves `ready` false indefinitely on a session that has neither listed models nor run a turn. `session.model.list` is the prerequisite and the signal: it resolves and caches the catalog for the session, so a successful return means the next read is ready. The exception is a session that resolves models without a Copilot catalog, that is a BYOK registry or an alternate provider: `session.model.list` returns an empty list without caching a catalog, so `ready` stays false and this policy is unavailable there. While false, every model-policy field is false and `visibility` is omitted; `experimentSettled` is independent of readiness and still reports the assignment state. + * Model identifier (e.g., "claude-sonnet-4.5") */ - ready: boolean; + id: string; /** - * Whether the session's reasoning-summaries experiment assignment has settled. False means this read does not wait for a pending assignment and reports the experiment-derived fields conservatively: `showHiddenHint` is false and `visibility` falls back to `persistedShowReasoning`, or is omitted when none was supplied. A host that wants the assigned answer re-reads until this is true. + * Display name */ - experimentSettled: boolean; + name: string; + capabilities: ModelCapabilities; /** - * Whether turns on this session produce reasoning summaries, honouring an explicit session reasoning-summary override. + * Provider-supplied model metadata. Keys and JSON-compatible values are preserved unchanged. This is factual metadata published by the model provider; it carries no picker or UX semantics. */ - sessionShowsSummaries: boolean; + metadata?: { + [k: string]: JsonValue | undefined; + }; /** - * Whether the selected model shows reasoning summaries by default. + * Model vendor as the Copilot API reports it, for example "Anthropic" or "Azure OpenAI". Open vocabulary, passed through unchanged. It can name the vendor that serves the model instead of the one that built it, or a label that is not a vendor, such as "Experimental". Absent when the Copilot API reports no vendor. */ - modelDefaultShowsSummaries: boolean; + vendor?: string; + policy?: ModelPolicy; + billing?: ModelBilling; /** - * Whether the selected model emits reasoning headers. + * Supported reasoning effort levels (only present if model supports reasoning effort) */ - showReasoningHeaders: boolean; + supportedReasoningEfforts?: string[]; /** - * Default reasoning visibility, and only meaningful once `ready` is true: false when the session produces no summaries, else the persisted setting, else the experiment's default. While `ready` is true it is omitted only when all three are unavailable, that is when the session produces summaries, no `persistedShowReasoning` was supplied, and `experimentSettled` is false. While `ready` is false there is no model policy to report and this field is always omitted, so an absent value alone does not imply a pending experiment. + * Default reasoning effort level (only present if model supports reasoning effort) */ - visibility?: boolean; + defaultReasoningEffort?: string; /** - * Whether to show the hint that reasoning summaries are hidden. Always false while `experimentSettled` is false. + * Context-window tiers this model offers, when the provider advertises them independently of tiered token pricing. Copilot models carry their tiers in `billing.tokenPrices`; a provider that has no pricing to publish (an agent host reached over AHP, for example) declares them here instead, so the model picker can still offer the tier toggle. */ - showHiddenHint: boolean; + supportedContextTiers?: string[]; + modelPickerCategory?: ModelPickerCategory; + modelPickerPriceCategory?: ModelPickerPriceCategory; + warningText?: ModelWarningText; /** - * Whether the supplied `persistedShowReasoning` setting only restates the model default. This reports a redundancy, not a standing instruction to delete the setting: it stays true for as long as the setting and the model default agree, including for a user who later chose that value deliberately. It exists for a one-time migration of a legacy setting written before the model default made it redundant, so a host that acts on it owns the cleanup and must gate it behind its own persisted `done` marker, delete only a setting whose value still matches the one it read, and never repeat the deletion on a later launch. Under an off-by-default reasoning-summaries experiment an explicit `showReasoning: true` opt-in also reads as redundant on a summary-producing model, so an ungated host would keep deleting that opt-in and hide summaries again on every launch. + * Informational notices the service published for this model, such as an upcoming change or a recommended alternative. Present only when the service published at least one notice. Hosts should surface these without implying anything is wrong with the model. */ - clearRedundantSetting: boolean; + infoMessages?: ModelMessage[]; + /** + * Warnings the service published for this model, such as a deprecated client version. Present only when the service published at least one warning. The model remains usable; hosts should surface these as advisory rather than blocking. + */ + warningMessages?: ModelMessage[]; + provider?: ModelProviderRef; } /** - * List of Copilot models available to the resolved user, including capabilities and billing metadata. + * Policy state (if applicable) * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelList". + * via the `definition` "ModelPolicy". */ /** @experimental */ -export interface ModelList { +export interface ModelPolicy { + state: ModelPolicyState; /** - * List of available models with full metadata + * Usage terms or conditions for this model */ - models: Model[]; + terms?: string; } - +/** + * Billing information + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelBilling". + */ /** @experimental */ -export interface ModelPickerPersistenceRequest { - settingsContext: ModelPickerSettingsContext; +export interface ModelBilling { /** - * Whether reasoning effort was explicitly selected and should be persisted. + * Billing cost multiplier relative to the base rate */ - reasoningEffortExplicit?: boolean; + multiplier?: number; + tokenPrices?: ModelBillingTokenPrices; /** - * Whether context tier was explicitly selected and should be persisted. + * Whole-number percentage discount (0-100) applied to usage billed through this model. Populated for the synthetic `auto` model, where requests routed by auto-mode are billed at a reduced rate; absent for concrete models. */ - contextTierExplicit?: boolean; + discountPercent?: number; + promo?: ModelBillingPromo; } /** - * Filesystem and environment context used to resolve model-picker settings. + * Token-level pricing information for this model * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelPickerSettingsContext". + * via the `definition` "ModelBillingTokenPrices". */ /** @experimental */ -export interface ModelPickerSettingsContext { +export interface ModelBillingTokenPrices { /** - * Optional Copilot configuration directory containing persisted settings. + * AI Credits cost per billing batch of input tokens */ - configDir?: string; + inputPrice?: number; /** - * User home directory used when resolving persisted settings. + * AI Credits cost per billing batch of output tokens */ - homeDirectory: string; + outputPrice?: number; /** - * Environment variables consulted while resolving model-picker settings. + * @deprecated + * Use cacheReadPrice instead. AI Credits cost per billing batch of cached tokens */ - environment: {}; -} -/** - * Normalized model-provider adapter definitions available to the session, not discovered instances. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelProviderAdapterCatalog". - */ -/** @experimental */ -export interface ModelProviderAdapterCatalog { + cachePrice?: number; /** - * Available provider adapters ordered by adapterId. + * AI Credits cost per billing batch of cached (read) tokens */ - providers: ModelProviderAdapterDescriptor[]; -} -/** - * A normalized model-provider adapter in the session's effective catalog. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelProviderAdapterDescriptor". - */ -/** @experimental */ -export interface ModelProviderAdapterDescriptor { + cacheReadPrice?: number; /** - * Stable opaque identity for routing to this adapter. Unique in the effective catalog, independent of live registration generations. + * AI Credits cost per billing batch of cache-write (cache creation) tokens. */ - adapterId: string; + cacheWritePrice?: number; /** - * Descriptive provider family, such as `ollama`. Different adapters may have the same family; use adapterId for routing. + * AI Credits cost per billing batch of 1-hour cache-write (cache creation) tokens. */ - providerKind: string; + cacheWrite1hPrice?: number; /** - * Human-readable provider name. + * Number of tokens per standard billing batch */ - displayName: string; - provenance: ModelProviderAttribution; - automaticDiscovery: ModelProviderAutomaticDiscoveryPolicy; + batchSize?: number; /** - * Operations supported by this provider adapter. + * @deprecated + * Use maxPromptTokens instead. Prompt token budget for the default tier. The total context window is this value plus the model's max_output_tokens. */ - operations: ModelProviderAdapterOperationDescriptor[]; + contextMax?: number; + /** + * Prompt token budget for the default tier. The total context window is this value plus the model's max_output_tokens. + */ + maxPromptTokens?: number; + longContext?: ModelBillingTokenPricesLongContext; } /** - * Contributor attribution, independent of routing identity and authorization. + * Long context tier pricing (available for models with extended context windows) * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelProviderAttribution". + * via the `definition` "ModelBillingTokenPricesLongContext". */ /** @experimental */ -export interface ModelProviderAttribution { - source: ModelProviderProvenanceSource; +export interface ModelBillingTokenPricesLongContext { /** - * Stable contributor identifier. Required and nonblank for extension and custom sources; optional for built-in and configured sources. Does not grant authority. + * AI Credits cost per billing batch of input tokens */ - ownerId?: string; + inputPrice?: number; /** - * Human-readable contributor name, not the adapter display name. + * AI Credits cost per billing batch of output tokens */ - ownerDisplayName?: string; -} -/** - * Adapter-declared policy that tells clients whether discovery may run automatically. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelProviderAutomaticDiscoveryPolicy". - */ -/** @experimental */ -export interface ModelProviderAutomaticDiscoveryPolicy { - mode: ModelProviderAutomaticDiscoveryMode; - networkScope: ModelProviderDiscoveryNetworkScope; + outputPrice?: number; /** - * True when discovery requires non-null caller input. Omission or null is rejected before adapter execution. When false, omitted or null input selects adapter defaults without schema validation. + * @deprecated + * Use cacheReadPrice instead. AI Credits cost per billing batch of cached tokens */ - requiresInput: boolean; + cachePrice?: number; /** - * True when the adapter must be enabled by a trusted owner, such as a trusted extension, before automatic discovery may run. + * AI Credits cost per billing batch of cached (read) tokens */ - requiresTrust: boolean; -} -/** - * An operation supported by a model-provider adapter. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelProviderAdapterOperationDescriptor". - */ -/** @experimental */ -export interface ModelProviderAdapterOperationDescriptor { + cacheReadPrice?: number; /** - * Supported operation name: `discover`, `getStatus`, or `models.list`. Unknown names and duplicate declarations are rejected. + * AI Credits cost per billing batch of cache-write (cache creation) tokens. */ - name: string; + cacheWritePrice?: number; /** - * Optional self-contained JSON Schema Draft 7 for non-null discovery input. Only supported on discover. No external references are resolved. Omitted or null input selects defaults when requiresInput is false. Without a schema, the adapter validates supplied input. + * AI Credits cost per billing batch of 1-hour cache-write (cache creation) tokens. */ - inputSchema?: JsonValue; -} -/** - * Provider configuration prepared from a discovered model. Preparing a plan changes nothing: it neither registers the model with the session nor writes durable configuration. To apply it, pass `provider` and `model` to `session.provider.add`, omitting whichever the dispositions report as already configured. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelProviderConfigurationPlan". - */ -/** @experimental */ -export interface ModelProviderConfigurationPlan { - provider: NamedProviderConfig; - model: ProviderModelConfig; + cacheWrite1hPrice?: number; /** - * Provider-qualified selection id (`provider/id`) to pass to `switchTo` once the plan is applied. + * @deprecated + * Use maxPromptTokens instead. Prompt token budget for the long context tier. The total context window is this value plus the model's max_output_tokens. */ - selectionId: string; - providerDisposition: ModelProviderConfigurationDisposition; - modelDisposition: ModelProviderConfigurationDisposition; + contextMax?: number; /** - * Non-fatal warnings carried over from the discovered model, such as capabilities the provider did not report. + * Prompt token budget for the long context tier. The total context window is this value plus the model's max_output_tokens. */ - warnings: ModelProviderWarning[]; + maxPromptTokens?: number; } /** - * External SDK input for a named custom model provider. Ingested by the native protocol boundary before host dispatch. + * Active server-driven promotion for a model, including its discount and optional expiry. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "NamedProviderConfig". + * via the `definition` "ModelBillingPromo". */ /** @experimental */ -export interface NamedProviderConfig { - /** - * Unique provider name used to qualify model selection IDs. - */ - name: string; - type?: ProviderConfigType; - wireApi?: ProviderConfigWireApi; - transport?: ProviderConfigTransport; +export interface ModelBillingPromo { /** - * Base URL for provider API requests. + * Stable identifier for the promotion campaign. */ - baseUrl: string; + id?: string; /** - * Static API key used to authenticate provider requests. + * Percentage discount (0-100) applied while the promotion is active. May be fractional. */ - apiKey?: string; + discountPercent?: number; /** - * Static bearer token used to authenticate provider requests. + * UTC ISO 8601 timestamp marking when the promotion ends. Optional: an open-ended promotion omits this field. When present, the API only surfaces a promo whose expiry parses and is in the future, so consumers should treat a past value as expired. */ - bearerToken?: string; - azure?: ProviderConfigAzure; + endsAt?: string; /** - * Additional HTTP headers included with provider requests. + * Human-readable promotion message. Does not include the expiry timestamp; consumers may format endsAt and append it when present. */ - headers?: { - [k: string]: string | undefined; - }; - modelProvider?: ProviderConfigModelProvider; + message?: string; /** - * Whether the host supplies bearer tokens dynamically. + * Whether the service asked hosts to give this promotion a prominent surface, such as a dedicated banner, in addition to listing it with the model. `true` requests that surface and `false` asks for the model list only. Absent means the service expressed no preference — for example a response that predates the field — so hosts should apply their own default rather than read it as `false`. */ - hasBearerTokenProvider?: boolean; + showBanner?: boolean; } /** - * Azure-specific provider options. + * Service-published warning text that hosts should display when presenting a model. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ProviderConfigAzure". + * via the `definition` "ModelWarningText". */ /** @experimental */ -export interface ProviderConfigAzure { +export interface ModelWarningText { /** - * API version. When set, uses the versioned deployment route. When omitted, uses the GA versionless v1 route. + * Data-retention warning for the model. The text may contain Markdown links and should be rendered as Markdown when supported. */ - apiVersion?: string; + dataRetention?: string; } /** - * A BYOK model definition referencing a named provider. + * A service-published message about a model, carrying a stable machine-readable code alongside human-readable text. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ProviderModelConfig". + * via the `definition` "ModelMessage". */ /** @experimental */ -export interface ProviderModelConfig { - /** - * Provider-local model id, unique within its provider. The session-wide selection id (shown in the model list and passed to switchTo) is the provider-qualified `provider/id`. - */ - id: string; - /** - * Name of the configured provider that serves this model. - */ - provider: string; - /** - * The model name sent to the provider API for inference. Defaults to `id`. - */ - wireModel?: string; +export interface ModelMessage { /** - * Well-known base model id used for behavior/capability/config lookup. Defaults to `id`. + * Stable machine-readable identifier for the message, such as `client_version_deprecated`. Hosts can key custom presentation off this; unrecognized codes should fall back to displaying `message`. */ - modelId?: string; + code: string; /** - * Display name for model pickers. Defaults to the provider-qualified selection id (`provider/id`). + * Human-readable message text intended for display to the user. */ - name?: string; + message: string; +} +/** + * Managed, repository, and CLI model overrides to overlay onto the session at startup. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelApplyStartupOverlayRequest". + */ +/** @experimental */ +export interface ModelApplyStartupOverlayRequest { /** - * Maximum prompt/input tokens for the model. + * Model required by device-managed policy, when configured. */ - maxPromptTokens?: number; + deviceManagedModel?: string; /** - * Maximum context window tokens for the model. + * Model required by server-managed policy, when configured. */ - maxContextWindowTokens?: number; + serverManagedModel?: string; /** - * Maximum output tokens for the model. + * Startup default model from the enterprise policy helper, when configured. Weakest of the managed sources: it applies only when neither device nor server policy names a model, and an explicit user selection still wins. */ - maxOutputTokens?: number; - capabilities?: ModelCapabilitiesOverride; - systemMessage?: ProtocolSystemMessageConfig; + policyHelperModel?: string; + autoTier?: AutoTier; /** - * Provider-published model metadata, preserved verbatim as the public Model.metadata object. + * Model selected by repository settings, when configured. */ - metadata?: { - [k: string]: JsonValue | undefined; - }; -} - -/** @experimental */ -export interface ProtocolSystemMessageAppendConfig { - mode?: ProtocolAppendMode; + repoModel?: string; /** - * Text appended to the standard system prompt. + * Provider owning the repository-selected model. Omitted repository provider identity retains legacy bare-model behavior. */ - content?: string; -} - -/** @experimental */ -export interface ProtocolSystemMessageReplaceConfig { - mode: ProtocolReplaceMode; + repoModelProviderId?: string; /** - * Complete replacement system-message text. + * Reasoning effort selected by repository settings, when configured. */ - content: string; + repoReasoningEffort?: string; /** - * Optional structured blocks corresponding to the replacement content. + * Context tier selected by repository settings, when configured. */ - contentBlocks?: SystemMessageBlock[]; -} - -/** @experimental */ -export interface SystemMessageBlock { + repoContextTier?: string; /** - * Text content for this system-message block. + * Auto routing preference selected by repository settings, when configured. Applied only when the overlay selects the Auto model; beside a concrete model it stays dormant. */ - content: string; + repoAutoTier?: string; /** - * Whether the block is static and may be cached independently of dynamic prompt content. + * Model explicitly selected by the CLI, when provided. */ - isStatic?: boolean; + cliModel?: string; /** - * Whether providers with explicit prompt caching should place a cache breakpoint after this block. + * Whether the overlay is being applied while resuming a deferred session. */ - cacheBreakpoint?: boolean; -} - -/** @experimental */ -export interface ProtocolSystemMessageCustomizeConfig { - mode: ProtocolCustomizeMode; + deferredResume?: boolean; /** - * Named standard-prompt section overrides. + * Reasoning effort paired with the effective organization-managed model. Applies only when that concrete managed model is selected; it is ignored for Auto and for CLI, resume, or user overrides. */ - sections?: { - [k: string]: ProtocolSectionOverride | undefined; - }; + managedReasoningEffort?: string; /** - * Text appended after the customized sections. + * Context tier paired with the effective organization-managed model. Applies only when that concrete managed model is selected; it is ignored for Auto and for CLI, resume, or user overrides. */ - content?: string; + managedContextTier?: string; } - +/** + * Optional capability overrides (vision, tool_calls, reasoning, etc.). + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ModelCapabilitiesOverride". + */ /** @experimental */ -export interface ProtocolStaticSectionOverride { - action: ProtocolStaticSectionAction; - /** - * Optional content used by replace, append, and prepend operations. - */ - content?: string; +export interface ModelCapabilitiesOverride { + supports?: ModelCapabilitiesOverrideSupports; + limits?: ModelCapabilitiesOverrideLimits; } /** - * One model provider available to the session — the model analog of the account `ProviderDescriptor`. Opaque id/label/kind plus a stable ordering; central code never branches on kind. + * Feature flags indicating what the model supports * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelProviderDescriptor". + * via the `definition` "ModelCapabilitiesOverrideSupports". */ /** @experimental */ -export interface ModelProviderDescriptor { - kind: ModelProviderKind; +export interface ModelCapabilitiesOverrideSupports { /** - * Opaque, stable provider id, stamped onto every model this provider returns. + * Whether this model supports vision/image input */ - id: string; + vision?: boolean; /** - * Human-readable menu label, owned by the runtime so every consumer renders identical text. + * Whether this model supports canonical tool calling */ - label: string; + toolCalls?: boolean; /** - * Stable ordering key for presenting providers in a deterministic sequence. + * Whether this model supports reasoning effort configuration */ - ordering: number; + reasoningEffort?: boolean; + adaptive_thinking?: AdaptiveThinkingSupport; } /** - * Provider discovery parameters. + * Token limits for prompts, outputs, and context window * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelProviderDiscoverRequest". + * via the `definition` "ModelCapabilitiesOverrideLimits". */ /** @experimental */ -export interface ModelProviderDiscoverRequest { +export interface ModelCapabilitiesOverrideLimits { /** - * Opaque adapter identity returned by `session.providers.getCatalog`. + * Maximum number of prompt/input tokens */ - adapterId: string; + max_prompt_tokens?: number; /** - * Provider-specific JSON input. Omission or null selects adapter defaults unless requiresInput is true. Non-null input is validated against the advertised Draft 7 schema when present; otherwise validation belongs to the adapter. + * Maximum number of output/completion tokens */ - input?: JsonValue; + max_output_tokens?: number; + /** + * Maximum total context window size in tokens + */ + max_context_window_tokens?: number; + vision?: ModelCapabilitiesOverrideLimitsVision; } /** - * Provider instances found by a discovery operation. + * Vision-specific limits * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelProviderDiscoverResult". + * via the `definition` "ModelCapabilitiesOverrideLimitsVision". */ /** @experimental */ -export interface ModelProviderDiscoverResult { - outcome: ModelProviderOperationOutcome; +export interface ModelCapabilitiesOverrideLimitsVision { /** - * Discovered provider instances. Empty when passive default discovery finds no reachable provider. + * MIME types the model accepts */ - instances: ModelProviderInstance[]; + supported_media_types?: string[]; + /** + * Maximum number of images per prompt + */ + max_prompt_images?: number; + /** + * Maximum image size in bytes + */ + max_prompt_image_size?: number; +} + +/** @experimental */ +/** @internal */ +export interface ModelClearStartupSeedRequest { + expectedModel: string; + /** + * Provider captured with the startup seed; omission matches only an unqualified seed. + */ + expectedProviderId?: string; +} + +/** @experimental */ +/** @internal */ +export interface ModelClearStartupSeedResult { + cleared: boolean; } /** - * A normalized model-provider instance discovered by the runtime. + * Host presentation state the reasoning-summaries policy depends on. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelProviderInstance". + * via the `definition` "ModelGetReasoningSummariesRequest". */ /** @experimental */ -export interface ModelProviderInstance { - reference: ModelProviderInstanceReference; +export interface ModelGetReasoningSummariesRequest { /** - * Human-readable instance name. + * The host's persisted `showReasoning` user setting, omitted when unset. */ - displayName: string; - provenance: ModelProviderProvenance; + persistedShowReasoning?: boolean; /** - * Inference API endpoint when the provider exposes one separately from its management endpoint. + * Whether the host is currently showing reasoning summaries. Defaults to false. */ - inferenceEndpoint?: string; - inferenceType?: ProviderEndpointType; - inferenceWireApi?: ProviderEndpointWireApi; - inferenceTransport?: ProviderEndpointTransport; + summariesVisible?: boolean; } /** - * Serializable reference to a discovered provider instance. + * Reasoning-summaries presentation policy for the session's current model. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelProviderInstanceReference". + * via the `definition` "ModelGetReasoningSummariesResult". */ /** @experimental */ -export interface ModelProviderInstanceReference { +export interface ModelGetReasoningSummariesResult { /** - * Stable opaque identity of the adapter that owns this reference. Must be present in the target session's effective catalog. + * False until the session has a model catalog and a selected model. This read never resolves the catalog itself, and the runtime emits no readiness notification, so repeating this call alone leaves `ready` false indefinitely on a session that has neither listed models nor run a turn. `session.model.list` is the prerequisite and the signal: it resolves and caches the catalog for the session, so a successful return means the next read is ready. The exception is a session that resolves models without a Copilot catalog, that is a BYOK registry or an alternate provider: `session.model.list` returns an empty list without caching a catalog, so `ready` stays false and this policy is unavailable there. While false, every model-policy field is false and `visibility` is omitted; `experimentSettled` is independent of readiness and still reports the assignment state. */ - adapterId: string; + ready: boolean; /** - * Descriptive provider family. Must match the selected adapter; not a routing key. + * Whether the session's reasoning-summaries experiment assignment has settled. False means this read does not wait for a pending assignment and reports the experiment-derived fields conservatively: `showHiddenHint` is false and `visibility` falls back to `persistedShowReasoning`, or is omitted when none was supplied. A host that wants the assigned answer re-reads until this is true. */ - providerKind: string; + experimentSettled: boolean; /** - * Stable instance identifier derived by the provider adapter, such as `ollama:{normalizedEndpoint}`. + * Whether turns on this session produce reasoning summaries, honouring an explicit session reasoning-summary override. */ - id: string; + sessionShowsSummaries: boolean; /** - * Absolute provider management URI. The adapter validates normalization, supported schemes, and permission to access it against its bound configuration; a reference does not grant authority. + * Whether the selected model shows reasoning summaries by default. */ - managementEndpoint: string; -} -/** - * Provider status request parameters. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelProviderGetStatusRequest". - */ -/** @experimental */ -export interface ModelProviderGetStatusRequest { - instance: ModelProviderInstanceReference; + modelDefaultShowsSummaries: boolean; + /** + * Whether the selected model emits reasoning headers. + */ + showReasoningHeaders: boolean; + /** + * Default reasoning visibility, and only meaningful once `ready` is true: false when the session produces no summaries, else the persisted setting, else the experiment's default. While `ready` is true it is omitted only when all three are unavailable, that is when the session produces summaries, no `persistedShowReasoning` was supplied, and `experimentSettled` is false. While `ready` is false there is no model policy to report and this field is always omitted, so an absent value alone does not imply a pending experiment. + */ + visibility?: boolean; + /** + * Whether to show the hint that reasoning summaries are hidden. Always false while `experimentSettled` is false. + */ + showHiddenHint: boolean; + /** + * Whether the supplied `persistedShowReasoning` setting only restates the model default. This reports a redundancy, not a standing instruction to delete the setting: it stays true for as long as the setting and the model default agree, including for a user who later chose that value deliberately. It exists for a one-time migration of a legacy setting written before the model default made it redundant, so a host that acts on it owns the cleanup and must gate it behind its own persisted `done` marker, delete only a setting whose value still matches the one it read, and never repeat the deletion on a later launch. Under an off-by-default reasoning-summaries experiment an explicit `showReasoning: true` opt-in also reads as redundant on a summary-producing model, so an ungated host would keep deleting that opt-in and hide summaries again on every launch. + */ + clearRedundantSetting: boolean; } /** - * Provider model inventory request parameters. + * List of Copilot models available to the resolved user, including capabilities and billing metadata. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelProviderModelsListRequest". + * via the `definition` "ModelList". */ /** @experimental */ -export interface ModelProviderModelsListRequest { - instance: ModelProviderInstanceReference; +export interface ModelList { + /** + * List of available models with full metadata + */ + models: Model[]; } -/** - * A discovered instance and one of its models to translate into provider configuration. Pass back the instance and model as returned by `session.providers.discover` and `session.providers.models.list`. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelProviderPrepareConfigurationRequest". - */ + /** @experimental */ -export interface ModelProviderPrepareConfigurationRequest { - instance: ModelProviderInstance; - model: DiscoveredModel; +export interface ModelPickerPersistenceRequest { + settingsContext: ModelPickerSettingsContext; + /** + * Whether reasoning effort was explicitly selected and should be persisted. + */ + reasoningEffortExplicit?: boolean; + /** + * Whether context tier was explicitly selected and should be persisted. + */ + contextTierExplicit?: boolean; } /** - * Current health information for a provider instance. + * Filesystem and environment context used to resolve model-picker settings. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelProviderStatus". + * via the `definition` "ModelPickerSettingsContext". */ /** @experimental */ -export interface ModelProviderStatus { - outcome: ModelProviderOperationOutcome; - instance: ModelProviderInstance; +export interface ModelPickerSettingsContext { /** - * Open provider status value, such as `healthy`, `unreachable`, or `notInstalled`. + * Optional Copilot configuration directory containing persisted settings. */ - status: string; + configDir?: string; /** - * Provider-reported version. + * User home directory used when resolving persisted settings. */ - version?: string; + homeDirectory: string; + /** + * Environment variables consulted while resolving model-picker settings. + */ + environment: {}; } /** - * Host-supplied exact model selection IDs to allow for this running session. CAPI IDs are intersected with repository `.github/allowed_models.txt` policy; provider-qualified IDs remain exempt from repository-only policy but are restricted by this host list. Omit or pass null to clear the host restriction; an explicit empty or disjoint list is rejected. Validation and pre-selection fallback failures preserve the previous restriction. Failures after a fallback selection commits retain the new restriction and selected model; callers should inspect current session state after such an error. + * Normalized model-provider adapter definitions available to the session, not discovered instances. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelSetAllowedModelsRequest". + * via the `definition` "ModelProviderAdapterCatalog". */ /** @experimental */ -export interface ModelSetAllowedModelsRequest { +export interface ModelProviderAdapterCatalog { /** - * Exact model IDs to permit, or null to clear the host restriction. + * Available provider adapters ordered by adapterId. */ - allowedModels?: string[] | null; + providers: ModelProviderAdapterDescriptor[]; } /** - * The applied host allowlist and effective session model policy after intersection. + * A normalized model-provider adapter in the session's effective catalog. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelSetAllowedModelsResult". + * via the `definition` "ModelProviderAdapterDescriptor". */ /** @experimental */ -export interface ModelSetAllowedModelsResult { +export interface ModelProviderAdapterDescriptor { /** - * Normalized host allowlist. Omitted when the host restriction was cleared, or when a relay client does not return the host policy. + * Stable opaque identity for routing to this adapter. Unique in the effective catalog, independent of live registration generations. */ - allowedModels?: string[]; + adapterId: string; /** - * Effective exact IDs or repository policy patterns after applying the host restriction. Omitted by relay clients that do not return the host policy. + * Descriptive provider family, such as `ollama`. Different adapters may have the same family; use adapterId for routing. */ - effectiveAllowedModels?: string[]; + providerKind: string; /** - * Effective deterministic fallback model, when the policy defines one. + * Human-readable provider name. */ - fallbackModel?: string; + displayName: string; + provenance: ModelProviderAttribution; + automaticDiscovery: ModelProviderAutomaticDiscoveryPolicy; /** - * Selected session model after reconciling a now-disallowed concrete selection. + * Operations supported by this provider adapter. */ - modelId?: string; + operations: ModelProviderAdapterOperationDescriptor[]; } /** - * Reasoning effort level to apply to the currently selected model. + * Contributor attribution, independent of routing identity and authorization. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelSetReasoningEffortRequest". + * via the `definition` "ModelProviderAttribution". */ /** @experimental */ -export interface ModelSetReasoningEffortRequest { +export interface ModelProviderAttribution { + source: ModelProviderProvenanceSource; /** - * Reasoning effort level to apply to the currently selected model. The host is responsible for validating the value against the model's supported levels before calling. + * Stable contributor identifier. Required and nonblank for extension and custom sources; optional for built-in and configured sources. Does not grant authority. */ - reasoningEffort: string; + ownerId?: string; + /** + * Human-readable contributor name, not the adapter display name. + */ + ownerDisplayName?: string; } /** - * Update the session's reasoning effort without changing the selected model. Use `switchTo` instead when you also need to change the model. The runtime stores the effort on the session and applies it to subsequent turns. + * Adapter-declared policy that tells clients whether discovery may run automatically. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelSetReasoningEffortResult". + * via the `definition` "ModelProviderAutomaticDiscoveryPolicy". */ /** @experimental */ -export interface ModelSetReasoningEffortResult { - /** - * Reasoning effort level recorded on the session after the update - */ - reasoningEffort: string; -} - -/** @experimental */ -export interface ModelsListRequest { +export interface ModelProviderAutomaticDiscoveryPolicy { + mode: ModelProviderAutomaticDiscoveryMode; + networkScope: ModelProviderDiscoveryNetworkScope; /** - * Opaque account identifier returned by `account.getAllUsers`. When omitted, the current account is used. + * True when discovery requires non-null caller input. Omission or null is rejected before adapter execution. When false, omitted or null input selects adapter defaults without schema validation. */ - selectionId?: string; + requiresInput: boolean; /** - * GitHub token accepted for compatibility with existing SDK clients. When provided, resolves this token instead of using the current account. + * True when the adapter must be enabled by a trusted owner, such as a trusted extension, before automatic discovery may run. */ - gitHubToken?: string; + requiresTrust: boolean; } /** - * An Auto preference request for the session. This updates Auto configuration only; it does not change the selected model to `auto`. + * An operation supported by a model-provider adapter. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelSwitchAutoTierRequest". + * via the `definition` "ModelProviderAdapterOperationDescriptor". */ /** @experimental */ -export interface ModelSwitchAutoTierRequest { +export interface ModelProviderAdapterOperationDescriptor { /** - * Auto preference to activate when a future user turn using the `auto` model safely mints a replacement model and token pair. Pass null to return to provider-default Auto routing. + * Supported operation name: `discover`, `getStatus`, or `models.list`. Unknown names and duplicate declarations are rejected. */ - autoTier: AutoTier | null; - source?: ModelChangeSource; + name: string; + /** + * Optional self-contained JSON Schema Draft 7 for non-null discovery input. Only supported on discover. No external references are resolved. Omitted or null input selects defaults when requiresInput is false. Without a schema, the adapter validates supplied input. + */ + inputSchema?: JsonValue; } /** - * Immediate acknowledgement and Auto preference snapshot after a switch request. This result never implies that a pending preference committed. + * Provider configuration prepared from a discovered model. Preparing a plan changes nothing: it neither registers the model with the session nor writes durable configuration. To apply it, pass `provider` and `model` to `session.provider.add`, omitting whichever the dispositions report as already configured. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelSwitchAutoTierResult". + * via the `definition` "ModelProviderConfigurationPlan". */ /** @experimental */ -export interface ModelSwitchAutoTierResult { - status: ModelSwitchAutoTierStatus; - effectiveAutoTier?: AutoTier; - /** - * Latest unclaimed Auto preference waiting for a future user turn. - */ - pendingAutoTier?: AutoTier | null; - /** - * Auto preference currently claimed by an in-progress activation. Null means the activation is returning to provider-default routing. - */ - activatingAutoTier?: AutoTier | null; - /** - * Earlier unclaimed preference replaced by this request. This can be present with either status, including when selecting the effective preference cancels pending work. - */ - supersededAutoTier?: AutoTier | null; -} - -/** @experimental */ -export interface ModelSwitchConfirmation { - /** - * Display name of the model that requires compaction confirmation. - */ - targetModelDisplayName: string; +export interface ModelProviderConfigurationPlan { + provider: NamedProviderConfig; + model: ProviderModelConfig; /** - * Current conversation token count before switching models. + * Provider-qualified selection id (`provider/id`) to pass to `switchTo` once the plan is applied. */ - currentTokens: number; + selectionId: string; + providerDisposition: ModelProviderConfigurationDisposition; + modelDisposition: ModelProviderConfigurationDisposition; /** - * Target model token limit used by the compaction preflight. + * Non-fatal warnings carried over from the discovered model, such as capabilities the provider did not report. */ - targetLimit: number; + warnings: ModelProviderWarning[]; } /** - * Target model identifier and optional reasoning effort, summary, capability overrides, and context tier. + * External SDK input for a named custom model provider. Ingested by the native protocol boundary before host dispatch. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelSwitchToRequest". + * via the `definition` "NamedProviderConfig". */ /** @experimental */ -export interface ModelSwitchToRequest { - /** - * Model id to switch to, as returned by `list`. Include providerId to select an exact catalog entry when providers share the id. Without providerId, a bare id retains incumbent selection behavior; a registry-qualified id (`provider/id`, e.g. `acme/claude-sonnet`) targets a BYOK model. - */ - modelId: string; - /** - * Provider id from the selected list entry's provider reference. Selects this exact provider/model pair; an unavailable pair fails rather than using another provider. Omit for deterministic legacy bare-model selection. - */ - providerId?: string; - /** - * Optional Auto routing preference to stage atomically with selecting `auto`. Pass null to return to provider-default Auto routing. This field is rejected when `modelId` is not `auto`. - */ - autoTier?: AutoTier | null; - /** - * Reasoning effort level to use for the model. CAPI values are model-defined and validated against the selected model; BYOK providers may define additional values. "none" disables reasoning. Pass null to clear any session effort override and fall back to the model's default. When omitted, the session's current effort is kept. - */ - reasoningEffort?: string | null; - reasoningSummary?: ReasoningSummary; - verbosity?: Verbosity; - modelCapabilities?: ModelCapabilitiesOverride; - contextTier?: ContextTier; - source?: ModelChangeSource; +export interface NamedProviderConfig { /** - * When true, defer this switch (enqueue it) if another model change is already queued, even when no turn is active — so it drains last (FIFO) and wins over the already-queued change. Intended for genuine user-initiated model selections; internal restore/reapply switches omit it and apply immediately when no turn is active. When no other model change is queued this has no effect (a switch still applies immediately unless a turn is active). + * Unique provider name used to qualify model selection IDs. */ - deferIfModelChangeQueued?: boolean; + name: string; + type?: ProviderConfigType; + wireApi?: ProviderConfigWireApi; + transport?: ProviderConfigTransport; /** - * Explicit response to a model-switch compaction preflight. Omit to request a confirmation projection when compaction is necessary. + * Base URL for provider API requests. */ - compactionDecision?: string; + baseUrl: string; /** - * When true, evaluate context-window compaction policy before applying the switch. + * Static API key used to authenticate provider requests. */ - runCompactionPreflight?: boolean; + apiKey?: string; /** - * Optional repository settings scope to persist after the switch commits. + * Static bearer token used to authenticate provider requests. */ - repoScope?: string; + bearerToken?: string; + azure?: ProviderConfigAzure; /** - * Settings scope used when persisting the selected model. + * Additional HTTP headers included with provider requests. */ - modelChangeScope?: string; + headers?: { + [k: string]: string | undefined; + }; + modelProvider?: ProviderConfigModelProvider; /** - * Require the target to be currently available and enabled before applying the switch. + * Whether the host supplies bearer tokens dynamically. */ - requireAvailable?: boolean; - pickerPersistence?: ModelPickerPersistenceRequest; + hasBearerTokenProvider?: boolean; } /** - * The model identifier active on the session after the switch. + * Azure-specific provider options. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelSwitchToResult". + * via the `definition` "ProviderConfigAzure". */ /** @experimental */ -export interface ModelSwitchToResult { - /** - * Stable queue item identifier when this request was enqueued. Remains present if the item drains before the response is returned. - */ - queueId?: string; - /** - * Currently active model identifier after the switch - */ - modelId?: string; - /** - * True when the switch was deferred (enqueued as a cancellable `/model` command) because a turn was active or another model change was already queued, rather than applied immediately. When true, the session's live model is unchanged until the queued change drains. - */ - deferred?: boolean; - /** - * Lifecycle result for the requested switch - */ - status?: string; - confirmation?: ModelSwitchConfirmation; - /** - * Persistence failure encountered after applying the model switch. - */ - persistenceError?: string; - /** - * User-facing outcome message for the model switch. - */ - message?: string; - /** - * User-facing warning produced while applying the model switch. - */ - warning?: string; +export interface ProviderConfigAzure { /** - * Deprecation warnings associated with the selected model or options. + * API version. When set, uses the versioned deployment route. When omitted, uses the GA versionless v1 route. */ - deprecationWarnings?: string[]; - modelState?: CurrentModel; + apiVersion?: string; } /** - * Agent interaction mode to apply to the session. + * A BYOK model definition referencing a named provider. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModeSetRequest". + * via the `definition` "ProviderModelConfig". */ /** @experimental */ -export interface ModeSetRequest { - mode: SessionMode; - expectedMode?: SessionMode; +export interface ProviderModelConfig { /** - * Session whose plan-mode base state should be inherited. + * Provider-local model id, unique within its provider. The session-wide selection id (shown in the model list and passed to switchTo) is the provider-qualified `provider/id`. */ - inheritPlanBaseFromSessionId?: string; + id: string; /** - * Whether a dedicated plan model is configured. + * Name of the configured provider that serves this model. */ - planModelConfigured?: boolean; + provider: string; /** - * Dedicated model to use in plan mode, when configured. + * The model name sent to the provider API for inference. Defaults to `id`. */ - planModel?: string; + wireModel?: string; /** - * Provider owning planModel. Omit for legacy bare-model selection. + * Well-known base model id used for behavior/capability/config lookup. Defaults to `id`. */ - planModelProviderId?: string; + modelId?: string; /** - * Reasoning effort to use with the dedicated plan model. + * Display name for model pickers. Defaults to the provider-qualified selection id (`provider/id`). */ - planReasoningEffort?: string; + name?: string; /** - * Context tier to use with the dedicated plan model. + * Maximum prompt/input tokens for the model. */ - planContextTier?: string; + maxPromptTokens?: number; /** - * Explicit response to a model-switch compaction preflight. + * Maximum context window tokens for the model. */ - compactionDecision?: string; + maxContextWindowTokens?: number; /** - * Whether leaving plan mode should restore the session's previous model. + * Maximum output tokens for the model. */ - restorePlanModel?: boolean; + maxOutputTokens?: number; + capabilities?: ModelCapabilitiesOverride; + systemMessage?: ProtocolSystemMessageConfig; /** - * Whether the selected plan model should be persisted. + * Provider-published model metadata, preserved verbatim as the public Model.metadata object. */ - persistPlanSelection?: boolean; - pickerSettingsContext?: ModelPickerSettingsContext; + metadata?: { + [k: string]: JsonValue | undefined; + }; +} + +/** @experimental */ +export interface ProtocolSystemMessageAppendConfig { + mode?: ProtocolAppendMode; /** - * Action to perform when leaving plan mode. + * Text appended to the standard system prompt. */ - planExitAction?: string; + content?: string; } -/** - * Outcome of a session mode change, including any model switch it triggered and follow-up the host must perform. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModeSetResult". - */ + /** @experimental */ -export interface ModeSetResult { +export interface ProtocolSystemMessageReplaceConfig { + mode: ProtocolReplaceMode; /** - * Lifecycle status of the requested mode change. + * Complete replacement system-message text. */ - status: string; + content: string; /** - * Whether applying the mode changed the active model. + * Optional structured blocks corresponding to the replacement content. */ - modelChanged: boolean; + contentBlocks?: SystemMessageBlock[]; +} + +/** @experimental */ +export interface SystemMessageBlock { /** - * Whether the requested mode was applied to the session. False only when an 'expectedMode' precondition did not hold, in which case any model change reported alongside it was still applied. + * Text content for this system-message block. */ - modeApplied?: boolean; - confirmation?: ModelSwitchConfirmation; + content: string; /** - * User-facing warning produced while applying the mode change. + * Whether the block is static and may be cached independently of dynamic prompt content. */ - warning?: string; + isStatic?: boolean; /** - * User-facing outcome message for the model switch triggered by the mode change. + * Whether providers with explicit prompt caching should place a cache breakpoint after this block. */ - message?: string; + cacheBreakpoint?: boolean; +} + +/** @experimental */ +export interface ProtocolSystemMessageCustomizeConfig { + mode: ProtocolCustomizeMode; /** - * Deprecation warnings associated with the model selected by the mode change. + * Named standard-prompt section overrides. */ - deprecationWarnings?: string[]; + sections?: { + [k: string]: ProtocolSectionOverride | undefined; + }; /** - * Whether the host must defer implementing the requested mode change. + * Text appended after the customized sections. */ - deferImplementation?: boolean; + content?: string; +} + +/** @experimental */ +export interface ProtocolStaticSectionOverride { + action: ProtocolStaticSectionAction; /** - * Whether the host should arm an interactive continuation after the mode change. + * Optional content used by replace, append, and prepend operations. */ - armInteractiveContinuation?: boolean; + content?: string; } /** - * Result of moving in-flight MCP loading to the background. + * One model provider available to the session — the model analog of the account `ProviderDescriptor`. Opaque id/label/kind plus a stable ordering; central code never branches on kind. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "MoveMcpLoadingToBackgroundResult". + * via the `definition` "ModelProviderDescriptor". */ /** @experimental */ -export interface MoveMcpLoadingToBackgroundResult { +export interface ModelProviderDescriptor { + kind: ModelProviderKind; /** - * Whether an in-flight MCP load was moved to the background, releasing turns that were waiting on it. False when no MCP load was in flight or the waiting turns had already been released. + * Opaque, stable provider id, stamped onto every model this provider returns. */ - movedToBackground: boolean; -} -/** - * The session's friendly name, or null when not yet set. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "NameGetResult". - */ -/** @experimental */ -export interface NameGetResult { + id: string; /** - * The session name (user-set or auto-generated), or null if not yet set + * Human-readable menu label, owned by the runtime so every consumer renders identical text. */ - name: string | null; -} -/** - * Auto-generated session summary to apply as the session's name when no user-set name exists. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "NameSetAutoRequest". - */ -/** @experimental */ -export interface NameSetAutoRequest { + label: string; /** - * Auto-generated session summary. Empty/whitespace-only values are ignored; values are trimmed before persisting. + * Stable ordering key for presenting providers in a deterministic sequence. */ - summary: string; + ordering: number; } /** - * Indicates whether the auto-generated summary was applied as the session's name. + * Provider discovery parameters. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "NameSetAutoResult". + * via the `definition` "ModelProviderDiscoverRequest". */ /** @experimental */ -export interface NameSetAutoResult { +export interface ModelProviderDiscoverRequest { /** - * Whether the auto-generated summary was persisted. False if the session already has a user-set name, the summary normalized to empty, or the session does not have a workspace. + * Opaque adapter identity returned by `session.providers.getCatalog`. */ - applied: boolean; + adapterId: string; + /** + * Provider-specific JSON input. Omission or null selects adapter defaults unless requiresInput is true. Non-null input is validated against the advertised Draft 7 schema when present; otherwise validation belongs to the adapter. + */ + input?: JsonValue; } /** - * New friendly name to apply to the session. + * Provider instances found by a discovery operation. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "NameSetRequest". + * via the `definition` "ModelProviderDiscoverResult". */ /** @experimental */ -export interface NameSetRequest { +export interface ModelProviderDiscoverResult { + outcome: ModelProviderOperationOutcome; /** - * New session name (1–100 characters, trimmed of leading/trailing whitespace) + * Discovered provider instances. Empty when passive default discovery finds no reachable provider. */ - name: string; + instances: ModelProviderInstance[]; } /** - * Content-exclusion policy supplied to `session.options.update`, with rules, last-updated data, and scope. + * A normalized model-provider instance discovered by the runtime. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "OptionsUpdateAdditionalContentExclusionPolicy". + * via the `definition` "ModelProviderInstance". */ /** @experimental */ -export interface OptionsUpdateAdditionalContentExclusionPolicy { +export interface ModelProviderInstance { + reference: ModelProviderInstanceReference; /** - * Content-exclusion rules to apply. + * Human-readable instance name. */ - rules: OptionsUpdateAdditionalContentExclusionPolicyRule[]; + displayName: string; + provenance: ModelProviderProvenance; /** - * Opaque policy update timestamp supplied by the host. + * Inference API endpoint when the provider exposes one separately from its management endpoint. */ - last_updated_at: JsonValue; - scope: OptionsUpdateAdditionalContentExclusionPolicyScope; + inferenceEndpoint?: string; + inferenceType?: ProviderEndpointType; + inferenceWireApi?: ProviderEndpointWireApi; + inferenceTransport?: ProviderEndpointTransport; } /** - * Single content-exclusion rule supplied to `session.options.update`, with paths, match conditions, and source. + * Serializable reference to a discovered provider instance. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "OptionsUpdateAdditionalContentExclusionPolicyRule". + * via the `definition` "ModelProviderInstanceReference". */ /** @experimental */ -export interface OptionsUpdateAdditionalContentExclusionPolicyRule { +export interface ModelProviderInstanceReference { /** - * Path patterns covered by this rule. + * Stable opaque identity of the adapter that owns this reference. Must be present in the target session's effective catalog. */ - paths: string[]; + adapterId: string; /** - * Conditions of which at least one must match. + * Descriptive provider family. Must match the selected adapter; not a routing key. */ - ifAnyMatch?: string[]; + providerKind: string; /** - * Conditions none of which may match. + * Stable instance identifier derived by the provider adapter, such as `ollama:{normalizedEndpoint}`. */ - ifNoneMatch?: string[]; - source: OptionsUpdateAdditionalContentExclusionPolicyRuleSource; + id: string; + /** + * Absolute provider management URI. The adapter validates normalization, supported schemes, and permission to access it against its bound configuration; a reference does not grant authority. + */ + managementEndpoint: string; } /** - * Source descriptor for a `session.options.update` content-exclusion rule, with source name and type. + * Provider status request parameters. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "OptionsUpdateAdditionalContentExclusionPolicyRuleSource". + * via the `definition` "ModelProviderGetStatusRequest". */ /** @experimental */ -export interface OptionsUpdateAdditionalContentExclusionPolicyRuleSource { - /** - * Name of the policy source. - */ - name: string; - /** - * Type of the policy source. - */ - type: string; +export interface ModelProviderGetStatusRequest { + instance: ModelProviderInstanceReference; } /** - * External tool call of the session or one of its sub-agents that is still waiting for session.tools.handlePendingToolCall. + * Provider model inventory request parameters. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PendingExternalToolRequest". + * via the `definition` "ModelProviderModelsListRequest". */ /** @experimental */ -export interface PendingExternalToolRequest { - /** - * Request ID to pass to session.tools.handlePendingToolCall - */ - requestId: string; - /** - * Tool call ID assigned to this external tool invocation - */ - toolCallId: string; - /** - * Name of the external tool to invoke - */ - toolName: string; - /** - * Arguments to pass to the external tool - */ - arguments?: JsonValue; - /** - * Stable identity of the provider that offered the tool, for hosts that route extension-owned tools by provider - */ - providerId?: string; - /** - * Sub-agent instance identifier (the envelope agentId of its events) of the agent that issued the call; absent for calls issued by the root agent - */ - agentId?: string; +export interface ModelProviderModelsListRequest { + instance: ModelProviderInstanceReference; } /** - * External tool calls still waiting for a result. + * A discovered instance and one of its models to translate into provider configuration. Pass back the instance and model as returned by `session.providers.discover` and `session.providers.models.list`. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PendingExternalToolRequestList". + * via the `definition` "ModelProviderPrepareConfigurationRequest". */ /** @experimental */ -export interface PendingExternalToolRequestList { - /** - * External tool calls of the session and its sub-agents that session.tools.handlePendingToolCall would still accept, in the order they were requested. Includes calls that were pending when the session was last suspended and resumed with pending work continued, so a host that did not observe the original external_tool.requested event can answer them. - */ - items: PendingExternalToolRequest[]; +export interface ModelProviderPrepareConfigurationRequest { + instance: ModelProviderInstance; + model: DiscoveredModel; } /** - * Pending permission prompt reconstructed from event history, with request ID and user-facing prompt details. + * Current health information for a provider instance. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PendingPermissionRequest". + * via the `definition` "ModelProviderStatus". */ /** @experimental */ -export interface PendingPermissionRequest { +export interface ModelProviderStatus { + outcome: ModelProviderOperationOutcome; + instance: ModelProviderInstance; /** - * Unique identifier for the pending permission request + * Open provider status value, such as `healthy`, `unreachable`, or `notInstalled`. */ - requestId: string; - request: PermissionPromptRequest; + status: string; /** - * Permission-recovery episode that authorized this request to surface for interactive attention + * Provider-reported version. */ - recoveryEpisodeId?: string; + version?: string; } /** - * List of pending permission requests reconstructed from event history. + * Host-supplied exact model selection IDs to allow for this running session. CAPI IDs are intersected with repository `.github/allowed_models.txt` policy; provider-qualified IDs remain exempt from repository-only policy but are restricted by this host list. Omit or pass null to clear the host restriction; an explicit empty or disjoint list is rejected. Validation and pre-selection fallback failures preserve the previous restriction. Failures after a fallback selection commits retain the new restriction and selected model; callers should inspect current session state after such an error. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PendingPermissionRequestList". + * via the `definition` "ModelSetAllowedModelsRequest". */ /** @experimental */ -export interface PendingPermissionRequestList { +export interface ModelSetAllowedModelsRequest { /** - * Pending permission prompts reconstructed from the session's event history. Equivalent to the set of `permission.requested` events that have not yet been followed by a matching `permission.completed` event. Used by clients (e.g. the CLI) to hydrate UI for prompts that were emitted before the client attached to the session. + * Exact model IDs to permit, or null to clear the host restriction. */ - items: PendingPermissionRequest[]; + allowedModels?: string[] | null; } /** - * Permission-decision request variant to approve only the current permission request. + * The applied host allowlist and effective session model policy after intersection. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveOnce". + * via the `definition` "ModelSetAllowedModelsResult". */ /** @experimental */ -export interface PermissionDecisionApproveOnce { +export interface ModelSetAllowedModelsResult { /** - * Approve this single request only + * Normalized host allowlist. Omitted when the host restriction was cleared, or when a relay client does not return the host policy. */ - kind: "approve-once"; + allowedModels?: string[]; /** - * True only when a host surfaced this request to a user who approved it. + * Effective exact IDs or repository policy patterns after applying the host restriction. Omitted by relay clients that do not return the host policy. */ - approvedInteractively?: boolean; + effectiveAllowedModels?: string[]; + /** + * Effective deterministic fallback model, when the policy defines one. + */ + fallbackModel?: string; + /** + * Selected session model after reconciling a now-disallowed concrete selection. + */ + modelId?: string; } /** - * Permission-decision request variant to approve for the rest of the session, with optional tool approval or URL domain. + * Reasoning effort level to apply to the currently selected model. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForSession". + * via the `definition` "ModelSetReasoningEffortRequest". */ /** @experimental */ -export interface PermissionDecisionApproveForSession { - /** - * Approve and remember for the rest of the session - */ - kind: "approve-for-session"; - approval?: PermissionDecisionApproveForSessionApproval; +export interface ModelSetReasoningEffortRequest { /** - * URL domain to approve for the rest of the session (URL prompts only) + * Reasoning effort level to apply to the currently selected model. The host is responsible for validating the value against the model's supported levels before calling. */ - domain?: string; + reasoningEffort: string; } /** - * Session-scoped approval details for specific command identifiers. + * Update the session's reasoning effort without changing the selected model. Use `switchTo` instead when you also need to change the model. The runtime stores the effort on the session and applies it to subsequent turns. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForSessionApprovalCommands". + * via the `definition` "ModelSetReasoningEffortResult". */ /** @experimental */ -export interface PermissionDecisionApproveForSessionApprovalCommands { +export interface ModelSetReasoningEffortResult { /** - * Approval scoped to specific command identifiers. + * Reasoning effort level recorded on the session after the update */ - kind: "commands"; + reasoningEffort: string; +} + +/** @experimental */ +export interface ModelsListRequest { /** - * Command identifiers covered by this approval. + * Opaque account identifier returned by `account.getAllUsers`. When omitted, the current account is used. */ - commandIdentifiers: string[]; + selectionId?: string; + /** + * GitHub token accepted for compatibility with existing SDK clients. When provided, resolves this token instead of using the current account. + */ + gitHubToken?: string; } /** - * Session-scoped approval details for read-only filesystem operations. + * An Auto preference request for the session. This updates Auto configuration only; it does not change the selected model to `auto`. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForSessionApprovalRead". + * via the `definition` "ModelSwitchAutoTierRequest". */ /** @experimental */ -export interface PermissionDecisionApproveForSessionApprovalRead { +export interface ModelSwitchAutoTierRequest { /** - * Approval covering read-only filesystem operations. + * Auto preference to activate when a future user turn using the `auto` model safely mints a replacement model and token pair. Pass null to return to provider-default Auto routing. */ - kind: "read"; + autoTier: AutoTier | null; + source?: ModelChangeSource; } /** - * Session-scoped approval details for filesystem write operations. + * Immediate acknowledgement and Auto preference snapshot after a switch request. This result never implies that a pending preference committed. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForSessionApprovalWrite". + * via the `definition` "ModelSwitchAutoTierResult". */ /** @experimental */ -export interface PermissionDecisionApproveForSessionApprovalWrite { +export interface ModelSwitchAutoTierResult { + status: ModelSwitchAutoTierStatus; + effectiveAutoTier?: AutoTier; /** - * Approval covering filesystem write operations. + * Latest unclaimed Auto preference waiting for a future user turn. */ - kind: "write"; + pendingAutoTier?: AutoTier | null; + /** + * Auto preference currently claimed by an in-progress activation. Null means the activation is returning to provider-default routing. + */ + activatingAutoTier?: AutoTier | null; + /** + * Earlier unclaimed preference replaced by this request. This can be present with either status, including when selecting the effective preference cancels pending work. + */ + supersededAutoTier?: AutoTier | null; } -/** - * Session-scoped approval details for an MCP server tool, or all tools on the server when `toolName` is null. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForSessionApprovalMcp". - */ + /** @experimental */ -export interface PermissionDecisionApproveForSessionApprovalMcp { +export interface ModelSwitchConfirmation { /** - * Approval covering an MCP tool. + * Display name of the model that requires compaction confirmation. */ - kind: "mcp"; + targetModelDisplayName: string; /** - * MCP server name. + * Current conversation token count before switching models. */ - serverName: string; + currentTokens: number; /** - * MCP tool name, or null to cover every tool on the server. + * Target model token limit used by the compaction preflight. */ - toolName: string | null; + targetLimit: number; } /** - * Session-scoped approval details for MCP sampling requests from a server. + * Target model identifier and optional reasoning effort, summary, capability overrides, and context tier. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForSessionApprovalMcpSampling". + * via the `definition` "ModelSwitchToRequest". */ /** @experimental */ -export interface PermissionDecisionApproveForSessionApprovalMcpSampling { +export interface ModelSwitchToRequest { /** - * Approval covering MCP sampling requests for a server. + * Model id to switch to, as returned by `list`. Include providerId to select an exact catalog entry when providers share the id. Without providerId, a bare id retains incumbent selection behavior; a registry-qualified id (`provider/id`, e.g. `acme/claude-sonnet`) targets a BYOK model. */ - kind: "mcp-sampling"; + modelId: string; /** - * MCP server name. + * Provider id from the selected list entry's provider reference. Selects this exact provider/model pair; an unavailable pair fails rather than using another provider. Omit for deterministic legacy bare-model selection. */ - serverName: string; -} -/** - * Session-scoped approval details for writes to long-term memory. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForSessionApprovalMemory". - */ -/** @experimental */ -export interface PermissionDecisionApproveForSessionApprovalMemory { + providerId?: string; /** - * Approval covering writes to long-term memory. + * Optional Auto routing preference to stage atomically with selecting `auto`. Pass null to return to provider-default Auto routing. This field is rejected when `modelId` is not `auto`. */ - kind: "memory"; -} -/** - * Session-scoped approval details for a custom tool, keyed by tool name. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForSessionApprovalCustomTool". - */ -/** @experimental */ -export interface PermissionDecisionApproveForSessionApprovalCustomTool { + autoTier?: AutoTier | null; /** - * Approval covering a custom tool. + * Reasoning effort level to use for the model. CAPI values are model-defined and validated against the selected model; BYOK providers may define additional values. "none" disables reasoning. Pass null to clear any session effort override and fall back to the model's default. When omitted, the session's current effort is kept. */ - kind: "custom-tool"; + reasoningEffort?: string | null; + reasoningSummary?: ReasoningSummary; + verbosity?: Verbosity; + modelCapabilities?: ModelCapabilitiesOverride; + contextTier?: ContextTier; + source?: ModelChangeSource; /** - * Custom tool name. + * When true, defer this switch (enqueue it) if another model change is already queued, even when no turn is active — so it drains last (FIFO) and wins over the already-queued change. Intended for genuine user-initiated model selections; internal restore/reapply switches omit it and apply immediately when no turn is active. When no other model change is queued this has no effect (a switch still applies immediately unless a turn is active). */ - toolName: string; -} -/** - * Session-scoped approval details for extension-management operations, optionally narrowed by operation. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForSessionApprovalExtensionManagement". - */ -/** @experimental */ -export interface PermissionDecisionApproveForSessionApprovalExtensionManagement { + deferIfModelChangeQueued?: boolean; /** - * Approval covering extension lifecycle operations such as enable, disable, or reload. + * Explicit response to a model-switch compaction preflight. Omit to request a confirmation projection when compaction is necessary. */ - kind: "extension-management"; + compactionDecision?: string; /** - * Optional operation identifier; when omitted, the approval covers all extension management operations. + * When true, evaluate context-window compaction policy before applying the switch. */ - operation?: string; -} -/** - * Session-scoped workflow approval, optionally narrowed by approval key. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForSessionApprovalWorkflow". - */ -/** @experimental */ -export interface PermissionDecisionApproveForSessionApprovalWorkflow { + runCompactionPreflight?: boolean; /** - * Approval covering workflow operations. + * Optional repository settings scope to persist after the switch commits. */ - kind: "workflow"; + repoScope?: string; /** - * Optional workflow operation name or canonical approval key; when omitted, the approval covers all workflow operations. + * Settings scope used when persisting the selected model. */ - approvalKey?: string; + modelChangeScope?: string; + /** + * Require the target to be currently available and enabled before applying the switch. + */ + requireAvailable?: boolean; + pickerPersistence?: ModelPickerPersistenceRequest; } /** - * Session-scoped approval details for an extension's permission-gated capability access, keyed by extension name. + * The model identifier active on the session after the switch. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess". + * via the `definition` "ModelSwitchToResult". */ /** @experimental */ -export interface PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess { +export interface ModelSwitchToResult { /** - * Approval covering an extension's request to access a permission-gated capability. + * Stable queue item identifier when this request was enqueued. Remains present if the item drains before the response is returned. */ - kind: "extension-permission-access"; + queueId?: string; /** - * Extension name. + * Currently active model identifier after the switch */ - extensionName: string; -} -/** - * Session-scoped approval details for an extension's access to sensitive environment variables, keyed by extension name and the exact set of variable names. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForSessionApprovalExtensionEnvAccess". - */ -/** @experimental */ -export interface PermissionDecisionApproveForSessionApprovalExtensionEnvAccess { + modelId?: string; /** - * Approval covering an extension's request to read sensitive environment variables. + * True when the switch was deferred (enqueued as a cancellable `/model` command) because a turn was active or another model change was already queued, rather than applied immediately. When true, the session's live model is unchanged until the queued change drains. */ - kind: "extension-env-access"; + deferred?: boolean; /** - * Extension name. + * Lifecycle result for the requested switch */ - extensionName: string; + status?: string; + confirmation?: ModelSwitchConfirmation; /** - * Names of the sensitive environment variables this approval covers. Values are never persisted. - * - * @minItems 1 + * Persistence failure encountered after applying the model switch. */ - environmentVariables: [string, ...string[]]; -} -/** - * Approve file-tool read access to specific directories for this logical session, including continuation or resume. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveReadOnlyForSession". - */ -/** @experimental */ -export interface PermissionDecisionApproveReadOnlyForSession { + persistenceError?: string; /** - * Approve read-only file-tool directory access for this session + * User-facing outcome message for the model switch. */ - kind: "approve-read-only-for-session"; + message?: string; /** - * Canonical directories covered by the read-only grant - * - * @minItems 1 + * User-facing warning produced while applying the model switch. */ - directories: [string, ...string[]]; + warning?: string; + /** + * Deprecation warnings associated with the selected model or options. + */ + deprecationWarnings?: string[]; + modelState?: CurrentModel; } /** - * Permission-decision request variant to approve and persist a permission for a project location, with approval details and location key. + * Agent interaction mode to apply to the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForLocation". + * via the `definition` "ModeSetRequest". */ /** @experimental */ -export interface PermissionDecisionApproveForLocation { +export interface ModeSetRequest { + mode: SessionMode; + expectedMode?: SessionMode; /** - * Approve and persist for this project location + * Session whose plan-mode base state should be inherited. */ - kind: "approve-for-location"; - approval: PermissionDecisionApproveForLocationApproval; + inheritPlanBaseFromSessionId?: string; /** - * Location key (git root or cwd) to persist the approval to + * Whether a dedicated plan model is configured. */ - locationKey: string; -} -/** - * Location-scoped approval details for specific command identifiers. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForLocationApprovalCommands". - */ -/** @experimental */ -export interface PermissionDecisionApproveForLocationApprovalCommands { + planModelConfigured?: boolean; /** - * Approval scoped to specific command identifiers. + * Dedicated model to use in plan mode, when configured. */ - kind: "commands"; + planModel?: string; /** - * Command identifiers covered by this approval. + * Provider owning planModel. Omit for legacy bare-model selection. */ - commandIdentifiers: string[]; + planModelProviderId?: string; + /** + * Reasoning effort to use with the dedicated plan model. + */ + planReasoningEffort?: string; + /** + * Context tier to use with the dedicated plan model. + */ + planContextTier?: string; + /** + * Explicit response to a model-switch compaction preflight. + */ + compactionDecision?: string; + /** + * Whether leaving plan mode should restore the session's previous model. + */ + restorePlanModel?: boolean; + /** + * Whether the selected plan model should be persisted. + */ + persistPlanSelection?: boolean; + pickerSettingsContext?: ModelPickerSettingsContext; + /** + * Action to perform when leaving plan mode. + */ + planExitAction?: string; } /** - * Location-scoped approval details for read-only filesystem operations. + * Outcome of a session mode change, including any model switch it triggered and follow-up the host must perform. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForLocationApprovalRead". + * via the `definition` "ModeSetResult". */ /** @experimental */ -export interface PermissionDecisionApproveForLocationApprovalRead { +export interface ModeSetResult { /** - * Approval covering read-only filesystem operations. + * Lifecycle status of the requested mode change. */ - kind: "read"; -} -/** - * Location-scoped approval details for filesystem write operations. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForLocationApprovalWrite". - */ -/** @experimental */ -export interface PermissionDecisionApproveForLocationApprovalWrite { + status: string; /** - * Approval covering filesystem write operations. + * Whether applying the mode changed the active model. */ - kind: "write"; -} -/** - * Location-scoped approval details for an MCP server tool, or all tools on the server when `toolName` is null. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForLocationApprovalMcp". - */ -/** @experimental */ -export interface PermissionDecisionApproveForLocationApprovalMcp { + modelChanged: boolean; /** - * Approval covering an MCP tool. + * Whether the requested mode was applied to the session. False only when an 'expectedMode' precondition did not hold, in which case any model change reported alongside it was still applied. */ - kind: "mcp"; + modeApplied?: boolean; + confirmation?: ModelSwitchConfirmation; /** - * MCP server name. + * User-facing warning produced while applying the mode change. */ - serverName: string; + warning?: string; /** - * MCP tool name, or null to cover every tool on the server. + * User-facing outcome message for the model switch triggered by the mode change. */ - toolName: string | null; + message?: string; + /** + * Deprecation warnings associated with the model selected by the mode change. + */ + deprecationWarnings?: string[]; + /** + * Whether the host must defer implementing the requested mode change. + */ + deferImplementation?: boolean; + /** + * Whether the host should arm an interactive continuation after the mode change. + */ + armInteractiveContinuation?: boolean; } /** - * Location-scoped approval details for MCP sampling requests from a server. + * Result of moving in-flight MCP loading to the background. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForLocationApprovalMcpSampling". + * via the `definition` "MoveMcpLoadingToBackgroundResult". */ /** @experimental */ -export interface PermissionDecisionApproveForLocationApprovalMcpSampling { - /** - * Approval covering MCP sampling requests for a server. - */ - kind: "mcp-sampling"; +export interface MoveMcpLoadingToBackgroundResult { /** - * MCP server name. + * Whether an in-flight MCP load was moved to the background, releasing turns that were waiting on it. False when no MCP load was in flight or the waiting turns had already been released. */ - serverName: string; + movedToBackground: boolean; } /** - * Location-scoped approval details for writes to long-term memory. + * The session's friendly name, or null when not yet set. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForLocationApprovalMemory". + * via the `definition` "NameGetResult". */ /** @experimental */ -export interface PermissionDecisionApproveForLocationApprovalMemory { +export interface NameGetResult { /** - * Approval covering writes to long-term memory. + * The session name (user-set or auto-generated), or null if not yet set */ - kind: "memory"; + name: string | null; } /** - * Location-scoped approval details for a custom tool, keyed by tool name. + * Auto-generated session summary to apply as the session's name when no user-set name exists. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForLocationApprovalCustomTool". + * via the `definition` "NameSetAutoRequest". */ /** @experimental */ -export interface PermissionDecisionApproveForLocationApprovalCustomTool { - /** - * Approval covering a custom tool. - */ - kind: "custom-tool"; +export interface NameSetAutoRequest { /** - * Custom tool name. + * Auto-generated session summary. Empty/whitespace-only values are ignored; values are trimmed before persisting. */ - toolName: string; + summary: string; } /** - * Location-scoped approval details for extension-management operations, optionally narrowed by operation. + * Indicates whether the auto-generated summary was applied as the session's name. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForLocationApprovalExtensionManagement". + * via the `definition` "NameSetAutoResult". */ /** @experimental */ -export interface PermissionDecisionApproveForLocationApprovalExtensionManagement { - /** - * Approval covering extension lifecycle operations such as enable, disable, or reload. - */ - kind: "extension-management"; +export interface NameSetAutoResult { /** - * Optional operation identifier; when omitted, the approval covers all extension management operations. + * Whether the auto-generated summary was persisted. False if the session already has a user-set name, the summary normalized to empty, or the session does not have a workspace. */ - operation?: string; + applied: boolean; } /** - * Location-scoped workflow approval, optionally narrowed by approval key. + * New friendly name to apply to the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForLocationApprovalWorkflow". + * via the `definition` "NameSetRequest". */ /** @experimental */ -export interface PermissionDecisionApproveForLocationApprovalWorkflow { - /** - * Approval covering workflow operations. - */ - kind: "workflow"; +export interface NameSetRequest { /** - * Optional workflow operation name or canonical approval key; when omitted, the approval covers all workflow operations. + * New session name (1–100 characters, trimmed of leading/trailing whitespace) */ - approvalKey?: string; + name: string; } /** - * Location-scoped approval details for an extension's permission-gated capability access, keyed by extension name. + * Content-exclusion policy supplied to `session.options.update`, with rules, last-updated data, and scope. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess". + * via the `definition` "OptionsUpdateAdditionalContentExclusionPolicy". */ /** @experimental */ -export interface PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess { +export interface OptionsUpdateAdditionalContentExclusionPolicy { /** - * Approval covering an extension's request to access a permission-gated capability. + * Content-exclusion rules to apply. */ - kind: "extension-permission-access"; + rules: OptionsUpdateAdditionalContentExclusionPolicyRule[]; /** - * Extension name. + * Opaque policy update timestamp supplied by the host. */ - extensionName: string; + last_updated_at: JsonValue; + scope: OptionsUpdateAdditionalContentExclusionPolicyScope; } /** - * Location-scoped approval details for an extension's access to sensitive environment variables, keyed by extension name and the exact set of variable names. + * Single content-exclusion rule supplied to `session.options.update`, with paths, match conditions, and source. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproveForLocationApprovalExtensionEnvAccess". + * via the `definition` "OptionsUpdateAdditionalContentExclusionPolicyRule". */ /** @experimental */ -export interface PermissionDecisionApproveForLocationApprovalExtensionEnvAccess { +export interface OptionsUpdateAdditionalContentExclusionPolicyRule { /** - * Approval covering an extension's request to read sensitive environment variables. + * Path patterns covered by this rule. */ - kind: "extension-env-access"; + paths: string[]; /** - * Extension name. + * Conditions of which at least one must match. */ - extensionName: string; + ifAnyMatch?: string[]; /** - * Names of the sensitive environment variables this approval covers. Values are never persisted. - * - * @minItems 1 + * Conditions none of which may match. */ - environmentVariables: [string, ...string[]]; + ifNoneMatch?: string[]; + source: OptionsUpdateAdditionalContentExclusionPolicyRuleSource; } /** - * Permission-decision request variant to permanently approve a URL domain across sessions. + * Source descriptor for a `session.options.update` content-exclusion rule, with source name and type. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApprovePermanently". + * via the `definition` "OptionsUpdateAdditionalContentExclusionPolicyRuleSource". */ /** @experimental */ -export interface PermissionDecisionApprovePermanently { +export interface OptionsUpdateAdditionalContentExclusionPolicyRuleSource { /** - * Approve and persist across sessions (URL prompts only) + * Name of the policy source. */ - kind: "approve-permanently"; + name: string; /** - * URL domain to approve permanently + * Type of the policy source. */ - domain: string; + type: string; } /** - * Permission-decision request variant to reject a pending permission request, with optional feedback. + * External tool call of the session or one of its sub-agents that is still waiting for session.tools.handlePendingToolCall. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionReject". + * via the `definition` "PendingExternalToolRequest". */ /** @experimental */ -export interface PermissionDecisionReject { +export interface PendingExternalToolRequest { /** - * Reject the request + * Request ID to pass to session.tools.handlePendingToolCall */ - kind: "reject"; + requestId: string; /** - * Optional feedback explaining the rejection + * Tool call ID assigned to this external tool invocation */ - feedback?: string; + toolCallId: string; + /** + * Name of the external tool to invoke + */ + toolName: string; + /** + * Arguments to pass to the external tool + */ + arguments?: JsonValue; + /** + * Stable identity of the provider that offered the tool, for hosts that route extension-owned tools by provider + */ + providerId?: string; + /** + * Sub-agent instance identifier (the envelope agentId of its events) of the agent that issued the call; absent for calls issued by the root agent + */ + agentId?: string; } /** - * Permission-decision variant indicating no user was available to confirm the request. + * External tool calls still waiting for a result. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionUserNotAvailable". + * via the `definition` "PendingExternalToolRequestList". */ /** @experimental */ -export interface PermissionDecisionUserNotAvailable { +export interface PendingExternalToolRequestList { /** - * No user is available to confirm the request + * External tool calls of the session and its sub-agents that session.tools.handlePendingToolCall would still accept, in the order they were requested. Includes calls that were pending when the session was last suspended and resumed with pending work continued, so a host that did not observe the original external_tool.requested event can answer them. */ - kind: "user-not-available"; + items: PendingExternalToolRequest[]; } /** - * Permission-decision variant indicating the request was approved. + * Pending permission prompt reconstructed from event history, with request ID and user-facing prompt details. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApproved". + * via the `definition` "PendingPermissionRequest". */ /** @experimental */ -export interface PermissionDecisionApproved { +export interface PendingPermissionRequest { /** - * The permission request was approved + * Unique identifier for the pending permission request */ - kind: "approved"; + requestId: string; + request: PermissionPromptRequest; + /** + * Permission-recovery episode that authorized this request to surface for interactive attention + */ + recoveryEpisodeId?: string; } /** - * Permission-decision variant indicating approval was remembered for the session, with approval details. + * List of pending permission requests reconstructed from event history. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApprovedForSession". + * via the `definition` "PendingPermissionRequestList". */ /** @experimental */ -export interface PermissionDecisionApprovedForSession { +export interface PendingPermissionRequestList { /** - * Approved and remembered for the rest of the session + * Pending permission prompts reconstructed from the session's event history. Equivalent to the set of `permission.requested` events that have not yet been followed by a matching `permission.completed` event. Used by clients (e.g. the CLI) to hydrate UI for prompts that were emitted before the client attached to the session. */ - kind: "approved-for-session"; - approval: UserToolSessionApproval; + items: PendingPermissionRequest[]; } /** - * Permission-decision variant indicating approval was persisted for a project location, with approval details and location key. + * Permission-decision request variant to approve only the current permission request. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionApprovedForLocation". + * via the `definition` "PermissionDecisionApproveOnce". */ /** @experimental */ -export interface PermissionDecisionApprovedForLocation { +export interface PermissionDecisionApproveOnce { /** - * Approved and persisted for this project location + * Approve this single request only */ - kind: "approved-for-location"; - approval: UserToolSessionApproval; + kind: "approve-once"; /** - * The location key (git root or cwd) to persist the approval to + * True only when a host surfaced this request to a user who approved it. */ - locationKey: string; + approvedInteractively?: boolean; } /** - * Permission-decision variant indicating the request was cancelled before use, with an optional reason. + * Permission-decision request variant to approve for the rest of the session, with optional tool approval or URL domain. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionCancelled". + * via the `definition` "PermissionDecisionApproveForSession". */ /** @experimental */ -export interface PermissionDecisionCancelled { +export interface PermissionDecisionApproveForSession { /** - * The permission request was cancelled before a response was used + * Approve and remember for the rest of the session */ - kind: "cancelled"; + kind: "approve-for-session"; + approval?: PermissionDecisionApproveForSessionApproval; /** - * Optional explanation of why the request was cancelled + * URL domain to approve for the rest of the session (URL prompts only) */ - reason?: string; + domain?: string; } /** - * Permission-decision variant indicating explicit denial by permission rules, with the matching rules. + * Session-scoped approval details for specific command identifiers. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionDeniedByRules". + * via the `definition` "PermissionDecisionApproveForSessionApprovalCommands". */ /** @experimental */ -export interface PermissionDecisionDeniedByRules { +export interface PermissionDecisionApproveForSessionApprovalCommands { /** - * Denied because approval rules explicitly blocked it + * Approval scoped to specific command identifiers. */ - kind: "denied-by-rules"; + kind: "commands"; /** - * Rules that denied the request + * Command identifiers covered by this approval. */ - rules: PermissionRule[]; + commandIdentifiers: string[]; } /** - * Permission-decision variant indicating no approval rule matched and user confirmation was unavailable. + * Session-scoped approval details for read-only filesystem operations. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser". + * via the `definition` "PermissionDecisionApproveForSessionApprovalRead". */ /** @experimental */ -export interface PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser { +export interface PermissionDecisionApproveForSessionApprovalRead { /** - * Denied because no approval rule matched and user confirmation was unavailable + * Approval covering read-only filesystem operations. */ - kind: "denied-no-approval-rule-and-could-not-request-from-user"; + kind: "read"; } /** - * Permission-decision variant indicating the user denied an interactive prompt, with optional feedback and force-reject flag. + * Session-scoped approval details for filesystem write operations. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionDeniedInteractivelyByUser". + * via the `definition` "PermissionDecisionApproveForSessionApprovalWrite". */ /** @experimental */ -export interface PermissionDecisionDeniedInteractivelyByUser { +export interface PermissionDecisionApproveForSessionApprovalWrite { /** - * Denied by the user during an interactive prompt + * Approval covering filesystem write operations. */ - kind: "denied-interactively-by-user"; + kind: "write"; +} +/** + * Session-scoped approval details for an MCP server tool, or all tools on the server when `toolName` is null. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionDecisionApproveForSessionApprovalMcp". + */ +/** @experimental */ +export interface PermissionDecisionApproveForSessionApprovalMcp { /** - * Optional feedback from the user explaining the denial + * Approval covering an MCP tool. */ - feedback?: string; + kind: "mcp"; /** - * Whether to force-reject the current agent turn + * MCP server name. */ - forceReject?: boolean; + serverName: string; + /** + * MCP tool name, or null to cover every tool on the server. + */ + toolName: string | null; } /** - * Permission-decision variant indicating denial by content-exclusion policy, with path and message. + * Session-scoped approval details for MCP sampling requests from a server. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionDeniedByContentExclusionPolicy". + * via the `definition` "PermissionDecisionApproveForSessionApprovalMcpSampling". */ /** @experimental */ -export interface PermissionDecisionDeniedByContentExclusionPolicy { +export interface PermissionDecisionApproveForSessionApprovalMcpSampling { /** - * Denied by the organization's content exclusion policy + * Approval covering MCP sampling requests for a server. */ - kind: "denied-by-content-exclusion-policy"; + kind: "mcp-sampling"; /** - * File path that triggered the exclusion + * MCP server name. */ - path: string; + serverName: string; +} +/** + * Session-scoped approval details for writes to long-term memory. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionDecisionApproveForSessionApprovalMemory". + */ +/** @experimental */ +export interface PermissionDecisionApproveForSessionApprovalMemory { /** - * Human-readable explanation of why the path was excluded + * Approval covering writes to long-term memory. */ - message: string; + kind: "memory"; } /** - * Permission-decision variant indicating denial by a permission request hook, with optional message and interrupt flag. + * Session-scoped approval details for a custom tool, keyed by tool name. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionDeniedByPermissionRequestHook". + * via the `definition` "PermissionDecisionApproveForSessionApprovalCustomTool". */ /** @experimental */ -export interface PermissionDecisionDeniedByPermissionRequestHook { +export interface PermissionDecisionApproveForSessionApprovalCustomTool { /** - * Denied by a permission request hook registered by an extension or plugin + * Approval covering a custom tool. */ - kind: "denied-by-permission-request-hook"; + kind: "custom-tool"; /** - * Optional message from the hook explaining the denial + * Custom tool name. */ - message?: string; + toolName: string; +} +/** + * Session-scoped approval details for extension-management operations, optionally narrowed by operation. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionDecisionApproveForSessionApprovalExtensionManagement". + */ +/** @experimental */ +export interface PermissionDecisionApproveForSessionApprovalExtensionManagement { /** - * Whether to interrupt the current agent turn + * Approval covering extension lifecycle operations such as enable, disable, or reload. */ - interrupt?: boolean; + kind: "extension-management"; + /** + * Optional operation identifier; when omitted, the approval covers all extension management operations. + */ + operation?: string; } /** - * Optional informational context describing how and where the permission decision was made. This does not affect permission behavior. + * Session-scoped workflow approval, optionally narrowed by approval key. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionContext". + * via the `definition` "PermissionDecisionApproveForSessionApprovalWorkflow". */ /** @experimental */ -export interface PermissionDecisionContext { - outcome: PermissionDecisionOutcome; - source: PermissionDecisionSource; - surface: PermissionDecisionSurface; - responseCapability?: PermissionResponseCapability; +export interface PermissionDecisionApproveForSessionApprovalWorkflow { + /** + * Approval covering workflow operations. + */ + kind: "workflow"; + /** + * Optional workflow operation name or canonical approval key; when omitted, the approval covers all workflow operations. + */ + approvalKey?: string; } /** - * Pending permission request ID and the decision to apply (approve/reject and scope). + * Session-scoped approval details for an extension's permission-gated capability access, keyed by extension name. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionDecisionRequest". + * via the `definition` "PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess". */ /** @experimental */ -export interface PermissionDecisionRequest { +export interface PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess { /** - * Request ID of the pending permission request + * Approval covering an extension's request to access a permission-gated capability. */ - requestId: string; - result: PermissionDecision; - decisionContext?: PermissionDecisionContext; + kind: "extension-permission-access"; + /** + * Extension name. + */ + extensionName: string; } /** - * Location-scoped tool approval to persist. + * Session-scoped approval details for an extension's access to sensitive environment variables, keyed by extension name and the exact set of variable names. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionLocationAddToolApprovalParams". + * via the `definition` "PermissionDecisionApproveForSessionApprovalExtensionEnvAccess". */ /** @experimental */ -export interface PermissionLocationAddToolApprovalParams { +export interface PermissionDecisionApproveForSessionApprovalExtensionEnvAccess { + /** + * Approval covering an extension's request to read sensitive environment variables. + */ + kind: "extension-env-access"; + /** + * Extension name. + */ + extensionName: string; + /** + * Names of the sensitive environment variables this approval covers. Values are never persisted. + * + * @minItems 1 + */ + environmentVariables: [string, ...string[]]; +} +/** + * Approve file-tool read access to specific directories for this logical session, including continuation or resume. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionDecisionApproveReadOnlyForSession". + */ +/** @experimental */ +export interface PermissionDecisionApproveReadOnlyForSession { + /** + * Approve read-only file-tool directory access for this session + */ + kind: "approve-read-only-for-session"; + /** + * Canonical directories covered by the read-only grant + * + * @minItems 1 + */ + directories: [string, ...string[]]; +} +/** + * Permission-decision request variant to approve and persist a permission for a project location, with approval details and location key. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionDecisionApproveForLocation". + */ +/** @experimental */ +export interface PermissionDecisionApproveForLocation { + /** + * Approve and persist for this project location + */ + kind: "approve-for-location"; + approval: PermissionDecisionApproveForLocationApproval; /** * Location key (git root or cwd) to persist the approval to */ locationKey: string; - approval: PermissionsLocationsAddToolApprovalDetails; } /** - * Location-persisted tool approval details for specific command identifiers. + * Location-scoped approval details for specific command identifiers. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsLocationsAddToolApprovalDetailsCommands". + * via the `definition` "PermissionDecisionApproveForLocationApprovalCommands". */ /** @experimental */ -export interface PermissionsLocationsAddToolApprovalDetailsCommands { +export interface PermissionDecisionApproveForLocationApprovalCommands { /** * Approval scoped to specific command identifiers. */ @@ -20609,39 +21190,39 @@ export interface PermissionsLocationsAddToolApprovalDetailsCommands { commandIdentifiers: string[]; } /** - * Location-persisted tool approval details for read-only filesystem operations. + * Location-scoped approval details for read-only filesystem operations. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsLocationsAddToolApprovalDetailsRead". + * via the `definition` "PermissionDecisionApproveForLocationApprovalRead". */ /** @experimental */ -export interface PermissionsLocationsAddToolApprovalDetailsRead { +export interface PermissionDecisionApproveForLocationApprovalRead { /** * Approval covering read-only filesystem operations. */ kind: "read"; } /** - * Location-persisted tool approval details for filesystem write operations. + * Location-scoped approval details for filesystem write operations. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsLocationsAddToolApprovalDetailsWrite". + * via the `definition` "PermissionDecisionApproveForLocationApprovalWrite". */ /** @experimental */ -export interface PermissionsLocationsAddToolApprovalDetailsWrite { +export interface PermissionDecisionApproveForLocationApprovalWrite { /** * Approval covering filesystem write operations. */ kind: "write"; } /** - * Location-persisted tool approval details for an MCP server tool, or all tools when `toolName` is null. + * Location-scoped approval details for an MCP server tool, or all tools on the server when `toolName` is null. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsLocationsAddToolApprovalDetailsMcp". + * via the `definition` "PermissionDecisionApproveForLocationApprovalMcp". */ /** @experimental */ -export interface PermissionsLocationsAddToolApprovalDetailsMcp { +export interface PermissionDecisionApproveForLocationApprovalMcp { /** * Approval covering an MCP tool. */ @@ -20656,13 +21237,13 @@ export interface PermissionsLocationsAddToolApprovalDetailsMcp { toolName: string | null; } /** - * Location-persisted tool approval details for MCP sampling requests from a server. + * Location-scoped approval details for MCP sampling requests from a server. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsLocationsAddToolApprovalDetailsMcpSampling". + * via the `definition` "PermissionDecisionApproveForLocationApprovalMcpSampling". */ /** @experimental */ -export interface PermissionsLocationsAddToolApprovalDetailsMcpSampling { +export interface PermissionDecisionApproveForLocationApprovalMcpSampling { /** * Approval covering MCP sampling requests for a server. */ @@ -20673,26 +21254,26 @@ export interface PermissionsLocationsAddToolApprovalDetailsMcpSampling { serverName: string; } /** - * Location-persisted tool approval details for writes to long-term memory. + * Location-scoped approval details for writes to long-term memory. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsLocationsAddToolApprovalDetailsMemory". + * via the `definition` "PermissionDecisionApproveForLocationApprovalMemory". */ /** @experimental */ -export interface PermissionsLocationsAddToolApprovalDetailsMemory { +export interface PermissionDecisionApproveForLocationApprovalMemory { /** * Approval covering writes to long-term memory. */ kind: "memory"; } /** - * Location-persisted tool approval details for a custom tool, keyed by tool name. + * Location-scoped approval details for a custom tool, keyed by tool name. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsLocationsAddToolApprovalDetailsCustomTool". + * via the `definition` "PermissionDecisionApproveForLocationApprovalCustomTool". */ /** @experimental */ -export interface PermissionsLocationsAddToolApprovalDetailsCustomTool { +export interface PermissionDecisionApproveForLocationApprovalCustomTool { /** * Approval covering a custom tool. */ @@ -20703,13 +21284,13 @@ export interface PermissionsLocationsAddToolApprovalDetailsCustomTool { toolName: string; } /** - * Location-persisted tool approval details for extension-management operations, optionally narrowed by operation. + * Location-scoped approval details for extension-management operations, optionally narrowed by operation. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsLocationsAddToolApprovalDetailsExtensionManagement". + * via the `definition` "PermissionDecisionApproveForLocationApprovalExtensionManagement". */ /** @experimental */ -export interface PermissionsLocationsAddToolApprovalDetailsExtensionManagement { +export interface PermissionDecisionApproveForLocationApprovalExtensionManagement { /** * Approval covering extension lifecycle operations such as enable, disable, or reload. */ @@ -20720,13 +21301,13 @@ export interface PermissionsLocationsAddToolApprovalDetailsExtensionManagement { operation?: string; } /** - * Location-persisted workflow approval, optionally narrowed by approval key. + * Location-scoped workflow approval, optionally narrowed by approval key. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsLocationsAddToolApprovalDetailsWorkflow". + * via the `definition` "PermissionDecisionApproveForLocationApprovalWorkflow". */ /** @experimental */ -export interface PermissionsLocationsAddToolApprovalDetailsWorkflow { +export interface PermissionDecisionApproveForLocationApprovalWorkflow { /** * Approval covering workflow operations. */ @@ -20737,13 +21318,13 @@ export interface PermissionsLocationsAddToolApprovalDetailsWorkflow { approvalKey?: string; } /** - * Location-persisted tool approval details for an extension's permission-gated capability access, keyed by extension name. + * Location-scoped approval details for an extension's permission-gated capability access, keyed by extension name. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsLocationsAddToolApprovalDetailsExtensionPermissionAccess". + * via the `definition` "PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess". */ /** @experimental */ -export interface PermissionsLocationsAddToolApprovalDetailsExtensionPermissionAccess { +export interface PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess { /** * Approval covering an extension's request to access a permission-gated capability. */ @@ -20754,13 +21335,13 @@ export interface PermissionsLocationsAddToolApprovalDetailsExtensionPermissionAc extensionName: string; } /** - * Location-persisted tool approval details for an extension's access to sensitive environment variables, keyed by extension name and the exact set of variable names. + * Location-scoped approval details for an extension's access to sensitive environment variables, keyed by extension name and the exact set of variable names. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsLocationsAddToolApprovalDetailsExtensionEnvAccess". + * via the `definition` "PermissionDecisionApproveForLocationApprovalExtensionEnvAccess". */ /** @experimental */ -export interface PermissionsLocationsAddToolApprovalDetailsExtensionEnvAccess { +export interface PermissionDecisionApproveForLocationApprovalExtensionEnvAccess { /** * Approval covering an extension's request to read sensitive environment variables. */ @@ -20777,12375 +21358,13649 @@ export interface PermissionsLocationsAddToolApprovalDetailsExtensionEnvAccess { environmentVariables: [string, ...string[]]; } /** - * Working directory to load persisted location permissions for. + * Permission-decision request variant to permanently approve a URL domain across sessions. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionLocationApplyParams". + * via the `definition` "PermissionDecisionApprovePermanently". */ /** @experimental */ -export interface PermissionLocationApplyParams { +export interface PermissionDecisionApprovePermanently { /** - * Working directory whose persisted location permissions should be applied + * Approve and persist across sessions (URL prompts only) */ - workingDirectory: string; + kind: "approve-permanently"; + /** + * URL domain to approve permanently + */ + domain: string; } /** - * Summary of persisted location permissions applied to the session. + * Permission-decision request variant to reject a pending permission request, with optional feedback. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionLocationApplyResult". + * via the `definition` "PermissionDecisionReject". */ /** @experimental */ -export interface PermissionLocationApplyResult { - /** - * Location key used in the location-permissions store - */ - locationKey: string; - locationType: PermissionLocationType; - /** - * Whether a different location was applied since the previous apply call - */ - changed: boolean; - /** - * Number of location-scoped rules added to the live permission service - */ - appliedRuleCount: number; +export interface PermissionDecisionReject { /** - * Number of persisted allowed directories added to the live path manager + * Reject the request */ - appliedDirectoryCount: number; + kind: "reject"; /** - * Location-scoped rules applied to the live permission service + * Optional feedback explaining the rejection */ - appliedRules: PermissionRule[]; + feedback?: string; } /** - * Working directory to resolve into a location-permissions key. + * Permission-decision variant indicating no user was available to confirm the request. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionLocationResolveParams". + * via the `definition` "PermissionDecisionUserNotAvailable". */ /** @experimental */ -export interface PermissionLocationResolveParams { +export interface PermissionDecisionUserNotAvailable { /** - * Working directory whose permission location should be resolved + * No user is available to confirm the request */ - workingDirectory: string; + kind: "user-not-available"; } /** - * Resolved location-permissions key and type. + * Permission-decision variant indicating the request was approved. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionLocationResolveResult". + * via the `definition` "PermissionDecisionApproved". */ /** @experimental */ -export interface PermissionLocationResolveResult { +export interface PermissionDecisionApproved { /** - * Location key used in the location-permissions store + * The permission request was approved */ - locationKey: string; - locationType: PermissionLocationType; + kind: "approved"; } /** - * Directory path to add to the session's allowed directories. + * Permission-decision variant indicating approval was remembered for the session, with approval details. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionPathsAddParams". + * via the `definition` "PermissionDecisionApprovedForSession". */ /** @experimental */ -export interface PermissionPathsAddParams { +export interface PermissionDecisionApprovedForSession { /** - * Directory to add to the allow-list. The runtime resolves and validates the path before adding, then loads conventional `.github/skills/` and `.github/agents/` definitions under it when their subsystem gates are enabled. Adding the directory is therefore also a trust decision for configuration stored there. + * Approved and remembered for the rest of the session */ - path: string; + kind: "approved-for-session"; + approval: UserToolSessionApproval; } /** - * Path to evaluate against the session's allowed directories. + * Permission-decision variant indicating approval was persisted for a project location, with approval details and location key. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionPathsAllowedCheckParams". + * via the `definition` "PermissionDecisionApprovedForLocation". */ /** @experimental */ -export interface PermissionPathsAllowedCheckParams { +export interface PermissionDecisionApprovedForLocation { /** - * Path to check against the session's allowed directories + * Approved and persisted for this project location */ - path: string; + kind: "approved-for-location"; + approval: UserToolSessionApproval; + /** + * The location key (git root or cwd) to persist the approval to + */ + locationKey: string; } /** - * Indicates whether the supplied path is within the session's allowed directories. + * Permission-decision variant indicating the request was cancelled before use, with an optional reason. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionPathsAllowedCheckResult". + * via the `definition` "PermissionDecisionCancelled". */ /** @experimental */ -export interface PermissionPathsAllowedCheckResult { +export interface PermissionDecisionCancelled { /** - * Whether the path is within the session's allowed directories + * The permission request was cancelled before a response was used */ - allowed: boolean; + kind: "cancelled"; + /** + * Optional explanation of why the request was cancelled + */ + reason?: string; } /** - * If specified, replaces the session's path-permission policy. The runtime constructs the appropriate PathManager based on these inputs (rooted at the session's working directory). Omit to leave the current path policy unchanged. + * Permission-decision variant indicating explicit denial by permission rules, with the matching rules. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionPathsConfig". + * via the `definition` "PermissionDecisionDeniedByRules". */ /** @experimental */ -export interface PermissionPathsConfig { - /** - * If true, the runtime allows access to all paths without prompting. Equivalent to constructing an UnrestrictedPathManager. - */ - unrestricted?: boolean; +export interface PermissionDecisionDeniedByRules { /** - * Additional directories to allow tool access to (in addition to the session's working directory). Conventional `.github/skills/` and `.github/agents/` definitions under them also join the session catalogs when their subsystem gates are enabled, so supplying a directory is a trust decision for configuration stored there. When `unrestricted` is true, these are still pre-populated on the UnrestrictedPathManager so they remain visible via getDirectories() (e.g. for @-mention completion). + * Denied because approval rules explicitly blocked it */ - additionalDirectories?: string[]; + kind: "denied-by-rules"; /** - * Whether to include the system temp directory in the allowed list (defaults to true). Ignored when `unrestricted` is true. + * Rules that denied the request */ - includeTempDirectory?: boolean; + rules: PermissionRule[]; +} +/** + * Permission-decision variant indicating no approval rule matched and user confirmation was unavailable. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser". + */ +/** @experimental */ +export interface PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser { /** - * Workspace root path (special-cased to be allowed even before the directory exists). Ignored when `unrestricted` is true. + * Denied because no approval rule matched and user confirmation was unavailable */ - workspacePath?: string; + kind: "denied-no-approval-rule-and-could-not-request-from-user"; } /** - * Snapshot of the session's recursive directory grants, exact session-approved paths, and primary working directory. + * Permission-decision variant indicating the user denied an interactive prompt, with optional feedback and force-reject flag. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionPathsList". + * via the `definition` "PermissionDecisionDeniedInteractivelyByUser". */ /** @experimental */ -export interface PermissionPathsList { +export interface PermissionDecisionDeniedInteractivelyByUser { /** - * All directories currently allowed for tool access on this session. + * Denied by the user during an interactive prompt */ - directories: string[]; + kind: "denied-interactively-by-user"; /** - * Exact paths approved for this session without recursively allowing their descendants. + * Optional feedback from the user explaining the denial */ - sessionApprovedPaths?: string[]; + feedback?: string; /** - * The primary working directory for this session. + * Whether to force-reject the current agent turn */ - primary: string; + forceReject?: boolean; } /** - * Directory path to set as the session's new primary working directory. + * Permission-decision variant indicating denial by content-exclusion policy, with path and message. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionPathsUpdatePrimaryParams". + * via the `definition` "PermissionDecisionDeniedByContentExclusionPolicy". */ /** @experimental */ -export interface PermissionPathsUpdatePrimaryParams { +export interface PermissionDecisionDeniedByContentExclusionPolicy { /** - * Directory to set as the new primary working directory for the session's permission policy. + * Denied by the organization's content exclusion policy + */ + kind: "denied-by-content-exclusion-policy"; + /** + * File path that triggered the exclusion */ path: string; + /** + * Human-readable explanation of why the path was excluded + */ + message: string; } /** - * Path to evaluate against the session's workspace (primary) directory. + * Permission-decision variant indicating denial by a permission request hook, with optional message and interrupt flag. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionPathsWorkspaceCheckParams". + * via the `definition` "PermissionDecisionDeniedByPermissionRequestHook". */ /** @experimental */ -export interface PermissionPathsWorkspaceCheckParams { +export interface PermissionDecisionDeniedByPermissionRequestHook { /** - * Path to check against the session workspace directory + * Denied by a permission request hook registered by an extension or plugin */ - path: string; + kind: "denied-by-permission-request-hook"; + /** + * Optional message from the hook explaining the denial + */ + message?: string; + /** + * Whether to interrupt the current agent turn + */ + interrupt?: boolean; } /** - * Indicates whether the supplied path is within the session's workspace directory. + * Optional informational context describing how and where the permission decision was made. This does not affect permission behavior. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionPathsWorkspaceCheckResult". + * via the `definition` "PermissionDecisionContext". */ /** @experimental */ -export interface PermissionPathsWorkspaceCheckResult { - /** - * Whether the path is within the session workspace directory - */ - allowed: boolean; +export interface PermissionDecisionContext { + outcome: PermissionDecisionOutcome; + source: PermissionDecisionSource; + surface: PermissionDecisionSurface; + responseCapability?: PermissionResponseCapability; } /** - * Notification payload describing the permission prompt that the client just rendered. + * Pending permission request ID and the decision to apply (approve/reject and scope). * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionPromptShownNotification". + * via the `definition` "PermissionDecisionRequest". */ /** @experimental */ -export interface PermissionPromptShownNotification { +export interface PermissionDecisionRequest { /** - * Human-readable description of the prompt the user is being asked to approve. Used by the runtime to fire the registered `permission_prompt` notification hook (e.g. terminal bell, desktop notification). + * Request ID of the pending permission request */ - message: string; + requestId: string; + result: PermissionDecision; + decisionContext?: PermissionDecisionContext; } /** - * Indicates whether the permission decision was applied; false when the request was already resolved. + * Location-scoped tool approval to persist. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionRequestResult". + * via the `definition` "PermissionLocationAddToolApprovalParams". */ /** @experimental */ -export interface PermissionRequestResult { +export interface PermissionLocationAddToolApprovalParams { /** - * Whether the permission request was handled successfully + * Location key (git root or cwd) to persist the approval to */ - success: boolean; + locationKey: string; + approval: PermissionsLocationsAddToolApprovalDetails; } /** - * If specified, replaces the session's approved/denied permission rules. Omit to leave the current rules unchanged. + * Location-persisted tool approval details for specific command identifiers. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionRulesSet". + * via the `definition` "PermissionsLocationsAddToolApprovalDetailsCommands". */ /** @experimental */ -export interface PermissionRulesSet { +export interface PermissionsLocationsAddToolApprovalDetailsCommands { /** - * Rules that auto-approve matching requests + * Approval scoped to specific command identifiers. */ - approved: PermissionRule[]; + kind: "commands"; /** - * Rules that auto-deny matching requests + * Command identifiers covered by this approval. */ - denied: PermissionRule[]; + commandIdentifiers: string[]; } /** - * Content-exclusion policy supplied to `session.permissions.configure`, with rules, last-updated data, and scope. + * Location-persisted tool approval details for read-only filesystem operations. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsConfigureAdditionalContentExclusionPolicy". + * via the `definition` "PermissionsLocationsAddToolApprovalDetailsRead". */ /** @experimental */ -export interface PermissionsConfigureAdditionalContentExclusionPolicy { +export interface PermissionsLocationsAddToolApprovalDetailsRead { /** - * Content-exclusion rules to apply. + * Approval covering read-only filesystem operations. */ - rules: PermissionsConfigureAdditionalContentExclusionPolicyRule[]; + kind: "read"; +} +/** + * Location-persisted tool approval details for filesystem write operations. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionsLocationsAddToolApprovalDetailsWrite". + */ +/** @experimental */ +export interface PermissionsLocationsAddToolApprovalDetailsWrite { /** - * Opaque policy update timestamp supplied by the host. + * Approval covering filesystem write operations. */ - last_updated_at: JsonValue; - scope: PermissionsConfigureAdditionalContentExclusionPolicyScope; + kind: "write"; } /** - * Single content-exclusion rule supplied to `session.permissions.configure`, with paths, match conditions, and source. + * Location-persisted tool approval details for an MCP server tool, or all tools when `toolName` is null. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsConfigureAdditionalContentExclusionPolicyRule". + * via the `definition` "PermissionsLocationsAddToolApprovalDetailsMcp". */ /** @experimental */ -export interface PermissionsConfigureAdditionalContentExclusionPolicyRule { +export interface PermissionsLocationsAddToolApprovalDetailsMcp { /** - * Path patterns covered by this rule. + * Approval covering an MCP tool. */ - paths: string[]; + kind: "mcp"; /** - * Conditions of which at least one must match. + * MCP server name. */ - ifAnyMatch?: string[]; + serverName: string; /** - * Conditions none of which may match. + * MCP tool name, or null to cover every tool on the server. */ - ifNoneMatch?: string[]; - source: PermissionsConfigureAdditionalContentExclusionPolicyRuleSource; + toolName: string | null; } /** - * Source descriptor for a `session.permissions.configure` content-exclusion rule, with source name and type. + * Location-persisted tool approval details for MCP sampling requests from a server. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsConfigureAdditionalContentExclusionPolicyRuleSource". + * via the `definition` "PermissionsLocationsAddToolApprovalDetailsMcpSampling". */ /** @experimental */ -export interface PermissionsConfigureAdditionalContentExclusionPolicyRuleSource { +export interface PermissionsLocationsAddToolApprovalDetailsMcpSampling { /** - * Name of the policy source. + * Approval covering MCP sampling requests for a server. */ - name: string; + kind: "mcp-sampling"; /** - * Type of the policy source. + * MCP server name. */ - type: string; + serverName: string; } /** - * Patch of permission policy fields to apply (omit a field to leave it unchanged). + * Location-persisted tool approval details for writes to long-term memory. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsConfigureParams". + * via the `definition` "PermissionsLocationsAddToolApprovalDetailsMemory". */ /** @experimental */ -export interface PermissionsConfigureParams { - /** - * If specified, sets whether tool permission requests are auto-approved without prompting. Omit to leave the current value unchanged. - */ - approveAllToolPermissionRequests?: boolean; - /** - * If specified, sets whether path/URL read permission requests are auto-approved. Omit to leave the current value unchanged. - */ - approveAllReadPermissionRequests?: boolean; - rules?: PermissionRulesSet; - paths?: PermissionPathsConfig; - urls?: PermissionUrlsConfig; +export interface PermissionsLocationsAddToolApprovalDetailsMemory { /** - * If specified, replaces the host-supplied GitHub Content Exclusion policies on the session (combined with natively-discovered policies when evaluating tool/file access). Omit to leave the current policies unchanged. + * Approval covering writes to long-term memory. */ - additionalContentExclusionPolicies?: PermissionsConfigureAdditionalContentExclusionPolicy[]; + kind: "memory"; } /** - * If specified, replaces the session's URL-permission policy. The runtime constructs a fresh DefaultUrlManager based on these inputs. Omit to leave the current URL policy unchanged. + * Location-persisted tool approval details for a custom tool, keyed by tool name. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionUrlsConfig". + * via the `definition` "PermissionsLocationsAddToolApprovalDetailsCustomTool". */ /** @experimental */ -export interface PermissionUrlsConfig { +export interface PermissionsLocationsAddToolApprovalDetailsCustomTool { /** - * If true, the runtime allows access to all URLs without prompting. Initial allow-list is ignored when this is true. + * Approval covering a custom tool. */ - unrestricted?: boolean; + kind: "custom-tool"; /** - * Initial list of allowed URL/domain patterns. Patterns may include path components. Ignored when `unrestricted` is true. + * Custom tool name. */ - initialAllowed?: string[]; + toolName: string; } /** - * Indicates whether the operation succeeded. + * Location-persisted tool approval details for extension-management operations, optionally narrowed by operation. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsConfigureResult". + * via the `definition` "PermissionsLocationsAddToolApprovalDetailsExtensionManagement". */ /** @experimental */ -export interface PermissionsConfigureResult { +export interface PermissionsLocationsAddToolApprovalDetailsExtensionManagement { /** - * Whether the operation succeeded + * Approval covering extension lifecycle operations such as enable, disable, or reload. */ - success: boolean; + kind: "extension-management"; + /** + * Optional operation identifier; when omitted, the approval covers all extension management operations. + */ + operation?: string; } /** - * Indicates whether the operation succeeded. + * Location-persisted workflow approval, optionally narrowed by approval key. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsFolderTrustAddTrustedResult". + * via the `definition` "PermissionsLocationsAddToolApprovalDetailsWorkflow". */ /** @experimental */ -export interface PermissionsFolderTrustAddTrustedResult { +export interface PermissionsLocationsAddToolApprovalDetailsWorkflow { /** - * Whether the operation succeeded + * Approval covering workflow operations. */ - success: boolean; + kind: "workflow"; + /** + * Optional workflow operation name or canonical approval key; when omitted, the approval covers all workflow operations. + */ + approvalKey?: string; } /** - * No parameters. + * Location-persisted tool approval details for an extension's permission-gated capability access, keyed by extension name. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsGetModeRequest". + * via the `definition` "PermissionsLocationsAddToolApprovalDetailsExtensionPermissionAccess". */ /** @experimental */ -export interface PermissionsGetModeRequest {} +export interface PermissionsLocationsAddToolApprovalDetailsExtensionPermissionAccess { + /** + * Approval covering an extension's request to access a permission-gated capability. + */ + kind: "extension-permission-access"; + /** + * Extension name. + */ + extensionName: string; +} /** - * Current permission mode. + * Location-persisted tool approval details for an extension's access to sensitive environment variables, keyed by extension name and the exact set of variable names. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsGetModeResult". + * via the `definition` "PermissionsLocationsAddToolApprovalDetailsExtensionEnvAccess". */ /** @experimental */ -export interface PermissionsGetModeResult { - mode: PermissionMode; +export interface PermissionsLocationsAddToolApprovalDetailsExtensionEnvAccess { + /** + * Approval covering an extension's request to read sensitive environment variables. + */ + kind: "extension-env-access"; + /** + * Extension name. + */ + extensionName: string; + /** + * Names of the sensitive environment variables this approval covers. Values are never persisted. + * + * @minItems 1 + */ + environmentVariables: [string, ...string[]]; } /** - * Indicates whether the operation succeeded. + * Working directory to load persisted location permissions for. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsLocationsAddToolApprovalResult". + * via the `definition` "PermissionLocationApplyParams". */ /** @experimental */ -export interface PermissionsLocationsAddToolApprovalResult { +export interface PermissionLocationApplyParams { /** - * Whether the operation succeeded + * Working directory whose persisted location permissions should be applied */ - success: boolean; + workingDirectory: string; } /** - * Scope and add/remove instructions for modifying session- or location-scoped permission rules. + * Summary of persisted location permissions applied to the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsModifyRulesParams". + * via the `definition` "PermissionLocationApplyResult". */ /** @experimental */ -export interface PermissionsModifyRulesParams { - scope: PermissionsModifyRulesScope; +export interface PermissionLocationApplyResult { /** - * Rules to add to the scope. Applied before `remove`/`removeAll`. + * Location key used in the location-permissions store */ - add?: PermissionRule[]; + locationKey: string; + locationType: PermissionLocationType; /** - * Specific rules to remove from the scope. Ignored when `removeAll` is true. + * Whether a different location was applied since the previous apply call */ - remove?: PermissionRule[]; + changed: boolean; /** - * When true, removes every rule currently in the scope (after any `add` is applied). Useful for clearing the location scope wholesale. + * Number of location-scoped rules added to the live permission service */ - removeAll?: boolean; + appliedRuleCount: number; + /** + * Number of persisted allowed directories added to the live path manager + */ + appliedDirectoryCount: number; + /** + * Location-scoped rules applied to the live permission service + */ + appliedRules: PermissionRule[]; } /** - * Indicates whether the operation succeeded. + * Working directory to resolve into a location-permissions key. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsModifyRulesResult". + * via the `definition` "PermissionLocationResolveParams". */ /** @experimental */ -export interface PermissionsModifyRulesResult { +export interface PermissionLocationResolveParams { /** - * Whether the operation succeeded + * Working directory whose permission location should be resolved */ - success: boolean; + workingDirectory: string; } /** - * Indicates whether the operation succeeded. + * Resolved location-permissions key and type. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsNotifyPromptShownResult". + * via the `definition` "PermissionLocationResolveResult". */ /** @experimental */ -export interface PermissionsNotifyPromptShownResult { +export interface PermissionLocationResolveResult { /** - * Whether the operation succeeded + * Location key used in the location-permissions store */ - success: boolean; + locationKey: string; + locationType: PermissionLocationType; } /** - * Indicates whether the operation succeeded. + * Directory path to add to the session's allowed directories. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsPathsAddResult". + * via the `definition` "PermissionPathsAddParams". */ /** @experimental */ -export interface PermissionsPathsAddResult { +export interface PermissionPathsAddParams { /** - * Whether the operation succeeded + * Directory to add to the allow-list. The runtime resolves and validates the path before adding, then loads conventional `.github/skills/` and `.github/agents/` definitions under it when their subsystem gates are enabled. Adding the directory is therefore also a trust decision for configuration stored there. */ - success: boolean; + path: string; } /** - * No parameters; returns the session's recursive directory grants and exact session-approved paths. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsPathsListRequest". - */ -/** @experimental */ -export interface PermissionsPathsListRequest {} -/** - * Indicates whether the operation succeeded. + * Path to evaluate against the session's allowed directories. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsPathsUpdatePrimaryResult". + * via the `definition` "PermissionPathsAllowedCheckParams". */ /** @experimental */ -export interface PermissionsPathsUpdatePrimaryResult { +export interface PermissionPathsAllowedCheckParams { /** - * Whether the operation succeeded + * Path to check against the session's allowed directories */ - success: boolean; + path: string; } /** - * No parameters; returns currently-pending permission requests for the session. + * Indicates whether the supplied path is within the session's allowed directories. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsPendingRequestsRequest". + * via the `definition` "PermissionPathsAllowedCheckResult". */ /** @experimental */ -export interface PermissionsPendingRequestsRequest {} +export interface PermissionPathsAllowedCheckResult { + /** + * Whether the path is within the session's allowed directories + */ + allowed: boolean; +} /** - * Clears session-scoped tool approvals and optionally clears location-scoped approvals and exact session-approved paths. + * If specified, replaces the session's path-permission policy. The runtime constructs the appropriate PathManager based on these inputs (rooted at the session's working directory). Omit to leave the current path policy unchanged. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsResetSessionApprovalsRequest". + * via the `definition` "PermissionPathsConfig". */ /** @experimental */ -export interface PermissionsResetSessionApprovalsRequest { +export interface PermissionPathsConfig { /** - * Whether location-scoped approvals and exact session-approved paths are cleared too. Defaults to `true`. + * If true, the runtime allows access to all paths without prompting. Equivalent to constructing an UnrestrictedPathManager. */ - includeLocation?: boolean; -} -/** - * Indicates whether the operation succeeded. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsResetSessionApprovalsResult". - */ -/** @experimental */ -export interface PermissionsResetSessionApprovalsResult { + unrestricted?: boolean; /** - * Whether the operation succeeded + * Additional directories to allow tool access to (in addition to the session's working directory). Conventional `.github/skills/` and `.github/agents/` definitions under them also join the session catalogs when their subsystem gates are enabled, so supplying a directory is a trust decision for configuration stored there. When `unrestricted` is true, these are still pre-populated on the UnrestrictedPathManager so they remain visible via getDirectories() (e.g. for @-mention completion). */ - success: boolean; + additionalDirectories?: string[]; + /** + * Whether to include the system temp directory in the allowed list (defaults to true). Ignored when `unrestricted` is true. + */ + includeTempDirectory?: boolean; + /** + * Workspace root path (special-cased to be allowed even before the directory exists). Ignored when `unrestricted` is true. + */ + workspacePath?: string; } /** - * Allow-all toggle for tool permission requests, with an optional telemetry source. + * Snapshot of the session's recursive directory grants, exact session-approved paths, and primary working directory. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsSetApproveAllRequest". + * via the `definition` "PermissionPathsList". */ /** @experimental */ -export interface PermissionsSetApproveAllRequest { +export interface PermissionPathsList { /** - * Whether to auto-approve all tool permission requests + * All directories currently allowed for tool access on this session. */ - enabled: boolean; - source?: PermissionsSetApproveAllSource; + directories: string[]; + /** + * Exact paths approved for this session without recursively allowing their descendants. + */ + sessionApprovedPaths?: string[]; + /** + * The primary working directory for this session. + */ + primary: string; } /** - * Indicates whether the operation succeeded. + * Directory path to set as the session's new primary working directory. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsSetApproveAllResult". + * via the `definition` "PermissionPathsUpdatePrimaryParams". */ /** @experimental */ -export interface PermissionsSetApproveAllResult { +export interface PermissionPathsUpdatePrimaryParams { /** - * Whether the operation succeeded + * Directory to set as the new primary working directory for the session's permission policy. */ - success: boolean; + path: string; } /** - * Permission mode to apply for the session. + * Path to evaluate against the session's workspace (primary) directory. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsSetModeRequest". + * via the `definition` "PermissionPathsWorkspaceCheckParams". */ /** @experimental */ -export interface PermissionsSetModeRequest { - mode: PermissionMode; +export interface PermissionPathsWorkspaceCheckParams { /** - * Optional judge model id for assisted mode. When omitted, the session resolves the provider default: `gpt-5.5` for CAPI sessions and the active session model for BYOK sessions. + * Path to check against the session workspace directory */ - assistedApprovalModel?: string; - source?: PermissionModeSource; + path: string; } /** - * Indicates whether the requested permission mode was applied and reports the authoritative post-mutation mode. + * Indicates whether the supplied path is within the session's workspace directory. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsSetModeResult". + * via the `definition` "PermissionPathsWorkspaceCheckResult". */ /** @experimental */ -export interface PermissionsSetModeResult { +export interface PermissionPathsWorkspaceCheckResult { /** - * Whether the operation succeeded + * Whether the path is within the session workspace directory */ - success: boolean; - mode: PermissionMode; + allowed: boolean; } /** - * Toggles whether permission prompts should be bridged into session events for this client. + * Notification payload describing the permission prompt that the client just rendered. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsSetRequiredRequest". + * via the `definition` "PermissionPromptShownNotification". */ /** @experimental */ -export interface PermissionsSetRequiredRequest { +export interface PermissionPromptShownNotification { /** - * Whether the client wants `permission.requested` events bridged from the session-owned permission service. CLI clients that render prompt UI set this to `true` for as long as their listener is mounted; headless callers leave it unset (the default is `false`). + * Human-readable description of the prompt the user is being asked to approve. Used by the runtime to fire the registered `permission_prompt` notification hook (e.g. terminal bell, desktop notification). */ - required: boolean; + message: string; } /** - * Indicates whether the operation succeeded. + * Indicates whether the permission decision was applied; false when the request was already resolved. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsSetRequiredResult". + * via the `definition` "PermissionRequestResult". */ /** @experimental */ -export interface PermissionsSetRequiredResult { +export interface PermissionRequestResult { /** - * Whether the operation succeeded + * Whether the permission request was handled successfully */ success: boolean; } /** - * Indicates whether the operation succeeded. + * If specified, replaces the session's approved/denied permission rules. Omit to leave the current rules unchanged. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionsUrlsSetUnrestrictedModeResult". + * via the `definition` "PermissionRulesSet". */ /** @experimental */ -export interface PermissionsUrlsSetUnrestrictedModeResult { +export interface PermissionRulesSet { /** - * Whether the operation succeeded + * Rules that auto-approve matching requests */ - success: boolean; + approved: PermissionRule[]; + /** + * Rules that auto-deny matching requests + */ + denied: PermissionRule[]; } /** - * Whether the URL-permission policy should run in unrestricted mode. + * Content-exclusion policy supplied to `session.permissions.configure`, with rules, last-updated data, and scope. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PermissionUrlsSetUnrestrictedModeParams". + * via the `definition` "PermissionsConfigureAdditionalContentExclusionPolicy". */ /** @experimental */ -export interface PermissionUrlsSetUnrestrictedModeParams { +export interface PermissionsConfigureAdditionalContentExclusionPolicy { /** - * Whether to allow access to all URLs without prompting. Toggles the runtime's URL-permission policy in place. + * Content-exclusion rules to apply. */ - enabled: boolean; + rules: PermissionsConfigureAdditionalContentExclusionPolicyRule[]; + /** + * Opaque policy update timestamp supplied by the host. + */ + last_updated_at: JsonValue; + scope: PermissionsConfigureAdditionalContentExclusionPolicyScope; } /** - * Optional message to echo back to the caller. + * Single content-exclusion rule supplied to `session.permissions.configure`, with paths, match conditions, and source. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PingRequest". + * via the `definition` "PermissionsConfigureAdditionalContentExclusionPolicyRule". */ /** @experimental */ -export interface PingRequest { +export interface PermissionsConfigureAdditionalContentExclusionPolicyRule { /** - * Optional message to echo back + * Path patterns covered by this rule. */ - message?: string; + paths: string[]; + /** + * Conditions of which at least one must match. + */ + ifAnyMatch?: string[]; + /** + * Conditions none of which may match. + */ + ifNoneMatch?: string[]; + source: PermissionsConfigureAdditionalContentExclusionPolicyRuleSource; } /** - * Server liveness response, including the echoed message, current server timestamp, and protocol version. + * Source descriptor for a `session.permissions.configure` content-exclusion rule, with source name and type. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PingResult". + * via the `definition` "PermissionsConfigureAdditionalContentExclusionPolicyRuleSource". */ /** @experimental */ -export interface PingResult { - /** - * Echoed message (or default greeting) - */ - message: string; +export interface PermissionsConfigureAdditionalContentExclusionPolicyRuleSource { /** - * ISO 8601 timestamp when the server handled the ping + * Name of the policy source. */ - timestamp: string; + name: string; /** - * Server protocol version number + * Type of the policy source. */ - protocolVersion: number; + type: string; } /** - * Existence, contents, and resolved path of the session plan file. + * Patch of permission policy fields to apply (omit a field to leave it unchanged). * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PlanReadResult". + * via the `definition` "PermissionsConfigureParams". */ /** @experimental */ -export interface PlanReadResult { +export interface PermissionsConfigureParams { /** - * Whether the plan file exists in the workspace + * If specified, sets whether tool permission requests are auto-approved without prompting. Omit to leave the current value unchanged. */ - exists: boolean; + approveAllToolPermissionRequests?: boolean; /** - * The content of the plan file, or null if it does not exist + * If specified, sets whether path/URL read permission requests are auto-approved. Omit to leave the current value unchanged. */ - content: string | null; + approveAllReadPermissionRequests?: boolean; + rules?: PermissionRulesSet; + paths?: PermissionPathsConfig; + urls?: PermissionUrlsConfig; /** - * Absolute file path of the plan file, or null if workspace is not enabled + * If specified, replaces the host-supplied GitHub Content Exclusion policies on the session (combined with natively-discovered policies when evaluating tool/file access). Omit to leave the current policies unchanged. */ - path: string | null; + additionalContentExclusionPolicies?: PermissionsConfigureAdditionalContentExclusionPolicy[]; } /** - * Todo rows read from the session SQL database. Empty when no session database is available. + * If specified, replaces the session's URL-permission policy. The runtime constructs a fresh DefaultUrlManager based on these inputs. Omit to leave the current URL policy unchanged. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PlanReadSqlTodosResult". + * via the `definition` "PermissionUrlsConfig". */ /** @experimental */ -export interface PlanReadSqlTodosResult { +export interface PermissionUrlsConfig { /** - * Rows from the session SQL todos table, ordered by creation time with insertion order used to break ties when available and id used for WITHOUT ROWID tables. + * If true, the runtime allows access to all URLs without prompting. Initial allow-list is ignored when this is true. */ - rows: PlanSqlTodosRow[]; + unrestricted?: boolean; + /** + * Initial list of allowed URL/domain patterns. Patterns may include path components. Ignored when `unrestricted` is true. + */ + initialAllowed?: string[]; } /** - * A single todo row read from the session SQL `todos` table. All fields are optional because the SQL schema is best-effort and the agent may not have populated every column. + * Indicates whether the operation succeeded. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PlanSqlTodosRow". + * via the `definition` "PermissionsConfigureResult". */ /** @experimental */ -export interface PlanSqlTodosRow { - /** - * Todo identifier. - */ - id?: string; - /** - * Todo title. - */ - title?: string; - /** - * Todo description. - */ - description?: string; - /** - * Todo status. - */ - status?: string; +export interface PermissionsConfigureResult { /** - * Todo creation time, as stored by the session SQL schema's `datetime('now')` default: `YYYY-MM-DD HH:MM:SS` in UTC. Lets clients attribute todos to the work item that created them (e.g. scoping a goal's progress to the todos it produced) rather than to the whole session. + * Whether the operation succeeded */ - createdAt?: string; + success: boolean; } /** - * Todo rows + dependency edges read from the session SQL database. + * The verbatim managed `permissions` slice to interpret. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PlanReadSqlTodosWithDependenciesResult". + * via the `definition` "PermissionsEvaluateManagedPolicyParams". */ /** @experimental */ -export interface PlanReadSqlTodosWithDependenciesResult { - /** - * Rows from the session SQL todos table, ordered by creation time with insertion order used to break ties when available and id used for WITHOUT ROWID tables. Empty when no database, no todos table, or the SELECT failed. - */ - rows: PlanSqlTodosRow[]; +/** @internal */ +export interface PermissionsEvaluateManagedPolicyParams { /** - * Edges from the session SQL todo_deps table. Empty when no database, no todo_deps table, or the SELECT failed. Read independently from `rows`, so a broken todo_deps table does not affect the rows result and vice versa. + * The `permissions` object from a managed settings layer, for example `{"disableBypassPermissionsMode":"disable"}`. Omitted or null means no managed policy applies. */ - dependencies: PlanSqlTodoDependency[]; + permissions?: JsonValue; } /** - * A single dependency edge read from the session SQL `todo_deps` table, indicating that one todo must complete before another. + * The policy questions a host asks before granting elevated permissions. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PlanSqlTodoDependency". + * via the `definition` "PermissionsEvaluateManagedPolicyResult". */ /** @experimental */ -export interface PlanSqlTodoDependency { +export interface PermissionsEvaluateManagedPolicyResult { /** - * ID of the todo that has the dependency. + * True when managed policy forbids bypass-permissions mode, so allow-all style flags must not take effect. */ - todoId: string; + bypassPermissionsDisabled: boolean; /** - * ID of the todo it depends on. + * True when a managed policy exists but this build could not determine its meaning. Hosts fail closed on it rather than assuming permission was granted. */ - dependsOn: string; + policyUndetermined: boolean; + /** + * True when the managed layer supplies permission rules that the session must enforce. + */ + permissionRulesActive: boolean; } /** - * Replacement contents to write to the session plan file. + * Indicates whether the operation succeeded. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PlanUpdateRequest". + * via the `definition` "PermissionsFolderTrustAddTrustedResult". */ /** @experimental */ -export interface PlanUpdateRequest { +export interface PermissionsFolderTrustAddTrustedResult { /** - * The new content for the plan file + * Whether the operation succeeded */ - content: string; + success: boolean; } /** - * Session plugin metadata, with name, marketplace, optional version, and enabled state. + * No parameters. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "Plugin". + * via the `definition` "PermissionsGetModeRequest". */ /** @experimental */ -export interface Plugin { - /** - * Plugin name - */ - name: string; - /** - * Marketplace the plugin came from - */ - marketplace: string; - /** - * Installed version - */ - version?: string; - /** - * Whether the plugin is currently enabled - */ - enabled: boolean; - /** - * Opaque stable identity for a direct plugin source. - */ - directSourceId?: string; - /** - * Absolute marketplace directory for a live plugin. - */ - installedFrom?: string; - /** - * Runtime plugin provenance, such as "builtin". - */ - source?: string; - /** - * Whether enterprise managed settings control this plugin. - */ - managed?: boolean; - /** - * Enabled state required by enterprise managed settings. - */ - managedDesiredEnabled?: boolean; +export interface PermissionsGetModeRequest {} +/** + * Current permission mode. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionsGetModeResult". + */ +/** @experimental */ +export interface PermissionsGetModeResult { + mode: PermissionMode; +} +/** + * Indicates whether the operation succeeded. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionsLocationsAddToolApprovalResult". + */ +/** @experimental */ +export interface PermissionsLocationsAddToolApprovalResult { /** - * Whether this managed desired plugin has an installed or live record. + * Whether the operation succeeded */ - installed?: boolean; + success: boolean; } /** - * Result of installing a plugin. + * Scope and add/remove instructions for modifying session- or location-scoped permission rules. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PluginInstallResult". + * via the `definition` "PermissionsModifyRulesParams". */ /** @experimental */ -export interface PluginInstallResult { - plugin: InstalledPluginInfo; +export interface PermissionsModifyRulesParams { + scope: PermissionsModifyRulesScope; /** - * Number of skills discovered and installed from the plugin + * Rules to add to the scope. Applied before `remove`/`removeAll`. */ - skillsInstalled: number; - stagingMode?: PluginInstallStagingMode; + add?: PermissionRule[]; /** - * Optional post-install message provided by the plugin (e.g. setup instructions) + * Specific rules to remove from the scope. Ignored when `removeAll` is true. */ - postInstallMessage?: string; + remove?: PermissionRule[]; /** - * Set when the install path is deprecated (e.g. direct repo / URL / local installs). Callers should surface this to end users. + * When true, removes every rule currently in the scope (after any `add` is applied). Useful for clearing the location scope wholesale. */ - deprecationWarning?: string; + removeAll?: boolean; } /** - * Plugins installed for the session, with their enabled state and version metadata. + * Indicates whether the operation succeeded. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PluginList". + * via the `definition` "PermissionsModifyRulesResult". */ /** @experimental */ -export interface PluginList { +export interface PermissionsModifyRulesResult { /** - * Installed plugins + * Whether the operation succeeded */ - plugins: Plugin[]; + success: boolean; } /** - * Plugins installed in user/global state. + * Indicates whether the operation succeeded. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PluginListResult". + * via the `definition` "PermissionsNotifyPromptShownResult". */ /** @experimental */ -export interface PluginListResult { +export interface PermissionsNotifyPromptShownResult { /** - * Installed plugins + * Whether the operation succeeded */ - plugins: InstalledPluginInfo[]; + success: boolean; } /** - * Trusted built-in plugin directories to use for this runtime process. + * Indicates whether the operation succeeded. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PluginsBuiltinSetRequest". + * via the `definition` "PermissionsPathsAddResult". */ /** @experimental */ -export interface PluginsBuiltinSetRequest { +export interface PermissionsPathsAddResult { /** - * Complete replacement set of trusted built-in plugin directories. Every entry must be an absolute local filesystem path no longer than 4096 characters. - * - * @maxItems 64 + * Whether the operation succeeded */ - paths: string[]; + success: boolean; } /** - * Plugin names (or specs) to disable, plus the optional working directory the repository-controlled guard is evaluated against. + * No parameters; returns the session's recursive directory grants and exact session-approved paths. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PluginsDisableRequest". + * via the `definition` "PermissionsPathsListRequest". */ /** @experimental */ -export interface PluginsDisableRequest { - /** - * Plugin names or "plugin@marketplace" specs to disable. Unknown names are ignored. Non-marketplace direct installs cannot be disabled via this API; uninstall them instead. Plugin-owned MCP servers are stopped in active sessions immediately; other plugin contributions remain available until each session reloads plugins. - */ - names: string[]; +export interface PermissionsPathsListRequest {} +/** + * Indicates whether the operation succeeded. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionsPathsUpdatePrimaryResult". + */ +/** @experimental */ +export interface PermissionsPathsUpdatePrimaryResult { /** - * Working directory whose repository `enabledPlugins` overlay decides whether this mutation is repository-controlled. Hosts that serve sessions across several repositories (the SDK server) should pass the session's directory; otherwise the guard is evaluated against the server process's own working directory, which may belong to a different repository. Defaults to the server's current working directory. + * Whether the operation succeeded */ - workingDirectory?: string; + success: boolean; } /** - * Plugin names (or specs) to enable, plus the optional working directory the repository-controlled guard is evaluated against. + * No parameters; returns currently-pending permission requests for the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PluginsEnableRequest". + * via the `definition` "PermissionsPendingRequestsRequest". */ /** @experimental */ -export interface PluginsEnableRequest { - /** - * Plugin names or "plugin@marketplace" specs to enable. Unknown names are ignored. Non-marketplace direct installs are always enabled and cannot be toggled via this API. - */ - names: string[]; +export interface PermissionsPendingRequestsRequest {} +/** + * Clears session-scoped tool approvals and optionally clears location-scoped approvals and exact session-approved paths. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionsResetSessionApprovalsRequest". + */ +/** @experimental */ +export interface PermissionsResetSessionApprovalsRequest { /** - * Working directory whose repository `enabledPlugins` overlay decides whether this mutation is repository-controlled. Hosts that serve sessions across several repositories (the SDK server) should pass the session's directory; otherwise the guard is evaluated against the server process's own working directory, which may belong to a different repository. Defaults to the server's current working directory. + * Whether location-scoped approvals and exact session-approved paths are cleared too. Defaults to `true`. */ - workingDirectory?: string; + includeLocation?: boolean; } /** - * Plugin source and optional working directory for relative-path resolution. + * Indicates whether the operation succeeded. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PluginsInstallRequest". + * via the `definition` "PermissionsResetSessionApprovalsResult". */ /** @experimental */ -export interface PluginsInstallRequest { - /** - * Plugin install spec. Accepts the same forms as the CLI: "plugin@marketplace" (marketplace install), "owner/repo" or "owner/repo:subpath" (GitHub direct), an http/https/ssh URL, or a local path. Direct (non-marketplace) installs are deprecated and will produce a deprecationWarning in the result. - */ - source: string; +export interface PermissionsResetSessionApprovalsResult { /** - * Working directory used to resolve relative local paths in `source`. Defaults to the server's current working directory. + * Whether the operation succeeded */ - workingDirectory?: string; + success: boolean; } /** - * Marketplace source and optional working directory for relative-path resolution. + * Allow-all toggle for tool permission requests, with an optional telemetry source. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PluginsMarketplacesAddRequest". + * via the `definition` "PermissionsSetApproveAllRequest". */ /** @experimental */ -export interface PluginsMarketplacesAddRequest { - /** - * Marketplace source. Accepts the same forms as the CLI: "owner/repo" or "owner/repo#ref" (GitHub), an http/https/ssh URL (optionally with #ref), a git scp-style URL (user@host:path), or a local path. The marketplace's own name (from its manifest) is used as the registration key. - */ - source: string; +export interface PermissionsSetApproveAllRequest { /** - * Working directory used to resolve relative local paths in `source`. Defaults to the server's current working directory. + * Whether to auto-approve all tool permission requests */ - workingDirectory?: string; + enabled: boolean; + source?: PermissionsSetApproveAllSource; } /** - * Name of the marketplace whose plugin catalog to fetch. + * Indicates whether the operation succeeded. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PluginsMarketplacesBrowseRequest". + * via the `definition` "PermissionsSetApproveAllResult". */ /** @experimental */ -export interface PluginsMarketplacesBrowseRequest { +export interface PermissionsSetApproveAllResult { /** - * Marketplace name to browse + * Whether the operation succeeded */ - name: string; + success: boolean; } - +/** + * Permission mode to apply for the session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionsSetModeRequest". + */ /** @experimental */ -export interface PluginsMarketplacesRefreshRequest { +export interface PermissionsSetModeRequest { + mode: PermissionMode; /** - * Marketplace name to refresh. When omitted, every registered marketplace is refreshed. + * Optional judge model id for assisted mode. When omitted, the session resolves the provider default: `gpt-5.5` for CAPI sessions and the active session model for BYOK sessions. */ - name?: string; + assistedApprovalModel?: string; + source?: PermissionModeSource; } /** - * Name of the marketplace to remove and an optional force flag. + * Indicates whether the requested permission mode was applied and reports the authoritative post-mutation mode. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PluginsMarketplacesRemoveRequest". + * via the `definition` "PermissionsSetModeResult". */ /** @experimental */ -export interface PluginsMarketplacesRemoveRequest { - /** - * Marketplace name to remove - */ - name: string; +export interface PermissionsSetModeResult { /** - * When true, also uninstall every plugin sourced from this marketplace. When false (default), removal is a no-op if any plugin from this marketplace is installed and the dependent plugin names are returned in the result. + * Whether the operation succeeded */ - force?: boolean; + success: boolean; + mode: PermissionMode; } /** - * Name (or spec) of the plugin to uninstall. + * Toggles whether permission prompts should be bridged into session events for this client. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PluginsUninstallRequest". + * via the `definition` "PermissionsSetRequiredRequest". */ /** @experimental */ -export interface PluginsUninstallRequest { - /** - * Plugin name or "plugin@marketplace" spec to uninstall. When ambiguous, prefer the fully-qualified spec. - */ - name: string; +export interface PermissionsSetRequiredRequest { /** - * Stable source identity for a direct (non-marketplace) install. Disambiguates uninstall when multiple installed plugins share the same name. + * Whether the client wants `permission.requested` events bridged from the session-owned permission service. CLI clients that render prompt UI set this to `true` for as long as their listener is mounted; headless callers leave it unset (the default is `false`). */ - directSourceId?: string | null; + required: boolean; } /** - * Name (or spec) of the plugin to update. + * Indicates whether the operation succeeded. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PluginsUpdateRequest". + * via the `definition` "PermissionsSetRequiredResult". */ /** @experimental */ -export interface PluginsUpdateRequest { +export interface PermissionsSetRequiredResult { /** - * Plugin name or "plugin@marketplace" spec to update. + * Whether the operation succeeded */ - name: string; + success: boolean; } /** - * Per-plugin result from updating all plugins, with versions, skills installed, success flag, and optional error. + * Indicates whether the operation succeeded. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PluginUpdateAllEntry". + * via the `definition` "PermissionsUrlsSetUnrestrictedModeResult". */ /** @experimental */ -export interface PluginUpdateAllEntry { +export interface PermissionsUrlsSetUnrestrictedModeResult { /** - * Plugin name that was updated + * Whether the operation succeeded */ - name: string; + success: boolean; +} +/** + * Whether the URL-permission policy should run in unrestricted mode. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PermissionUrlsSetUnrestrictedModeParams". + */ +/** @experimental */ +export interface PermissionUrlsSetUnrestrictedModeParams { /** - * Marketplace the plugin came from. Empty string ("") for direct installs. + * Whether to allow access to all URLs without prompting. Toggles the runtime's URL-permission policy in place. */ - marketplace: string; + enabled: boolean; +} +/** + * A complete JSON snapshot to write under the runtime's per-path file lock. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PersistenceWriteRawJsonLockedRequest". + */ +/** @experimental */ +export interface PersistenceWriteRawJsonLockedRequest { /** - * Whether the update succeeded for this plugin + * Absolute path of the file to replace. Parent directories are created when missing. */ - success: boolean; + path: string; /** - * Previously installed version, when available + * The serialized JSON document to write. It replaces the file's contents entirely; nothing is merged. */ - previousVersion?: string; + dataJson: string; /** - * Version after the update, when available + * Comment lines to emit above the document, for a format that tolerates them. Omit for strict JSON. */ - newVersion?: string; + fileHeader?: string | null; +} +/** + * The outcome of a locked snapshot write. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PersistenceWriteRawJsonLockedResult". + */ +/** @experimental */ +export interface PersistenceWriteRawJsonLockedResult { /** - * Number of skills installed after the update (success only) + * Whether the file now holds the requested contents. */ - skillsInstalled?: number; + success: boolean; /** - * Error message (failure only) + * Why the write failed. Absent when `success` is true. A lock the runtime could not acquire in time reports here rather than raising. */ - error?: string; + error?: string | null; } /** - * Result of updating all installed plugins. + * Optional message to echo back to the caller. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PluginUpdateAllResult". + * via the `definition` "PingRequest". */ /** @experimental */ -export interface PluginUpdateAllResult { +export interface PingRequest { /** - * Per-plugin update results in deterministic order. + * Optional message to echo back */ - results: PluginUpdateAllEntry[]; + message?: string; } /** - * Result of updating a single plugin. + * Server liveness response, including the echoed message, current server timestamp, and protocol version. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PluginUpdateResult". + * via the `definition` "PingResult". */ /** @experimental */ -export interface PluginUpdateResult { +export interface PingResult { /** - * Version that was previously installed, when available + * Echoed message (or default greeting) */ - previousVersion?: string; + message: string; /** - * Version after the update, when reported by the plugin manifest + * ISO 8601 timestamp when the server handled the ping */ - newVersion?: string; + timestamp: string; /** - * Number of skills discovered and installed after the update + * Server protocol version number */ - skillsInstalled: number; + protocolVersion: number; } /** - * Serializable definition of a caller-implemented tool whose execution is handled over the SDK connection. + * Existence, contents, and resolved path of the session plan file. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ProtocolExternalToolDefinition". + * via the `definition` "PlanReadResult". */ /** @experimental */ -export interface ProtocolExternalToolDefinition { +export interface PlanReadResult { /** - * Unique model-visible tool name. + * Whether the plan file exists in the workspace */ - name: string; + exists: boolean; /** - * Model-visible explanation of what the tool does. + * The content of the plan file, or null if it does not exist */ - description: string; + content: string | null; /** - * Optional human-readable display title. + * Absolute file path of the plan file, or null if workspace is not enabled */ - title?: string; + path: string | null; +} +/** + * Todo rows read from the session SQL database. Empty when no session database is available. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PlanReadSqlTodosResult". + */ +/** @experimental */ +export interface PlanReadSqlTodosResult { /** - * JSON Schema describing the tool's input arguments. + * Rows from the session SQL todos table, ordered by creation time with insertion order used to break ties when available and id used for WITHOUT ROWID tables. */ - parameters?: { - [k: string]: JsonValue | undefined; - }; + rows: PlanSqlTodosRow[]; +} +/** + * A single todo row read from the session SQL `todos` table. All fields are optional because the SQL schema is best-effort and the agent may not have populated every column. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PlanSqlTodosRow". + */ +/** @experimental */ +export interface PlanSqlTodosRow { /** - * Whether this definition replaces a built-in tool with the same name. + * Todo identifier. */ - overridesBuiltInTool?: boolean; + id?: string; /** - * Whether execution bypasses the normal tool permission prompt. + * Todo title. */ - skipPermission?: boolean; - defer?: ProtocolExternalToolDefer; + title?: string; /** - * Whether the tool executes commands in a terminal. + * Todo description. */ - isTerminal?: boolean; + description?: string; /** - * Optional caller-defined metadata associated with the tool. + * Todo status. */ - metadata?: { - [k: string]: JsonValue | undefined; - }; + status?: string; + /** + * Todo creation time, as stored by the session SQL schema's `datetime('now')` default: `YYYY-MM-DD HH:MM:SS` in UTC. Lets clients attribute todos to the work item that created them (e.g. scoping a goal's progress to the todos it produced) rather than to the whole session. + */ + createdAt?: string; } /** - * BYOK providers and/or models to add to the session's registry at runtime. Both fields are optional; provide providers, models, or both. + * Todo rows + dependency edges read from the session SQL database. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ProviderAddRequest". + * via the `definition` "PlanReadSqlTodosWithDependenciesResult". */ /** @experimental */ -export interface ProviderAddRequest { +export interface PlanReadSqlTodosWithDependenciesResult { /** - * Named BYOK provider connections to register, additive to any providers already in the registry. Each name must be unique across the registry and must not contain '/'. + * Rows from the session SQL todos table, ordered by creation time with insertion order used to break ties when available and id used for WITHOUT ROWID tables. Empty when no database, no todos table, or the SELECT failed. */ - providers?: NamedProviderConfig[]; + rows: PlanSqlTodosRow[]; /** - * BYOK model definitions to register. Each must reference a provider that is already registered or included in this same call. Selection ids (`provider/id`) must be unique across the registry. + * Edges from the session SQL todo_deps table. Empty when no database, no todo_deps table, or the SELECT failed. Read independently from `rows`, so a broken todo_deps table does not affect the rows result and vice versa. */ - models?: ProviderModelConfig[]; + dependencies: PlanSqlTodoDependency[]; } /** - * The selectable model entries synthesized for the models added by this call. + * A single dependency edge read from the session SQL `todo_deps` table, indicating that one todo must complete before another. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ProviderAddResult". + * via the `definition` "PlanSqlTodoDependency". */ /** @experimental */ -export interface ProviderAddResult { +export interface PlanSqlTodoDependency { /** - * Synthesized selectable model entries for the newly added BYOK models, each under its provider-qualified selection id (`provider/id`). Empty when only providers were added. + * ID of the todo that has the dependency. */ - models: JsonValue[]; + todoId: string; + /** + * ID of the todo it depends on. + */ + dependsOn: string; } /** - * Custom model-provider configuration (BYOK). + * Replacement contents to write to the session plan file. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ProviderConfig". + * via the `definition` "PlanUpdateRequest". */ /** @experimental */ -export interface ProviderConfig { - type?: ProviderConfigType; - wireApi?: ProviderConfigWireApi; - transport?: ProviderConfigTransport; +export interface PlanUpdateRequest { /** - * API endpoint URL. + * The new content for the plan file */ - baseUrl: string; + content: string; +} +/** + * Session plugin metadata, with name, marketplace, optional version, and enabled state. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "Plugin". + */ +/** @experimental */ +export interface Plugin { /** - * API key. Optional for local providers like Ollama. + * Plugin name */ - apiKey?: string; + name: string; /** - * Bearer token for authentication. Sets the Authorization header directly. Takes precedence over apiKey when both are set. + * Marketplace the plugin came from */ - bearerToken?: string; - azure?: ProviderConfigAzure; + marketplace: string; /** - * Well-known model ID used for capability lookup. When set, agent behavior config and token limits are inferred from this model. + * Installed version */ - modelId?: string; - modelCapabilities?: ModelCapabilitiesOverride; + version?: string; /** - * Provider name used for model and telemetry attribution. + * Whether the plugin is currently enabled */ - providerName?: string; - modelProvider?: ProviderConfigModelProvider; + enabled: boolean; /** - * The model identifier sent to the provider API for inference (the "wire" model), as opposed to modelId which is the well-known base. + * Opaque stable identity for a direct plugin source. */ - wireModel?: string; + directSourceId?: string; /** - * Maximum prompt/input tokens for the model. + * Absolute marketplace directory for a live plugin. */ - maxPromptTokens?: number; + installedFrom?: string; /** - * Maximum context window tokens for the model. + * Runtime plugin provenance, such as "builtin". */ - maxContextWindowTokens?: number; + source?: string; /** - * Maximum output tokens for the model. + * Whether enterprise managed settings control this plugin. */ - maxOutputTokens?: number; + managed?: boolean; /** - * Custom HTTP headers to include in all outbound requests to the provider. + * Enabled state required by enterprise managed settings. */ - headers?: { - [k: string]: string | undefined; - }; + managedDesiredEnabled?: boolean; /** - * When true, the SDK client supplies bearer tokens on demand: the runtime calls the client-session `providerToken.getToken` callback before each request and applies the returned token as an `Authorization: Bearer ` header. This is the bearer/OAuth scheme used by Azure AD / managed-identity tokens and provider OAuth access tokens (including Anthropic's), not a provider-specific API-key header such as Anthropic's `x-api-key`. The token-acquiring function itself stays on the SDK side and is never serialized; only this flag crosses the wire. When set alongside `apiKey`/`bearerToken`, the callback takes precedence: the runtime applies the token returned by `providerToken.getToken` as the `Authorization: Bearer` header for each request and does not send the static credential. + * Whether this managed desired plugin has an installed or live record. */ - hasBearerTokenProvider?: boolean; + installed?: boolean; } /** - * A snapshot of the provider endpoint the session is currently configured to talk to. + * Result of installing a plugin. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ProviderEndpoint". + * via the `definition` "PluginInstallResult". */ /** @experimental */ -export interface ProviderEndpoint { - type: ProviderEndpointType; - wireApi?: ProviderEndpointWireApi; - transport?: ProviderEndpointTransport; +export interface PluginInstallResult { + plugin: InstalledPluginInfo; /** - * Base URL to pass to the LLM client library. + * Number of skills discovered and installed from the plugin */ - baseUrl: string; + skillsInstalled: number; + stagingMode?: PluginInstallStagingMode; /** - * A credential the caller should use with this endpoint. Omitted only when the endpoint accepts unauthenticated requests. + * Optional post-install message provided by the plugin (e.g. setup instructions) */ - apiKey?: string; + postInstallMessage?: string; /** - * HTTP headers the caller must include on every outbound request. + * Set when the install path is deprecated (e.g. direct repo / URL / local installs). Callers should surface this to end users. */ - headers: { - [k: string]: string | undefined; - }; - sessionToken?: ProviderSessionToken; + deprecationWarning?: string; } /** - * Short-lived, rotating credential the caller must send on every request, in addition to `apiKey` if one is present. Omitted when the endpoint does not require one. + * Plugins installed for the session, with their enabled state and version metadata. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ProviderSessionToken". + * via the `definition` "PluginList". */ /** @experimental */ -export interface ProviderSessionToken { - /** - * The short-lived token value. - */ - token: string; - /** - * HTTP header name the token must be sent under. - */ - header: string; - /** - * The model the token is bound to, when applicable. When set, the token is only valid for requests against this model. - */ - model?: string; +export interface PluginList { /** - * When the token expires, if known. Callers should refresh by calling `getEndpoint` again before this time, or reactively on any 401/403 response from `baseUrl`. + * Installed plugins */ - expiresAt?: string; + plugins: Plugin[]; } /** - * Authoritative BYOK provider and model registry snapshot to apply atomically to the session. + * Plugins installed in user/global state. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ProviderSyncRequest". + * via the `definition` "PluginListResult". */ /** @experimental */ -export interface ProviderSyncRequest { - /** - * Named BYOK provider connection snapshot. Providers absent from this list are removed. - */ - providers?: NamedProviderConfig[]; +export interface PluginListResult { /** - * BYOK model definition snapshot. Models absent from this list are removed. + * Installed plugins */ - models?: ProviderModelConfig[]; + plugins: InstalledPluginInfo[]; } /** - * The selectable model entries and selection ids synthesized for the synchronized BYOK models. + * Trusted built-in plugin directories to use for this runtime process. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ProviderSyncResult". + * via the `definition` "PluginsBuiltinSetRequest". */ /** @experimental */ -export interface ProviderSyncResult { - /** - * Synthesized selectable model entries for the synchronized BYOK models. - */ - models: JsonValue[]; - /** - * Provider-qualified model selection ids present after synchronization. - */ - selectionIds: string[]; +export interface PluginsBuiltinSetRequest { /** - * True when synchronization withdrew the selected host-managed model, leaving the session with no explicit selection, so ordinary model resolution picks the session default. Synchronization never promotes a surviving host model in its place: publishing a model offers it, and the choice of which model to use stays with the user. + * Complete replacement set of trusted built-in plugin directories. Every entry must be an absolute local filesystem path no longer than 4096 characters. + * + * @maxItems 64 */ - modelDeselected?: boolean; + paths: string[]; } /** - * Asks the SDK client to acquire a bearer token for a BYOK provider whose config set `hasBearerTokenProvider: true`. Issued by the runtime before each outbound model request; the runtime does no caching, so this is sent once per request. + * Plugin names (or specs) to disable, plus the optional working directory the repository-controlled guard is evaluated against. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ProviderTokenAcquireRequest". + * via the `definition` "PluginsDisableRequest". */ /** @experimental */ -export interface ProviderTokenAcquireRequest { +export interface PluginsDisableRequest { /** - * Target session identifier + * Plugin names or "plugin@marketplace" specs to disable. Unknown names are ignored. Non-marketplace direct installs cannot be disabled via this API; uninstall them instead. Plugin-owned MCP servers are stopped in active sessions immediately; other plugin contributions remain available until each session reloads plugins. */ - sessionId: string; + names: string[]; /** - * Name of the BYOK provider needing a token. For the legacy whole-session provider this is the implicit provider name; for named providers it is the configured provider name. + * Working directory whose repository `enabledPlugins` overlay decides whether this mutation is repository-controlled. Hosts that serve sessions across several repositories (the SDK server) should pass the session's directory; otherwise the guard is evaluated against the server process's own working directory, which may belong to a different repository. Defaults to the server's current working directory. */ - providerName: string; + workingDirectory?: string; } /** - * A bearer token supplied by the SDK client for a BYOK provider. The runtime sets it as `Authorization: Bearer ` on the outbound request and does no caching; the SDK consumer owns token caching and refresh. + * Plugin names (or specs) to enable, plus the optional working directory the repository-controlled guard is evaluated against. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ProviderTokenAcquireResult". + * via the `definition` "PluginsEnableRequest". */ /** @experimental */ -export interface ProviderTokenAcquireResult { +export interface PluginsEnableRequest { /** - * The bearer token value (without the `Bearer ` prefix). + * Plugin names or "plugin@marketplace" specs to enable. Unknown names are ignored. Non-marketplace direct installs are always enabled and cannot be toggled via this API. */ - token: string; + names: string[]; + /** + * Working directory whose repository `enabledPlugins` overlay decides whether this mutation is repository-controlled. Hosts that serve sessions across several repositories (the SDK server) should pass the session's directory; otherwise the guard is evaluated against the server process's own working directory, which may belong to a different repository. Defaults to the server's current working directory. + */ + workingDirectory?: string; } /** - * Host-managed model selection ids to withdraw from the session's BYOK registry. + * Plugin source and optional working directory for relative-path resolution. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ProviderWithdrawRequest". + * via the `definition` "PluginsInstallRequest". */ /** @experimental */ -export interface ProviderWithdrawRequest { +export interface PluginsInstallRequest { /** - * Provider-qualified selection ids to withdraw. Ids that are not registered are ignored, so withdrawal is idempotent. A provider left with no models referencing it is removed too. + * Plugin install spec. Accepts the same forms as the CLI: "plugin@marketplace" (marketplace install), "owner/repo" or "owner/repo:subpath" (GitHub direct), an http/https/ssh URL, or a local path. Direct (non-marketplace) installs are deprecated and will produce a deprecationWarning in the result. */ - models: string[]; + source: string; + /** + * Working directory used to resolve relative local paths in `source`. Defaults to the server's current working directory. + */ + workingDirectory?: string; } /** - * What the withdrawal actually removed from the registry. + * Marketplace source and optional working directory for relative-path resolution. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ProviderWithdrawResult". + * via the `definition` "PluginsMarketplacesAddRequest". */ /** @experimental */ -export interface ProviderWithdrawResult { - /** - * Selection ids that were registered and are now withdrawn. Excludes requested ids that were not present. - */ - withdrawn: string[]; +export interface PluginsMarketplacesAddRequest { /** - * Providers removed because one of the withdrawn models was the last entry referencing them. A provider that merely has no models is not removed. + * Marketplace source. Accepts the same forms as the CLI: "owner/repo" or "owner/repo#ref" (GitHub), an http/https/ssh URL (optionally with #ref), a git scp-style URL (user@host:path), or a local path. The marketplace's own name (from its manifest) is used as the registration key. */ - providersRemoved: string[]; + source: string; /** - * True when withdrawal removed the selected host-managed model, leaving the session with no explicit selection, so ordinary model resolution picks the session default. Withdrawal never promotes a surviving model in its place: the choice of which model to use stays with the user. + * Working directory used to resolve relative local paths in `source`. Defaults to the server's current working directory. */ - modelDeselected?: boolean; + workingDirectory?: string; } /** - * File attachment + * Name of the marketplace whose plugin catalog to fetch. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PushAttachmentFile". + * via the `definition` "PluginsMarketplacesBrowseRequest". */ /** @experimental */ -export interface PushAttachmentFile { - /** - * Attachment type discriminator - */ - type: "file"; +export interface PluginsMarketplacesBrowseRequest { /** - * Absolute file path + * Marketplace name to browse */ - path: string; + name: string; +} + +/** @experimental */ +export interface PluginsMarketplacesRefreshRequest { /** - * User-facing display name for the attachment + * Marketplace name to refresh. When omitted, every registered marketplace is refreshed. */ - displayName: string; - lineRange?: PushAttachmentFileLineRange; + name?: string; } /** - * Optional line range to scope the attachment to a specific section of the file + * Name of the marketplace to remove and an optional force flag. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PushAttachmentFileLineRange". + * via the `definition` "PluginsMarketplacesRemoveRequest". */ /** @experimental */ -export interface PushAttachmentFileLineRange { +export interface PluginsMarketplacesRemoveRequest { /** - * Start line number (1-based) + * Marketplace name to remove */ - start: number; + name: string; /** - * End line number (1-based, inclusive) + * When true, also uninstall every plugin sourced from this marketplace. When false (default), removal is a no-op if any plugin from this marketplace is installed and the dependent plugin names are returned in the result. */ - end: number; + force?: boolean; } /** - * Directory attachment + * Name (or spec) of the plugin to uninstall. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PushAttachmentDirectory". + * via the `definition` "PluginsUninstallRequest". */ /** @experimental */ -export interface PushAttachmentDirectory { +export interface PluginsUninstallRequest { /** - * Attachment type discriminator + * Plugin name or "plugin@marketplace" spec to uninstall. When ambiguous, prefer the fully-qualified spec. */ - type: "directory"; + name: string; /** - * Absolute directory path + * Stable source identity for a direct (non-marketplace) install. Disambiguates uninstall when multiple installed plugins share the same name. */ - path: string; + directSourceId?: string | null; +} +/** + * Name (or spec) of the plugin to update. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PluginsUpdateRequest". + */ +/** @experimental */ +export interface PluginsUpdateRequest { /** - * User-facing display name for the attachment + * Plugin name or "plugin@marketplace" spec to update. */ - displayName: string; + name: string; } /** - * Code selection attachment from an editor + * Per-plugin result from updating all plugins, with versions, skills installed, success flag, and optional error. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PushAttachmentSelection". + * via the `definition` "PluginUpdateAllEntry". */ /** @experimental */ -export interface PushAttachmentSelection { +export interface PluginUpdateAllEntry { /** - * Attachment type discriminator + * Plugin name that was updated */ - type: "selection"; + name: string; /** - * Absolute path to the file containing the selection + * Marketplace the plugin came from. Empty string ("") for direct installs. */ - filePath: string; + marketplace: string; /** - * User-facing display name for the selection + * Whether the update succeeded for this plugin */ - displayName: string; + success: boolean; /** - * The selected text content + * Previously installed version, when available */ - text: string; - selection: PushAttachmentSelectionDetails; + previousVersion?: string; + /** + * Version after the update, when available + */ + newVersion?: string; + /** + * Number of skills installed after the update (success only) + */ + skillsInstalled?: number; + /** + * Error message (failure only) + */ + error?: string; } /** - * Position range of the selection within the file + * Result of updating all installed plugins. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PushAttachmentSelectionDetails". + * via the `definition` "PluginUpdateAllResult". */ /** @experimental */ -export interface PushAttachmentSelectionDetails { - start: PushAttachmentSelectionDetailsStart; - end: PushAttachmentSelectionDetailsEnd; +export interface PluginUpdateAllResult { + /** + * Per-plugin update results in deterministic order. + */ + results: PluginUpdateAllEntry[]; } /** - * Start position of the selection + * Result of updating a single plugin. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PushAttachmentSelectionDetailsStart". + * via the `definition` "PluginUpdateResult". */ /** @experimental */ -export interface PushAttachmentSelectionDetailsStart { +export interface PluginUpdateResult { /** - * Start line number (0-based) + * Version that was previously installed, when available */ - line: number; + previousVersion?: string; /** - * Start character offset within the line (0-based) + * Version after the update, when reported by the plugin manifest */ - character: number; + newVersion?: string; + /** + * Number of skills discovered and installed after the update + */ + skillsInstalled: number; } /** - * End position of the selection + * Serializable definition of a caller-implemented tool whose execution is handled over the SDK connection. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PushAttachmentSelectionDetailsEnd". + * via the `definition` "ProtocolExternalToolDefinition". */ /** @experimental */ -export interface PushAttachmentSelectionDetailsEnd { +export interface ProtocolExternalToolDefinition { /** - * End line number (0-based) + * Unique model-visible tool name. */ - line: number; + name: string; /** - * End character offset within the line (0-based) + * Model-visible explanation of what the tool does. */ - character: number; -} -/** - * GitHub issue, pull request, or discussion reference - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PushAttachmentGitHubReference". - */ -/** @experimental */ -export interface PushAttachmentGitHubReference { + description: string; /** - * Attachment type discriminator + * Optional human-readable display title. */ - type: "github_reference"; + title?: string; /** - * Issue, pull request, or discussion number + * JSON Schema describing the tool's input arguments. */ - number: number; + parameters?: { + [k: string]: JsonValue | undefined; + }; /** - * Title of the referenced item + * Whether this definition replaces a built-in tool with the same name. */ - title: string; - referenceType: PushAttachmentGitHubReferenceType; + overridesBuiltInTool?: boolean; /** - * Current state of the referenced item (e.g., open, closed, merged) + * Whether execution bypasses the normal tool permission prompt. */ - state: string; + skipPermission?: boolean; + defer?: ProtocolExternalToolDefer; /** - * URL to the referenced item on GitHub + * Whether the tool executes commands in a terminal. */ - url: string; + isTerminal?: boolean; + /** + * Optional caller-defined metadata associated with the tool. + */ + metadata?: { + [k: string]: JsonValue | undefined; + }; } /** - * Pointer to a GitHub commit. + * BYOK providers and/or models to add to the session's registry at runtime. Both fields are optional; provide providers, models, or both. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PushAttachmentGitHubCommit". + * via the `definition` "ProviderAddRequest". */ /** @experimental */ -export interface PushAttachmentGitHubCommit { - /** - * Attachment type discriminator - */ - type: "github_commit"; - repo: PushGitHubRepoRef; - /** - * Full commit SHA - */ - oid: string; +export interface ProviderAddRequest { /** - * First line of the commit message + * Named BYOK provider connections to register, additive to any providers already in the registry. Each name must be unique across the registry and must not contain '/'. */ - message: string; + providers?: NamedProviderConfig[]; /** - * URL to the commit on GitHub + * BYOK model definitions to register. Each must reference a provider that is already registered or included in this same call. Selection ids (`provider/id`) must be unique across the registry. */ - url: string; + models?: ProviderModelConfig[]; } /** - * Pointer to a GitHub repository. + * The selectable model entries synthesized for the models added by this call. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PushGitHubRepoRef". + * via the `definition` "ProviderAddResult". */ /** @experimental */ -export interface PushGitHubRepoRef { - /** - * Numeric GitHub repository id - */ - id?: number; - /** - * Repository name (without owner) - */ - name: string; +export interface ProviderAddResult { /** - * Repository owner login (user or organization) + * Synthesized selectable model entries for the newly added BYOK models, each under its provider-qualified selection id (`provider/id`). Empty when only providers were added. */ - owner: string; + models: JsonValue[]; } /** - * Pointer to a GitHub release. + * Custom model-provider configuration (BYOK). * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PushAttachmentGitHubRelease". + * via the `definition` "ProviderConfig". */ /** @experimental */ -export interface PushAttachmentGitHubRelease { +export interface ProviderConfig { + type?: ProviderConfigType; + wireApi?: ProviderConfigWireApi; + transport?: ProviderConfigTransport; /** - * Attachment type discriminator + * API endpoint URL. */ - type: "github_release"; - repo: PushGitHubRepoRef; + baseUrl: string; /** - * Git tag the release is anchored to + * API key. Optional for local providers like Ollama. */ - tagName: string; + apiKey?: string; /** - * Human-readable release name + * Bearer token for authentication. Sets the Authorization header directly. Takes precedence over apiKey when both are set. */ - name: string; + bearerToken?: string; + azure?: ProviderConfigAzure; /** - * URL to the release on GitHub + * Well-known model ID used for capability lookup. When set, agent behavior config and token limits are inferred from this model. */ - url: string; -} -/** - * Pointer to a GitHub Actions job. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PushAttachmentGitHubActionsJob". - */ -/** @experimental */ -export interface PushAttachmentGitHubActionsJob { + modelId?: string; + modelCapabilities?: ModelCapabilitiesOverride; /** - * Attachment type discriminator + * Provider name used for model and telemetry attribution. */ - type: "github_actions_job"; - repo: PushGitHubRepoRef; + providerName?: string; + modelProvider?: ProviderConfigModelProvider; /** - * Job id within the workflow run + * The model identifier sent to the provider API for inference (the "wire" model), as opposed to modelId which is the well-known base. */ - jobId: number; + wireModel?: string; /** - * Display name of the job + * Maximum prompt/input tokens for the model. */ - jobName: string; + maxPromptTokens?: number; /** - * Display name of the workflow the job ran in + * Maximum context window tokens for the model. */ - workflowName: string; + maxContextWindowTokens?: number; /** - * URL to the job on GitHub + * Maximum output tokens for the model. */ - url: string; + maxOutputTokens?: number; /** - * Terminal conclusion of the job when finished (e.g., success, failure, cancelled). Absent for in-progress jobs. + * Custom HTTP headers to include in all outbound requests to the provider. */ - conclusion?: string; + headers?: { + [k: string]: string | undefined; + }; + /** + * When true, the SDK client supplies bearer tokens on demand: the runtime calls the client-session `providerToken.getToken` callback before each request and applies the returned token as an `Authorization: Bearer ` header. This is the bearer/OAuth scheme used by Azure AD / managed-identity tokens and provider OAuth access tokens (including Anthropic's), not a provider-specific API-key header such as Anthropic's `x-api-key`. The token-acquiring function itself stays on the SDK side and is never serialized; only this flag crosses the wire. When set alongside `apiKey`/`bearerToken`, the callback takes precedence: the runtime applies the token returned by `providerToken.getToken` as the `Authorization: Bearer` header for each request and does not send the static credential. + */ + hasBearerTokenProvider?: boolean; } /** - * Pointer to a GitHub repository. + * A snapshot of the provider endpoint the session is currently configured to talk to. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PushAttachmentGitHubRepository". + * via the `definition` "ProviderEndpoint". */ /** @experimental */ -export interface PushAttachmentGitHubRepository { - /** - * Attachment type discriminator - */ - type: "github_repository"; - repo: PushGitHubRepoRef; +export interface ProviderEndpoint { + type: ProviderEndpointType; + wireApi?: ProviderEndpointWireApi; + transport?: ProviderEndpointTransport; /** - * URL to the repository on GitHub + * Base URL to pass to the LLM client library. */ - url: string; + baseUrl: string; /** - * Short description of the repository + * A credential the caller should use with this endpoint. Omitted only when the endpoint accepts unauthenticated requests. */ - description?: string; + apiKey?: string; /** - * Git ref this attachment is anchored at (branch, tag, or commit). When absent the default branch is implied. + * HTTP headers the caller must include on every outbound request. */ - ref?: string; + headers: { + [k: string]: string | undefined; + }; + sessionToken?: ProviderSessionToken; } /** - * Pointer to a single-file diff. At least one of `head` and `base` must be present. + * Short-lived, rotating credential the caller must send on every request, in addition to `apiKey` if one is present. Omitted when the endpoint does not require one. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PushAttachmentGitHubFileDiff". + * via the `definition` "ProviderSessionToken". */ /** @experimental */ -export interface PushAttachmentGitHubFileDiff { +export interface ProviderSessionToken { /** - * Attachment type discriminator + * The short-lived token value. */ - type: "github_file_diff"; + token: string; /** - * URL to the diff on GitHub (e.g., a commit, compare, or PR-file URL) + * HTTP header name the token must be sent under. */ - url: string; - head?: PushAttachmentGitHubFileDiffSide; - base?: PushAttachmentGitHubFileDiffSide; + header: string; + /** + * The model the token is bound to, when applicable. When set, the token is only valid for requests against this model. + */ + model?: string; + /** + * When the token expires, if known. Callers should refresh by calling `getEndpoint` again before this time, or reactively on any 401/403 response from `baseUrl`. + */ + expiresAt?: string; } /** - * One side of a file diff (head or base) + * Authoritative BYOK provider and model registry snapshot to apply atomically to the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PushAttachmentGitHubFileDiffSide". + * via the `definition` "ProviderSyncRequest". */ /** @experimental */ -export interface PushAttachmentGitHubFileDiffSide { - repo: PushGitHubRepoRef; +export interface ProviderSyncRequest { /** - * Git ref (branch, tag, or commit SHA) the file is read at + * Named BYOK provider connection snapshot. Providers absent from this list are removed. */ - ref: string; + providers?: NamedProviderConfig[]; /** - * Repository-relative path to the file + * BYOK model definition snapshot. Models absent from this list are removed. */ - path: string; + models?: ProviderModelConfig[]; } /** - * Pointer to a comparison between two git revisions. + * The selectable model entries and selection ids synthesized for the synchronized BYOK models. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PushAttachmentGitHubTreeComparison". + * via the `definition` "ProviderSyncResult". */ /** @experimental */ -export interface PushAttachmentGitHubTreeComparison { +export interface ProviderSyncResult { /** - * Attachment type discriminator + * Synthesized selectable model entries for the synchronized BYOK models. */ - type: "github_tree_comparison"; + models: JsonValue[]; /** - * URL to the comparison on GitHub + * Provider-qualified model selection ids present after synchronization. */ - url: string; - base: PushAttachmentGitHubTreeComparisonSide; - head: PushAttachmentGitHubTreeComparisonSide; + selectionIds: string[]; + /** + * True when synchronization withdrew the selected host-managed model, leaving the session with no explicit selection, so ordinary model resolution picks the session default. Synchronization never promotes a surviving host model in its place: publishing a model offers it, and the choice of which model to use stays with the user. + */ + modelDeselected?: boolean; } /** - * One side of a tree comparison (head or base) + * Asks the SDK client to acquire a bearer token for a BYOK provider whose config set `hasBearerTokenProvider: true`. Issued by the runtime before each outbound model request; the runtime does no caching, so this is sent once per request. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PushAttachmentGitHubTreeComparisonSide". + * via the `definition` "ProviderTokenAcquireRequest". */ /** @experimental */ -export interface PushAttachmentGitHubTreeComparisonSide { - repo: PushGitHubRepoRef; +export interface ProviderTokenAcquireRequest { /** - * Git revision (branch, tag, or commit SHA) + * Target session identifier */ - revision: string; + sessionId: string; + /** + * Name of the BYOK provider needing a token. For the legacy whole-session provider this is the implicit provider name; for named providers it is the configured provider name. + */ + providerName: string; } /** - * Generic GitHub URL reference. + * A bearer token supplied by the SDK client for a BYOK provider. The runtime sets it as `Authorization: Bearer ` on the outbound request and does no caching; the SDK consumer owns token caching and refresh. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PushAttachmentGitHubUrl". + * via the `definition` "ProviderTokenAcquireResult". */ /** @experimental */ -export interface PushAttachmentGitHubUrl { - /** - * Attachment type discriminator - */ - type: "github_url"; +export interface ProviderTokenAcquireResult { /** - * URL to the GitHub resource + * The bearer token value (without the `Bearer ` prefix). */ - url: string; + token: string; } /** - * Pointer to a file in a GitHub repository at a specific ref. + * Host-managed model selection ids to withdraw from the session's BYOK registry. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PushAttachmentGitHubFile". + * via the `definition` "ProviderWithdrawRequest". */ /** @experimental */ -export interface PushAttachmentGitHubFile { +export interface ProviderWithdrawRequest { /** - * Attachment type discriminator + * Provider-qualified selection ids to withdraw. Ids that are not registered are ignored, so withdrawal is idempotent. A provider left with no models referencing it is removed too. */ - type: "github_file"; - repo: PushGitHubRepoRef; + models: string[]; +} +/** + * What the withdrawal actually removed from the registry. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ProviderWithdrawResult". + */ +/** @experimental */ +export interface ProviderWithdrawResult { /** - * Git ref the file is read at (branch, tag, or commit SHA) + * Selection ids that were registered and are now withdrawn. Excludes requested ids that were not present. */ - ref: string; + withdrawn: string[]; /** - * Repository-relative path to the file + * Providers removed because one of the withdrawn models was the last entry referencing them. A provider that merely has no models is not removed. */ - path: string; + providersRemoved: string[]; /** - * URL to the file on GitHub + * True when withdrawal removed the selected host-managed model, leaving the session with no explicit selection, so ordinary model resolution picks the session default. Withdrawal never promotes a surviving model in its place: the choice of which model to use stays with the user. */ - url: string; + modelDeselected?: boolean; } /** - * Pointer to a line range inside a file in a GitHub repository. + * File attachment * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PushAttachmentGitHubSnippet". + * via the `definition` "PushAttachmentFile". */ /** @experimental */ -export interface PushAttachmentGitHubSnippet { +export interface PushAttachmentFile { /** * Attachment type discriminator */ - type: "github_snippet"; - repo: PushGitHubRepoRef; - /** - * Git ref the file is read at (branch, tag, or commit SHA) - */ - ref: string; + type: "file"; /** - * Repository-relative path to the file + * Absolute file path */ path: string; /** - * URL to the snippet on GitHub (with line anchor) + * User-facing display name for the attachment */ - url: string; - lineRange: PushAttachmentFileLineRange; + displayName: string; + lineRange?: PushAttachmentFileLineRange; } /** - * Blob attachment with inline base64-encoded data + * Optional line range to scope the attachment to a specific section of the file * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "PushAttachmentBlob". + * via the `definition` "PushAttachmentFileLineRange". */ /** @experimental */ -export interface PushAttachmentBlob { +export interface PushAttachmentFileLineRange { /** - * Attachment type discriminator + * Start line number (1-based) */ - type: "blob"; + start: number; /** - * Base64-encoded content + * End line number (1-based, inclusive) */ - data: string; + end: number; +} +/** + * Directory attachment + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PushAttachmentDirectory". + */ +/** @experimental */ +export interface PushAttachmentDirectory { /** - * MIME type of the inline data + * Attachment type discriminator */ - mimeType: string; + type: "directory"; + /** + * Absolute directory path + */ + path: string; /** * User-facing display name for the attachment */ - displayName?: string; + displayName: string; } /** - * Append to one pending steering message without changing its identity or delivery position. + * Code selection attachment from an editor * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueAppendSteeringRequest". + * via the `definition` "PushAttachmentSelection". */ /** @experimental */ -export interface QueueAppendSteeringRequest { - /** - * Message identity returned by send, not the queue item id. Only unclaimed user steering messages are eligible. - */ - messageId: string; +export interface PushAttachmentSelection { /** - * Expected current prompt, including any previous appends. The runtime applies plan-mode normalization before comparing and refuses a changed message. + * Attachment type discriminator */ - expectedPrompt: string; - agentMode: SendAgentMode; + type: "selection"; /** - * Text to append after a blank line. + * Absolute path to the file containing the selection */ - prompt: string; + filePath: string; /** - * Display text to append to the existing preview after a blank line. + * User-facing display name for the selection */ - displayPrompt: string; + displayName: string; /** - * Attachments to add after the message's existing attachments. An empty list preserves the existing attachments. + * The selected text content */ - attachments: Attachment[]; + text: string; + selection: PushAttachmentSelectionDetails; } /** - * Inputs for starting a deferred-idle drain. + * Position range of the selection within the file * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueBeginDeferredIdleDrainRequest". + * via the `definition` "PushAttachmentSelectionDetails". */ /** @experimental */ -export interface QueueBeginDeferredIdleDrainRequest { - /** - * Whether the host still has active background work. - */ - activeBackgroundWork: boolean; +export interface PushAttachmentSelectionDetails { + start: PushAttachmentSelectionDetailsStart; + end: PushAttachmentSelectionDetailsEnd; } /** - * Whether a deferred-idle drain should run. + * Start position of the selection * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueBeginDeferredIdleDrainResult". + * via the `definition` "PushAttachmentSelectionDetailsStart". */ /** @experimental */ -export interface QueueBeginDeferredIdleDrainResult { +export interface PushAttachmentSelectionDetailsStart { /** - * True when the host should run finishDeferredIdleDrain asynchronously. + * Start line number (0-based) */ - shouldDrain: boolean; -} -/** - * Internal filter for consuming queued system notifications. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueConsumeSystemNotificationsRequest". - */ -/** @experimental */ -export interface QueueConsumeSystemNotificationsRequest { + line: number; /** - * Opaque runtime-owned filter object. + * Start character offset within the line (0-based) */ - filter: JsonValue; + character: number; } /** - * Inputs for marking session.idle deferred in native state. + * End position of the selection * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueDeferSessionIdleRequest". + * via the `definition` "PushAttachmentSelectionDetailsEnd". */ /** @experimental */ -export interface QueueDeferSessionIdleRequest { +export interface PushAttachmentSelectionDetailsEnd { /** - * Whether the deferred idle was caused by an aborted foreground turn. + * End line number (0-based) */ - aborted: boolean; -} -/** - * Parameters for duplicating a queued item. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueDuplicateAtRequest". - */ -/** @experimental */ -export interface QueueDuplicateAtRequest { + line: number; /** - * Stable opaque ID of the queued item to duplicate. + * End character offset within the line (0-based) */ - id: string; + character: number; } /** - * Result of duplicating a queued item. + * GitHub issue, pull request, or discussion reference * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueDuplicateAtResult". + * via the `definition` "PushAttachmentGitHubReference". */ /** @experimental */ -export interface QueueDuplicateAtResult { +export interface PushAttachmentGitHubReference { /** - * Fresh stable opaque id assigned to the duplicate. + * Attachment type discriminator */ - id: string; + type: "github_reference"; + /** + * Issue, pull request, or discussion number + */ + number: number; + /** + * Title of the referenced item + */ + title: string; + referenceType: PushAttachmentGitHubReferenceType; + /** + * Current state of the referenced item (e.g., open, closed, merged) + */ + state: string; + /** + * URL to the referenced item on GitHub + */ + url: string; } /** - * Result of enqueueing the resume-pending wake item. + * Pointer to a GitHub commit. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueEnqueueResumePendingResult". + * via the `definition` "PushAttachmentGitHubCommit". */ /** @experimental */ -export interface QueueEnqueueResumePendingResult { +export interface PushAttachmentGitHubCommit { /** - * True when a wake item was newly queued. + * Attachment type discriminator */ - queued: boolean; + type: "github_commit"; + repo: PushGitHubRepoRef; + /** + * Full commit SHA + */ + oid: string; + /** + * First line of the commit message + */ + message: string; + /** + * URL to the commit on GitHub + */ + url: string; } /** - * Inputs for completing a deferred-idle drain. + * Pointer to a GitHub repository. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueFinishDeferredIdleDrainRequest". + * via the `definition` "PushGitHubRepoRef". */ /** @experimental */ -export interface QueueFinishDeferredIdleDrainRequest { +export interface PushGitHubRepoRef { /** - * Whether the host still has active background work. + * Numeric GitHub repository id */ - activeBackgroundWork: boolean; + id?: number; /** - * Whether native queued work remains. + * Repository name (without owner) */ - hasPending: boolean; + name: string; + /** + * Repository owner login (user or organization) + */ + owner: string; } /** - * Action selected by the native deferred-idle drain. + * Pointer to a GitHub release. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueFinishDeferredIdleDrainResult". + * via the `definition` "PushAttachmentGitHubRelease". */ /** @experimental */ -export interface QueueFinishDeferredIdleDrainResult { +export interface PushAttachmentGitHubRelease { /** - * One of none, processQueue, or emitSessionIdle. + * Attachment type discriminator */ - action: string; + type: "github_release"; + repo: PushGitHubRepoRef; /** - * Whether the deferred idle was caused by an aborted foreground turn. + * Git tag the release is anchored to */ - aborted: boolean; -} -/** - * Whether the native queue has pending work. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueHasPendingResult". - */ -/** @experimental */ -export interface QueueHasPendingResult { + tagName: string; /** - * True when queued or immediate native work is pending. + * Human-readable release name */ - hasPending: boolean; -} -/** - * Parameters for inserting a queued message at a public visible position. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueInsertAtRequest". - */ -/** @experimental */ -export interface QueueInsertAtRequest { + name: string; /** - * Zero-based position in the public visible queue. Values outside the queue clamp to an end. + * URL to the release on GitHub */ - position: number; - message: QueueInsertMessage; + url: string; } /** - * Serializable message fields accepted by queue.insertAt. + * Pointer to a GitHub Actions job. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueInsertMessage". + * via the `definition` "PushAttachmentGitHubActionsJob". */ /** @experimental */ -export interface QueueInsertMessage { +export interface PushAttachmentGitHubActionsJob { /** - * The user message text. + * Attachment type discriminator */ - prompt: string; + type: "github_actions_job"; + repo: PushGitHubRepoRef; /** - * Optional user-facing display text. + * Job id within the workflow run */ - displayPrompt?: string; + jobId: number; /** - * Optional attachments for the message. + * Display name of the job */ - attachments?: Attachment[]; - agentMode?: SendAgentMode; + jobName: string; /** - * Optional provenance source. `system` is rejected: it would hide the inserted row from `pendingItems` and make it unaddressable while still executing, so inserted items must stay visible. + * Display name of the workflow the job ran in */ - source?: string; + workflowName: string; /** - * Whether the message is billable. + * URL to the job on GitHub */ - billable?: boolean; + url: string; /** - * Required tool name for the turn, when any. + * Terminal conclusion of the job when finished (e.g., success, failure, cancelled). Absent for in-progress jobs. */ - requiredTool?: string; + conclusion?: string; +} +/** + * Pointer to a GitHub repository. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PushAttachmentGitHubRepository". + */ +/** @experimental */ +export interface PushAttachmentGitHubRepository { /** - * Per-turn request headers. + * Attachment type discriminator */ - requestHeaders?: { - [k: string]: string | undefined; - }; - mode?: SendMode; + type: "github_repository"; + repo: PushGitHubRepoRef; /** - * Accepted for SendOptions compatibility but ignored; the requested public position controls placement. + * URL to the repository on GitHub */ - prepend?: boolean; + url: string; /** - * Accepted for SendOptions compatibility but ignored; insertion scheduling is controlled by the queue drain state. + * Short description of the repository */ - wait?: boolean; + description?: string; /** - * Accepted for internal SendOptions compatibility but ignored; delivery is derived from current session activity. + * Git ref this attachment is anchored at (branch, tag, or commit). When absent the default branch is implied. */ - delivery?: string; + ref?: string; } /** - * Result of inserting a queued message. + * Pointer to a single-file diff. At least one of `head` and `base` must be present. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueInsertAtResult". + * via the `definition` "PushAttachmentGitHubFileDiff". */ /** @experimental */ -export interface QueueInsertAtResult { +export interface PushAttachmentGitHubFileDiff { /** - * Fresh stable opaque id assigned to the inserted item. + * Attachment type discriminator */ - id: string; + type: "github_file_diff"; + /** + * URL to the diff on GitHub (e.g., a commit, compare, or PR-file URL) + */ + url: string; + head?: PushAttachmentGitHubFileDiffSide; + base?: PushAttachmentGitHubFileDiffSide; } /** - * Parameters for moving a queued item by stable id. + * One side of a file diff (head or base) * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueMoveItemRequest". + * via the `definition` "PushAttachmentGitHubFileDiffSide". */ /** @experimental */ -export interface QueueMoveItemRequest { +export interface PushAttachmentGitHubFileDiffSide { + repo: PushGitHubRepoRef; /** - * Stable opaque queued-item id. + * Git ref (branch, tag, or commit SHA) the file is read at */ - id: string; + ref: string; /** - * Zero-based target position in the public visible queue. Values outside the queue clamp to an end. + * Repository-relative path to the file */ - toPosition: number; + path: string; } /** - * Result of moving a queued item. + * Pointer to a comparison between two git revisions. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueMoveItemResult". + * via the `definition` "PushAttachmentGitHubTreeComparison". */ /** @experimental */ -export interface QueueMoveItemResult { +export interface PushAttachmentGitHubTreeComparison { /** - * True when the item changed position; false when it was already at the requested position. + * Attachment type discriminator */ - changed: boolean; + type: "github_tree_comparison"; + /** + * URL to the comparison on GitHub + */ + url: string; + base: PushAttachmentGitHubTreeComparisonSide; + head: PushAttachmentGitHubTreeComparisonSide; } /** - * User-facing pending queue entry, with kind and display text for a queued message, slash command, or model change. + * One side of a tree comparison (head or base) * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueuePendingItems". + * via the `definition` "PushAttachmentGitHubTreeComparisonSide". */ /** @experimental */ -export interface QueuePendingItems { - /** - * Stable opaque id for the canonical queued item. Batch rows share one id. - */ - id: string; +export interface PushAttachmentGitHubTreeComparisonSide { + repo: PushGitHubRepoRef; /** - * Stable identity of the queued user message. Present for message rows and absent for slash commands and model changes. + * Git revision (branch, tag, or commit SHA) */ - messageId?: string; - kind: QueuePendingItemsKind; + revision: string; +} +/** + * Generic GitHub URL reference. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "PushAttachmentGitHubUrl". + */ +/** @experimental */ +export interface PushAttachmentGitHubUrl { /** - * Human-readable text to display for this queue entry in the UI + * Attachment type discriminator */ - displayText: string; - agentMode: SendAgentMode; + type: "github_url"; /** - * Optional source tag associated with this pending queue entry. This is an open string, not authenticated authorship. In particular, `user` does not prove that a person typed the message. If the source is absent or unrecognized, consumers must not infer human or agent authorship and should handle the entry neutrally. Consumers should tolerate future source values. + * URL to the GitHub resource */ - source?: string; + url: string; } /** - * Snapshot of the session's pending queued items and immediate-steering messages. + * Pointer to a file in a GitHub repository at a specific ref. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueuePendingItemsResult". + * via the `definition` "PushAttachmentGitHubFile". */ /** @experimental */ -export interface QueuePendingItemsResult { +export interface PushAttachmentGitHubFile { /** - * Pending queued items in submission order. Includes user messages, queued slash commands, and queued model changes; omits internal system items. + * Attachment type discriminator */ - items: QueuePendingItems[]; + type: "github_file"; + repo: PushGitHubRepoRef; /** - * Display text for messages currently in the immediate steering queue (interjections sent during a running turn). + * Git ref the file is read at (branch, tag, or commit SHA) */ - steeringMessages: string[]; + ref: string; /** - * How many leading entries of `steeringMessages` have already been folded into the running turn (and so have an emitted `user.message`), as opposed to still waiting for one. Absent for hosts that do not distinguish the two. + * Repository-relative path to the file */ - inFlightSteeringCount?: number; + path: string; /** - * ID of the running turn's user message while the model has not answered it, so `withdrawMessage` can still take it back once nothing sent after it is pending. A message leaves `items` when its turn starts, before its `user.message` is recorded; this tells that message apart from one that was removed. Absent when no turn prompt can be taken back. + * URL to the file on GitHub */ - withdrawableTurnMessageId?: string; + url: string; } /** - * Parameters for removing a queued item by stable id. + * Pointer to a line range inside a file in a GitHub repository. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueRemoveAtRequest". + * via the `definition` "PushAttachmentGitHubSnippet". */ /** @experimental */ -export interface QueueRemoveAtRequest { +export interface PushAttachmentGitHubSnippet { /** - * Stable opaque ID of the queued item to remove. + * Attachment type discriminator */ - id: string; + type: "github_snippet"; + repo: PushGitHubRepoRef; + /** + * Git ref the file is read at (branch, tag, or commit SHA) + */ + ref: string; + /** + * Repository-relative path to the file + */ + path: string; + /** + * URL to the snippet on GitHub (with line anchor) + */ + url: string; + lineRange: PushAttachmentFileLineRange; } /** - * Result of removing a queued item. + * Blob attachment with inline base64-encoded data * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueRemoveAtResult". + * via the `definition` "PushAttachmentBlob". */ /** @experimental */ -export interface QueueRemoveAtResult { +export interface PushAttachmentBlob { /** - * True when the addressed item was removed. + * Attachment type discriminator */ - removed: boolean; + type: "blob"; + /** + * Base64-encoded content + */ + data: string; + /** + * MIME type of the inline data + */ + mimeType: string; + /** + * User-facing display name for the attachment + */ + displayName?: string; } /** - * Indicates whether a user-facing pending item was removed. + * Append to one pending steering message without changing its identity or delivery position. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueRemoveMostRecentResult". + * via the `definition` "QueueAppendSteeringRequest". */ /** @experimental */ -export interface QueueRemoveMostRecentResult { +export interface QueueAppendSteeringRequest { /** - * True if a user-facing pending item was removed (LIFO across both queues); false when no removable items remained. + * Message identity returned by send, not the queue item id. Only unclaimed user steering messages are eligible. */ - removed: boolean; + messageId: string; + /** + * Expected current prompt, including any previous appends. The runtime applies plan-mode normalization before comparing and refuses a changed message. + */ + expectedPrompt: string; + agentMode: SendAgentMode; + /** + * Text to append after a blank line. + */ + prompt: string; + /** + * Display text to append to the existing preview after a blank line. + */ + displayPrompt: string; + /** + * Attachments to add after the message's existing attachments. An empty list preserves the existing attachments. + */ + attachments: Attachment[]; } /** - * Parameters for steering a queued message into a live turn. + * Inputs for starting a deferred-idle drain. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueSendNowRequest". + * via the `definition` "QueueBeginDeferredIdleDrainRequest". */ /** @experimental */ -export interface QueueSendNowRequest { +export interface QueueBeginDeferredIdleDrainRequest { /** - * Stable opaque ID of the queued item to steer into the live turn. + * Whether the host still has active background work. */ - id: string; + activeBackgroundWork: boolean; } /** - * Result of trying to steer a queued message into a live turn. + * Whether a deferred-idle drain should run. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueSendNowResult". + * via the `definition` "QueueBeginDeferredIdleDrainResult". */ /** @experimental */ -export interface QueueSendNowResult { +export interface QueueBeginDeferredIdleDrainResult { /** - * True when the item was accepted into the steering lane; false when no main turn was live. + * True when the host should run finishDeferredIdleDrain asynchronously. */ - steered: boolean; + shouldDrain: boolean; } /** - * Parameters for acquiring or releasing the queued-lane drain pause. Acquisition is exclusive and non-idempotent: `paused: true` against an already-paused session fails with `queue_already_paused`. The pause is never released automatically — it is not tied to the caller's lifetime, so a client that exits without sending `paused: false` leaves the lane frozen. Release is unowned: `paused: false` clears the pause for any caller, including one that never acquired it. + * Internal filter for consuming queued system notifications. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueSetDrainPausedRequest". + * via the `definition` "QueueConsumeSystemNotificationsRequest". */ /** @experimental */ -export interface QueueSetDrainPausedRequest { +export interface QueueConsumeSystemNotificationsRequest { /** - * Whether queued-lane draining should be paused. + * Opaque runtime-owned filter object. */ - paused: boolean; + filter: JsonValue; } /** - * Internal snapshot of native queue state for local session orchestration. + * Inputs for marking session.idle deferred in native state. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueSnapshotResult". + * via the `definition` "QueueDeferSessionIdleRequest". */ /** @experimental */ -export interface QueueSnapshotResult { - /** - * Queue item identifier of a model switch that has been dequeued but not yet applied. - */ - inFlightModelChangeId?: string; - /** - * User-facing pending items in FIFO order. - */ - items: QueuePendingItems[]; - /** - * Immediate steering messages waiting for an active turn. - */ - steeringMessages: string[]; - /** - * Insertion orders for queued items, aligned with `items`. - */ - itemOrders?: number[]; +export interface QueueDeferSessionIdleRequest { /** - * Insertion orders for immediate steering messages, aligned with `steeringMessages`. + * Whether the deferred idle was caused by an aborted foreground turn. */ - steeringMessageOrders?: number[]; + aborted: boolean; } /** - * Parameters for editing a single queued message. + * Parameters for duplicating a queued item. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueUpdateTextRequest". + * via the `definition` "QueueDuplicateAtRequest". */ /** @experimental */ -export interface QueueUpdateTextRequest { +export interface QueueDuplicateAtRequest { /** - * Stable opaque ID of the queued item to edit. + * Stable opaque ID of the queued item to duplicate. */ id: string; - /** - * Replacement prompt sent to the model. - */ - prompt: string; - /** - * Optional replacement prompt displayed to the user. - */ - displayPrompt?: string; } /** - * Result of editing a queued message. + * Result of duplicating a queued item. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueUpdateTextResult". + * via the `definition` "QueueDuplicateAtResult". */ /** @experimental */ -export interface QueueUpdateTextResult { +export interface QueueDuplicateAtResult { /** - * True when the stored text changed. + * Fresh stable opaque id assigned to the duplicate. */ - updated: boolean; + id: string; } /** - * Conditional withdrawal of a single user message, from its queue or from the running turn it started. + * Result of enqueueing the resume-pending wake item. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueWithdrawMessageRequest". + * via the `definition` "QueueEnqueueResumePendingResult". */ /** @experimental */ -export interface QueueWithdrawMessageRequest { - /** - * Message identity returned by send, not the queue item id. Batch messages are not eligible. - */ - messageId: string; +export interface QueueEnqueueResumePendingResult { /** - * The prompt originally sent. A message edited since submission is not withdrawn, so an obsolete draft cannot replace the edit. + * True when a wake item was newly queued. */ - expectedPrompt: string; + queued: boolean; } /** - * Result of withdrawing a user message. + * Inputs for completing a deferred-idle drain. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QueueWithdrawMessageResult". + * via the `definition` "QueueFinishDeferredIdleDrainRequest". */ /** @experimental */ -export interface QueueWithdrawMessageResult { +export interface QueueFinishDeferredIdleDrainRequest { /** - * True when the message left the queue or, for a running turn, history. + * Whether the host still has active background work. */ - removed: boolean; + activeBackgroundWork: boolean; /** - * True when the running turn was interrupted to withdraw the message. With removed false, the turn was interrupted but its events could not be removed, for example because the model answered first, so the message stays in the interrupted turn. + * Whether native queued work remains. */ - interrupted: boolean; + hasPending: boolean; } /** - * A pending session quota warning, consumed once by takeWarnings. + * Action selected by the native deferred-idle drain. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "QuotaWarningProjection". + * via the `definition` "QueueFinishDeferredIdleDrainResult". */ /** @experimental */ -export interface QuotaWarningProjection { - /** - * Existing warning category. - */ - warningType: string; +export interface QueueFinishDeferredIdleDrainResult { /** - * User-facing warning text. + * One of none, processQueue, or emitSessionIdle. */ - message: string; + action: string; /** - * Related account or upgrade link. + * Whether the deferred idle was caused by an aborted foreground turn. */ - url?: string; + aborted: boolean; } /** - * Event type to register consumer interest for, used by runtime gating logic. + * Whether the native queue has pending work. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RegisterEventInterestParams". + * via the `definition` "QueueHasPendingResult". */ /** @experimental */ -export interface RegisterEventInterestParams { +export interface QueueHasPendingResult { /** - * The event type the consumer wants the runtime to treat as 'observed' for behavior-switching gating. Some runtime code paths inspect whether any consumer is interested in a specific event type and choose a different implementation accordingly (e.g. `mcp.oauth_required`: when interest is registered the runtime delegates interactive OAuth token acquisition to the consumer via `mcp.oauth_required` events; when no interest is registered the runtime still attempts non-interactive reconnect from cached or refreshable tokens, and only marks the server `needs-auth` if usable credentials are unavailable — it does not open a browser or start interactive OAuth without a consumer). SDK clients that long-poll events do NOT automatically appear as listeners to these gating checks — they must explicitly call `registerInterest` for each event type they want the runtime to count as having a consumer. Multiple registrations for the same event type from the same or different consumers are tracked independently and must each be released. See: `mcp.oauth_required`, `sampling.requested`, `auto_mode_switch.requested`, `session_limits_exhausted.requested`, `user_input.requested`, `elicitation.requested`, `command.queued`, `exit_plan_mode.requested`. + * True when queued or immediate native work is pending. */ - eventType: string; + hasPending: boolean; } /** - * Opaque handle representing an event-type interest registration. + * Parameters for inserting a queued message at a public visible position. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RegisterEventInterestResult". + * via the `definition` "QueueInsertAtRequest". */ /** @experimental */ -export interface RegisterEventInterestResult { +export interface QueueInsertAtRequest { /** - * Opaque handle for this registration. Pass to releaseInterest to release. Each call to registerInterest produces a fresh handle, even when the same eventType is registered multiple times. + * Zero-based position in the public visible queue. Values outside the queue clamp to an end. */ - handle: string; + position: number; + message: QueueInsertMessage; } /** - * Opaque handle previously returned by `registerInterest` to release. + * Serializable message fields accepted by queue.insertAt. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ReleaseEventInterestParams". + * via the `definition` "QueueInsertMessage". */ /** @experimental */ -export interface ReleaseEventInterestParams { +export interface QueueInsertMessage { /** - * Handle returned by a previous `registerInterest` call. Idempotent: releasing an unknown or already-released handle is a no-op (returns success). When the last outstanding handle for an event type is released, the runtime reverts to its 'no consumer' code path for that event type. + * The user message text. */ - handle: string; -} -/** - * Configuration for the runtime-managed remote-control singleton. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteControlConfig". - */ -/** @experimental */ -export interface RemoteControlConfig { + prompt: string; /** - * Whether remote export should be enabled. + * Optional user-facing display text. */ - remote: boolean; + displayPrompt?: string; /** - * Whether the MC session may steer the local session (write mode). + * Optional attachments for the message. */ - steerable: boolean; + attachments?: Attachment[]; + agentMode?: SendAgentMode; /** - * Whether the user explicitly requested remote (vs. implicit session-sync). Controls warning surfacing for missing-repo cases. + * Optional provenance source. `system` is rejected: it would hide the inserted row from `pendingItems` and make it unaddressable while still executing, so inserted items must stay visible. */ - explicit: boolean; + source?: string; /** - * When true, suppresses timeline messages on successful setup. + * Whether the message is billable. */ - silent: boolean; + billable?: boolean; /** - * Existing Mission Control task ID to attach the exported session to. + * Required tool name for the turn, when any. */ - taskId?: string; - existingMcSession?: RemoteControlConfigExistingMcSession; -} -/** - * Reattach to an existing MC session without creating a new one. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteControlConfigExistingMcSession". - */ -/** @experimental */ -export interface RemoteControlConfigExistingMcSession { + requiredTool?: string; /** - * Existing MC session ID to reattach to. + * Per-turn request headers. */ - mcSessionId: string; + requestHeaders?: { + [k: string]: string | undefined; + }; + mode?: SendMode; /** - * Existing MC task ID for the reattached session. + * Accepted for SendOptions compatibility but ignored; the requested public position controls placement. */ - mcTaskId: string; + prepend?: boolean; + /** + * Accepted for SendOptions compatibility but ignored; insertion scheduling is controlled by the queue drain state. + */ + wait?: boolean; + /** + * Accepted for internal SendOptions compatibility but ignored; delivery is derived from current session activity. + */ + delivery?: string; } /** - * Remote control is not connected. + * Result of inserting a queued message. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteControlStatusOff". + * via the `definition` "QueueInsertAtResult". */ /** @experimental */ -export interface RemoteControlStatusOff { +export interface QueueInsertAtResult { /** - * Remote control state tag: not connected. + * Fresh stable opaque id assigned to the inserted item. */ - state: "off"; + id: string; } /** - * Remote control is in the middle of initial setup. + * Parameters for moving a queued item by stable id. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteControlStatusConnecting". + * via the `definition` "QueueMoveItemRequest". */ /** @experimental */ -export interface RemoteControlStatusConnecting { +export interface QueueMoveItemRequest { /** - * Remote control state tag: connecting. + * Stable opaque queued-item id. */ - state: "connecting"; + id: string; /** - * Session id the connection is attaching to. + * Zero-based target position in the public visible queue. Values outside the queue clamp to an end. */ - attachedSessionId: string; + toPosition: number; } /** - * Remote control is connected to a local session. + * Result of moving a queued item. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteControlStatusActive". + * via the `definition` "QueueMoveItemResult". */ /** @experimental */ -export interface RemoteControlStatusActive { - /** - * Remote control state tag: active. - */ - state: "active"; +export interface QueueMoveItemResult { /** - * Session id remote control is pointed at. + * True when the item changed position; false when it was already at the requested position. */ - attachedSessionId: string; + changed: boolean; +} +/** + * User-facing pending queue entry, with kind and display text for a queued message, slash command, or model change. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "QueuePendingItems". + */ +/** @experimental */ +export interface QueuePendingItems { /** - * MC frontend URL for this session, when known. + * Stable opaque id for the canonical queued item. Batch rows share one id. */ - frontendUrl?: string; + id: string; /** - * Whether the MC session may steer this session. + * Stable identity of the queued user message. Present for message rows and absent for slash commands and model changes. */ - isSteerable: boolean; + messageId?: string; + kind: QueuePendingItemsKind; /** - * In-process prompt-manager handle (CLI-only optimization). Marked internal: this field is excluded from the public SDK surface. Retained as an optional compatibility field; native remote control does not populate or consume it. - * - * @internal + * Human-readable text to display for this queue entry in the UI */ - promptManager?: OpaqueInProcessValue; + displayText: string; + agentMode: SendAgentMode; /** - * True while a read-only/session-sync export is deferred, awaiting the first `user.message` before its MC session exists. Marked internal: this field is excluded from the public SDK surface and is populated only on the CLI in-process path. - * - * @internal + * Optional source tag associated with this pending queue entry. This is an open string, not authenticated authorship. In particular, `user` does not prove that a person typed the message. If the source is absent or unrecognized, consumers must not infer human or agent authorship and should handle the entry neutrally. Consumers should tolerate future source values. */ - awaitingFirstMessage?: boolean; + source?: string; } /** - * The last setup attempt failed. The singleton is otherwise off. + * Snapshot of the session's pending queued items and immediate-steering messages. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteControlStatusError". + * via the `definition` "QueuePendingItemsResult". */ /** @experimental */ -export interface RemoteControlStatusError { +export interface QueuePendingItemsResult { /** - * Remote control state tag: setup failed. + * Pending queued items in submission order. Includes user messages, queued slash commands, and queued model changes; omits internal system items. */ - state: "error"; + items: QueuePendingItems[]; /** - * Human-readable error message from the last setup attempt. + * Display text for messages currently in the immediate steering queue (interjections sent during a running turn). */ - error: string; + steeringMessages: string[]; /** - * Session id the failing setup attempt targeted, when known. + * How many leading entries of `steeringMessages` have already been folded into the running turn (and so have an emitted `user.message`), as opposed to still waiting for one. Absent for hosts that do not distinguish the two. */ - attachedSessionId?: string; + inFlightSteeringCount?: number; + /** + * ID of the running turn's user message while the model has not answered it, so `withdrawMessage` can still take it back once nothing sent after it is pending. A message leaves `items` when its turn starts, before its `user.message` is recorded; this tells that message apart from one that was removed. Absent when no turn prompt can be taken back. + */ + withdrawableTurnMessageId?: string; } /** - * Wrapper for the singleton's current status. + * Parameters for removing a queued item by stable id. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteControlStatusResult". + * via the `definition` "QueueRemoveAtRequest". */ /** @experimental */ -export interface RemoteControlStatusResult { - status: RemoteControlStatus; +export interface QueueRemoveAtRequest { + /** + * Stable opaque ID of the queued item to remove. + */ + id: string; } /** - * Outcome of a stopRemoteControl call. + * Result of removing a queued item. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteControlStopResult". + * via the `definition` "QueueRemoveAtResult". */ /** @experimental */ -export interface RemoteControlStopResult { - status: RemoteControlStatus; +export interface QueueRemoveAtResult { /** - * Whether the singleton was actually torn down by this call. + * True when the addressed item was removed. */ - stopped: boolean; + removed: boolean; } /** - * Outcome of a transferRemoteControl call. + * Indicates whether a user-facing pending item was removed. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteControlTransferResult". + * via the `definition` "QueueRemoveMostRecentResult". */ /** @experimental */ -export interface RemoteControlTransferResult { - status: RemoteControlStatus; +export interface QueueRemoveMostRecentResult { /** - * Whether the rebinding actually happened. + * True if a user-facing pending item was removed (LIFO across both queues); false when no removable items remained. */ - transferred: boolean; + removed: boolean; } /** - * Optional remote session mode ("off", "export", or "on"); defaults to enabling both export and remote steering. + * Parameters for steering a queued message into a live turn. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteEnableRequest". + * via the `definition` "QueueSendNowRequest". */ /** @experimental */ -export interface RemoteEnableRequest { - mode?: RemoteSessionMode; +export interface QueueSendNowRequest { + /** + * Stable opaque ID of the queued item to steer into the live turn. + */ + id: string; } /** - * GitHub URL for the session and a flag indicating whether remote steering is enabled. + * Result of trying to steer a queued message into a live turn. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteEnableResult". + * via the `definition` "QueueSendNowResult". */ /** @experimental */ -export interface RemoteEnableResult { - /** - * GitHub frontend URL for this session - */ - url?: string; +export interface QueueSendNowResult { /** - * Whether remote steering is enabled + * True when the item was accepted into the steering lane; false when no main turn was live. */ - remoteSteerable: boolean; + steered: boolean; } /** - * New remote-steerability state to persist as a `session.remote_steerable_changed` event. + * Parameters for acquiring or releasing the queued-lane drain pause. Acquisition is exclusive and non-idempotent: `paused: true` against an already-paused session fails with `queue_already_paused`. The pause is never released automatically — it is not tied to the caller's lifetime, so a client that exits without sending `paused: false` leaves the lane frozen. Release is unowned: `paused: false` clears the pause for any caller, including one that never acquired it. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteNotifySteerableChangedRequest". + * via the `definition` "QueueSetDrainPausedRequest". */ /** @experimental */ -export interface RemoteNotifySteerableChangedRequest { +export interface QueueSetDrainPausedRequest { /** - * Whether the session now supports remote steering via GitHub. The runtime persists this as a `session.remote_steerable_changed` event so resume/replay sees the up-to-date capability. + * Whether queued-lane draining should be paused. */ - remoteSteerable: boolean; + paused: boolean; } /** - * Persist a steerability change as a `session.remote_steerable_changed` event. Used by the host (CLI / SDK consumer) when it has just finished enabling or disabling steering on a remote exporter that the runtime does not directly own. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteNotifySteerableChangedResult". - */ -/** @experimental */ -export interface RemoteNotifySteerableChangedResult {} -/** - * Remote session connection result. + * Internal snapshot of native queue state for local session orchestration. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteSessionConnectionResult". + * via the `definition` "QueueSnapshotResult". */ /** @experimental */ -export interface RemoteSessionConnectionResult { +export interface QueueSnapshotResult { /** - * SDK session ID for the connected remote session. + * Queue item identifier of a model switch that has been dequeued but not yet applied. */ - sessionId: string; - metadata: ConnectedRemoteSessionMetadata; + inFlightModelChangeId?: string; + /** + * User-facing pending items in FIFO order. + */ + items: QueuePendingItems[]; + /** + * Immediate steering messages waiting for an active turn. + */ + steeringMessages: string[]; + /** + * Insertion orders for queued items, aligned with `items`. + */ + itemOrders?: number[]; + /** + * Insertion orders for immediate steering messages, aligned with `steeringMessages`. + */ + steeringMessageOrders?: number[]; } /** - * GitHub repository the remote session belongs to. + * Parameters for editing a single queued message. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteSessionMetadataRepository". + * via the `definition` "QueueUpdateTextRequest". */ /** @experimental */ -export interface RemoteSessionMetadataRepository { +export interface QueueUpdateTextRequest { /** - * Repository owner. + * Stable opaque ID of the queued item to edit. */ - owner: string; + id: string; /** - * Repository name. + * Replacement prompt sent to the model. */ - name: string; + prompt: string; /** - * Branch associated with the remote session. + * Optional replacement prompt displayed to the user. */ - branch: string; + displayPrompt?: string; } /** - * Remote session metadata for the session to hand off (typically obtained from `sessions.list` with `source: "remote"`). + * Result of editing a queued message. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteSessionMetadataValue". + * via the `definition` "QueueUpdateTextResult". */ /** @experimental */ -export interface RemoteSessionMetadataValue { +export interface QueueUpdateTextResult { /** - * Stable session identifier. + * True when the stored text changed. */ - sessionId: string; + updated: boolean; +} +/** + * Conditional withdrawal of a single user message, from its queue or from the running turn it started. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "QueueWithdrawMessageRequest". + */ +/** @experimental */ +export interface QueueWithdrawMessageRequest { /** - * Session creation time as an ISO 8601 timestamp. + * Message identity returned by send, not the queue item id. Batch messages are not eligible. */ - startTime: string; + messageId: string; /** - * Last-modified time as an ISO 8601 timestamp. + * The prompt originally sent. A message edited since submission is not withdrawn, so an obsolete draft cannot replace the edit. */ - modifiedTime: string; + expectedPrompt: string; +} +/** + * Result of withdrawing a user message. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "QueueWithdrawMessageResult". + */ +/** @experimental */ +export interface QueueWithdrawMessageResult { /** - * Short summary of the session, when one has been derived. + * True when the message left the queue or, for a running turn, history. */ - summary?: string; + removed: boolean; /** - * Optional human-friendly name set via /rename. + * True when the running turn was interrupted to withdraw the message. With removed false, the turn was interrupted but its events could not be removed, for example because the model answered first, so the message stays in the interrupted turn. */ - name?: string; + interrupted: boolean; +} +/** + * A pending session quota warning, consumed once by takeWarnings. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "QuotaWarningProjection". + */ +/** @experimental */ +export interface QuotaWarningProjection { /** - * Always true for remote sessions. + * Existing warning category. */ - isRemote: true; - context?: SessionContext; - repository: RemoteSessionMetadataRepository; + warningType: string; /** - * Backing remote session IDs (most recent first). + * User-facing warning text. */ - remoteSessionIds: string[]; + message: string; /** - * Pull request number associated with the session. - */ - pullRequestNumber?: number; - /** - * Original remote resource identifier (task ID or PR node ID). - */ - resourceId?: string; - taskType?: RemoteSessionMetadataTaskType; - /** - * Deadline (ISO 8601) at which a CLI remote session becomes stale without further heartbeats. - */ - staleAt?: string; - /** - * Server-side task state returned by GitHub. - */ - state?: string; - hostStatus?: RemoteSessionHostStatus; - /** - * Host-supplied human description of what the session is doing right now ("running tests", "waiting for approval"). Optional in the protocol and absent on hosts that do not publish it, so never rely on it -- it enriches `hostStatus`, it does not replace it. + * Related account or upgrade link. */ - hostActivity?: string; + url?: string; } /** - * Repository context for the remote session. + * Event type to register consumer interest for, used by runtime gating logic. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RemoteSessionRepository". + * via the `definition` "RegisterEventInterestParams". */ /** @experimental */ -export interface RemoteSessionRepository { - /** - * Repository owner or organization login. - */ - owner: string; - /** - * Repository name. - */ - name: string; +export interface RegisterEventInterestParams { /** - * Optional branch associated with the remote session. + * The event type the consumer wants the runtime to treat as 'observed' for behavior-switching gating. Some runtime code paths inspect whether any consumer is interested in a specific event type and choose a different implementation accordingly (e.g. `mcp.oauth_required`: when interest is registered the runtime delegates interactive OAuth token acquisition to the consumer via `mcp.oauth_required` events; when no interest is registered the runtime still attempts non-interactive reconnect from cached or refreshable tokens, and only marks the server `needs-auth` if usable credentials are unavailable — it does not open a browser or start interactive OAuth without a consumer). SDK clients that long-poll events do NOT automatically appear as listeners to these gating checks — they must explicitly call `registerInterest` for each event type they want the runtime to count as having a consumer. Multiple registrations for the same event type from the same or different consumers are tracked independently and must each be released. See: `mcp.oauth_required`, `sampling.requested`, `auto_mode_switch.requested`, `session_limits_exhausted.requested`, `user_input.requested`, `elicitation.requested`, `command.queued`, `exit_plan_mode.requested`. */ - branch?: string; + eventType: string; } /** - * Which repository settings file to read. + * Opaque handle representing an event-type interest registration. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RepoSettingsReadRawRequest". + * via the `definition` "RegisterEventInterestResult". */ /** @experimental */ -/** @internal */ -export interface RepoSettingsReadRawRequest { - /** - * Absolute path of the repository root. - */ - repoRoot: string; +export interface RegisterEventInterestResult { /** - * Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + * Opaque handle for this registration. Pass to releaseInterest to release. Each call to registerInterest produces a fresh handle, even when the same eventType is registered multiple times. */ - scope: string; + handle: string; } /** - * Parsed repository settings without normalization or layering. + * Opaque handle previously returned by `registerInterest` to release. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RepoSettingsReadRawResult". + * via the `definition` "ReleaseEventInterestParams". */ /** @experimental */ -/** @internal */ -export interface RepoSettingsReadRawResult { - /** - * Stored JSON values after the existing JSONC parser and prototype-safety checks. Empty when the file is missing, blank, or invalid. - */ - config: JsonValue; +export interface ReleaseEventInterestParams { /** - * True when the file exists but did not parse, so `config` is empty for that reason rather than because nothing is set. + * Handle returned by a previous `registerInterest` call. Idempotent: releasing an unknown or already-released handle is a no-op (returns success). When the last outstanding handle for an event type is released, the runtime reverts to its 'no consumer' code path for that event type. */ - invalid: boolean; + handle: string; } /** - * The complete set of repository-overridable settings to store. + * Configuration for the runtime-managed remote-control singleton. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RepoSettingsWriteAllRequest". + * via the `definition` "RemoteControlConfig". */ /** @experimental */ -/** @internal */ -export interface RepoSettingsWriteAllRequest { +export interface RemoteControlConfig { /** - * Absolute path of the repository root. + * Whether remote export should be enabled. */ - repoRoot: string; + remote: boolean; /** - * Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + * Whether the MC session may steer the local session (write mode). */ - scope: string; + steerable: boolean; /** - * Object of allowed settings to store. Missing allowlisted keys are removed. Other input keys are ignored, while unknown stored keys are preserved. + * Whether the user explicitly requested remote (vs. implicit session-sync). Controls warning surfacing for missing-repo cases. */ - settings: JsonValue; + explicit: boolean; + /** + * When true, suppresses timeline messages on successful setup. + */ + silent: boolean; + /** + * Existing Mission Control task ID to attach the exported session to. + */ + taskId?: string; + existingMcSession?: RemoteControlConfigExistingMcSession; } /** - * One key to write or remove in a repository settings file. + * Reattach to an existing MC session without creating a new one. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "RepoSettingsWriteKeyRequest". + * via the `definition` "RemoteControlConfigExistingMcSession". */ /** @experimental */ -/** @internal */ -export interface RepoSettingsWriteKeyRequest { +export interface RemoteControlConfigExistingMcSession { /** - * Absolute path of the repository root. + * Existing MC session ID to reattach to. */ - repoRoot: string; + mcSessionId: string; /** - * Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + * Existing MC task ID for the reattached session. */ - scope: string; + mcTaskId: string; +} +/** + * Remote control is not connected. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "RemoteControlStatusOff". + */ +/** @experimental */ +export interface RemoteControlStatusOff { /** - * Canonical top-level key permitted by the repository settings allowlist. + * Remote control state tag: not connected. */ - key: string; + state: "off"; +} +/** + * Remote control is in the middle of initial setup. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "RemoteControlStatusConnecting". + */ +/** @experimental */ +export interface RemoteControlStatusConnecting { /** - * Value to validate and write. Required unless delete is true; a null value is validated, not treated as deletion. + * Remote control state tag: connecting. */ - value?: JsonValue; + state: "connecting"; /** - * True to remove the key instead of writing it. + * Session id the connection is attaching to. */ - delete?: boolean; + attachedSessionId: string; } /** - * Resolved sandbox configuration. + * Remote control is connected to a local session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxConfig". + * via the `definition` "RemoteControlStatusActive". */ /** @experimental */ -export interface SandboxConfig { - /** - * Whether sandboxing is enabled for the session. - */ - enabled: boolean; - userPolicy?: SandboxConfigUserPolicy; +export interface RemoteControlStatusActive { /** - * Whether to auto-add the current working directory to readwritePaths. Default: true. + * Remote control state tag: active. */ - addCurrentWorkingDirectory?: boolean; + state: "active"; /** - * Whether MCP servers the session launches are confined by the sandbox. Only an explicit `false` opts out; doing so also lets remote-MCP egress leave the sandbox, so the flag and `enabled` are always read together. Ignored while `enabled` is false. Default: true (enabled by default; set to false to opt out). + * Session id remote control is pointed at. */ - sandboxMcpServers?: boolean; + attachedSessionId: string; /** - * Whether language servers the session launches are confined by the sandbox. Only an explicit `false` opts out. Ignored while `enabled` is false. Default: true (enabled by default; set to false to opt out). + * MC frontend URL for this session, when known. */ - sandboxLspServers?: boolean; + frontendUrl?: string; /** - * Whether the agent may request that an individual command run outside the sandbox, which the host then approves or denies through the usual permission flow. A host capability flag rather than part of the policy: it is stripped from the effective spawn policy and only has an effect while `enabled` is true. Fail-closed, unlike the opt-out flags on this object: omitting it offers no bypass. Default: false (opt-in). + * Whether the MC session may steer this session. */ - allowBypass?: boolean; + isSteerable: boolean; /** - * Set by the runtime when a managed policy forced `sandboxMcpServers` on and took the local opt-out away. Provenance rather than policy: it lets a sandbox startup failure point at the administrator instead of a setting the next managed merge would override, and it is ignored when comparing two configs for change. Only the managed merge may set it; a caller-supplied value is stripped. + * In-process prompt-manager handle (CLI-only optimization). Marked internal: this field is excluded from the public SDK surface. Retained as an optional compatibility field; native remote control does not populate or consume it. * * @internal */ - managedMcpRoutingLocked?: boolean; + promptManager?: OpaqueInProcessValue; /** - * The `sandboxLspServers` counterpart of `managedMcpRoutingLocked`. + * True while a read-only/session-sync export is deferred, awaiting the first `user.message` before its MC session exists. Marked internal: this field is excluded from the public SDK surface and is populated only on the CLI in-process path. * * @internal */ - managedLspRoutingLocked?: boolean; - auth?: SandboxConfigAuth; - credentials?: SandboxCredentialsConfig; - /** - * Whether to auto-grant read access to tool directories discovered on PATH and in toolchain environment variables (GOROOT, JAVA_HOME, VIRTUAL_ENV, and similar), and to common developer-tool caches, config, and toolchains. Writable grants cover scratch caches, the Unix GitHub CLI cache, and Cargo's registry, git store, and lock/tracker files. A relocated CARGO_HOME gets the same narrow split: registry and git are read-write; bin is read-only; the home root, config.toml, and credentials.toml stay ungranted. Set to false to disable every grant listed above; user-installed toolchains and caches then need explicit userPolicy.filesystem readonlyPaths and readwritePaths entries. The working directory (see addCurrentWorkingDirectory), temporary storage, session log paths, and system locations follow their own rules and stay granted. Default: true (enabled by default; set to false to opt out). - */ - allowDevToolAccess?: boolean; -} -/** - * User-managed sandbox policy fragment merged into the auto-discovered base policy. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxConfigUserPolicy". - */ -/** @experimental */ -export interface SandboxConfigUserPolicy { - filesystem?: SandboxConfigUserPolicyFilesystem; - network?: SandboxConfigUserPolicyNetwork; - seatbelt?: SandboxConfigUserPolicySeatbelt; - experimental?: SandboxConfigUserPolicyExperimental; + awaitingFirstMessage?: boolean; } /** - * Filesystem rules to merge into the base policy. + * The last setup attempt failed. The singleton is otherwise off. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxConfigUserPolicyFilesystem". + * via the `definition` "RemoteControlStatusError". */ /** @experimental */ -export interface SandboxConfigUserPolicyFilesystem { - /** - * Paths granted read/write access. - */ - readwritePaths?: string[]; +export interface RemoteControlStatusError { /** - * Paths granted read-only access. + * Remote control state tag: setup failed. */ - readonlyPaths?: string[]; + state: "error"; /** - * Paths explicitly denied. + * Human-readable error message from the last setup attempt. */ - deniedPaths?: string[]; + error: string; /** - * Whether to clear the policy when the session exits. + * Session id the failing setup attempt targeted, when known. */ - clearPolicyOnExit?: boolean; + attachedSessionId?: string; } /** - * Network rules to merge into the base policy. + * Wrapper for the singleton's current status. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxConfigUserPolicyNetwork". + * via the `definition` "RemoteControlStatusResult". */ /** @experimental */ -export interface SandboxConfigUserPolicyNetwork { - /** - * Hosts allowed through the built-in sandbox proxy. A non-empty list denies unmatched hosts; an absent or empty list allows all hosts not blocked. Supports exact hostnames, IP addresses, and *.example.com for strict subdomains. Host rules do not override the outbound or local-network toggles. - */ - allowedHosts?: string[]; - /** - * Hosts denied by the built-in sandbox proxy. Deny rules take precedence over allowedHosts. A domain also denies all its subdomains. IP addresses match exactly; *.example.com matches strict subdomains, and * denies every host. - */ - blockedHosts?: string[]; - /** - * Whether outbound network traffic is allowed at all. - */ - allowOutbound?: boolean; - /** - * Whether traffic to local/loopback addresses is allowed. - */ - allowLocalNetwork?: boolean; - proxy?: SandboxConfigUserPolicyNetworkProxy; +export interface RemoteControlStatusResult { + status: RemoteControlStatus; } /** - * HTTP proxy configuration for sandboxed traffic. + * Outcome of a stopRemoteControl call. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxConfigUserPolicyNetworkProxy". + * via the `definition` "RemoteControlStopResult". */ /** @experimental */ -export interface SandboxConfigUserPolicyNetworkProxy { - /** - * Proxy URL (e.g. http://proxy.example.com:8080). The port is optional and defaults to the scheme's standard port when omitted; an explicit port must be between 1 and 65535. Credentials must not be embedded here — a `user:pass@` authority is rejected; put them in the separate `username`/`password` fields. A credential-free http:// loopback proxy URL is routed through the localhost proxy automatically; loopback covers localhost and any *.localhost subdomain, the whole 127.0.0.0/8 range, ::1, and IPv4-mapped loopback (::ffff:127.0.0.1). An https:// URL, or one with a username/password set, is used as-is. - */ - url: string; +export interface RemoteControlStopResult { + status: RemoteControlStatus; /** - * Optional username for proxy authentication. Combined with the URL (and `password`) into `user:pass@host` when the sandboxed process routes through the proxy. + * Whether the singleton was actually torn down by this call. */ - username?: string; - /** - * Optional password for proxy authentication, combined with the URL at spawn time. The persisted value may be a literal password, a `${secret:…}` reference resolved from the OS keychain, or a `${VAR}`/`$VAR` environment reference; it is resolved just before the sandboxed process routes through the proxy. The /sandbox dialog stores a real password in the OS keychain and persists only a `${secret:…}` placeholder (never plaintext in settings.json); the field is masked in the dialog and redacted by /settings show. - */ - password?: string; + stopped: boolean; } /** - * macOS seatbelt-specific options. + * Outcome of a transferRemoteControl call. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxConfigUserPolicySeatbelt". + * via the `definition` "RemoteControlTransferResult". */ /** @experimental */ -export interface SandboxConfigUserPolicySeatbelt { +export interface RemoteControlTransferResult { + status: RemoteControlStatus; /** - * Whether the macOS seatbelt profile may access the keychain. + * Whether the rebinding actually happened. */ - keychainAccess?: boolean; + transferred: boolean; } /** - * Platform-specific experimental policy fields. + * Optional remote session mode ("off", "export", or "on"); defaults to enabling both export and remote steering. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxConfigUserPolicyExperimental". + * via the `definition` "RemoteEnableRequest". */ /** @experimental */ -export interface SandboxConfigUserPolicyExperimental { - seatbelt?: SandboxConfigUserPolicyExperimentalSeatbelt; +export interface RemoteEnableRequest { + mode?: RemoteSessionMode; } /** - * macOS seatbelt experimental options. + * GitHub URL for the session and a flag indicating whether remote steering is enabled. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxConfigUserPolicyExperimentalSeatbelt". + * via the `definition` "RemoteEnableResult". */ /** @experimental */ -export interface SandboxConfigUserPolicyExperimentalSeatbelt { +export interface RemoteEnableResult { /** - * Whether the macOS seatbelt profile may access the keychain. + * GitHub frontend URL for this session */ - keychainAccess?: boolean; + url?: string; + /** + * Whether remote steering is enabled + */ + remoteSteerable: boolean; } /** - * Credential-injection capability flags applied while the sandbox is enabled. For the same capability independent of sandboxing, and matched to the credential's GitHub host, see `shell.credentials`; the two are additive. + * New remote-steerability state to persist as a `session.remote_steerable_changed` event. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxConfigAuth". + * via the `definition` "RemoteNotifySteerableChangedRequest". */ /** @experimental */ -export interface SandboxConfigAuth { - /** - * Whether to authenticate sandboxed HTTPS git through the local masking proxy. The child receives a fake `http..extraheader`; the real Authorization header is substituted only at its original HTTPS host, port, and repository path scope. github.com uses the Copilot token; other forges use credentials resolved from the user's own helper on the host. Default: false (opt-in). - */ - git?: boolean; +export interface RemoteNotifySteerableChangedRequest { /** - * Whether to authenticate sandboxed gh through the local masking proxy. The child receives a fake GH_TOKEN; its real value is substituted only at github.com, api.github.com and uploads.github.com (github.com because gh repo clone authenticates git through gh auth git-credential). The repository's GitHub account takes precedence over the Copilot login. Default: false (opt-in). + * Whether the session now supports remote steering via GitHub. The runtime persists this as a `session.remote_steerable_changed` event so resume/replay sees the up-to-date capability. */ - gh?: boolean; + remoteSteerable: boolean; } /** - * Whole-value environment credential masking for sandboxed children. + * Persist a steerability change as a `session.remote_steerable_changed` event. Used by the host (CLI / SDK consumer) when it has just finished enabling or disabling steering on a remote exporter that the runtime does not directly own. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxCredentialsConfig". + * via the `definition` "RemoteNotifySteerableChangedResult". */ /** @experimental */ -export interface SandboxCredentialsConfig { - /** - * Environment variable names and their HTTPS injection destinations. Absent variables stay absent. No real values or sentinels are stored in this map. - */ - envVars: { - [k: string]: SandboxMaskedEnvVar | undefined; - }; -} +export interface RemoteNotifySteerableChangedResult {} /** - * Destinations authorized to receive one masked environment credential. + * Remote session connection result. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxMaskedEnvVar". + * via the `definition` "RemoteSessionConnectionResult". */ /** @experimental */ -export interface SandboxMaskedEnvVar { +export interface RemoteSessionConnectionResult { /** - * Nonempty list of HTTPS injection hostnames or *.example.com patterns. Bare * is not accepted. These grants never override the sandbox network policy. Values in plaintext HTTP requests, URLs, bodies, encoded credentials, and signed requests are not substituted. + * SDK session ID for the connected remote session. */ - injectHosts: string[]; + sessionId: string; + metadata: ConnectedRemoteSessionMetadata; } /** - * A possible secret-bearing environment variable and optional locally suggested HTTPS injection hosts. This is a draft for user review, not an active grant. + * GitHub repository the remote session belongs to. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxCredentialSuggestion". + * via the `definition` "RemoteSessionMetadataRepository". */ /** @experimental */ -export interface SandboxCredentialSuggestion { +export interface RemoteSessionMetadataRepository { /** - * Environment variable name. The secret value is never returned. + * Repository owner. + */ + owner: string; + /** + * Repository name. */ name: string; /** - * HTTPS hostnames suggested by a local known-provider mapping. An empty list requires the user to supply injection hosts before adding a masking entry. These suggestions do not allow network access. + * Branch associated with the remote session. */ - suggestedInjectHosts: string[]; + branch: string; } /** - * Possible unconfigured secrets in the sandbox shell environment, sorted by variable name, with no secret values. + * Remote session metadata for the session to hand off (typically obtained from `sessions.list` with `source: "remote"`). * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxCredentialSuggestionsResult". + * via the `definition` "RemoteSessionMetadataValue". */ /** @experimental */ -export interface SandboxCredentialSuggestionsResult { +export interface RemoteSessionMetadataValue { /** - * Candidates for user review. Empty when sandboxing is disabled or no unconfigured candidates are present. + * Stable session identifier. */ - suggestions: SandboxCredentialSuggestion[]; -} -/** - * Request to disable sandboxing for the current session while resolving an active sandbox-bypass permission prompt. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxDisableForSessionRequest". - */ -/** @experimental */ -export interface SandboxDisableForSessionRequest { + sessionId: string; /** - * Identifier of the exact pending sandbox-bypass permission request that authorized the session opt-out. + * Session creation time as an ISO 8601 timestamp. */ - requestId: string; - decisionContext?: PermissionDecisionContext; -} -/** - * Result of attempting to disable sandboxing for the current session. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxDisableForSessionResult". - */ -/** @experimental */ -export interface SandboxDisableForSessionResult { + startTime: string; /** - * Whether this call resolved the pending request and applied the session opt-out. + * Last-modified time as an ISO 8601 timestamp. */ - success: boolean; + modifiedTime: string; /** - * The authoritative sandbox enabled state after the operation. + * Short summary of the session, when one has been derived. */ - enabled: boolean; + summary?: string; + /** + * Optional human-friendly name set via /rename. + */ + name?: string; + /** + * Always true for remote sessions. + */ + isRemote: true; + context?: SessionContext; + repository: RemoteSessionMetadataRepository; + /** + * Backing remote session IDs (most recent first). + */ + remoteSessionIds: string[]; + /** + * Pull request number associated with the session. + */ + pullRequestNumber?: number; + /** + * Original remote resource identifier (task ID or PR node ID). + */ + resourceId?: string; + taskType?: RemoteSessionMetadataTaskType; + /** + * Deadline (ISO 8601) at which a CLI remote session becomes stale without further heartbeats. + */ + staleAt?: string; + /** + * Server-side task state returned by GitHub. + */ + state?: string; + hostStatus?: RemoteSessionHostStatus; + /** + * Host-supplied human description of what the session is doing right now ("running tests", "waiting for approval"). Optional in the protocol and absent on hosts that do not publish it, so never rely on it -- it enriches `hostStatus`, it does not replace it. + */ + hostActivity?: string; } /** - * Managed sandbox enforcement state for a session. + * Repository context for the remote session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxEnforcementStatus". + * via the `definition` "RemoteSessionRepository". */ /** @experimental */ -export interface SandboxEnforcementStatus { +export interface RemoteSessionRepository { /** - * Whether the effective managed policy requires an available sandbox backend. + * Repository owner or organization login. */ - required: boolean; + owner: string; /** - * Whether an enforcement failure has permanently blocked the session. + * Repository name. */ - blocked: boolean; + name: string; /** - * The first sandbox enforcement failure that blocked the session. + * Optional branch associated with the remote session. */ - reason?: string; + branch?: string; } /** - * Request to accept the sandbox path grant offered on an active sandbox escalation permission prompt. + * One atomic edit of an allowed top-level repository setting. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxGrantPathForRequestRequest". + * via the `definition` "RepoSettingsEditRequest". */ /** @experimental */ -export interface SandboxGrantPathForRequestRequest { +/** @internal */ +export interface RepoSettingsEditRequest { /** - * Identifier of the exact pending sandbox escalation permission request whose sandboxPathGrant to accept. + * Absolute path of the repository root. */ - requestId: string; - decisionContext?: PermissionDecisionContext; + repoRoot: string; + scope: RepoSettingsEditScope; + /** + * One canonical top-level repository setting that the allowlist permits. + */ + key: string; + operation: SettingsEditOperation; + /** + * Required boolean, string or number for set, required string for add-item and remove-item, and forbidden for remove. The runtime rejects all other JSON values. + */ + value?: JsonValue; } /** - * Result of accepting a sandbox path grant. + * Which repository settings file to read. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxGrantPathForRequestResult". + * via the `definition` "RepoSettingsReadRawRequest". */ /** @experimental */ -export interface SandboxGrantPathForRequestResult { +/** @internal */ +export interface RepoSettingsReadRawRequest { /** - * Whether this call resolved the pending request and added the path to the session's sandbox policy. + * Absolute path of the repository root. */ - success: boolean; + repoRoot: string; + /** + * Use repo for shared settings or local for settings.local.json. Other scopes are rejected. + */ + scope: string; } /** - * Whether this host can run one sandbox policy feature. A session whose effective policy uses an unsupported feature fails each sandboxed command with `reason`, except `filesystem_enumeration`, whose absence degrades sandboxed PowerShell instead of failing it. + * Parsed repository settings without normalization or layering. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxHostCapability". + * via the `definition` "RepoSettingsReadRawResult". */ /** @experimental */ -export interface SandboxHostCapability { - name: SandboxHostCapabilityName; +/** @internal */ +export interface RepoSettingsReadRawResult { /** - * Whether this host can run the feature. + * Stored JSON values after the existing JSONC parser and prototype-safety checks. Empty when the file is missing, blank, or invalid. */ - supported: boolean; + config: JsonValue; /** - * Human-readable reason and remedy when the feature is unsupported, such as a package to install or an OS update. Present only when `supported` is false. + * True when the file exists but did not parse, so `config` is empty for that reason rather than because nothing is set. */ - reason?: string; + invalid: boolean; } /** - * Whether the host running this runtime can run the command sandbox. The runtime checks `supported` once per process. A capability answer can change while the process runs, for example after the user installs a missing package. + * The complete set of repository-overridable settings to store. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxHostSupport". + * via the `definition` "RepoSettingsWriteAllRequest". */ /** @experimental */ -export interface SandboxHostSupport { +/** @internal */ +export interface RepoSettingsWriteAllRequest { /** - * Whether a process-containment backend is usable on this host: Seatbelt on macOS, Bubblewrap on Linux, or ProcessContainer on Windows. + * Absolute path of the repository root. */ - supported: boolean; + repoRoot: string; /** - * Human-readable reason the sandbox cannot run on this host. Present only when `supported` is false. + * Use repo for shared settings or local for settings.local.json. Other scopes are rejected. */ - reason?: string; + scope: string; /** - * Sandbox policy features whose availability varies between hosts that can run the backend. Empty when `supported` is false, because no feature can run without a backend. Later runtimes can add entries; ignore an entry whose `name` you do not recognize. + * Object of allowed settings to store. Missing allowlisted keys are removed. Other input keys are ignored, while unknown stored keys are preserved. */ - capabilities: SandboxHostCapability[]; + settings: JsonValue; } /** - * Result of creating the persistent certificate authority of the sandbox credential proxy. + * One key to write or remove in a repository settings file. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxProxyCaCreateResult". + * via the `definition` "RepoSettingsWriteKeyRequest". */ /** @experimental */ -export interface SandboxProxyCaCreateResult { +/** @internal */ +export interface RepoSettingsWriteKeyRequest { /** - * Absolute path of the public certificate of the certificate authority, in PEM format. + * Absolute path of the repository root. */ - certificatePath: string; -} -/** - * Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxProxyCaRequest". - */ -/** @experimental */ -export interface SandboxProxyCaRequest { - sandboxConfig?: SandboxConfig; -} -/** - * Status of the persistent certificate authority of the sandbox credential proxy. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SandboxProxyCaStatus". - */ -/** @experimental */ -export interface SandboxProxyCaStatus { - state: SandboxProxyCaState; + repoRoot: string; /** - * Human-readable reason for the state. On `installed` or `notInstalled`, present only when the certificate authority must be rotated, and then says why. + * Use repo for shared settings or local for settings.local.json. Other scopes are rejected. */ - detail?: string; + scope: string; /** - * Whether this process can add the certificate authority to OS trust without credentials from a different user. False where OS trust is unsupported, and on Windows when the process cannot elevate itself to write the machine trust store. When false, do not offer to set up the certificate authority. + * Canonical top-level key permitted by the repository settings allowlist. */ - canInstall: boolean; + key: string; + /** + * Value to validate and write. Required unless delete is true; a null value is validated, not treated as deletion. + */ + value?: JsonValue; + /** + * True to remove the key instead of writing it. + */ + delete?: boolean; } /** - * Register an absolute-time scheduled prompt. + * The stored sandbox settings to resolve against the defaults. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ScheduleAddAtRequest". + * via the `definition` "SandboxApplyDefaultsRequest". */ /** @experimental */ -export interface ScheduleAddAtRequest { - /** - * Epoch milliseconds when the prompt should fire. - */ - at: number; - /** - * Prompt text to enqueue when the schedule fires. - */ - prompt: string; - /** - * Whether the schedule should re-arm after each tick. Defaults to false. - */ - recurring?: boolean; +export interface SandboxApplyDefaultsRequest { /** - * Optional display-only prompt label. + * The sandbox settings as stored in the settings file. An empty object resolves to the defaults alone. */ - displayPrompt?: string; + stored: JsonValue; } /** - * Register a cron scheduled prompt. + * Resolved sandbox configuration. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ScheduleAddCronRequest". + * via the `definition` "SandboxConfig". */ /** @experimental */ -export interface ScheduleAddCronRequest { - /** - * 5-field cron expression. - */ - cron: string; +export interface SandboxConfig { /** - * Prompt text to enqueue when the schedule fires. + * Whether sandboxing is enabled for the session. */ - prompt: string; + enabled: boolean; + userPolicy?: SandboxConfigUserPolicy; /** - * Whether the schedule should re-arm after each tick. Defaults to true. + * Whether to auto-add the current working directory to readwritePaths. Default: true. */ - recurring?: boolean; + addCurrentWorkingDirectory?: boolean; /** - * Optional display-only prompt label. + * Whether MCP servers the session launches are confined by the sandbox. Only an explicit `false` opts out; doing so also lets remote-MCP egress leave the sandbox, so the flag and `enabled` are always read together. Ignored while `enabled` is false. Default: true (enabled by default; set to false to opt out). */ - displayPrompt?: string; + sandboxMcpServers?: boolean; /** - * IANA timezone for evaluating the cron expression. + * Whether language servers the session launches are confined by the sandbox. Only an explicit `false` opts out. Ignored while `enabled` is false. Default: true (enabled by default; set to false to opt out). */ - tz?: string; -} -/** - * Register a relative-interval scheduled prompt. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ScheduleAddRequest". - */ -/** @experimental */ -export interface ScheduleAddRequest { + sandboxLspServers?: boolean; /** - * Human-readable interval such as `30s`, `5m`, or `2h`. + * Whether the agent may request that an individual command run outside the sandbox, which the host then approves or denies through the usual permission flow. A host capability flag rather than part of the policy: it is stripped from the effective spawn policy and only has an effect while `enabled` is true. Fail-closed, unlike the opt-out flags on this object: omitting it offers no bypass. Default: false (opt-in). */ - interval: string; + allowBypass?: boolean; /** - * Prompt text to enqueue when the schedule fires. + * Set by the runtime when a managed policy forced `sandboxMcpServers` on and took the local opt-out away. Provenance rather than policy: it lets a sandbox startup failure point at the administrator instead of a setting the next managed merge would override, and it is ignored when comparing two configs for change. Only the managed merge may set it; a caller-supplied value is stripped. + * + * @internal */ - prompt: string; + managedMcpRoutingLocked?: boolean; /** - * Whether the schedule should re-arm after each tick. Defaults to true. + * The `sandboxLspServers` counterpart of `managedMcpRoutingLocked`. + * + * @internal */ - recurring?: boolean; + managedLspRoutingLocked?: boolean; + auth?: SandboxConfigAuth; + credentials?: SandboxCredentialsConfig; /** - * Optional display-only prompt label. + * Whether to auto-grant read access to tool directories discovered on PATH and in toolchain environment variables (GOROOT, JAVA_HOME, VIRTUAL_ENV, and similar), and to common developer-tool caches, config, and toolchains. Writable grants cover scratch caches, the Unix GitHub CLI cache, and Cargo's registry, git store, and lock/tracker files. A relocated CARGO_HOME gets the same narrow split: registry and git are read-write; bin is read-only; the home root, config.toml, and credentials.toml stay ungranted. Set to false to disable every grant listed above; user-installed toolchains and caches then need explicit userPolicy.filesystem readonlyPaths and readwritePaths entries. The working directory (see addCurrentWorkingDirectory), temporary storage, session log paths, and system locations follow their own rules and stay granted. Default: true (enabled by default; set to false to opt out). */ - displayPrompt?: string; + allowDevToolAccess?: boolean; } /** - * Result of registering or re-arming a scheduled prompt. + * User-managed sandbox policy fragment merged into the auto-discovered base policy. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ScheduleAddResult". + * via the `definition` "SandboxConfigUserPolicy". */ /** @experimental */ -export interface ScheduleAddResult { - entry?: ScheduleEntry; - /** - * User-facing validation error, when registration failed. - */ - error?: string; +export interface SandboxConfigUserPolicy { + filesystem?: SandboxConfigUserPolicyFilesystem; + network?: SandboxConfigUserPolicyNetwork; + seatbelt?: SandboxConfigUserPolicySeatbelt; + experimental?: SandboxConfigUserPolicyExperimental; } /** - * Scheduled prompt entry with ID, timing (`intervalMs`, `cron`, or `at`), prompt text, recurrence, and next run time. + * Filesystem rules to merge into the base policy. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ScheduleEntry". + * via the `definition` "SandboxConfigUserPolicyFilesystem". */ /** @experimental */ -export interface ScheduleEntry { - /** - * Sequential id assigned by the runtime within the session. Stable across resumes (rebuilt from the event log). - */ - id: number; - /** - * Interval between scheduled ticks, in milliseconds (relative-interval schedules). - */ - intervalMs?: number; +export interface SandboxConfigUserPolicyFilesystem { /** - * 5-field cron expression for a recurring calendar schedule, evaluated in `tz`. + * Paths granted read/write access. */ - cron?: string; + readwritePaths?: string[]; /** - * IANA timezone the `cron` expression is evaluated in. + * Paths granted read-only access. */ - tz?: string; + readonlyPaths?: string[]; /** - * Absolute fire time (epoch milliseconds) for a one-shot calendar schedule. + * Paths explicitly denied. */ - at?: number; + deniedPaths?: string[]; /** - * Prompt text that gets enqueued on every tick. + * Whether to clear the policy when the session exits. */ - prompt: string; + clearPolicyOnExit?: boolean; +} +/** + * Network rules to merge into the base policy. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SandboxConfigUserPolicyNetwork". + */ +/** @experimental */ +export interface SandboxConfigUserPolicyNetwork { /** - * Whether the schedule re-arms after each tick (`/every`) or fires once (`/after`). + * Hosts allowed through the built-in sandbox proxy. A non-empty list denies unmatched hosts; an absent or empty list allows all hosts not blocked. Supports exact hostnames, IP addresses, and *.example.com for strict subdomains. Host rules do not override the outbound or local-network toggles. */ - recurring: boolean; + allowedHosts?: string[]; /** - * True for a self-paced (`dynamic`) schedule: no fixed cadence; the model arms each next run via the `manage_schedule` `wakeup` action. `nextRunAt` is model-controlled. + * Hosts denied by the built-in sandbox proxy. Deny rules take precedence over allowedHosts. A domain also denies all its subdomains. IP addresses match exactly; *.example.com matches strict subdomains, and * denies every host. */ - selfPaced?: boolean; + blockedHosts?: string[]; /** - * Display-only label for the prompt as shown in the UI (e.g. `/skill-name` for a skill-invocation schedule). The actual enqueued prompt is `prompt`. + * Whether outbound network traffic is allowed at all. */ - displayPrompt?: string; + allowOutbound?: boolean; /** - * ISO 8601 timestamp when the next tick is scheduled to fire. + * Whether traffic to local/loopback addresses is allowed. */ - nextRunAt: string; + allowLocalNetwork?: boolean; + proxy?: SandboxConfigUserPolicyNetworkProxy; } /** - * Register a self-paced scheduled prompt. + * HTTP proxy configuration for sandboxed traffic. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ScheduleAddSelfPacedRequest". + * via the `definition` "SandboxConfigUserPolicyNetworkProxy". */ /** @experimental */ -export interface ScheduleAddSelfPacedRequest { +export interface SandboxConfigUserPolicyNetworkProxy { /** - * Prompt text to enqueue when the schedule fires. + * Proxy URL (e.g. http://proxy.example.com:8080). The port is optional and defaults to the scheme's standard port when omitted; an explicit port must be between 1 and 65535. Credentials must not be embedded here — a `user:pass@` authority is rejected; put them in the separate `username`/`password` fields. A credential-free http:// loopback proxy URL is routed through the localhost proxy automatically; loopback covers localhost and any *.localhost subdomain, the whole 127.0.0.0/8 range, ::1, and IPv4-mapped loopback (::ffff:127.0.0.1). An https:// URL, or one with a username/password set, is used as-is. */ - prompt: string; + url: string; /** - * Optional display-only prompt label. + * Optional username for proxy authentication. Combined with the URL (and `password`) into `user:pass@host` when the sandboxed process routes through the proxy. */ - displayPrompt?: string; + username?: string; + /** + * Optional password for proxy authentication, combined with the URL at spawn time. The persisted value may be a literal password, a `${secret:…}` reference resolved from the OS keychain, or a `${VAR}`/`$VAR` environment reference; it is resolved just before the sandboxed process routes through the proxy. The /sandbox dialog stores a real password in the OS keychain and persists only a `${secret:…}` placeholder (never plaintext in settings.json); the field is masked in the dialog and redacted by /settings show. + */ + password?: string; } /** - * Whether the session currently has an active self-paced schedule. + * macOS seatbelt-specific options. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ScheduleHasSelfPacedResult". + * via the `definition` "SandboxConfigUserPolicySeatbelt". */ /** @experimental */ -export interface ScheduleHasSelfPacedResult { +export interface SandboxConfigUserPolicySeatbelt { /** - * True when at least one active schedule is self-paced. + * Whether the macOS seatbelt profile may access the keychain. */ - hasSelfPaced: boolean; + keychainAccess?: boolean; } /** - * Snapshot of the currently active recurring prompts for this session. + * Platform-specific experimental policy fields. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ScheduleList". + * via the `definition` "SandboxConfigUserPolicyExperimental". */ /** @experimental */ -export interface ScheduleList { - /** - * Active scheduled prompts, ordered by id. - */ - entries: ScheduleEntry[]; +export interface SandboxConfigUserPolicyExperimental { + seatbelt?: SandboxConfigUserPolicyExperimentalSeatbelt; } /** - * Re-arm a self-paced scheduled prompt. + * macOS seatbelt experimental options. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ScheduleRearmSelfPacedRequest". + * via the `definition` "SandboxConfigUserPolicyExperimentalSeatbelt". */ /** @experimental */ -export interface ScheduleRearmSelfPacedRequest { - /** - * Id of the self-paced scheduled prompt. - */ - id: number; +export interface SandboxConfigUserPolicyExperimentalSeatbelt { /** - * Epoch milliseconds when the prompt should next fire. + * Whether the macOS seatbelt profile may access the keychain. */ - at: number; + keychainAccess?: boolean; } /** - * Identifier of the scheduled prompt to remove. + * Credential-injection capability flags applied while the sandbox is enabled. For the same capability independent of sandboxing, and matched to the credential's GitHub host, see `shell.credentials`; the two are additive. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ScheduleStopRequest". + * via the `definition` "SandboxConfigAuth". */ /** @experimental */ -export interface ScheduleStopRequest { +export interface SandboxConfigAuth { /** - * Id of the scheduled prompt to remove. + * Whether to authenticate sandboxed HTTPS git through the local masking proxy. The child receives a fake `http..extraheader`; the real Authorization header is substituted only at its original HTTPS host, port, and repository path scope. github.com uses the Copilot token; other forges use credentials resolved from the user's own helper on the host. Default: false (opt-in). */ - id: number; -} -/** - * Remove a scheduled prompt by id. The result entry is omitted if the id was unknown. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ScheduleStopResult". - */ -/** @experimental */ -export interface ScheduleStopResult { - entry?: ScheduleEntry; + git?: boolean; + /** + * Whether to authenticate sandboxed gh through the local masking proxy. The child receives a fake GH_TOKEN; its real value is substituted only at github.com, api.github.com and uploads.github.com (github.com because gh repo clone authenticates git through gh auth git-credential). The repository's GitHub account takes precedence over the Copilot login. Default: false (opt-in). + */ + gh?: boolean; } /** - * Secret values to add to the redaction filter. + * Whole-value environment credential masking for sandboxed children. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SecretsAddFilterValuesRequest". + * via the `definition` "SandboxCredentialsConfig". */ /** @experimental */ -export interface SecretsAddFilterValuesRequest { +export interface SandboxCredentialsConfig { /** - * Raw secret values to register for redaction + * Environment variable names and their HTTPS injection destinations. Absent variables stay absent. No real values or sentinels are stored in this map. */ - values: string[]; + envVars: { + [k: string]: SandboxMaskedEnvVar | undefined; + }; } /** - * Confirmation that the secret values were registered. + * Destinations authorized to receive one masked environment credential. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SecretsAddFilterValuesResult". + * via the `definition` "SandboxMaskedEnvVar". */ /** @experimental */ -export interface SecretsAddFilterValuesResult { +export interface SandboxMaskedEnvVar { /** - * Whether the values were successfully registered + * Nonempty list of HTTPS injection hostnames or *.example.com patterns. Bare * is not accepted. These grants never override the sandbox network policy. Values in plaintext HTTP requests, URLs, bodies, encoded credentials, and signed requests are not substituted. */ - ok: true; + injectHosts: string[]; } /** - * Parameters for session.extensions.sendAttachmentsToMessage. + * A possible secret-bearing environment variable and optional locally suggested HTTPS injection hosts. This is a draft for user review, not an active grant. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SendAttachmentsToMessageParams". + * via the `definition` "SandboxCredentialSuggestion". */ /** @experimental */ -export interface SendAttachmentsToMessageParams { +export interface SandboxCredentialSuggestion { /** - * Optional canvas instance binding the push for provenance. When supplied, the runtime resolves the canvas, verifies it is owned by the calling extension, and stamps canvasId/instanceId onto each extension_context entry. When omitted, no resolution runs and those fields stay unset on the attachment. + * Environment variable name. The secret value is never returned. */ - instanceId?: string; + name: string; /** - * Attachments to push into the next user-message turn. extension_context entries take the slim shape; standard variants take their full AttachmentSchema shape. + * HTTPS hostnames suggested by a local known-provider mapping. An empty list requires the user to supply injection hosts before adding a masking entry. These suggestions do not allow network access. */ - attachments: PushAttachment[]; + suggestedInjectHosts: string[]; } /** - * A single user message to append to the session as part of a `session.sendMessages` turn + * Possible unconfigured secrets in the sandbox shell environment, sorted by variable name, with no secret values. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SendMessageItem". + * via the `definition` "SandboxCredentialSuggestionsResult". */ /** @experimental */ -export interface SendMessageItem { - /** - * The user message text - */ - prompt: string; - /** - * If provided, this is shown in the timeline instead of `prompt` - */ - displayPrompt?: string; - /** - * Optional attachments (files, directories, selections, blobs, GitHub references) to include with this message - */ - attachments?: Attachment[]; - /** - * If false, this message will not trigger a Premium Request Unit charge. User messages default to billable. - * - * @internal - */ - billable?: boolean; - /** - * If set, the request will fail if the named tool is not available when this message is among the user messages at the start of the current exchange - */ - requiredTool?: string; +export interface SandboxCredentialSuggestionsResult { /** - * Optional provenance tag copied to the resulting user.message event. Must be `user`, `system`, `command-` for command-originated messages, `schedule-` for scheduled prompts, or `agent-` for prompts sent by another agent. - * - * @internal + * Candidates for user review. Empty when sandboxing is disabled or no unconfigured candidates are present. */ - source?: string; + suggestions: SandboxCredentialSuggestion[]; } /** - * Parameters for sending zero or more user messages to the session in a single turn. Remote-backed (Mission Control) sessions do not support this method and will return an error. + * Request to disable sandboxing for the current session while resolving an active sandbox-bypass permission prompt. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SendMessagesRequest". + * via the `definition` "SandboxDisableForSessionRequest". */ /** @experimental */ -export interface SendMessagesRequest { - /** - * The user messages to append to the conversation, in order, before running one agent loop. When the batch starts a run, its final message is the primary initiating message; earlier messages provide context, not separate runs or replies. May be empty, in which case a single turn runs over the existing history with no new user message or originatingMessageId. - */ - messages: SendMessageItem[]; - mode?: SendMode; - /** - * If true, adds the messages to the front of the queue instead of the end - */ - prepend?: boolean; - agentMode?: SendAgentMode; - /** - * Custom HTTP headers to include in outbound model requests for this turn. Merged with session-level provider headers; per-turn headers augment and overwrite session-level headers with the same key. - */ - requestHeaders?: { - [k: string]: string | undefined; - }; - responseFormat?: ResponseFormat; +export interface SandboxDisableForSessionRequest { /** - * W3C Trace Context traceparent header for distributed tracing of this agent turn + * Identifier of the exact pending sandbox-bypass permission request that authorized the session opt-out. */ - traceparent?: string; + requestId: string; + decisionContext?: PermissionDecisionContext; +} +/** + * Result of attempting to disable sandboxing for the current session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SandboxDisableForSessionResult". + */ +/** @experimental */ +export interface SandboxDisableForSessionResult { /** - * W3C Trace Context tracestate header for distributed tracing + * Whether this call resolved the pending request and applied the session opt-out. */ - tracestate?: string; + success: boolean; /** - * If true, await completion of the agentic loop for this turn before returning. Defaults to false (fire-and-forget). When true, the result still contains the same `messageIds`; the caller can rely on the agent having processed the messages before the call resolves. Transport-dependent tail semantics: on a LOCAL (in-process) session the wait additionally blocks until the completed turn's event tail has been dispatched to this session's in-process subscribers, so a subsequent read of subscriber state already reflects the turn; on a REMOTE session the wait resolves once the loop completes and mirrored delivery follows over the wire. Callers that need the stronger local guarantee on remote sessions should await the event stream explicitly. + * The authoritative sandbox enabled state after the operation. */ - wait?: boolean; + enabled: boolean; } /** - * Result of sending zero or more user messages + * The documentation URL a host cites when it declines or downgrades a sandbox setting. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SendMessagesResult". + * via the `definition` "SandboxDocsUrlResult". */ /** @experimental */ -export interface SendMessagesResult { +export interface SandboxDocsUrlResult { /** - * Unique identifiers assigned to the messages, one per provided message in order. For a batch that starts a run, assistant messages use the final ID as originatingMessageId throughout that run, including tool iterations and stop-hook corrections. Immediate steering does not replace the active run's origin. Empty when no messages were provided; that run has no originatingMessageId. + * Documentation URL describing the sandbox and the settings that control it. */ - messageIds: string[]; + url: string; } /** - * Parameters for sending a user message to the session + * A sandbox config and the per-feature routing flag to resolve it for. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SendRequest". + * via the `definition` "SandboxEffectiveForOptionalParams". */ /** @experimental */ -export interface SendRequest { +/** @internal */ +export interface SandboxEffectiveForOptionalParams { /** - * The user message text + * The session's resolved `sandbox` slice. Omitted when the host has none, which yields a disabled sandbox rather than an error. */ - prompt: string; + sandbox?: JsonValue; /** - * If provided, this is shown in the timeline instead of `prompt` + * The routing flag naming the feature being launched, such as `sandboxMcpServers` or `sandboxLspServers`. */ - displayPrompt?: string; + routingFlag: string; +} +/** + * The sandbox a named feature actually launches under. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SandboxEffectiveForOptionalResult". + */ +/** @experimental */ +/** @internal */ +export interface SandboxEffectiveForOptionalResult { /** - * Optional attachments (files, directories, selections, blobs, GitHub references) to include with the message + * The effective sandbox config for the requested feature, or a disabled sandbox when the feature is routed out of it. */ - attachments?: Attachment[]; - mode?: SendMode; + sandboxJson: JsonValue; +} +/** + * One slash command, as typed, to test against the enforcement-block allowlist. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SandboxEnforcementCommandAllowedParams". + */ +/** @experimental */ +/** @internal */ +export interface SandboxEnforcementCommandAllowedParams { /** - * If true, adds the message to the front of the queue instead of the end + * The command name as the user typed it, with or without its leading slash. */ - prepend?: boolean; + commandName: string; /** - * If false, this message will not trigger a Premium Request Unit charge. User messages default to billable. + * The command's arguments, in order. Pass an empty array for a bare command: several entries in the allowlist admit the bare form and refuse every argument. */ - billable?: boolean; + args: string[]; +} +/** + * Managed sandbox enforcement state for a session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SandboxEnforcementStatus". + */ +/** @experimental */ +export interface SandboxEnforcementStatus { /** - * If set, the request will fail if the named tool is not available when this message is among the user messages at the start of the current exchange + * Whether the effective managed policy requires an available sandbox backend. */ - requiredTool?: string; + required: boolean; /** - * Optional provenance tag copied to the resulting user.message event. Must be `user`, `system`, `command-` for command-originated messages, `schedule-` for scheduled prompts, or `agent-` for prompts sent by another agent. - * - * @internal + * Whether an enforcement failure has permanently blocked the session. */ - source?: string; - agentMode?: SendAgentMode; + blocked: boolean; /** - * Custom HTTP headers to include in outbound model requests for this turn. Merged with session-level provider headers; per-turn headers augment and overwrite session-level headers with the same key. + * The first sandbox enforcement failure that blocked the session. */ - requestHeaders?: { - [k: string]: string | undefined; - }; - responseFormat?: ResponseFormat; + reason?: string; +} +/** + * A batch of file-picker candidates to check against a prepared policy. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SandboxFilterPickerCandidatesParams". + */ +/** @experimental */ +/** @internal */ +export interface SandboxFilterPickerCandidatesParams { /** - * W3C Trace Context traceparent header for distributed tracing of this agent turn + * The candidates to check, in the order the answers are returned. */ - traceparent?: string; + candidates: SandboxPickerCandidate[]; /** - * W3C Trace Context tracestate header for distributed tracing + * The session's working directory, matching the one the policy was prepared from. */ - tracestate?: string; + cwd: string; /** - * If true, await completion of the agentic loop for this message before returning. Defaults to false (fire-and-forget). When true, the result still contains the same `messageId`; the caller can rely on the agent having processed the message before the call resolves. Transport-dependent tail semantics: on a LOCAL (in-process) session the wait additionally blocks until the completed turn's event tail has been dispatched to this session's in-process subscribers, so a subsequent read of subscriber state already reflects the turn; on a REMOTE session the wait resolves once the loop completes and mirrored delivery follows over the wire. Callers that need the stronger local guarantee on remote sessions should await the event stream explicitly. + * The policy returned by `sandbox.preparePickerPolicy`. Omitted keeps every candidate. */ - wait?: boolean; + sandbox?: JsonValue; } /** - * Result of sending a user message + * One file-picker suggestion offered up for the sandbox filesystem check. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SendResult". + * via the `definition` "SandboxPickerCandidate". */ /** @experimental */ -export interface SendResult { +/** @internal */ +export interface SandboxPickerCandidate { /** - * Unique identifier assigned to the message + * Absolute path the suggestion would attach. */ - messageId: string; + path: string; + /** + * Whether the suggestion is a directory. A directory the policy does not itself allow may still be needed as a waypoint to an allowed subtree. + */ + isDirectory: boolean; } /** - * Internal request for sending a system notification. + * Per-candidate allow decisions, positionally aligned with the request. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SendSystemNotificationRequest". + * via the `definition` "SandboxFilterPickerCandidatesResult". */ /** @experimental */ -export interface SendSystemNotificationRequest { - /** - * Notification text to deliver to the model. - */ - message: string; - /** - * Optional structured notification kind. - */ - kind?: JsonValue; +/** @internal */ +export interface SandboxFilterPickerCandidatesResult { /** - * Internal delivery options, including passive policy. + * One decision per candidate, in the same order. Always the same length as the request's `candidates`. */ - options?: JsonValue; + allowed: boolean[]; } /** - * Agents discovered across user, project, plugin, and remote sources. + * Request to accept the sandbox path grant offered on an active sandbox escalation permission prompt. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ServerAgentList". + * via the `definition` "SandboxGrantPathForRequestRequest". */ /** @experimental */ -export interface ServerAgentList { +export interface SandboxGrantPathForRequestRequest { /** - * All discovered agents across all sources + * Identifier of the exact pending sandbox escalation permission request whose sandboxPathGrant to accept. */ - agents: AgentInfo[]; + requestId: string; + decisionContext?: PermissionDecisionContext; } /** - * Instruction sources discovered across user, repository, and plugin sources. + * Result of accepting a sandbox path grant. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ServerInstructionSourceList". + * via the `definition` "SandboxGrantPathForRequestResult". */ /** @experimental */ -export interface ServerInstructionSourceList { +export interface SandboxGrantPathForRequestResult { /** - * All discovered instruction sources + * Whether this call resolved the pending request and added the path to the session's sandbox policy. */ - sources: InstructionSource[]; + success: boolean; } /** - * Server-side skill metadata, including name, description, source, enabled/invocable state, path, project path, and argument hint. + * Whether this host can run one sandbox policy feature. A session whose effective policy uses an unsupported feature fails each sandboxed command with `reason`, except `filesystem_enumeration`, whose absence degrades sandboxed PowerShell instead of failing it. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ServerSkill". + * via the `definition` "SandboxHostCapability". */ /** @experimental */ -export interface ServerSkill { - /** - * Unique identifier for the skill - */ - name: string; - /** - * Canonical slash command name used to invoke the skill, without the leading '/' - */ - commandName?: string; - /** - * Description of what the skill does - */ - description: string; - source: SkillSource; +export interface SandboxHostCapability { + name: SandboxHostCapabilityName; /** - * Whether the skill can be invoked by the user as a slash command + * Whether this host can run the feature. */ - userInvocable: boolean; + supported: boolean; /** - * Whether the skill is currently enabled (based on global config) + * Human-readable reason and remedy when the feature is unsupported, such as a package to install or an OS update. Present only when `supported` is false. */ - enabled: boolean; + reason?: string; +} +/** + * Whether the host running this runtime can run the command sandbox. The runtime checks `supported` once per process. A capability answer can change while the process runs, for example after the user installs a missing package. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SandboxHostSupport". + */ +/** @experimental */ +export interface SandboxHostSupport { /** - * Absolute path to the skill file + * Whether a process-containment backend is usable on this host: Seatbelt on macOS, Bubblewrap on Linux, or ProcessContainer on Windows. */ - path?: string; + supported: boolean; /** - * The project path this skill belongs to (only for project/inherited skills) + * Human-readable reason the sandbox cannot run on this host. Present only when `supported` is false. */ - projectPath?: string; + reason?: string; /** - * Optional freeform hint describing the skill's expected arguments, from the `argument-hint` frontmatter field + * Sandbox policy features whose availability varies between hosts that can run the backend. Empty when `supported` is false, because no feature can run without a backend. Later runtimes can add entries; ignore an entry whose `name` you do not recognize. */ - argumentHint?: string; + capabilities: SandboxHostCapability[]; } /** - * Skills discovered across global and project sources. + * The working directory and sandbox settings to build a file-picker policy from. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ServerSkillList". + * via the `definition` "SandboxPreparePickerPolicyParams". */ /** @experimental */ -export interface ServerSkillList { +/** @internal */ +export interface SandboxPreparePickerPolicyParams { /** - * All discovered skills across all sources + * The session's working directory. Git discovery and grant canonicalization are resolved against it. */ - skills: ServerSkill[]; + cwd: string; /** - * Messages for skills that failed to load (e.g. malformed SKILL.md). Empty when host skills are excluded so host-local paths are not disclosed to multitenant callers. + * The session's resolved `sandbox` slice. Omitted, or disabled, yields no policy and every candidate is kept. */ - errors?: string[]; + sandbox?: JsonValue; } /** - * Current activity flags for the session. + * The prepared file-picker policy, or none when the sandbox is disabled. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionActivity". + * via the `definition` "SandboxPreparePickerPolicyResult". */ /** @experimental */ -export interface SessionActivity { - /** - * Whether an in-flight operation can currently be aborted. - */ - abortable: boolean; +/** @internal */ +export interface SandboxPreparePickerPolicyResult { /** - * Whether the session currently has active work, including running turns or tasks. + * The prepared policy to pass back to `sandbox.filterPickerCandidates`. Absent when the sandbox is disabled or absent, in which case filtering keeps every candidate. */ - hasActiveWork: boolean; + sandboxJson?: JsonValue; } /** - * Internal GitHub login parameters. + * Result of creating the persistent certificate authority of the sandbox credential proxy. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionAuthLoginRequest". + * via the `definition` "SandboxProxyCaCreateResult". */ /** @experimental */ -export interface SessionAuthLoginRequest { - /** - * GitHub host URL - */ - host: string; - /** - * GitHub login - */ - login: string; - /** - * GitHub authentication token - */ - token: string; +export interface SandboxProxyCaCreateResult { /** - * Whether to persist the token after login + * Absolute path of the public certificate of the certificate authority, in PEM format. */ - persist?: boolean; + certificatePath: string; } /** - * Parameters identifying a GitHub authentication to log out. + * Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionAuthLogoutUserRequest". + * via the `definition` "SandboxProxyCaRequest". */ /** @experimental */ -export interface SessionAuthLogoutUserRequest { - authInfo: AuthInfo; +export interface SandboxProxyCaRequest { + sandboxConfig?: SandboxConfig; } /** - * Authentication status and account metadata for the session. + * Status of the persistent certificate authority of the sandbox credential proxy. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionAuthStatus". + * via the `definition` "SandboxProxyCaStatus". */ /** @experimental */ -export interface SessionAuthStatus { - /** - * Whether the session has resolved authentication - */ - isAuthenticated: boolean; - authType?: AuthInfoType; - /** - * Authentication host URL - */ - host?: string; - /** - * Authenticated login/username, if available - */ - login?: string; +export interface SandboxProxyCaStatus { + state: SandboxProxyCaState; /** - * Human-readable authentication status description + * Human-readable reason for the state. On `installed` or `notInstalled`, present only when the certificate authority must be rotated, and then says why. */ - statusMessage?: string; + detail?: string; /** - * Copilot plan tier (e.g., individual_pro, business) + * Whether this process can add the certificate authority to OS trust without credentials from a different user. False where OS trust is unsupported, and on Windows when the process cannot elevate itself to write the machine trust store. When false, do not offer to set up the certificate authority. */ - copilotPlan?: string; + canInstall: boolean; } /** - * Parameters for switching the session's active authentication. + * The stored sandbox proxy password, if one is present. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionAuthSwitchRequest". + * via the `definition` "SandboxProxySecretGetResult". */ /** @experimental */ -export interface SessionAuthSwitchRequest { - authInfo: AuthInfo; +export interface SandboxProxySecretGetResult { /** - * Optional token paired with the authentication information + * The stored password. Absent when no entry exists in either the keychain or the on-disk fallback store. */ - token?: string; + value?: string; } /** - * Map of sessionId -> bytes freed by removing the session's workspace directory. + * Where this runtime keeps the sandbox proxy password. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionBulkDeleteResult". + * via the `definition` "SandboxProxySecretLocation". */ /** @experimental */ -export interface SessionBulkDeleteResult { +export interface SandboxProxySecretLocation { /** - * Map of sessionId -> bytes freed by removing the session's workspace directory. Sessions whose deletion failed are omitted from this map (failures are logged on the server but not surfaced per-id; check the map for absent IDs to detect them). + * Absolute path of the credential store holding the sandbox proxy password. The proxy password belongs to no MCP server, so it is kept in its own directory rather than in the MCP secret store. */ - freedBytes: { - [k: string]: number | undefined; - }; + configDir: string; + /** + * Identifier of the proxy password entry within that store. Derived from the configuration directory, so two Copilot homes on one machine never share an entry. Use it to recognize a `${secret:…}` reference in stored settings as this runtime's own proxy password. + */ + secretId: string; } /** - * The IDE a host is connected to, as reported to the session. + * The sandbox proxy password to store. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionConnectedIdeInfo". + * via the `definition` "SandboxProxySecretSaveRequest". */ /** @experimental */ -export interface SessionConnectedIdeInfo { - /** - * Display name of the connected IDE, for example `VS Code`. - */ - ideName: string; +export interface SandboxProxySecretSaveRequest { /** - * Absolute path of the workspace folder the IDE has open. + * The password to store for the sandbox proxy. */ - workspaceFolder: string; + value: string; } /** - * The enriched metadata records, with summary and context fields backfilled where available. Sessions confirmed empty and unnamed are omitted. + * Where the sandbox proxy password was stored. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionEnrichMetadataResult". + * via the `definition` "SandboxProxySecretSaveResult". */ /** @experimental */ -export interface SessionEnrichMetadataResult { +export interface SandboxProxySecretSaveResult { /** - * Enriched records, with summary and context backfilled. Sessions confirmed empty and unnamed may be omitted. + * Whether the OS keychain accepted the value. False means it was written to the on-disk fallback store instead, which is still readable by `sandbox.proxySecret.get`. */ - sessions: LocalSessionMetadataValue[]; + storedInKeychain: boolean; } /** - * File path, content to append, and optional mode for the client-provided session filesystem. Implementations create parent directories as needed. + * The user's sandbox settings and the managed sandbox floor to raise them to. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsAppendFileRequest". + * via the `definition` "SandboxResolveFlooredConfigParams". */ /** @experimental */ -export interface SessionFsAppendFileRequest { - /** - * Target session identifier - */ - sessionId: string; - /** - * Path using SessionFs conventions - */ - path: string; +/** @internal */ +export interface SandboxResolveFlooredConfigParams { /** - * Content to append + * The user's own `sandbox` settings slice. Omitted when the user has configured none, which still yields the managed floor rather than a disabled sandbox. */ - content: string; + userSandbox?: JsonValue; /** - * Optional POSIX-style mode for newly created files + * The effective managed `sandbox` slice acting as a floor. Omitted when no administrator policy applies, in which case the user's own settings stand unchanged. */ - mode?: number; + managedSandbox?: JsonValue; } /** - * Describes a filesystem error. + * The user's sandbox settings raised to the managed floor. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsError". + * via the `definition` "SandboxResolveFlooredConfigResult". */ /** @experimental */ -export interface SessionFsError { - code: SessionFsErrorCode; - /** - * Free-form detail about the error, for logging/diagnostics - */ - message?: string; +export interface SandboxResolveFlooredConfigResult { /** - * For failed writeFile requests only: true if the provider changed the target before failing. Omit when unknown or unchanged. + * The floored sandbox config, normalized through the declared sandbox shape so only declared fields in a fixed order are present. */ - writeChanged?: boolean; + sandboxJson: JsonValue; } /** - * Path to test for existence in the client-provided session filesystem. + * The managed sandbox policy in force, which selects which remedy the notice offers. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsExistsRequest". + * via the `definition` "SandboxUnsupportedStartupNoticeParams". */ /** @experimental */ -export interface SessionFsExistsRequest { +/** @internal */ +export interface SandboxUnsupportedStartupNoticeParams { /** - * Target session identifier + * The managed `sandbox` slice, when a policy supplies one. The notice treats the sandbox as enforced only when this both enables it and sets `failIfUnavailable`, because a managed sandbox that tolerates being unavailable still leaves the user able to turn it off. */ - sessionId: string; + managedSandbox?: JsonValue; /** - * Path using SessionFs conventions + * True when the sandbox stayed on only because the managed policy could not be determined. Distinguishes a policy that positively enforces the sandbox from one that merely failed to resolve, which is the difference between telling the user to contact an administrator and telling them to wait. Defaults to false. */ - path: string; + enabledByUndeterminedPolicy?: boolean; } /** - * Indicates whether the requested path exists in the client-provided session filesystem. + * The startup warning, absent when the machine can run a sandbox. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsExistsResult". + * via the `definition` "SandboxUnsupportedStartupNoticeResult". */ /** @experimental */ -export interface SessionFsExistsResult { +/** @internal */ +export interface SandboxUnsupportedStartupNoticeResult { /** - * Whether the path exists + * The user-facing warning, carrying the platform remedy and the recovery the policy in force actually allows. Absent when this machine supports a sandbox, so a host can call unconditionally and print only what it gets. */ - exists: boolean; + notice?: string; } /** - * Directory path to create in the client-provided session filesystem, with options for recursive creation and POSIX mode. + * Register an absolute-time scheduled prompt. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsMkdirRequest". + * via the `definition` "ScheduleAddAtRequest". */ /** @experimental */ -export interface SessionFsMkdirRequest { +export interface ScheduleAddAtRequest { /** - * Target session identifier + * Epoch milliseconds when the prompt should fire. */ - sessionId: string; + at: number; /** - * Path using SessionFs conventions + * Prompt text to enqueue when the schedule fires. */ - path: string; + prompt: string; /** - * Create parent directories as needed + * Whether the schedule should re-arm after each tick. Defaults to false. */ - recursive?: boolean; + recurring?: boolean; /** - * Optional POSIX-style mode for newly created directories + * Optional display-only prompt label. */ - mode?: number; + displayPrompt?: string; } /** - * Directory path whose entries should be listed from the client-provided session filesystem. + * Register a cron scheduled prompt. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReaddirRequest". + * via the `definition` "ScheduleAddCronRequest". */ /** @experimental */ -export interface SessionFsReaddirRequest { +export interface ScheduleAddCronRequest { /** - * Target session identifier + * 5-field cron expression. */ - sessionId: string; + cron: string; /** - * Path using SessionFs conventions + * Prompt text to enqueue when the schedule fires. */ - path: string; -} -/** - * Names of entries in the requested directory, or a filesystem error if the read failed. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReaddirResult". - */ -/** @experimental */ -export interface SessionFsReaddirResult { + prompt: string; /** - * Entry names in the directory + * Whether the schedule should re-arm after each tick. Defaults to true. */ - entries: string[]; - error?: SessionFsError; + recurring?: boolean; + /** + * Optional display-only prompt label. + */ + displayPrompt?: string; + /** + * IANA timezone for evaluating the cron expression. + */ + tz?: string; } /** - * Directory entry returned by session filesystem `readdirWithTypes`, with name and entry type. + * Register a relative-interval scheduled prompt. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReaddirWithTypesEntry". + * via the `definition` "ScheduleAddRequest". */ /** @experimental */ -export interface SessionFsReaddirWithTypesEntry { +export interface ScheduleAddRequest { /** - * Entry name + * Human-readable interval such as `30s`, `5m`, or `2h`. */ - name: string; - type: SessionFsReaddirWithTypesEntryType; -} -/** - * Directory path whose entries (with type information) should be listed from the client-provided session filesystem. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReaddirWithTypesRequest". - */ -/** @experimental */ -export interface SessionFsReaddirWithTypesRequest { + interval: string; /** - * Target session identifier + * Prompt text to enqueue when the schedule fires. */ - sessionId: string; + prompt: string; /** - * Path using SessionFs conventions + * Whether the schedule should re-arm after each tick. Defaults to true. */ - path: string; + recurring?: boolean; + /** + * Optional display-only prompt label. + */ + displayPrompt?: string; } /** - * Entries in the requested directory paired with file/directory type information, or a filesystem error if the read failed. + * Result of registering or re-arming a scheduled prompt. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReaddirWithTypesResult". + * via the `definition` "ScheduleAddResult". */ /** @experimental */ -export interface SessionFsReaddirWithTypesResult { +export interface ScheduleAddResult { + entry?: ScheduleEntry; /** - * Directory entries with type information + * User-facing validation error, when registration failed. */ - entries: SessionFsReaddirWithTypesEntry[]; - error?: SessionFsError; + error?: string; } /** - * Path of the binary file to read from the client-provided session filesystem. + * Scheduled prompt entry with ID, timing (`intervalMs`, `cron`, or `at`), prompt text, recurrence, and next run time. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReadFileBytesRequest". + * via the `definition` "ScheduleEntry". */ /** @experimental */ -export interface SessionFsReadFileBytesRequest { +export interface ScheduleEntry { /** - * Target session identifier + * Sequential id assigned by the runtime within the session. Stable across resumes (rebuilt from the event log). */ - sessionId: string; + id: number; /** - * Path using SessionFs conventions + * Interval between scheduled ticks, in milliseconds (relative-interval schedules). */ - path: string; -} -/** - * File bytes as standard base64, or a filesystem error if the read failed. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReadFileBytesResult". - */ -/** @experimental */ -export interface SessionFsReadFileBytesResult { + intervalMs?: number; /** - * Exact file bytes encoded as standard base64 + * 5-field cron expression for a recurring calendar schedule, evaluated in `tz`. */ - content: string; - error?: SessionFsError; + cron?: string; + /** + * IANA timezone the `cron` expression is evaluated in. + */ + tz?: string; + /** + * Absolute fire time (epoch milliseconds) for a one-shot calendar schedule. + */ + at?: number; + /** + * Prompt text that gets enqueued on every tick. + */ + prompt: string; + /** + * Whether the schedule re-arms after each tick (`/every`) or fires once (`/after`). + */ + recurring: boolean; + /** + * True for a self-paced (`dynamic`) schedule: no fixed cadence; the model arms each next run via the `manage_schedule` `wakeup` action. `nextRunAt` is model-controlled. + */ + selfPaced?: boolean; + /** + * Display-only label for the prompt as shown in the UI (e.g. `/skill-name` for a skill-invocation schedule). The actual enqueued prompt is `prompt`. + */ + displayPrompt?: string; + /** + * ISO 8601 timestamp when the next tick is scheduled to fire. + */ + nextRunAt: string; } /** - * Path of the file to read from the client-provided session filesystem. + * Register a self-paced scheduled prompt. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReadFileRequest". + * via the `definition` "ScheduleAddSelfPacedRequest". */ /** @experimental */ -export interface SessionFsReadFileRequest { +export interface ScheduleAddSelfPacedRequest { /** - * Target session identifier + * Prompt text to enqueue when the schedule fires. */ - sessionId: string; + prompt: string; /** - * Path using SessionFs conventions + * Optional display-only prompt label. */ - path: string; + displayPrompt?: string; } /** - * File content as a UTF-8 string, or a filesystem error if the read failed. + * Whether the session currently has an active self-paced schedule. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsReadFileResult". + * via the `definition` "ScheduleHasSelfPacedResult". */ /** @experimental */ -export interface SessionFsReadFileResult { +export interface ScheduleHasSelfPacedResult { /** - * File content as UTF-8 string + * True when at least one active schedule is self-paced. */ - content: string; - error?: SessionFsError; + hasSelfPaced: boolean; } /** - * Source and destination paths for renaming or moving an entry in the client-provided session filesystem. + * Snapshot of the currently active recurring prompts for this session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsRenameRequest". + * via the `definition` "ScheduleList". */ /** @experimental */ -export interface SessionFsRenameRequest { - /** - * Target session identifier - */ - sessionId: string; - /** - * Source path using SessionFs conventions - */ - src: string; +export interface ScheduleList { /** - * Destination path using SessionFs conventions + * Active scheduled prompts, ordered by id. */ - dest: string; + entries: ScheduleEntry[]; } /** - * Path to remove from the client-provided session filesystem, with options for recursive removal and force. + * Re-arm a self-paced scheduled prompt. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsRmRequest". + * via the `definition` "ScheduleRearmSelfPacedRequest". */ /** @experimental */ -export interface SessionFsRmRequest { - /** - * Target session identifier - */ - sessionId: string; - /** - * Path using SessionFs conventions - */ - path: string; +export interface ScheduleRearmSelfPacedRequest { /** - * Remove directories and their contents recursively + * Id of the self-paced scheduled prompt. */ - recursive?: boolean; + id: number; /** - * Ignore errors if the path does not exist + * Epoch milliseconds when the prompt should next fire. */ - force?: boolean; + at: number; } /** - * Optional capabilities declared by the provider + * Identifier of the scheduled prompt to remove. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSetProviderCapabilities". + * via the `definition` "ScheduleStopRequest". */ /** @experimental */ -export interface SessionFsSetProviderCapabilities { - /** - * Whether the provider supports SQLite query/exists operations - */ - sqlite?: boolean; +export interface ScheduleStopRequest { /** - * Whether the provider supports binary reads and writes through sessionFs.readFileBytes and sessionFs.writeFileBytes + * Id of the scheduled prompt to remove. */ - binary?: boolean; + id: number; } /** - * Initial working directory, session-state path layout, and path conventions used to register the calling SDK client as the session filesystem provider. A registered provider is authoritative for path interpretation and filesystem facts used by workspace permission validation. Paths are interpreted lexically; home-relative paths (`~` and `~/...`) and Windows drive-relative paths such as `C:foo` are unsupported. Until provider-side canonicalization is supported, providers must not expose symlinks inside allowed roots that escape those roots. + * Remove a scheduled prompt by id. The result entry is omitted if the id was unknown. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSetProviderRequest". + * via the `definition` "ScheduleStopResult". */ /** @experimental */ -export interface SessionFsSetProviderRequest { - /** - * Absolute initial working directory for sessions. Registering the provider establishes this path as the root of its virtual namespace; the runtime does not require the provider to materialize or stat it before creating a session. - */ - initialCwd: string; - /** - * Path within each session's SessionFs where the runtime stores files for that session - */ - sessionStatePath: string; - conventions: SessionFsSetProviderConventions; - capabilities?: SessionFsSetProviderCapabilities; +export interface ScheduleStopResult { + entry?: ScheduleEntry; } /** - * Indicates whether the calling client was registered as the session filesystem provider. + * Secret values to add to the redaction filter. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSetProviderResult". + * via the `definition` "SecretsAddFilterValuesRequest". */ /** @experimental */ -export interface SessionFsSetProviderResult { +export interface SecretsAddFilterValuesRequest { /** - * Whether the provider was set successfully + * Raw secret values to register for redaction */ - success: boolean; + values: string[]; } /** - * Indicates whether the per-session SQLite database already exists. + * Confirmation that the secret values were registered. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSqliteExistsResult". + * via the `definition` "SecretsAddFilterValuesResult". */ /** @experimental */ -export interface SessionFsSqliteExistsResult { +export interface SecretsAddFilterValuesResult { /** - * Whether the session database already exists + * Whether the values were successfully registered */ - exists: boolean; + ok: true; } /** - * SQL query, query type, and optional bind parameters for executing a SQLite query against the per-session database. The provider applies its SQLite busy timeout for every call. + * Parameters for session.extensions.sendAttachmentsToMessage. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSqliteQueryRequest". + * via the `definition` "SendAttachmentsToMessageParams". */ /** @experimental */ -export interface SessionFsSqliteQueryRequest { - /** - * Target session identifier - */ - sessionId: string; +export interface SendAttachmentsToMessageParams { /** - * SQL query to execute + * Optional canvas instance binding the push for provenance. When supplied, the runtime resolves the canvas, verifies it is owned by the calling extension, and stamps canvasId/instanceId onto each extension_context entry. When omitted, no resolution runs and those fields stay unset on the attachment. */ - query: string; - queryType: SessionFsSqliteQueryType; + instanceId?: string; /** - * Optional named bind parameters + * Attachments to push into the next user-message turn. extension_context entries take the slim shape; standard variants take their full AttachmentSchema shape. */ - params?: { - [k: string]: JsonValue | undefined; - }; + attachments: PushAttachment[]; } /** - * Query results including rows, columns, and rows affected, or a filesystem error if execution failed. + * A single user message to append to the session as part of a `session.sendMessages` turn * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSqliteQueryResult". + * via the `definition` "SendMessageItem". */ /** @experimental */ -export interface SessionFsSqliteQueryResult { +export interface SendMessageItem { /** - * For SELECT: array of row objects. For others: empty array. + * The user message text */ - rows: { - [k: string]: JsonValue | undefined; - }[]; + prompt: string; /** - * Column names from the result set + * If provided, this is shown in the timeline instead of `prompt` */ - columns: string[]; + displayPrompt?: string; /** - * Number of rows affected (for INSERT/UPDATE/DELETE) + * Optional attachments (files, directories, selections, blobs, GitHub references) to include with this message */ - rowsAffected: number; + attachments?: Attachment[]; /** - * SQLite last_insert_rowid() value for INSERT. + * If false, this message will not trigger a Premium Request Unit charge. User messages default to billable. + * + * @internal */ - lastInsertRowid?: number; - error?: SessionFsError; -} -/** - * Classified SQLite transaction failure. busyOrLocked guarantees rollback; postCommitAmbiguous must never be retried. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSqliteTransactionError". - */ -/** @experimental */ -export interface SessionFsSqliteTransactionError { - errorClass: SessionFsSqliteTransactionErrorClass; + billable?: boolean; /** - * Human-readable transaction failure message. + * If set, the request will fail if the named tool is not available when this message is among the user messages at the start of the current exchange */ - message: string; + requiredTool?: string; + /** + * Optional provenance tag copied to the resulting user.message event. Must be `user`, `system`, `command-` for command-originated messages, `schedule-` for scheduled prompts, or `agent-` for prompts sent by another agent. + * + * @internal + */ + source?: string; } /** - * Statements to execute atomically. Providers apply busy handling for every call. + * Parameters for sending zero or more user messages to the session in a single turn. Remote-backed (Mission Control) sessions do not support this method and will return an error. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSqliteTransactionRequest". + * via the `definition` "SendMessagesRequest". */ /** @experimental */ -export interface SessionFsSqliteTransactionRequest { +export interface SendMessagesRequest { /** - * Target session identifier + * The user messages to append to the conversation, in order, before running one agent loop. When the batch starts a run, its final message is the primary initiating message; earlier messages provide context, not separate runs or replies. May be empty, in which case a single turn runs over the existing history with no new user message or originatingMessageId. */ - sessionId: string; + messages: SendMessageItem[]; + mode?: SendMode; /** - * Ordered SQL statements to execute in one transaction. + * If true, adds the messages to the front of the queue instead of the end */ - statements: SessionFsSqliteTransactionStatement[]; -} -/** - * One statement in an atomic SQLite transaction. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSqliteTransactionStatement". - */ -/** @experimental */ -export interface SessionFsSqliteTransactionStatement { + prepend?: boolean; + agentMode?: SendAgentMode; /** - * SQL statement to execute. + * Custom HTTP headers to include in outbound model requests for this turn. Merged with session-level provider headers; per-turn headers augment and overwrite session-level headers with the same key. */ - query: string; - queryType: SessionFsSqliteQueryType; + requestHeaders?: { + [k: string]: string | undefined; + }; + responseFormat?: ResponseFormat; /** - * Optional named bind parameters. + * W3C Trace Context traceparent header for distributed tracing of this agent turn */ - params?: { - [k: string]: JsonValue | undefined; - }; + traceparent?: string; + /** + * W3C Trace Context tracestate header for distributed tracing + */ + tracestate?: string; + /** + * If true, await completion of the agentic loop for this turn before returning. Defaults to false (fire-and-forget). When true, the result still contains the same `messageIds`; the caller can rely on the agent having processed the messages before the call resolves. Transport-dependent tail semantics: on a LOCAL (in-process) session the wait additionally blocks until the completed turn's event tail has been dispatched to this session's in-process subscribers, so a subsequent read of subscriber state already reflects the turn; on a REMOTE session the wait resolves once the loop completes and mirrored delivery follows over the wire. Callers that need the stronger local guarantee on remote sessions should await the event stream explicitly. + */ + wait?: boolean; } /** - * Per-statement results, or a classified transaction error. + * Result of sending zero or more user messages * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSqliteTransactionResult". + * via the `definition` "SendMessagesResult". */ /** @experimental */ -export interface SessionFsSqliteTransactionResult { +export interface SendMessagesResult { /** - * Per-statement query results in input order. + * Unique identifiers assigned to the messages, one per provided message in order. For a batch that starts a run, assistant messages use the final ID as originatingMessageId throughout that run, including tool iterations and stop-hook corrections. Immediate steering does not replace the active run's origin. Empty when no messages were provided; that run has no originatingMessageId. */ - results: SessionFsSqliteQueryResult[]; - error?: SessionFsSqliteTransactionError; + messageIds: string[]; } /** - * Path whose metadata should be returned from the client-provided session filesystem. + * Parameters for sending a user message to the session * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsStatRequest". + * via the `definition` "SendRequest". */ /** @experimental */ -export interface SessionFsStatRequest { +export interface SendRequest { /** - * Target session identifier + * The user message text */ - sessionId: string; + prompt: string; /** - * Path using SessionFs conventions + * If provided, this is shown in the timeline instead of `prompt` */ - path: string; -} -/** - * Filesystem metadata for the requested path, or a filesystem error if the stat failed. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsStatResult". - */ -/** @experimental */ -export interface SessionFsStatResult { + displayPrompt?: string; /** - * Whether the path is a file + * Optional attachments (files, directories, selections, blobs, GitHub references) to include with the message */ - isFile: boolean; + attachments?: Attachment[]; + mode?: SendMode; /** - * Whether the path is a directory + * If true, adds the message to the front of the queue instead of the end */ - isDirectory: boolean; + prepend?: boolean; /** - * File size in bytes + * If false, this message will not trigger a Premium Request Unit charge. User messages default to billable. */ - size: number; + billable?: boolean; /** - * ISO 8601 timestamp of last modification + * If set, the request will fail if the named tool is not available when this message is among the user messages at the start of the current exchange */ - mtime: string; + requiredTool?: string; /** - * ISO 8601 timestamp of creation + * Optional provenance tag copied to the resulting user.message event. Must be `user`, `system`, `command-` for command-originated messages, `schedule-` for scheduled prompts, or `agent-` for prompts sent by another agent. + * + * @internal */ - birthtime: string; - error?: SessionFsError; + source?: string; + agentMode?: SendAgentMode; + /** + * Custom HTTP headers to include in outbound model requests for this turn. Merged with session-level provider headers; per-turn headers augment and overwrite session-level headers with the same key. + */ + requestHeaders?: { + [k: string]: string | undefined; + }; + responseFormat?: ResponseFormat; + /** + * W3C Trace Context traceparent header for distributed tracing of this agent turn + */ + traceparent?: string; + /** + * W3C Trace Context tracestate header for distributed tracing + */ + tracestate?: string; + /** + * If true, await completion of the agentic loop for this message before returning. Defaults to false (fire-and-forget). When true, the result still contains the same `messageId`; the caller can rely on the agent having processed the message before the call resolves. Transport-dependent tail semantics: on a LOCAL (in-process) session the wait additionally blocks until the completed turn's event tail has been dispatched to this session's in-process subscribers, so a subsequent read of subscriber state already reflects the turn; on a REMOTE session the wait resolves once the loop completes and mirrored delivery follows over the wire. Callers that need the stronger local guarantee on remote sessions should await the event stream explicitly. + */ + wait?: boolean; } /** - * File path, standard-base64-encoded bytes to write, and optional mode for the client-provided session filesystem. + * Result of sending a user message * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsWriteFileBytesRequest". + * via the `definition` "SendResult". */ /** @experimental */ -export interface SessionFsWriteFileBytesRequest { +export interface SendResult { /** - * Target session identifier + * Unique identifier assigned to the message */ - sessionId: string; + messageId: string; +} +/** + * Internal request for sending a system notification. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SendSystemNotificationRequest". + */ +/** @experimental */ +export interface SendSystemNotificationRequest { /** - * Path using SessionFs conventions + * Notification text to deliver to the model. */ - path: string; + message: string; /** - * Exact file bytes encoded as standard base64 + * Optional structured notification kind. */ - content: string; + kind?: JsonValue; /** - * Optional POSIX-style mode for newly created files + * Internal delivery options, including passive policy. */ - mode?: number; + options?: JsonValue; } /** - * File path, content to write, and optional mode for the client-provided session filesystem. + * Agents discovered across user, project, plugin, and remote sources. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsWriteFileRequest". + * via the `definition` "ServerAgentList". */ /** @experimental */ -export interface SessionFsWriteFileRequest { - /** - * Target session identifier - */ - sessionId: string; - /** - * Path using SessionFs conventions - */ - path: string; +export interface ServerAgentList { /** - * Content to write + * All discovered agents across all sources */ - content: string; + agents: AgentInfo[]; +} +/** + * Instruction sources discovered across user, repository, and plugin sources. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ServerInstructionSourceList". + */ +/** @experimental */ +export interface ServerInstructionSourceList { /** - * Optional POSIX-style mode for newly created files + * All discovered instruction sources */ - mode?: number; + sources: InstructionSource[]; } /** - * Installed plugin record for a session, with marketplace, version, install time, enabled state, cache path, and source. + * Server-side skill metadata, including name, description, source, enabled/invocable state, path, project path, and argument hint. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionInstalledPlugin". + * via the `definition` "ServerSkill". */ /** @experimental */ -export interface SessionInstalledPlugin { +export interface ServerSkill { /** - * Plugin name + * Unique identifier for the skill */ name: string; /** - * Marketplace the plugin came from (empty string for direct repo installs) + * Canonical slash command name used to invoke the skill, without the leading '/' */ - marketplace: string; + commandName?: string; /** - * Installed version, if known + * Description of what the skill does */ - version?: string; + description: string; + source: SkillSource; /** - * Installation timestamp (ISO-8601) + * Whether the skill can be invoked by the user as a slash command */ - installed_at: string; + userInvocable: boolean; /** - * Whether the plugin is currently enabled + * Whether the skill is currently enabled (based on global config) */ enabled: boolean; /** - * Path where the plugin is cached locally + * Absolute path to the skill file */ - cache_path?: string; - source?: SessionInstalledPluginSource; + path?: string; /** - * Per-plugin source fingerprint (a SHA-256 hash of the plugin's catalog source spec plus its resolved source subtree — NOT a Git commit SHA) captured at marketplace install/update time. Auto-update compares it against the freshly recomputed fingerprint to detect a content change that does not bump the version. Absent for pre-existing installs and for direct (non-marketplace) installs. + * The project path this skill belongs to (only for project/inherited skills) */ - source_sha?: string; + projectPath?: string; /** - * Absolute path of the marketplace directory a live plugin was resolved from. Present only on live, never-persisted records — those synthesized at session start for a directory/local marketplace, whose cache_path points at the real plugin directory on disk rather than a copy under the installed-plugins cache. Its presence is what marks a record as live, and no record carrying it is ever written to the persisted installedPlugins key. + * Optional freeform hint describing the skill's expected arguments, from the `argument-hint` frontmatter field */ - installed_from?: string; + argumentHint?: string; } /** - * Source descriptor for a direct GitHub plugin install, with `owner/repo`, optional ref or full commit SHA, and optional subpath. + * Skills discovered across global and project sources. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionInstalledPluginSourceGitHub". + * via the `definition` "ServerSkillList". */ /** @experimental */ -export interface SessionInstalledPluginSourceGitHub { +export interface ServerSkillList { /** - * Constant value. Always "github". + * All discovered skills across all sources */ - source: "github"; + skills: ServerSkill[]; /** - * GitHub repository in `owner/repo` form. - */ - repo: string; - /** - * Optional Git ref to resolve. - */ - ref?: string; - /** - * Optional full 40-character hexadecimal commit SHA. - */ - sha?: string; - /** - * Optional repository-relative path to the plugin. + * Messages for skills that failed to load (e.g. malformed SKILL.md). Empty when host skills are excluded so host-local paths are not disclosed to multitenant callers. */ - path?: string; + errors?: string[]; } /** - * Source descriptor for a direct URL plugin install, with URL, optional ref or full commit SHA, and optional subpath. + * Current activity flags for the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionInstalledPluginSourceUrl". + * via the `definition` "SessionActivity". */ /** @experimental */ -export interface SessionInstalledPluginSourceUrl { - /** - * Constant value. Always "url". - */ - source: "url"; - /** - * URL of the plugin source. - */ - url: string; - /** - * Optional Git ref to resolve. - */ - ref?: string; +export interface SessionActivity { /** - * Optional full 40-character hexadecimal commit SHA. + * Whether an in-flight operation can currently be aborted. */ - sha?: string; + abortable: boolean; /** - * Optional source-relative path to the plugin. + * Whether the session currently has active work, including running turns or tasks. */ - path?: string; + hasActiveWork: boolean; } /** - * Source descriptor for a direct local plugin install, with a local filesystem path. + * Internal GitHub login parameters. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionInstalledPluginSourceLocal". + * via the `definition` "SessionAuthLoginRequest". */ /** @experimental */ -export interface SessionInstalledPluginSourceLocal { +export interface SessionAuthLoginRequest { /** - * Constant value. Always "local". + * GitHub host URL */ - source: "local"; + host: string; /** - * Local filesystem path to the plugin. + * GitHub login */ - path: string; + login: string; + /** + * GitHub authentication token + */ + token: string; + /** + * Whether to persist the token after login + */ + persist?: boolean; } /** - * Baseline data provenance for a prediction. + * Parameters identifying a GitHub authentication to log out. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionLimitPredictionBaselineData". + * via the `definition` "SessionAuthLogoutUserRequest". */ /** @experimental */ -export interface SessionLimitPredictionBaselineData { - /** - * Start of the baseline data slice. - */ - windowStart: string; - /** - * End of the baseline data slice. - */ - windowEnd: string; +export interface SessionAuthLogoutUserRequest { + authInfo: AuthInfo; } /** - * Explainable AI-credit session-limit prediction. + * Authentication status and account metadata for the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionLimitPredictionDetails". + * via the `definition` "SessionAuthStatus". */ /** @experimental */ -export interface SessionLimitPredictionDetails { - clientType: SessionLimitPredictionClientType; +export interface SessionAuthStatus { /** - * Model identifier used for lookup. + * Whether the session has resolved authentication */ - modelId: string; - source: SessionLimitPredictionSource; + isAuthenticated: boolean; + authType?: AuthInfoType; /** - * Key matched at the source level, such as a model id, family id, or `global`. + * Authentication host URL */ - sourceKey: string; + host?: string; /** - * Resolved model family when known. + * Authenticated login/username, if available */ - family?: string; + login?: string; /** - * Ordered usage tiers and their AI-credit caps. + * Human-readable authentication status description */ - tiers: SessionLimitPredictionTierOption[]; - baselineData: SessionLimitPredictionBaselineData; - recommendedTier: SessionLimitPredictionTier; + statusMessage?: string; /** - * Recommended maximum AI credits for this session. + * Copilot plan tier (e.g., individual_pro, business) */ - recommendedCap: number; + copilotPlan?: string; } /** - * Semantic usage tier and its AI-credit cap. + * Parameters for switching the session's active authentication. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionLimitPredictionTierOption". + * via the `definition` "SessionAuthSwitchRequest". */ /** @experimental */ -export interface SessionLimitPredictionTierOption { - tier: SessionLimitPredictionTier; +export interface SessionAuthSwitchRequest { + authInfo: AuthInfo; /** - * AI-credit cap for this tier. + * Optional token paired with the authentication information */ - cap: number; + token?: string; } /** - * Sessions matching the filter, ordered most-recently-modified first. + * Map of sessionId -> bytes freed by removing the session's workspace directory. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionList". + * via the `definition` "SessionBulkDeleteResult". */ /** @experimental */ -export interface SessionList { +export interface SessionBulkDeleteResult { /** - * Sessions ordered most-recently-modified first. Discriminated by `isRemote`. + * Map of sessionId -> bytes freed by removing the session's workspace directory. Sessions whose deletion failed are omitted from this map (failures are logged on the server but not surfaced per-id; check the map for absent IDs to detect them). */ - sessions: SessionListEntry[]; + freedBytes: { + [k: string]: number | undefined; + }; } /** - * Optional filter applied to the returned sessions + * The IDE a host is connected to, as reported to the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionListFilter". + * via the `definition` "SessionConnectedIdeInfo". */ /** @experimental */ -export interface SessionListFilter { - /** - * Match sessions whose context.cwd equals this value - */ - cwd?: string; - /** - * Match sessions whose context.gitRoot equals this value - */ - gitRoot?: string; +export interface SessionConnectedIdeInfo { /** - * Match sessions whose context.repository equals this value + * Display name of the connected IDE, for example `VS Code`. */ - repository?: string; + ideName: string; /** - * Match sessions whose context.branch equals this value + * Absolute path of the workspace folder the IDE has open. */ - branch?: string; + workspaceFolder: string; } /** - * Queued repo-level startup prompts and the total hook command count after loading. + * The enriched metadata records, with summary and context fields backfilled where available. Sessions confirmed empty and unnamed are omitted. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionLoadDeferredRepoHooksResult". + * via the `definition` "SessionEnrichMetadataResult". */ /** @experimental */ -export interface SessionLoadDeferredRepoHooksResult { - /** - * Repo-level startup prompts queued from repo hook configs. Empty on resume, when no repo configs were pending, or when disableAllHooks is set. - */ - startupPrompts: string[]; +export interface SessionEnrichMetadataResult { /** - * Total hook command count (user + plugin + repo) loaded for the session by this call. Captured atomically with startupPrompts so callers don't need to read a separate counter. + * Enriched records, with summary and context backfilled. Sessions confirmed empty and unnamed may be omitted. */ - hookCount: number; + sessions: LocalSessionMetadataValue[]; } /** - * Enterprise permission policy expressed with the runtime's managed permission-rule syntax. + * File path, content to append, and optional mode for the client-provided session filesystem. Implementations create parent directories as needed. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionManagedPermissions". + * via the `definition` "SessionFsAppendFileRequest". */ /** @experimental */ -export interface SessionManagedPermissions { +export interface SessionFsAppendFileRequest { /** - * When set to `disable`, prevents bypass/allow-all permission modes. Advisory auto-approval remains available because normal prompt paths stay active. Any other value is accepted rather than failing the session, but is enforced as `disable`: the key is only present to restrict something, so a mode this runtime cannot interpret fails closed to the most restrictive one it knows. Omit the key entirely to impose no restriction. + * Target session identifier */ - disableBypassPermissionsMode?: string; + sessionId: string; /** - * When true, prevents Assisted Permissions from being activated. An actively Assisted session falls back to Manual Approval while the policy is in force. Omit the key or set it to false to impose no restriction. + * Path using SessionFs conventions */ - disableAssistedPermissionsMode?: boolean; + path: string; /** - * Permission rules that block matching operations. Deny has highest precedence. + * Content to append */ - deny?: string[]; + content: string; /** - * Permission rules that require explicit human approval. + * Optional POSIX-style mode for newly created files */ - ask?: string[]; + mode?: number; +} +/** + * Describes a filesystem error. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsError". + */ +/** @experimental */ +export interface SessionFsError { + code: SessionFsErrorCode; /** - * Permission rules that allow matching operations unless another managed source, deny, or ask rule restricts them. + * Free-form detail about the error, for logging/diagnostics */ - allow?: string[]; + message?: string; /** - * Closed-world host boundary expressed as `Domain(hostname)`, `Domain(IP)`, or `Domain(*.example.com)` rules. Schemes, ports, paths, queries, and fragments are rejected because every network request must be enforceable at host-level egress. Multiple managed sources intersect their lists; an empty list denies all hosts. + * For failed writeFile requests only: true if the provider changed the target before failing. Omit when unknown or unchanged. */ - limitTo?: string[]; + writeChanged?: boolean; } /** - * Managed settings an SDK host may inject at session startup. Only permissions are accepted in this initial contract. + * Path to test for existence in the client-provided session filesystem. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionManagedSettings". + * via the `definition` "SessionFsExistsRequest". */ /** @experimental */ -export interface SessionManagedSettings { - permissions?: SessionManagedPermissions; +export interface SessionFsExistsRequest { + /** + * Target session identifier + */ + sessionId: string; + /** + * Path using SessionFs conventions + */ + path: string; } /** - * Records which IDE the host is connected to, or clears it. + * Indicates whether the requested path exists in the client-provided session filesystem. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionMcpSetConnectedIdeInfoParams". + * via the `definition` "SessionFsExistsResult". */ /** @experimental */ -export interface SessionMcpSetConnectedIdeInfoParams { +export interface SessionFsExistsResult { /** - * The connected IDE. Null or omitted clears the recorded IDE, which is how a host reports that it is disconnected. + * Whether the path exists */ - ide?: SessionConnectedIdeInfo | null; + exists: boolean; } /** - * Point-in-time snapshot of slow-changing session identifier and state fields + * Directory path to create in the client-provided session filesystem, with options for recursive creation and POSIX mode. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionMetadataSnapshot". + * via the `definition` "SessionFsMkdirRequest". */ /** @experimental */ -export interface SessionMetadataSnapshot { +export interface SessionFsMkdirRequest { /** - * The unique identifier of the session + * Target session identifier */ sessionId: string; /** - * ISO 8601 timestamp of when the session started - */ - startTime: string; - /** - * ISO 8601 timestamp of when the session's persisted state was last modified on disk. For new sessions, equals startTime. For resumed sessions, reflects the previous modification time at construction. + * Path using SessionFs conventions */ - modifiedTime: string; + path: string; /** - * Whether this is a remote session (i.e., one whose runtime executes elsewhere and is steered through this process) + * Create parent directories as needed */ - isRemote: boolean; + recursive?: boolean; /** - * True when the session was detected to be in use by another process at construction time. Local consumers may surface a confirmation prompt before fully attaching. Always false for new sessions. + * Optional POSIX-style mode for newly created directories */ - alreadyInUse: boolean; - /** - * Absolute path to the session's workspace directory on disk, or null if the session has no associated workspace - */ - workspacePath: string | null; - /** - * User-provided name supplied at session construction (via `--name`), if any. Immutable after construction. - */ - initialName?: string; + mode?: number; +} +/** + * Directory path whose entries should be listed from the client-provided session filesystem. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsReaddirRequest". + */ +/** @experimental */ +export interface SessionFsReaddirRequest { /** - * Runtime client name associated with the session (telemetry identifier). + * Target session identifier */ - clientName?: string; - remoteMetadata?: MetadataSnapshotRemoteMetadata; + sessionId: string; /** - * Short human-readable summary of the session, if known. Omitted when no summary has been generated. + * Path using SessionFs conventions */ - summary?: string; + path: string; +} +/** + * Names of entries in the requested directory, or a filesystem error if the read failed. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsReaddirResult". + */ +/** @experimental */ +export interface SessionFsReaddirResult { /** - * Absolute path to the session's current working directory + * Entry names in the directory */ - workingDirectory: string; - currentMode: MetadataSnapshotCurrentMode; + entries: string[]; + error?: SessionFsError; +} +/** + * Directory entry returned by session filesystem `readdirWithTypes`, with name and entry type. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsReaddirWithTypesEntry". + */ +/** @experimental */ +export interface SessionFsReaddirWithTypesEntry { /** - * Currently selected model identifier, if any + * Entry name */ - selectedModel?: string; + name: string; + type: SessionFsReaddirWithTypesEntryType; +} +/** + * Directory path whose entries (with type information) should be listed from the client-provided session filesystem. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsReaddirWithTypesRequest". + */ +/** @experimental */ +export interface SessionFsReaddirWithTypesRequest { /** - * Current session limits, or null when no limits are active + * Target session identifier */ - sessionLimits: SessionLimitsConfig | null; - indexedSearch?: IndexedSearchState; + sessionId: string; /** - * Public-facing workspace metadata for this session, or null if the session has no associated workspace. Excludes runtime-internal fields (GitHub IDs, summary count, internal flags). + * Path using SessionFs conventions */ - workspace?: WorkspaceSummary | null; + path: string; } /** - * The list of models available to this session. + * Entries in the requested directory paired with file/directory type information, or a filesystem error if the read failed. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionModelList". + * via the `definition` "SessionFsReaddirWithTypesResult". */ /** @experimental */ -export interface SessionModelList { - /** - * Available models, ordered with the most preferred default first. Includes both Copilot (CAPI) models and any registry BYOK models; a BYOK model appears under its provider-qualified selection id (`provider/id`). - */ - list: JsonValue[]; +export interface SessionFsReaddirWithTypesResult { /** - * The model providers available to this session, in ordering order, resolved from the account roster; empty when no provider is entitled (logged out / seatless). Each model in `list` carries its own provider reference; this roster gives the deterministic provider sequence and lets a consumer group by provider without deriving ordering from the model list. Central code never branches on a provider kind. + * Directory entries with type information */ - providers?: ModelProviderDescriptor[]; + entries: SessionFsReaddirWithTypesEntry[]; + error?: SessionFsError; +} +/** + * Path of the binary file to read from the client-provided session filesystem. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsReadFileBytesRequest". + */ +/** @experimental */ +export interface SessionFsReadFileBytesRequest { /** - * Cost categories for the full CAPI catalog, including picker-disabled models that Auto may select. Metadata only; entries absent from `list` are not manually selectable. + * Target session identifier */ - modelPriceCategories?: SessionModelPriceCategory[]; + sessionId: string; /** - * Per-quota snapshots returned alongside the model list, keyed by quota type. + * Path using SessionFs conventions */ - quotaSnapshots?: { - [k: string]: JsonValue | undefined; - }; - auto?: AutoTierMetadata; + path: string; } /** - * Cost-category metadata for a CAPI model. + * File bytes as standard base64, or a filesystem error if the read failed. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionModelPriceCategory". + * via the `definition` "SessionFsReadFileBytesResult". */ /** @experimental */ -export interface SessionModelPriceCategory { +export interface SessionFsReadFileBytesResult { /** - * CAPI model identifier. + * Exact file bytes encoded as standard base64 */ - id: string; - priceCategory: ModelPickerPriceCategory; + content: string; + error?: SessionFsError; } /** - * Session construction options. + * Path of the file to read from the client-provided session filesystem. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionOpenOptions". + * via the `definition` "SessionFsReadFileRequest". */ /** @experimental */ -export interface SessionOpenOptions { +export interface SessionFsReadFileRequest { /** - * Optional stable session identifier to use for a new session. + * Target session identifier */ - sessionId?: string; + sessionId: string; /** - * Optional human-friendly session name. + * Path using SessionFs conventions */ - name?: string; + path: string; +} +/** + * File content as a UTF-8 string, or a filesystem error if the read failed. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsReadFileResult". + */ +/** @experimental */ +export interface SessionFsReadFileResult { /** - * Initial model identifier. + * File content as UTF-8 string */ - model?: string; + content: string; + error?: SessionFsError; +} +/** + * Source and destination paths for renaming or moving an entry in the client-provided session filesystem. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsRenameRequest". + */ +/** @experimental */ +export interface SessionFsRenameRequest { /** - * Initial reasoning effort level. CAPI values are model-defined and validated against the selected model; BYOK providers may define additional values. When omitted, no effort override is applied. + * Target session identifier */ - reasoningEffort?: string; - reasoningSummary?: SessionOpenOptionsReasoningSummary; - verbosity?: Verbosity; + sessionId: string; /** - * Identifier of the client driving the session. + * Source path using SessionFs conventions */ - clientName?: string; + src: string; /** - * OAuth Client ID Metadata Document URL used by this host for MCP authorization. + * Destination path using SessionFs conventions */ - authClientIdMetadataUrl?: string; + dest: string; +} +/** + * Path to remove from the client-provided session filesystem, with options for recursive removal and force. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsRmRequest". + */ +/** @experimental */ +export interface SessionFsRmRequest { /** - * Structured client kind used for runtime behavior gates. + * Target session identifier */ - clientKind?: string; + sessionId: string; /** - * Identifier sent to LSP-style integrations. + * Path using SessionFs conventions */ - lspClientName?: string; + path: string; /** - * Stable integration identifier for analytics. + * Remove directories and their contents recursively */ - integrationId?: string; + recursive?: boolean; /** - * ExP assignment ('flight') data injected by an SDK integrator, in the same JSON shape the Copilot CLI fetches from the experimentation service (CopilotExpAssignmentResponse). When supplied this is fed into the FeatureFlagService exactly like CLI-fetched assignments and ExP-backed flags wait for it. When absent the session does not block on ExP. - * - * @internal + * Ignore errors if the path does not exist */ - expAssignments?: JsonValue; + force?: boolean; +} +/** + * Optional capabilities declared by the provider + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsSetProviderCapabilities". + */ +/** @experimental */ +export interface SessionFsSetProviderCapabilities { /** - * Opt-in: self-fetch and enforce enterprise managed settings, including managed hook policies, at session bootstrap. + * Whether the provider supports SQLite query/exists operations */ - enableManagedSettings?: boolean; + sqlite?: boolean; /** - * Opt in to enforcing non-overridable managed model controls on session model, Auto-tier, reasoning-effort, and context-tier changes. Managed defaults still apply when omitted; this option only turns conflicting changes into errors. + * Whether the provider supports binary reads and writes through sessionFs.readFileBytes and sessionFs.writeFileBytes */ - enforceManagedModelDefaults?: boolean; - managedSettings?: SessionManagedSettings; + binary?: boolean; +} +/** + * Initial working directory, session-state path layout, and path conventions used to register the calling SDK client as the session filesystem provider. A registered provider is authoritative for path interpretation and filesystem facts used by workspace permission validation. Paths are interpreted lexically; home-relative paths (`~` and `~/...`) and Windows drive-relative paths such as `C:foo` are unsupported. Until provider-side canonicalization is supported, providers must not expose symlinks inside allowed roots that escape those roots. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsSetProviderRequest". + */ +/** @experimental */ +export interface SessionFsSetProviderRequest { /** - * Opt in to capturing file changes for session rewind and session diff. Capture cannot reconstruct changes made before it was enabled. On create it starts capture from the first turn. It is also honored on resume: for a session that already has tracked prior turns, tracking continues automatically even if this is omitted; passing it on resume additionally enables tracking for an eligible session that has no prior root turn yet. Resuming a session whose prior root turns were never tracked has no restorable baseline, so tracking stays disabled for it and rewind reports file change tracking as unavailable; the resume itself still succeeds, so sessions that predate tracking remain loadable. The opt-in is only rejected when the session can never track (a subagent session, or one without local session storage). It is intentionally absent from the mutable options update because enabling it after edits have occurred would create an incomplete, misleading baseline. Subagents share the parent session's capture store and are not tracked as separate rewind points: a file a subagent writes is attributed to whichever root user turn was open when the capture was staged, just before the tool body ran. A turn cannot open while a staged capture is still in flight, so a subagent tool that staged under the spawning turn stays attributed to it however late the write lands, while a capture it stages after the user's next message belongs to that later turn. Attribution decides which turn's rewind point counts and file preview include that write; it does not narrow which rewinds revert it, because a rewind restores every capture from the selected turn onward, so the earlier spawning turn reverts it as well. + * Absolute initial working directory for sessions. Registering the provider establishes this path as the root of its virtual namespace; the runtime does not require the provider to materialize or stat it before creating a session. */ - enableFileChangeTracking?: boolean; + initialCwd: string; /** - * Feature-flag values resolved by the host. + * Path within each session's SessionFs where the runtime stores files for that session */ - featureFlags?: { - [k: string]: boolean | undefined; - }; + sessionStatePath: string; + conventions: SessionFsSetProviderConventions; + capabilities?: SessionFsSetProviderCapabilities; +} +/** + * Indicates whether the calling client was registered as the session filesystem provider. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsSetProviderResult". + */ +/** @experimental */ +export interface SessionFsSetProviderResult { /** - * Whether experimental behavior is enabled. + * Whether the provider was set successfully */ - isExperimentalMode?: boolean; - authInfo?: AuthInfo; - provider?: ProviderConfig; - capi?: CapiSessionOptions; - /** - * Whether a CLI host explicitly requested the initial Auto preference. False preserves a settings-derived preference without validating availability during creation; execution still validates it. Defaults to true and is ignored for non-CLI callers. - * - * @internal - */ - autoTierIsExplicit?: boolean; - /** - * Named BYOK provider connections, additive to CAPI auth. Combining with `provider` is rejected. - * - * @experimental - */ - providers?: NamedProviderConfig[]; - /** - * BYOK model definitions added to the selectable model list, each referencing a provider name. - * - * @experimental - */ - models?: ProviderModelConfig[]; + success: boolean; +} +/** + * Indicates whether the per-session SQLite database already exists. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsSqliteExistsResult". + */ +/** @experimental */ +export interface SessionFsSqliteExistsResult { /** - * Working directory to anchor the session. + * Whether the session database already exists */ - workingDirectory?: string; + exists: boolean; +} +/** + * SQL query, query type, and optional bind parameters for executing a SQLite query against the per-session database. The provider applies its SQLite busy timeout for every call. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsSqliteQueryRequest". + */ +/** @experimental */ +export interface SessionFsSqliteQueryRequest { /** - * Additional directories the agent may access beyond the working directory. Each entry is granted to the session's file-access allow-list and surfaced to the model (system prompt context and `@`-mention completion). Conventional `.github/skills/` and `.github/agents/` definitions under each directory also join the session's project catalogs when their existing subsystem gates are enabled: added-root skills require both `enableConfigDiscovery` and effective `enableSkills`; added-root agents require `enableConfigDiscovery`. Supplying a directory therefore activates configuration from it and should be treated as a trust decision. Absolute paths are recommended; a relative path is resolved against the session's working directory. Nonexistent or unresolvable entries are skipped with a warning. This is applied during session creation and cold resume and is not persisted, so a cold resume must re-supply the directories. + * Target session identifier */ - additionalDirectories?: string[]; - workingDirectoryContext?: SessionContext; + sessionId: string; /** - * Whether this session supports remote steering. + * SQL query to execute */ - remoteSteerable?: boolean; + query: string; + queryType: SessionFsSqliteQueryType; /** - * Telemetry-only remote exporting flag. + * Optional named bind parameters */ - remoteExporting?: boolean; + params?: { + [k: string]: JsonValue | undefined; + }; +} +/** + * Query results including rows, columns, and rows affected, or a filesystem error if execution failed. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsSqliteQueryResult". + */ +/** @experimental */ +export interface SessionFsSqliteQueryResult { /** - * Telemetry-only remote-defaulted flag. + * For SELECT: array of row objects. For others: empty array. */ - remoteDefaultedOn?: boolean; + rows: { + [k: string]: JsonValue | undefined; + }[]; /** - * Parent session ID for detached child telemetry rollup. + * Column names from the result set */ - detachedFromSpawningParentSessionId?: string; + columns: string[]; /** - * Parent engagement ID for detached child telemetry rollup. + * Number of rows affected (for INSERT/UPDATE/DELETE) */ - detachedFromSpawningParentEngagementId?: string; + rowsAffected: number; /** - * Allowlist of available tool names. + * SQLite last_insert_rowid() value for INSERT. */ - availableTools?: string[]; + lastInsertRowid?: number; + error?: SessionFsError; +} +/** + * Classified SQLite transaction failure. busyOrLocked guarantees rollback; postCommitAmbiguous must never be retried. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsSqliteTransactionError". + */ +/** @experimental */ +export interface SessionFsSqliteTransactionError { + errorClass: SessionFsSqliteTransactionErrorClass; /** - * Denylist of tool names. + * Human-readable transaction failure message. */ - excludedTools?: string[]; + message: string; +} +/** + * Statements to execute atomically. Providers apply busy handling for every call. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsSqliteTransactionRequest". + */ +/** @experimental */ +export interface SessionFsSqliteTransactionRequest { /** - * Built-in subagent names to include in this session. When specified, only these built-ins are available, subject to runtime availability and exclusions. Custom agents with the same name remain available. + * Target session identifier */ - includedBuiltinAgents?: string[]; + sessionId: string; /** - * Built-in subagent names to exclude from this session. Excluded built-ins are hidden from agent discovery and cannot be dispatched unless a custom agent with the same name is available. + * Ordered SQL statements to execute in one transaction. */ - excludedBuiltinAgents?: string[]; + statements: SessionFsSqliteTransactionStatement[]; +} +/** + * One statement in an atomic SQLite transaction. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsSqliteTransactionStatement". + */ +/** @experimental */ +export interface SessionFsSqliteTransactionStatement { /** - * Whether shell-script safety heuristics are enabled. + * SQL statement to execute. */ - enableScriptSafety?: boolean; - shell?: ShellOptions; + query: string; + queryType: SessionFsSqliteQueryType; /** - * @deprecated - * Use shell.initProfile instead. Shell init profile. + * Optional named bind parameters. */ - shellInitProfile?: string; + params?: { + [k: string]: JsonValue | undefined; + }; +} +/** + * Per-statement results, or a classified transaction error. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsSqliteTransactionResult". + */ +/** @experimental */ +export interface SessionFsSqliteTransactionResult { /** - * PowerShell process flags applied to built-in and user-requested shell commands. + * Per-statement query results in input order. */ - shellProcessFlags?: string[]; - sandboxConfig?: SandboxConfig; + results: SessionFsSqliteQueryResult[]; + error?: SessionFsSqliteTransactionError; +} +/** + * Path whose metadata should be returned from the client-provided session filesystem. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsStatRequest". + */ +/** @experimental */ +export interface SessionFsStatRequest { /** - * Origin of the sandbox choice. Settings-derived origins (never_configured, user_enabled, user_disabled, repository_policy) let managed policy floor a host preference; explicit below-floor changes remain policy conflicts unless a session opt-out is authorized. Also used for telemetry provenance. - * - * @experimental + * Target session identifier */ - sandboxConfigSource?: SandboxConfigSource; + sessionId: string; /** - * Whether interactive shell sessions are logged. + * Path using SessionFs conventions */ - logInteractiveShells?: boolean; - envValueMode?: SessionOpenOptionsEnvValueMode; + path: string; +} +/** + * Filesystem metadata for the requested path, or a filesystem error if the stat failed. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsStatResult". + */ +/** @experimental */ +export interface SessionFsStatResult { /** - * MCP server names disabled for this session. Disabled servers are not started or authenticated on create or cold resume. + * Whether the path is a file */ - disabledMcpServers?: string[]; + isFile: boolean; /** - * Non-secret host-managed HTTP MCP servers keyed by stable managed identity. Managed provenance is runtime-established from this separate field and credentials are supplied through dynamic-header refresh. - * - * @experimental + * Whether the path is a directory */ - managedMcpServers?: { - [k: string]: ManagedMcpServerConfig; - }; + isDirectory: boolean; /** - * Whether to include instructions from every MCP server in the system prompt instead of only allowlisted servers. + * File size in bytes */ - allowAllMcpServerInstructions?: boolean; + size: number; /** - * Explicit discovery-only skill roots, not filesystem grants. Available without enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + * ISO 8601 timestamp of last modification */ - skillDirectories?: string[]; + mtime: string; /** - * Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + * ISO 8601 timestamp of creation */ - agentDirectories?: string[]; + birthtime: string; + error?: SessionFsError; +} +/** + * File path, standard-base64-encoded bytes to write, and optional mode for the client-provided session filesystem. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsWriteFileBytesRequest". + */ +/** @experimental */ +export interface SessionFsWriteFileBytesRequest { /** - * Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without enableConfigDiscovery, subject to instruction/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + * Target session identifier */ - instructionDirectories?: string[]; + sessionId: string; /** - * Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without enableConfigDiscovery or enableFileHooks, which controls repository-origin hooks only; hook/managed disables still apply. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. + * Path using SessionFs conventions */ - hookDirectories?: string[]; + path: string; /** - * Skill scan directories and descendants excluded from discovery. Supports `~`-relative paths. + * Exact file bytes encoded as standard base64 */ - ignoredSkillsLocations?: string[]; + content: string; /** - * Whether skill loading is enabled. When omitted, explicit SDK skill roots or an SDK skill provider enable skills independently of enableConfigDiscovery. + * Optional POSIX-style mode for newly created files */ - enableSkills?: boolean; + mode?: number; +} +/** + * File path, content to write, and optional mode for the client-provided session filesystem. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsWriteFileRequest". + */ +/** @experimental */ +export interface SessionFsWriteFileRequest { /** - * Whether the requesting SDK session has a skill provider. The provider remains ephemeral and is never persisted in session options or history. When enableSkills is false, it remains bound but dormant and receives no callbacks. Cloud, relay, handoff, and raw sessions.open flows reject it because they cannot safely pre-register the callback handler. - * - * @internal - * @experimental + * Target session identifier */ - hasSkillProvider?: boolean; + sessionId: string; /** - * Built-in skill names to include in this session. When specified, only these runtime-bundled skills are available. Skills from other sources with the same name remain available. + * Path using SessionFs conventions */ - includedBuiltinSkills?: string[]; + path: string; /** - * Skill IDs disabled for this session. + * Content to write */ - disabledSkills?: string[]; + content: string; /** - * Installed plugins visible to the session. + * Optional POSIX-style mode for newly created files */ - installedPlugins?: InstalledPlugin[]; - /** - * Whether custom agents default to local-only execution. - */ - customAgentsLocalOnly?: boolean; - /** - * Whether to skip custom instruction sources. - */ - skipCustomInstructions?: boolean; + mode?: number; +} +/** + * Installed plugin record for a session, with marketplace, version, install time, enabled state, cache path, and source. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionInstalledPlugin". + */ +/** @experimental */ +export interface SessionInstalledPlugin { /** - * Whether to invalidate cached custom-instruction discovery before constructing the session. Use when instruction files may have changed earlier in the same runtime process. + * Plugin name */ - refreshCustomInstructions?: boolean; + name: string; /** - * Instruction source IDs disabled for this session. + * Marketplace the plugin came from (empty string for direct repo installs) */ - disabledInstructionSources?: string[]; + marketplace: string; /** - * Whether commit-message coauthor trailers are enabled. + * Installed version, if known */ - coauthorEnabled?: boolean; + version?: string; /** - * Optional trajectory output file path. + * Installation timestamp (ISO-8601) */ - trajectoryFile?: string; + installed_at: string; /** - * Whether model responses stream as delta events. + * Whether the plugin is currently enabled */ - enableStreaming?: boolean; + enabled: boolean; /** - * Experimental: enable native model citations for supported Anthropic and OpenAI models, normalized onto the `assistant.message` event. Off by default; may change or be removed while the citations surface is experimental. - * - * @experimental + * Path where the plugin is cached locally */ - enableCitations?: boolean; + cache_path?: string; + source?: SessionInstalledPluginSource; /** - * Override URL for the Copilot API endpoint. + * Per-plugin source fingerprint (a SHA-256 hash of the plugin's catalog source spec plus its resolved source subtree — NOT a Git commit SHA) captured at marketplace install/update time. Auto-update compares it against the freshly recomputed fingerprint to detect a content change that does not bump the version. Absent for pre-existing installs and for direct (non-marketplace) installs. */ - copilotUrl?: string; + source_sha?: string; /** - * Whether ask_user is explicitly disabled. + * Absolute path of the marketplace directory a live plugin was resolved from. Present only on live, never-persisted records — those synthesized at session start for a directory/local marketplace, whose cache_path points at the real plugin directory on disk rather than a copy under the installed-plugins cache. Its presence is what marks a record as live, and no record carrying it is ever written to the persisted installedPlugins key. */ - askUserDisabled?: boolean; + installed_from?: string; +} +/** + * Source descriptor for a direct GitHub plugin install, with `owner/repo`, optional ref or full commit SHA, and optional subpath. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionInstalledPluginSourceGitHub". + */ +/** @experimental */ +export interface SessionInstalledPluginSourceGitHub { /** - * Whether auto-mode continuation is enabled. + * Constant value. Always "github". */ - continueOnAutoMode?: boolean; + source: "github"; /** - * Whether the host is an interactive UI. + * GitHub repository in `owner/repo` form. */ - runningInInteractiveMode?: boolean; + repo: string; /** - * Whether on-demand custom instruction discovery is enabled. + * Optional Git ref to resolve. */ - enableOnDemandInstructionDiscovery?: boolean; + ref?: string; /** - * Maximum decoded byte size of a single inline model-facing binary tool result persisted in session events (default 10 MB). + * Optional full 40-character hexadecimal commit SHA. */ - maxInlineBinaryBytes?: number; - modelCapabilitiesOverrides?: ModelCapabilitiesOverride; - sessionLimits?: SessionLimitsConfig; + sha?: string; /** - * Runtime context discriminator for agent filtering. + * Optional repository-relative path to the plugin. */ - agentContext?: string; + path?: string; +} +/** + * Source descriptor for a direct URL plugin install, with URL, optional ref or full commit SHA, and optional subpath. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionInstalledPluginSourceUrl". + */ +/** @experimental */ +export interface SessionInstalledPluginSourceUrl { /** - * Override directory for session event logs. + * Constant value. Always "url". */ - eventsLogDirectory?: string; + source: "url"; /** - * Whether subagent callback events should be forwarded into the session event log sink. + * URL of the plugin source. */ - eventsLogIncludesSubagents?: boolean; + url: string; /** - * Override Copilot configuration directory. + * Optional Git ref to resolve. */ - configDir?: string; + ref?: string; /** - * Additional content-exclusion policies to merge into the session policy set. - * - * @experimental + * Optional full 40-character hexadecimal commit SHA. */ - additionalContentExclusionPolicies?: SessionOpenOptionsAdditionalContentExclusionPolicy[]; - memory?: MemoryConfiguration; + sha?: string; /** - * Capabilities enabled for this session. + * Optional source-relative path to the plugin. */ - sessionCapabilities?: SessionCapability[]; + path?: string; } /** - * Per-session settings for built-in shell tools. + * Source descriptor for a direct local plugin install, with a local filesystem path. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ShellOptions". + * via the `definition` "SessionInstalledPluginSourceLocal". */ /** @experimental */ -export interface ShellOptions { - initProfile?: ShellInitProfile; +export interface SessionInstalledPluginSourceLocal { /** - * Ordered host-provided script paths sourced before each built-in shell command when the - * entry's shell target matches the active shell. Use these for rc files, environment setup scripts, - * or other custom scripts. A script that returns a nonzero status is reported, and later scripts - * and the user command continue while the shell remains running. Because scripts are sourced into - * the command shell, `exit`, `exec`, failures under `set -e`, or other shell-terminating behavior - * can prevent continuation. Script standard output is preserved; Bash script stderr is discarded, - * PowerShell exception messages are replaced, and runtime-generated failure notices omit - * configured script paths. When sandboxing is enabled, each script must already be readable under - * the active sandbox filesystem policy. Pass an empty array to clear the list. + * Constant value. Always "local". */ - initScripts?: ShellInitScript[]; + source: "local"; /** - * Flags passed to the active built-in shell process on startup, replacing its default flags. - * When omitted, the built-in Bash shell uses `--norc --noprofile`, - * and the built-in PowerShell shell uses `-NoProfile -NoLogo`. + * Local filesystem path to the plugin. */ - processFlags?: string[]; - credentials?: ShellCredentials; + path: string; } /** - * A host-provided script sourced before each built-in shell command when its shell target matches the active shell. + * Baseline data provenance for a prediction. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ShellInitScript". + * via the `definition` "SessionLimitPredictionBaselineData". */ /** @experimental */ -export interface ShellInitScript { +export interface SessionLimitPredictionBaselineData { /** - * Path to the script to source. + * Start of the baseline data slice. */ - path: string; - shell: ShellInitScriptShell; + windowStart: string; + /** + * End of the baseline data slice. + */ + windowEnd: string; } /** - * Command-scoped GitHub credential injection for the shell commands an agent runs. - * - * Each channel is opt-in and independent, and injection is scoped to the individual command - * spawn: the credential is resolved from the session's *current* authentication at every spawn - * and reaches only spawns whose script actually invokes `git` or `gh`. Because nothing is - * retained between spawns, replacing the session credential (`session.gitHubAuth.setCredentials`) - * changes what the next spawned command presents — which seeding a credential into the runtime - * process's own environment cannot do, since a child's environment is fixed at `exec`. - * - * The credential is matched to the host it authenticates to, so a github.com credential is never - * presented to a GitHub Enterprise host and vice versa. Where a channel cannot express that - * boundary it injects nothing rather than crossing it -- see `gh` below. - * - * This is independent of `sandboxConfig`: it is a decision about which identity the agent - * presents, not about what the agent may touch, and it works on every platform whether or not - * an OS sandboxing backend is available. `sandboxConfig.auth` remains the sandbox-scoped - * spelling and is additive with this one. + * Explainable AI-credit session-limit prediction. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ShellCredentials". + * via the `definition` "SessionLimitPredictionDetails". */ /** @experimental */ -export interface ShellCredentials { +export interface SessionLimitPredictionDetails { + clientType: SessionLimitPredictionClientType; /** - * Whether to authenticate the agent's `git` commands as the session's GitHub credential, by - * injecting an `http..extraheader` (plus `insteadOf` rewrites so SSH-spelled remotes for - * that host use the authenticated HTTPS transport). Applied only to a spawn that runs a - * remote-contacting `git` subcommand. Default: false (opt-in). + * Model identifier used for lookup. */ - git?: boolean; + modelId: string; + source: SessionLimitPredictionSource; /** - * Whether to authenticate the agent's `gh` commands as the session's GitHub credential, by - * exporting `GH_TOKEN` to a spawn that runs `gh`. Any inherited `gh` credential is removed from - * spawns that do not, so the credential stays command-scoped. - * - * Applies to a github.com credential only. `gh` picks its credential variable from the host a - * command targets rather than the one the credential belongs to, and the command can choose that - * target, so `GH_ENTERPRISE_TOKEN` would offer a single-tenant enterprise credential to every - * other enterprise host. A session whose credential is enterprise-scoped therefore runs `gh` - * unauthenticated; its `git` commands are unaffected, because `http..extraheader` is scoped - * to one host by construction. Default: false (opt-in). + * Key matched at the source level, such as a model id, family id, or `global`. */ - gh?: boolean; + sourceKey: string; + /** + * Resolved model family when known. + */ + family?: string; + /** + * Ordered usage tiers and their AI-credit caps. + */ + tiers: SessionLimitPredictionTierOption[]; + baselineData: SessionLimitPredictionBaselineData; + recommendedTier: SessionLimitPredictionTier; + /** + * Recommended maximum AI credits for this session. + */ + recommendedCap: number; } /** - * Content-exclusion policy supplied to `sessions.open` options, with rules, last-updated data, and scope. + * Semantic usage tier and its AI-credit cap. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionOpenOptionsAdditionalContentExclusionPolicy". + * via the `definition` "SessionLimitPredictionTierOption". */ /** @experimental */ -export interface SessionOpenOptionsAdditionalContentExclusionPolicy { - /** - * Content-exclusion rules to apply. - */ - rules: SessionOpenOptionsAdditionalContentExclusionPolicyRule[]; +export interface SessionLimitPredictionTierOption { + tier: SessionLimitPredictionTier; /** - * Opaque policy update timestamp supplied by the host. + * AI-credit cap for this tier. */ - last_updated_at: JsonValue; - scope: SessionOpenOptionsAdditionalContentExclusionPolicyScope; + cap: number; } /** - * Single content-exclusion rule supplied to `sessions.open` options, with paths, match conditions, and source. + * Sessions matching the filter, ordered most-recently-modified first. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionOpenOptionsAdditionalContentExclusionPolicyRule". + * via the `definition` "SessionList". */ /** @experimental */ -export interface SessionOpenOptionsAdditionalContentExclusionPolicyRule { - /** - * Path patterns covered by this rule. - */ - paths: string[]; - /** - * Conditions of which at least one must match. - */ - ifAnyMatch?: string[]; +export interface SessionList { /** - * Conditions none of which may match. + * Sessions ordered most-recently-modified first. Discriminated by `isRemote`. */ - ifNoneMatch?: string[]; - source: SessionOpenOptionsAdditionalContentExclusionPolicyRuleSource; + sessions: SessionListEntry[]; } /** - * Source descriptor for a `sessions.open` content-exclusion rule, with source name and type. + * Optional filter applied to the returned sessions * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionOpenOptionsAdditionalContentExclusionPolicyRuleSource". + * via the `definition` "SessionListFilter". */ /** @experimental */ -export interface SessionOpenOptionsAdditionalContentExclusionPolicyRuleSource { +export interface SessionListFilter { /** - * Name of the policy source. + * Match sessions whose context.cwd equals this value */ - name: string; + cwd?: string; /** - * Type of the policy source. + * Match sessions whose context.gitRoot equals this value */ - type: string; + gitRoot?: string; + /** + * Match sessions whose context.repository equals this value + */ + repository?: string; + /** + * Match sessions whose context.branch equals this value + */ + branch?: string; } /** - * Parameters for creating a new local session. + * Queued repo-level startup prompts and the total hook command count after loading. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsOpenCreate". + * via the `definition` "SessionLoadDeferredRepoHooksResult". */ /** @experimental */ -export interface SessionsOpenCreate { +export interface SessionLoadDeferredRepoHooksResult { /** - * Create a new local session. + * Repo-level startup prompts queued from repo hook configs. Empty on resume, when no repo configs were pending, or when disableAllHooks is set. */ - kind: "create"; - options?: SessionOpenOptions; + startupPrompts: string[]; /** - * Whether to emit session.start during creation. Defaults to true. + * Total hook command count (user + plugin + repo) loaded for the session by this call. Captured atomically with startupPrompts so callers don't need to read a separate counter. */ - emitStart?: boolean; + hookCount: number; } /** - * Parameters for resuming a specific local session. + * Enterprise permission policy expressed with the runtime's managed permission-rule syntax. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsOpenResume". + * via the `definition` "SessionManagedPermissions". */ /** @experimental */ -export interface SessionsOpenResume { +export interface SessionManagedPermissions { /** - * Resume a specific local session by ID or prefix. + * When set to `disable`, prevents bypass/allow-all permission modes. Advisory auto-approval remains available because normal prompt paths stay active. Any other value is accepted rather than failing the session, but is enforced as `disable`: the key is only present to restrict something, so a mode this runtime cannot interpret fails closed to the most restrictive one it knows. Omit the key entirely to impose no restriction. */ - kind: "resume"; + disableBypassPermissionsMode?: string; /** - * Session ID or unique prefix to resume. + * When true, prevents Assisted Permissions from being activated. An actively Assisted session falls back to Manual Approval while the policy is in force. Omit the key or set it to false to impose no restriction. */ - sessionId: string; - options?: SessionOpenOptions; + disableAssistedPermissionsMode?: boolean; /** - * Whether to emit session.resume after loading. Defaults to true. + * Permission rules that block matching operations. Deny has highest precedence. */ - resume?: boolean; + deny?: string[]; /** - * Suppress workspace.yaml metadata writeback when resuming from an incidental cwd. + * Permission rules that require explicit human approval. */ - suppressResumeWorkspaceMetadataWriteback?: boolean; -} -/** - * Parameters for resuming the most relevant local session. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsOpenResumeLast". - */ -/** @experimental */ -export interface SessionsOpenResumeLast { + ask?: string[]; /** - * Resume the most relevant existing local session. + * Permission rules that allow matching operations unless another managed source, deny, or ask rule restricts them. */ - kind: "resumeLast"; - context?: SessionContext; - options?: SessionOpenOptions; + allow?: string[]; /** - * Suppress workspace.yaml metadata writeback when resuming from an incidental cwd. + * Closed-world host boundary expressed as `Domain(hostname)`, `Domain(IP)`, or `Domain(*.example.com)` rules. Schemes, ports, paths, queries, and fragments are rejected because every network request must be enforceable at host-level egress. Multiple managed sources intersect their lists; an empty list denies all hosts. */ - suppressResumeWorkspaceMetadataWriteback?: boolean; + limitTo?: string[]; } /** - * Parameters for attaching to an already-active session by ID. + * Managed settings an SDK host may inject at session startup. Only permissions are accepted in this initial contract. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsOpenAttach". + * via the `definition` "SessionManagedSettings". */ /** @experimental */ -export interface SessionsOpenAttach { - /** - * Attach to an already-active in-process session by ID. Unlike `resume`, this does NOT re-load from disk; the session must already be loaded by an earlier `create`/`resume` call. Returns `status: 'not_found'` when no active session matches the id. Useful for in-process consumers that need a fresh API handle to a session opened elsewhere (e.g., a peer foreground-session switch). - */ - kind: "attach"; - /** - * Session ID to attach to. - */ - sessionId: string; +export interface SessionManagedSettings { + permissions?: SessionManagedPermissions; } /** - * Parameters for connecting to a live remote session. + * Records which IDE the host is connected to, or clears it. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsOpenRemote". + * via the `definition` "SessionMcpSetConnectedIdeInfoParams". */ /** @experimental */ -export interface SessionsOpenRemote { - /** - * Connect to a live remote session. - */ - kind: "remote"; +export interface SessionMcpSetConnectedIdeInfoParams { /** - * Remote session identifier to connect to. + * The connected IDE. Null or omitted clears the recorded IDE, which is how a host reports that it is disconnected. */ - remoteSessionId: string; - repository?: RemoteSessionRepository; - options?: SessionOpenOptions; + ide?: SessionConnectedIdeInfo | null; } /** - * Parameters for creating a new cloud session. + * Point-in-time snapshot of slow-changing session identifier and state fields * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsOpenCloud". + * via the `definition` "SessionMetadataSnapshot". */ /** @experimental */ -export interface SessionsOpenCloud { +export interface SessionMetadataSnapshot { /** - * Create a new cloud (coding-agent) session. + * The unique identifier of the session */ - kind: "cloud"; - repository?: RemoteSessionRepository; + sessionId: string; /** - * Optional owner (user or organization login) to associate with the cloud session when no repository is provided. Ignored when `repository` is set (the repo's owner takes precedence). + * ISO 8601 timestamp of when the session started */ - owner?: string; - options?: SessionOpenOptions; + startTime: string; /** - * In-process callback invoked when the cloud task is created, before connection. Internal because function references cannot cross the JSON-RPC boundary. - * - * @internal + * ISO 8601 timestamp of when the session's persisted state was last modified on disk. For new sessions, equals startTime. For resumed sessions, reflects the previous modification time at construction. */ - onTaskCreated?: OpaqueInProcessValue; -} -/** - * Parameters for fetching a remote session and handing it off to a new local session. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsOpenHandoff". - */ -/** @experimental */ -export interface SessionsOpenHandoff { + modifiedTime: string; /** - * Fetch a remote session and hand it off to a new local session. + * Whether this is a remote session (i.e., one whose runtime executes elsewhere and is steered through this process) */ - kind: "handoff"; - metadata: RemoteSessionMetadataValue; - options?: SessionOpenOptions; - taskType?: SessionsOpenHandoffTaskType; + isRemote: boolean; /** - * In-process progress callback `(update) => void` invoked for each handoff step. Marked internal because a function reference cannot cross the JSON-RPC boundary. The host-side `handoffSession` is already declared as `AsyncGenerator`; the schema layer flattens it because it does not yet support streaming methods. The wire-clean replacement is to expose the AsyncGenerator directly (or use vscode-jsonrpc `$/progress` notifications) once the schema/transport layer supports it. - * - * @internal + * True when the session was detected to be in use by another process at construction time. Local consumers may surface a confirmation prompt before fully attaching. Always false for new sessions. */ - onProgress?: OpaqueInProcessValue; + alreadyInUse: boolean; /** - * In-process confirmation callback `(request) => boolean | Promise` invoked when the handoff needs the caller to confirm a non-fatal blocker (e.g. a repository mismatch between the current working directory and the remote session). Returning `true` proceeds with the handoff; returning `false` (or omitting the callback) aborts it. Marked internal because a function reference cannot cross the JSON-RPC boundary, for the same reasons as `onProgress`. - * - * @internal + * Absolute path to the session's workspace directory on disk, or null if the session has no associated workspace */ - onConfirm?: OpaqueInProcessValue; -} -/** - * Result of opening a session. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionOpenResult". - */ -/** @experimental */ -export interface SessionOpenResult { - status: SessionsOpenStatus; + workspacePath: string | null; /** - * Opened session ID. Omitted when status is `not_found`. + * User-provided name supplied at session construction (via `--name`), if any. Immutable after construction. */ - sessionId?: string; + initialName?: string; /** - * In-process SessionClientApi handle for the opened session, returned to CLI callers as a transitional shortcut. Marked internal so the public SDK surface does not expose it; SDK consumers should construct per-session clients from `sessionId` instead. - * - * @internal - * - * @internal + * Runtime client name associated with the session (telemetry identifier). */ - sessionApi?: OpaqueInProcessValue; + clientName?: string; + remoteMetadata?: MetadataSnapshotRemoteMetadata; /** - * Startup prompts queued by user-level hook configs at session creation. Only populated when status is `created`; resumed sessions return an empty array. + * Short human-readable summary of the session, if known. Omitted when no summary has been generated. */ - startupPrompts?: string[]; + summary?: string; /** - * Remote session ID, present when status is `connected`. + * Absolute path to the session's current working directory */ - remoteSessionId?: string; - metadata?: RemoteSessionMetadataValue; + workingDirectory: string; + currentMode: MetadataSnapshotCurrentMode; /** - * Handoff progress steps, present when status is `handed_off`. + * Currently selected model identifier, if any */ - progress?: SessionsOpenProgress[]; -} -/** - * `sessions.open` handoff progress update with step, status, and optional message. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsOpenProgress". - */ -/** @experimental */ -export interface SessionsOpenProgress { - step: SessionsOpenProgressStep; - status: SessionsOpenProgressStatus; + selectedModel?: string; /** - * Optional step message. + * Current session limits, or null when no limits are active */ - message?: string; + sessionLimits: SessionLimitsConfig | null; + indexedSearch?: IndexedSearchState; + /** + * Public-facing workspace metadata for this session, or null if the session has no associated workspace. Excludes runtime-internal fields (GitHub IDs, summary count, internal flags). + */ + workspace?: WorkspaceSummary | null; } /** - * Plugin names (or specs) to disable in the session's authoritative working directory. + * The list of models available to this session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionPluginsDisableRequest". + * via the `definition` "SessionModelList". */ /** @experimental */ -export interface SessionPluginsDisableRequest { +export interface SessionModelList { /** - * Plugin names or "plugin@marketplace" specs to disable. Unknown names are ignored. Non-marketplace direct installs cannot be disabled via this API; uninstall them instead. Plugin-owned MCP servers are stopped in active sessions immediately; other plugin contributions remain available until each session reloads plugins. + * Available models, ordered with the most preferred default first. Includes both Copilot (CAPI) models and any registry BYOK models; a BYOK model appears under its provider-qualified selection id (`provider/id`). */ - names: string[]; + list: JsonValue[]; + /** + * The model providers available to this session, in ordering order, resolved from the account roster; empty when no provider is entitled (logged out / seatless). Each model in `list` carries its own provider reference; this roster gives the deterministic provider sequence and lets a consumer group by provider without deriving ordering from the model list. Central code never branches on a provider kind. + */ + providers?: ModelProviderDescriptor[]; + /** + * Cost categories for the full CAPI catalog, including picker-disabled models that Auto may select. Metadata only; entries absent from `list` are not manually selectable. + */ + modelPriceCategories?: SessionModelPriceCategory[]; + /** + * Per-quota snapshots returned alongside the model list, keyed by quota type. + */ + quotaSnapshots?: { + [k: string]: JsonValue | undefined; + }; + auto?: AutoTierMetadata; } /** - * Plugin names (or specs) to enable in the session's authoritative working directory. + * Cost-category metadata for a CAPI model. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionPluginsEnableRequest". + * via the `definition` "SessionModelPriceCategory". */ /** @experimental */ -export interface SessionPluginsEnableRequest { +export interface SessionModelPriceCategory { /** - * Plugin names or "plugin@marketplace" specs to enable. Unknown names are ignored. Non-marketplace direct installs are always enabled and cannot be toggled via this API. + * CAPI model identifier. */ - names: string[]; + id: string; + priceCategory: ModelPickerPriceCategory; } /** - * Plugin source resolved relative to the session's authoritative working directory. + * Session construction options. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionPluginsInstallRequest". + * via the `definition` "SessionOpenOptions". */ /** @experimental */ -export interface SessionPluginsInstallRequest { +export interface SessionOpenOptions { /** - * Plugin install spec. Accepts the same forms as the CLI: "plugin@marketplace" (marketplace install), "owner/repo" or "owner/repo:subpath" (GitHub direct), an http/https/ssh URL, or a local path. Direct (non-marketplace) installs are deprecated and will produce a deprecationWarning in the result. + * Optional stable session identifier to use for a new session. */ - source: string; -} - -/** @experimental */ -export interface SessionPluginsRetryManagedRequest { + sessionId?: string; /** - * "plugin@marketplace" specs to retry. Omit to retry every plugin the session's managed settings require. + * Optional human-friendly session name. */ - plugins?: string[]; -} -/** - * Per-plugin outcomes of retrying the plugins required by the session's managed settings. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionPluginsRetryManagedResult". - */ -/** @experimental */ -export interface SessionPluginsRetryManagedResult { + name?: string; /** - * One entry per requested plugin, in request order. When no plugins were requested, one entry per plugin the managed settings require. + * Initial model identifier. */ - plugins: ManagedPluginRetryEntry[]; -} -/** - * Outcome of the prune operation: deleted IDs, dry-run candidates, skipped IDs, total bytes freed, and the dry-run flag. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionPruneResult". - */ -/** @experimental */ -export interface SessionPruneResult { + model?: string; /** - * Session IDs that were deleted (always empty in dry-run mode) + * Initial reasoning effort level. CAPI values are model-defined and validated against the selected model; BYOK providers may define additional values. When omitted, no effort override is applied. */ - deleted: string[]; + reasoningEffort?: string; + reasoningSummary?: SessionOpenOptionsReasoningSummary; + verbosity?: Verbosity; /** - * Session IDs that would be deleted in dry-run mode (always empty otherwise) + * Identifier of the client driving the session. */ - candidates: string[]; + clientName?: string; /** - * Session IDs that were skipped (e.g., named sessions) + * OAuth Client ID Metadata Document URL used by this host for MCP authorization. */ - skipped: string[]; + authClientIdMetadataUrl?: string; /** - * Total bytes freed (actual when not dry-run, projected when dry-run) + * Structured client kind used for runtime behavior gates. */ - freedBytes: number; + clientKind?: string; /** - * True when no deletions were actually performed + * Identifier sent to LSP-style integrations. */ - dryRun: boolean; -} -/** - * Existing delegation guidance for an account without delegation access. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionQuotaDelegateWarning". - */ -/** @experimental */ -export interface SessionQuotaDelegateWarning { + lspClientName?: string; /** - * User-facing guidance. + * Stable integration identifier for analytics. */ - text: string; + integrationId?: string; /** - * Link to upgrade the account. + * ExP assignment ('flight') data injected by an SDK integrator, in the same JSON shape the Copilot CLI fetches from the experimentation service (CopilotExpAssignmentResponse). When supplied this is fed into the FeatureFlagService exactly like CLI-fetched assignments and ExP-backed flags wait for it. When absent the session does not block on ExP. + * + * @internal */ - url: string; -} -/** - * The incumbent session-owned quota and account projection. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionQuotaProjection". - */ -/** @experimental */ -export interface SessionQuotaProjection { + expAssignments?: JsonValue; /** - * Known quota snapshots, keyed by the provider's quota type. + * Opt-in: self-fetch and enforce enterprise managed settings, including managed hook policies, at session bootstrap. */ - snapshots: { - [k: string]: SessionQuotaSnapshot | undefined; - }; + enableManagedSettings?: boolean; /** - * Provider-owned account quota state, including snapshots without numeric balances. + * Opt in to enforcing non-overridable managed model controls on session model, Auto-tier, reasoning-effort, and context-tier changes. Managed defaults still apply when omitted; this option only turns conflicting changes into errors. */ - providerQuotas?: ProviderQuotaState[]; + enforceManagedModelDefaults?: boolean; + managedSettings?: SessionManagedSettings; /** - * Whether the account uses the free limited Copilot plan. + * Opt in to capturing file changes for session rewind and session diff. Capture cannot reconstruct changes made before it was enabled. On create it starts capture from the first turn. It is also honored on resume: for a session that already has tracked prior turns, tracking continues automatically even if this is omitted; passing it on resume additionally enables tracking for an eligible session that has no prior root turn yet. Resuming a session whose prior root turns were never tracked has no restorable baseline, so tracking stays disabled for it and rewind reports file change tracking as unavailable; the resume itself still succeeds, so sessions that predate tracking remain loadable. The opt-in is only rejected when the session can never track (a subagent session, or one without local session storage). It is intentionally absent from the mutable options update because enabling it after edits have occurred would create an incomplete, misleading baseline. Subagents share the parent session's capture store and are not tracked as separate rewind points: a file a subagent writes is attributed to whichever root user turn was open when the capture was staged, just before the tool body ran. A turn cannot open while a staged capture is still in flight, so a subagent tool that staged under the spawning turn stays attributed to it however late the write lands, while a capture it stages after the user's next message belongs to that later turn. Attribution decides which turn's rewind point counts and file preview include that write; it does not narrow which rewinds revert it, because a rewind restores every capture from the selected turn onward, so the earlier spawning turn reverts it as well. */ - isFreeUser: boolean; + enableFileChangeTracking?: boolean; /** - * Whether the account uses token-based billing. + * Feature-flag values resolved by the host. */ - isTbbUser: boolean; - planTier: SessionQuotaPlanTier; + featureFlags?: { + [k: string]: boolean | undefined; + }; /** - * Whether premium-request costs are billable. + * Whether experimental behavior is enabled. */ - premiumRequestsBillable: boolean; + isExperimentalMode?: boolean; + authInfo?: AuthInfo; + provider?: ProviderConfig; + capi?: CapiSessionOptions; /** - * Whether model cost columns should be shown. + * Whether a CLI host explicitly requested the initial Auto preference. False preserves a settings-derived preference without validating availability during creation; execution still validates it. Defaults to true and is ignored for non-CLI callers. + * + * @internal */ - modelCostColumnVisible: boolean; + autoTierIsExplicit?: boolean; /** - * Whether the account can delegate tasks to GitHub. + * Named BYOK provider connections, additive to CAPI auth. Combining with `provider` is rejected. + * + * @experimental */ - delegateAvailable: boolean; + providers?: NamedProviderConfig[]; /** - * Whether the account can sign up for Copilot Free. + * BYOK model definitions added to the selectable model list, each referencing a provider name. + * + * @experimental */ - canSignupForCopilotFree: boolean; + models?: ProviderModelConfig[]; /** - * Whether dynamic workflows are enabled for the active account. + * Working directory to anchor the session. */ - dynamicWorkflowsEnabled: boolean; + workingDirectory?: string; /** - * Whether dynamic workflows are visible under the session's feature flags. + * Additional directories the agent may access beyond the working directory. Each entry is granted to the session's file-access allow-list and surfaced to the model (system prompt context and `@`-mention completion). Conventional `.github/skills/` and `.github/agents/` definitions under each directory also join the session's project catalogs when their existing subsystem gates are enabled: added-root skills require both `enableConfigDiscovery` and effective `enableSkills`; added-root agents require `enableConfigDiscovery`. Supplying a directory therefore activates configuration from it and should be treated as a trust decision. Absolute paths are recommended; a relative path is resolved against the session's working directory. Nonexistent or unresolvable entries are skipped with a warning. This is applied during session creation and cold resume and is not persisted, so a cold resume must re-supply the directories. */ - dynamicWorkflowsUiVisible: boolean; + additionalDirectories?: string[]; + workingDirectoryContext?: SessionContext; /** - * Upgrade link for a free account. + * Whether this session supports remote steering. */ - upgradeUrl?: string; - delegateWarning?: SessionQuotaDelegateWarning; -} -/** - * Session quota snapshot, preserving the incumbent numeric units and reset metadata. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionQuotaSnapshot". - */ -/** @experimental */ -export interface SessionQuotaSnapshot { + remoteSteerable?: boolean; /** - * Whether the entitlement is unlimited. + * Telemetry-only remote exporting flag. */ - isUnlimitedEntitlement: boolean; + remoteExporting?: boolean; /** - * Entitled quantity in this quota's units. + * Telemetry-only remote-defaulted flag. */ - entitlementRequests: number; + remoteDefaultedOn?: boolean; /** - * Consumed quantity in this quota's units. + * Parent session ID for detached child telemetry rollup. */ - usedRequests: number; + detachedFromSpawningParentSessionId?: string; /** - * Whether usage is allowed after quota exhaustion. + * Parent engagement ID for detached child telemetry rollup. */ - usageAllowedWithExhaustedQuota: boolean; + detachedFromSpawningParentEngagementId?: string; /** - * Additional usage in this quota's units. + * Allowlist of available tool names. */ - overage: number; + availableTools?: string[]; /** - * Whether additional usage is allowed after quota exhaustion. + * Denylist of tool names. */ - overageAllowedWithExhaustedQuota: boolean; + excludedTools?: string[]; /** - * Percentage of the entitlement remaining. + * Built-in subagent names to include in this session. When specified, only these built-ins are available, subject to runtime availability and exclusions. Custom agents with the same name remain available. */ - remainingPercentage: number; + includedBuiltinAgents?: string[]; /** - * Quota reset time in milliseconds since the Unix epoch, when known. + * Built-in subagent names to exclude from this session. Excluded built-ins are hidden from agent discovery and cannot be dispatched unless a custom agent with the same name is available. */ - resetDateEpochMs?: number; + excludedBuiltinAgents?: string[]; /** - * Whether the reset time is estimated. + * Whether shell-script safety heuristics are enabled. */ - resetDateEstimated?: boolean; + enableScriptSafety?: boolean; + shell?: ShellOptions; /** - * Whether the provider reports available quota. + * @deprecated + * Use shell.initProfile instead. Shell init profile. */ - hasQuota?: boolean; + shellInitProfile?: string; /** - * Whether this quota uses token-based billing. + * PowerShell process flags applied to built-in and user-requested shell commands. */ - tokenBasedBilling?: boolean; + shellProcessFlags?: string[]; + sandboxConfig?: SandboxConfig; /** - * Additional-usage budget cap, when provided. + * Origin of the sandbox choice. Settings-derived origins (never_configured, user_enabled, user_disabled, repository_policy) let managed policy floor a host preference; explicit below-floor changes remain policy conflicts unless a session opt-out is authorized. Also used for telemetry provenance. + * + * @experimental */ - overageEntitlement?: number; -} -/** - * Session IDs to close, deactivate, and delete from disk. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsBulkDeleteRequest". - */ -/** @experimental */ -export interface SessionsBulkDeleteRequest { + sandboxConfigSource?: SandboxConfigSource; /** - * Session IDs to close, deactivate, and delete from disk + * Whether interactive shell sessions are logged. */ - sessionIds: string[]; -} -/** - * Session IDs to test for live in-use locks. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsCheckInUseRequest". - */ -/** @experimental */ -export interface SessionsCheckInUseRequest { + logInteractiveShells?: boolean; + envValueMode?: SessionOpenOptionsEnvValueMode; /** - * Session IDs to test for live in-use locks + * MCP server names disabled for this session. Disabled servers are not started or authenticated on create or cold resume. */ - sessionIds: string[]; -} -/** - * Session IDs from the input set that are currently in use by another process. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsCheckInUseResult". - */ -/** @experimental */ -export interface SessionsCheckInUseResult { + disabledMcpServers?: string[]; /** - * Session IDs from the input set that are currently held by another running process via an alive lock file + * Non-secret host-managed HTTP MCP servers keyed by stable managed identity. Managed provenance is runtime-established from this separate field and credentials are supplied through dynamic-header refresh. + * + * @experimental */ - inUse: string[]; -} -/** - * Session ID to close. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsCloseRequest". - */ -/** @experimental */ -export interface SessionsCloseRequest { - /** - * Session ID to close + managedMcpServers?: { + [k: string]: ManagedMcpServerConfig; + }; + /** + * Whether to include instructions from every MCP server in the system prompt instead of only allowlisted servers. */ - sessionId: string; -} -/** - * Closes a session: emits shutdown, flushes pending events to disk, releases the in-use lock, disposes the active session. Idempotent: succeeds even if the session is not currently active. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsCloseResult". - */ -/** @experimental */ -export interface SessionsCloseResult {} -/** - * Identity, state location and starting context for a workspace record. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsCreateWorkspaceRequest". - */ -/** @experimental */ -export interface SessionsCreateWorkspaceRequest { + allowAllMcpServerInstructions?: boolean; /** - * Session ID the workspace record belongs to + * Explicit discovery-only skill roots, not filesystem grants. Available without enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ - sessionId: string; + skillDirectories?: string[]; /** - * Directory the session's state is written under when no session filesystem provider is configured. Ignored when a provider is configured; the provider's session state path is used instead. + * Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ - sessionStatePath: string; + agentDirectories?: string[]; /** - * `windows` (any letter case) selects Windows path rules. Any other value selects POSIX path rules. + * Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without enableConfigDiscovery, subject to instruction/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ - convention: string; - context?: SessionWorkingDirectoryContextWithClient; + instructionDirectories?: string[]; /** - * User-supplied display name for the workspace + * Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without enableConfigDiscovery or enableFileHooks, which controls repository-origin hooks only; hook/managed disables still apply. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ - name?: string; -} -/** - * A working-directory context together with the client that produced it. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionWorkingDirectoryContextWithClient". - */ -/** @experimental */ -export interface SessionWorkingDirectoryContextWithClient { + hookDirectories?: string[]; /** - * Current working directory path + * Skill scan directories and descendants excluded from discovery. Supports `~`-relative paths. */ - cwd: string; + ignoredSkillsLocations?: string[]; /** - * Root directory of the git repository + * Whether skill loading is enabled. When omitted, explicit SDK skill roots or an SDK skill provider enable skills independently of enableConfigDiscovery. */ - gitRoot?: string; + enableSkills?: boolean; /** - * Repository identifier derived from the git remote URL + * Whether the requesting SDK session has a skill provider. The provider remains ephemeral and is never persisted in session options or history. When enableSkills is false, it remains bound but dormant and receives no callbacks. Cloud, relay, handoff, and raw sessions.open flows reject it because they cannot safely pre-register the callback handler. + * + * @internal + * @experimental */ - repository?: string; + hasSkillProvider?: boolean; /** - * Hosting platform type of the repository + * Built-in skill names to include in this session. When specified, only these runtime-bundled skills are available. Skills from other sources with the same name remain available. */ - hostType?: string; + includedBuiltinSkills?: string[]; /** - * Current git branch name + * Skill IDs disabled for this session. */ - branch?: string; + disabledSkills?: string[]; /** - * Raw host string from the git remote URL + * Installed plugins visible to the session. */ - repositoryHost?: string; + installedPlugins?: InstalledPlugin[]; /** - * Head commit of the current git branch + * Whether custom agents default to local-only execution. */ - headCommit?: string; + customAgentsLocalOnly?: boolean; /** - * Merge-base commit SHA + * Whether to skip custom instruction sources. */ - baseCommit?: string; + skipCustomInstructions?: boolean; /** - * Name of the client that created the session + * Whether to invalidate cached custom-instruction discovery before constructing the session. Use when instruction files may have changed earlier in the same runtime process. */ - clientName?: string; -} -/** - * The workspace record that was written. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsCreateWorkspaceResult". - */ -/** @experimental */ -export interface SessionsCreateWorkspaceResult { + refreshCustomInstructions?: boolean; /** - * The created workspace record, as JSON + * Instruction source IDs disabled for this session. */ - workspaceJson: string; -} -/** - * Session ID to delete from disk. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsDeleteRequest". - */ -/** @experimental */ -export interface SessionsDeleteRequest { + disabledInstructionSources?: string[]; /** - * Session ID to delete + * Whether commit-message coauthor trailers are enabled. */ - sessionId: string; + coauthorEnabled?: boolean; /** - * Internal resolved session directory path to delete + * Optional trajectory output file path. */ - sessionPath?: string | null; -} -/** - * Session metadata records to enrich with summary and context information. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsEnrichMetadataRequest". - */ -/** @experimental */ -export interface SessionsEnrichMetadataRequest { + trajectoryFile?: string; /** - * Session metadata records to enrich. Records that already have summary and context are returned unchanged. + * Whether model responses stream as delta events. */ - sessions: LocalSessionMetadataValue[]; -} -/** - * New auth credentials to install on the session. Omit to leave credentials unchanged. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionSetCredentialsParams". - */ -/** @experimental */ -export interface SessionSetCredentialsParams { - credentials?: SettableAuthInfo; -} -/** - * Token authentication accepted by session.gitHubAuth.setCredentials. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SettableTokenAuthInfo". - */ -/** @experimental */ -export interface SettableTokenAuthInfo { + enableStreaming?: boolean; /** - * SDK-side token authentication; the host configured the token directly via the SDK. + * Experimental: enable native model citations for supported Anthropic and OpenAI models, normalized onto the `assistant.message` event. Off by default; may change or be removed while the citations surface is experimental. + * + * @experimental */ - type: "token"; + enableCitations?: boolean; /** - * Authentication host. + * Override URL for the Copilot API endpoint. */ - host: string; + copilotUrl?: string; /** - * The token value itself. Treat as a secret. + * Whether ask_user is explicitly disabled. */ - token: string; - copilotUser?: CopilotUserResponse; -} -/** - * Indicates whether the credential update succeeded. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionSetCredentialsResult". - */ -/** @experimental */ -export interface SessionSetCredentialsResult { + askUserDisabled?: boolean; /** - * Whether the operation succeeded + * Whether auto-mode continuation is enabled. */ - success: boolean; + continueOnAutoMode?: boolean; /** - * Whether the session ended up with a populated `copilotUser` for the installed credentials. `true` when the supplied credential already carried `copilotUser` or it was successfully re-resolved server-side. `false` when the credential is installed without `copilotUser` — either re-resolution failed, or the variant cannot be re-resolved from the credential alone (only the raw-token variants `token`, `env`, and `gh-cli` can). In both `false` cases the token swap still applied, but plan/quota/billing metadata is degraded. Present whenever a credential was supplied; omitted only when no credential was supplied (no-op call). + * Whether the host is an interactive UI. */ - copilotUserResolved?: boolean; + runningInInteractiveMode?: boolean; + /** + * Whether on-demand custom instruction discovery is enabled. + */ + enableOnDemandInstructionDiscovery?: boolean; + /** + * Maximum decoded byte size of a single inline model-facing binary tool result persisted in session events (default 10 MB). + */ + maxInlineBinaryBytes?: number; + modelCapabilitiesOverrides?: ModelCapabilitiesOverride; + sessionLimits?: SessionLimitsConfig; + /** + * Runtime context discriminator for agent filtering. + */ + agentContext?: string; + /** + * Override directory for session event logs. + */ + eventsLogDirectory?: string; + /** + * Whether subagent callback events should be forwarded into the session event log sink. + */ + eventsLogIncludesSubagents?: boolean; + /** + * Override Copilot configuration directory. + */ + configDir?: string; + /** + * Additional content-exclusion policies to merge into the session policy set. + * + * @experimental + */ + additionalContentExclusionPolicies?: SessionOpenOptionsAdditionalContentExclusionPolicy[]; + memory?: MemoryConfiguration; + /** + * Capabilities enabled for this session. + */ + sessionCapabilities?: SessionCapability[]; } /** - * Availability of built-in job tools surfaced to boundary consumers. + * Per-session settings for built-in shell tools. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionSettingsBuiltInToolAvailabilitySnapshot". + * via the `definition` "ShellOptions". */ /** @experimental */ -export interface SessionSettingsBuiltInToolAvailabilitySnapshot { +export interface ShellOptions { + initProfile?: ShellInitProfile; /** - * Whether the report-progress tool is available. + * Ordered host-provided script paths sourced before each built-in shell command when the + * entry's shell target matches the active shell. Use these for rc files, environment setup scripts, + * or other custom scripts. A script that returns a nonzero status is reported, and later scripts + * and the user command continue while the shell remains running. Because scripts are sourced into + * the command shell, `exit`, `exec`, failures under `set -e`, or other shell-terminating behavior + * can prevent continuation. Script standard output is preserved; Bash script stderr is discarded, + * PowerShell exception messages are replaced, and runtime-generated failure notices omit + * configured script paths. When sandboxing is enabled, each script must already be readable under + * the active sandbox filesystem policy. Pass an empty array to clear the list. */ - reportProgress?: boolean; + initScripts?: ShellInitScript[]; /** - * Whether the create-pull-request tool is available. + * Flags passed to the active built-in shell process on startup, replacing its default flags. + * When omitted, the built-in Bash shell uses `--norc --noprofile`, + * and the built-in PowerShell shell uses `-NoProfile -NoLogo`. */ - createPullRequest?: boolean; + processFlags?: string[]; + credentials?: ShellCredentials; } /** - * Named Rust-owned settings predicate to evaluate for this session. + * A host-provided script sourced before each built-in shell command when its shell target matches the active shell. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionSettingsEvaluatePredicateRequest". + * via the `definition` "ShellInitScript". */ /** @experimental */ -export interface SessionSettingsEvaluatePredicateRequest { - name: SessionSettingsPredicateName; +export interface ShellInitScript { /** - * Tool name for tool-scoped predicates such as trivial-change handling. + * Path to the script to source. */ - toolName?: string; + path: string; + shell: ShellInitScriptShell; } /** - * Result of evaluating a Rust-owned settings predicate. + * Command-scoped GitHub credential injection for the shell commands an agent runs. + * + * Each channel is opt-in and independent, and injection is scoped to the individual command + * spawn: the credential is resolved from the session's *current* authentication at every spawn + * and reaches only spawns whose script actually invokes `git` or `gh`. Because nothing is + * retained between spawns, replacing the session credential (`session.gitHubAuth.setCredentials`) + * changes what the next spawned command presents — which seeding a credential into the runtime + * process's own environment cannot do, since a child's environment is fixed at `exec`. + * + * The credential is matched to the host it authenticates to, so a github.com credential is never + * presented to a GitHub Enterprise host and vice versa. Where a channel cannot express that + * boundary it injects nothing rather than crossing it -- see `gh` below. + * + * This is independent of `sandboxConfig`: it is a decision about which identity the agent + * presents, not about what the agent may touch, and it works on every platform whether or not + * an OS sandboxing backend is available. `sandboxConfig.auth` remains the sandbox-scoped + * spelling and is additive with this one. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionSettingsEvaluatePredicateResult". + * via the `definition` "ShellCredentials". */ /** @experimental */ -export interface SessionSettingsEvaluatePredicateResult { +export interface ShellCredentials { /** - * Whether the named settings predicate evaluated to enabled. + * Whether to authenticate the agent's `git` commands as the session's GitHub credential, by + * injecting an `http..extraheader` (plus `insteadOf` rewrites so SSH-spelled remotes for + * that host use the authenticated HTTPS transport). Applied only to a spawn that runs a + * remote-contacting `git` subcommand. Default: false (opt-in). */ - enabled: boolean; + git?: boolean; + /** + * Whether to authenticate the agent's `gh` commands as the session's GitHub credential, by + * exporting `GH_TOKEN` to a spawn that runs `gh`. Any inherited `gh` credential is removed from + * spawns that do not, so the credential stays command-scoped. + * + * Applies to a github.com credential only. `gh` picks its credential variable from the host a + * command targets rather than the one the credential belongs to, and the command can choose that + * target, so `GH_ENTERPRISE_TOKEN` would offer a single-tenant enterprise credential to every + * other enterprise host. A session whose credential is enterprise-scoped therefore runs `gh` + * unauthenticated; its `git` commands are unaffected, because `http..extraheader` is scoped + * to one host by construction. Default: false (opt-in). + */ + gh?: boolean; } /** - * Redacted job settings for a session. The job nonce is excluded. + * Content-exclusion policy supplied to `sessions.open` options, with rules, last-updated data, and scope. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionSettingsJobSnapshot". + * via the `definition` "SessionOpenOptionsAdditionalContentExclusionPolicy". */ /** @experimental */ -export interface SessionSettingsJobSnapshot { +export interface SessionOpenOptionsAdditionalContentExclusionPolicy { /** - * GitHub Actions event type for the job. + * Content-exclusion rules to apply. */ - eventType?: string; + rules: SessionOpenOptionsAdditionalContentExclusionPolicyRule[]; /** - * Whether this is the workflow's trigger job. + * Opaque policy update timestamp supplied by the host. */ - isTriggerJob?: boolean; - builtInToolAvailability?: SessionSettingsBuiltInToolAvailabilitySnapshot; + last_updated_at: JsonValue; + scope: SessionOpenOptionsAdditionalContentExclusionPolicyScope; } /** - * Redacted model routing settings for a session. + * Single content-exclusion rule supplied to `sessions.open` options, with paths, match conditions, and source. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionSettingsModelSnapshot". + * via the `definition` "SessionOpenOptionsAdditionalContentExclusionPolicyRule". */ /** @experimental */ -export interface SessionSettingsModelSnapshot { - /** - * Selected model identifier. - */ - model?: string; +export interface SessionOpenOptionsAdditionalContentExclusionPolicyRule { /** - * Default reasoning effort for the selected model. + * Path patterns covered by this rule. */ - defaultReasoningEffort?: string; + paths: string[]; /** - * Agent job identifier for the session. + * Conditions of which at least one must match. */ - instanceId?: string; + ifAnyMatch?: string[]; /** - * Agent service callback URL for job and progress updates. + * Conditions none of which may match. */ - callbackUrl?: string; + ifNoneMatch?: string[]; + source: SessionOpenOptionsAdditionalContentExclusionPolicyRuleSource; } /** - * Online-evaluation settings safe to expose across the SDK boundary. + * Source descriptor for a `sessions.open` content-exclusion rule, with source name and type. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionSettingsOnlineEvaluationSnapshot". + * via the `definition` "SessionOpenOptionsAdditionalContentExclusionPolicyRuleSource". */ /** @experimental */ -export interface SessionSettingsOnlineEvaluationSnapshot { +export interface SessionOpenOptionsAdditionalContentExclusionPolicyRuleSource { /** - * Whether online evaluation is disabled. + * Name of the policy source. */ - disableOnlineEvaluation?: boolean; + name: string; /** - * Whether online-evaluation output-file generation is enabled. + * Type of the policy source. */ - enableOnlineEvaluationOutputFile?: boolean; + type: string; } /** - * Redacted repository and GitHub host settings for a session. + * Parameters for creating a new local session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionSettingsRepoSnapshot". + * via the `definition` "SessionsOpenCreate". */ /** @experimental */ -export interface SessionSettingsRepoSnapshot { +export interface SessionsOpenCreate { /** - * Repository name. + * Create a new local session. */ - name?: string; + kind: "create"; + options?: SessionOpenOptions; /** - * GitHub repository database ID. + * Whether to emit session.start during creation. Defaults to true. */ - id?: number; + emitStart?: boolean; +} +/** + * Parameters for resuming a specific local session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsOpenResume". + */ +/** @experimental */ +export interface SessionsOpenResume { /** - * Checked-out repository branch. + * Resume a specific local session by ID or prefix. */ - branch?: string; + kind: "resume"; /** - * Checked-out commit SHA. + * Session ID or unique prefix to resume. */ - commit?: string; + sessionId: string; + options?: SessionOpenOptions; /** - * Whether the repository is writable. + * Whether to emit session.resume after loading. Defaults to true. */ - readWrite?: boolean; + resume?: boolean; /** - * Repository owner login. + * Suppress workspace.yaml metadata writeback when resuming from an incidental cwd. */ - ownerName?: string; + suppressResumeWorkspaceMetadataWriteback?: boolean; +} +/** + * Parameters for resuming the most relevant local session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsOpenResumeLast". + */ +/** @experimental */ +export interface SessionsOpenResumeLast { /** - * GitHub repository owner database ID. + * Resume the most relevant existing local session. */ - ownerId?: number; + kind: "resumeLast"; + context?: SessionContext; + options?: SessionOpenOptions; /** - * GitHub server base URL. + * Suppress workspace.yaml metadata writeback when resuming from an incidental cwd. */ - serverUrl?: string; + suppressResumeWorkspaceMetadataWriteback?: boolean; +} +/** + * Parameters for attaching to an already-active session by ID. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsOpenAttach". + */ +/** @experimental */ +export interface SessionsOpenAttach { /** - * GitHub server host name. + * Attach to an already-active in-process session by ID. Unlike `resume`, this does NOT re-load from disk; the session must already be loaded by an earlier `create`/`resume` call. Returns `status: 'not_found'` when no active session matches the id. Useful for in-process consumers that need a fresh API handle to a session opened elsewhere (e.g., a peer foreground-session switch). */ - host?: string; + kind: "attach"; /** - * Protocol used to access the GitHub host. + * Session ID to attach to. */ - hostProtocol?: string; + sessionId: string; +} +/** + * Parameters for connecting to a live remote session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsOpenRemote". + */ +/** @experimental */ +export interface SessionsOpenRemote { /** - * GitHub secret-scanning service URL. + * Connect to a live remote session. */ - secretScanningUrl?: string; + kind: "remote"; /** - * Number of commits in the pull request. + * Remote session identifier to connect to. */ - prCommitCount?: number; + remoteSessionId: string; + repository?: RemoteSessionRepository; + options?: SessionOpenOptions; } /** - * Redacted, serializable view of session runtime settings for SDK boundary consumers. Secrets and raw feature flags are intentionally excluded. + * Parameters for creating a new cloud session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionSettingsSnapshot". + * via the `definition` "SessionsOpenCloud". */ /** @experimental */ -export interface SessionSettingsSnapshot { - /** - * Agent runtime version selector copied from the session settings, such as `latest` or a runtime release identifier. - */ - version?: string; +export interface SessionsOpenCloud { /** - * Name of the SDK client that created the session. + * Create a new cloud (coding-agent) session. */ - clientName?: string; + kind: "cloud"; + repository?: RemoteSessionRepository; /** - * Session timeout in milliseconds. + * Optional owner (user or organization login) to associate with the cloud session when no repository is provided. Ignored when `repository` is set (the repo's owner takes precedence). */ - timeoutMs?: number; + owner?: string; + options?: SessionOpenOptions; /** - * Session start time as Unix epoch milliseconds. + * In-process callback invoked when the cloud task is created, before connection. Internal because function references cannot cross the JSON-RPC boundary. + * + * @internal */ - startTimeMs?: number; - repo: SessionSettingsRepoSnapshot; - model: SessionSettingsModelSnapshot; - validation: SessionSettingsValidationSnapshot; - job: SessionSettingsJobSnapshot; - onlineEvaluation: SessionSettingsOnlineEvaluationSnapshot; + onTaskCreated?: OpaqueInProcessValue; } /** - * Redacted validation and memory-tool settings for a session. + * Parameters for fetching a remote session and handing it off to a new local session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionSettingsValidationSnapshot". + * via the `definition` "SessionsOpenHandoff". */ /** @experimental */ -export interface SessionSettingsValidationSnapshot { - /** - * General validation timeout budget in seconds. - */ - timeout?: number; - /** - * Dependabot validation timeout budget in seconds. - */ - dependabotTimeout?: number; +export interface SessionsOpenHandoff { /** - * Whether CodeQL validation is enabled. + * Fetch a remote session and hand it off to a new local session. */ - codeqlEnabled?: boolean; + kind: "handoff"; + metadata: RemoteSessionMetadataValue; + options?: SessionOpenOptions; + taskType?: SessionsOpenHandoffTaskType; /** - * Whether code-review validation is enabled. + * In-process progress callback `(update) => void` invoked for each handoff step. Marked internal because a function reference cannot cross the JSON-RPC boundary. The host-side `handoffSession` is already declared as `AsyncGenerator`; the schema layer flattens it because it does not yet support streaming methods. The wire-clean replacement is to expose the AsyncGenerator directly (or use vscode-jsonrpc `$/progress` notifications) once the schema/transport layer supports it. + * + * @internal */ - codeReviewEnabled?: boolean; + onProgress?: OpaqueInProcessValue; /** - * Model used for code-review validation. + * In-process confirmation callback `(request) => boolean | Promise` invoked when the handoff needs the caller to confirm a non-fatal blocker (e.g. a repository mismatch between the current working directory and the remote session). Returning `true` proceeds with the handoff; returning `false` (or omitting the callback) aborts it. Marked internal because a function reference cannot cross the JSON-RPC boundary, for the same reasons as `onProgress`. + * + * @internal */ - codeReviewModel?: string; + onConfirm?: OpaqueInProcessValue; +} +/** + * Result of opening a session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionOpenResult". + */ +/** @experimental */ +export interface SessionOpenResult { + status: SessionsOpenStatus; /** - * Whether advisory validation is enabled. + * Opened session ID. Omitted when status is `not_found`. */ - advisoryEnabled?: boolean; + sessionId?: string; /** - * Whether secret-scanning validation is enabled. + * In-process SessionClientApi handle for the opened session, returned to CLI callers as a transitional shortcut. Marked internal so the public SDK surface does not expose it; SDK consumers should construct per-session clients from `sessionId` instead. + * + * @internal + * + * @internal */ - secretScanningEnabled?: boolean; + sessionApi?: OpaqueInProcessValue; /** - * Whether the memory-store tool is enabled. + * Startup prompts queued by user-level hook configs at session creation. Only populated when status is `created`; resumed sessions return an empty array. */ - memoryStoreEnabled?: boolean; + startupPrompts?: string[]; /** - * Whether the memory-vote tool is enabled. + * Remote session ID, present when status is `connected`. */ - memoryVoteEnabled?: boolean; -} -/** - * UUID prefix to resolve to a unique session ID. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsFindByPrefixRequest". - */ -/** @experimental */ -export interface SessionsFindByPrefixRequest { + remoteSessionId?: string; + metadata?: RemoteSessionMetadataValue; /** - * UUID prefix (>=7 hex chars, <36 chars). Returns the unique session ID, or undefined when there is no match or the prefix matches multiple sessions. + * Handoff progress steps, present when status is `handed_off`. */ - prefix: string; + progress?: SessionsOpenProgress[]; } /** - * Session ID matching the prefix, omitted when no unique match exists. + * `sessions.open` handoff progress update with step, status, and optional message. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsFindByPrefixResult". + * via the `definition` "SessionsOpenProgress". */ /** @experimental */ -export interface SessionsFindByPrefixResult { +export interface SessionsOpenProgress { + step: SessionsOpenProgressStep; + status: SessionsOpenProgressStatus; /** - * Omitted when no unique session matches the prefix (no match or ambiguous) + * Optional step message. */ - sessionId?: string; + message?: string; } /** - * GitHub task ID to look up. + * Plugin names (or specs) to disable in the session's authoritative working directory. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsFindByTaskIDRequest". + * via the `definition` "SessionPluginsDisableRequest". */ /** @experimental */ -export interface SessionsFindByTaskIDRequest { +export interface SessionPluginsDisableRequest { /** - * GitHub task ID to look up + * Plugin names or "plugin@marketplace" specs to disable. Unknown names are ignored. Non-marketplace direct installs cannot be disabled via this API; uninstall them instead. Plugin-owned MCP servers are stopped in active sessions immediately; other plugin contributions remain available until each session reloads plugins. */ - taskId: string; + names: string[]; } /** - * ID of the local session bound to the given GitHub task, or omitted when none. + * Plugin names (or specs) to enable in the session's authoritative working directory. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsFindByTaskIDResult". + * via the `definition` "SessionPluginsEnableRequest". */ /** @experimental */ -export interface SessionsFindByTaskIDResult { +export interface SessionPluginsEnableRequest { /** - * Omitted when no local session is bound to that GitHub task + * Plugin names or "plugin@marketplace" specs to enable. Unknown names are ignored. Non-marketplace direct installs are always enabled and cannot be toggled via this API. */ - sessionId?: string; + names: string[]; } /** - * Source session identifier to fork from, optional event-ID boundary, and optional friendly name for the new session. + * Plugin source resolved relative to the session's authoritative working directory. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsForkRequest". + * via the `definition` "SessionPluginsInstallRequest". */ /** @experimental */ -export interface SessionsForkRequest { - /** - * Source session ID to fork from - */ - sessionId: string; - /** - * Optional event ID boundary. When provided, the fork includes only events before this ID (exclusive). When omitted, all events are included. - */ - toEventId?: string; +export interface SessionPluginsInstallRequest { /** - * Optional friendly name to assign to the forked session. + * Plugin install spec. Accepts the same forms as the CLI: "plugin@marketplace" (marketplace install), "owner/repo" or "owner/repo:subpath" (GitHub direct), an http/https/ssh URL, or a local path. Direct (non-marketplace) installs are deprecated and will produce a deprecationWarning in the result. */ - name?: string; + source: string; } -/** - * Identifier and optional friendly name assigned to the newly forked session. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsForkResult". - */ + /** @experimental */ -export interface SessionsForkResult { - /** - * The new forked session's ID - */ - sessionId: string; +export interface SessionPluginsRetryManagedRequest { /** - * Friendly name assigned to the forked session, if any. + * "plugin@marketplace" specs to retry. Omit to retry every plugin the session's managed settings require. */ - name?: string; + plugins?: string[]; } /** - * Session ID whose board entry count should be returned. + * Per-plugin outcomes of retrying the plugins required by the session's managed settings. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsGetBoardEntryCountRequest". + * via the `definition` "SessionPluginsRetryManagedResult". */ /** @experimental */ -export interface SessionsGetBoardEntryCountRequest { +export interface SessionPluginsRetryManagedResult { /** - * Session ID whose board entry count should be returned. + * One entry per requested plugin, in request order. When no plugins were requested, one entry per plugin the managed settings require. */ - sessionId: string; + plugins: ManagedPluginRetryEntry[]; } /** - * Dynamic-context board entry count, when available. + * Outcome of the prune operation: deleted IDs, dry-run candidates, skipped IDs, total bytes freed, and the dry-run flag. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsGetBoardEntryCountResult". + * via the `definition` "SessionPruneResult". */ /** @experimental */ -export interface SessionsGetBoardEntryCountResult { +export interface SessionPruneResult { /** - * Board entry count, when available. + * Session IDs that were deleted (always empty in dry-run mode) */ - count?: number; -} -/** - * Bounded batch request for client-owned metadata from persisted local sessions. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsGetClientMetadataRequest". - */ -/** @experimental */ -export interface SessionsGetClientMetadataRequest { + deleted: string[]; /** - * Session IDs to inspect. Results preserve this order. - * - * @maxItems 1000 + * Session IDs that would be deleted in dry-run mode (always empty otherwise) */ - sessionIds: string[]; + candidates: string[]; /** - * Case-sensitive keys to project from each valid bag. Each key must be non-empty, at most 256 UTF-8 bytes, and outside the reserved `copilot/` and `github/` namespaces. Omit to return every entry. - * - * @maxItems 128 + * Session IDs that were skipped (e.g., named sessions) */ - keys?: string[]; -} -/** - * Session ID whose event-log file path to compute. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsGetEventFilePathRequest". - */ -/** @experimental */ -export interface SessionsGetEventFilePathRequest { + skipped: string[]; /** - * Session ID whose event-log file path to compute + * Total bytes freed (actual when not dry-run, projected when dry-run) */ - sessionId: string; -} -/** - * Absolute path to the session's events.jsonl file on disk. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsGetEventFilePathResult". - */ -/** @experimental */ -export interface SessionsGetEventFilePathResult { + freedBytes: number; /** - * Absolute path to the session's events.jsonl file + * True when no deletions were actually performed */ - filePath: string; + dryRun: boolean; } /** - * Optional working-directory context used to score session relevance. + * Existing delegation guidance for an account without delegation access. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsGetLastForContextRequest". + * via the `definition` "SessionQuotaDelegateWarning". */ /** @experimental */ -export interface SessionsGetLastForContextRequest { - context?: SessionContext; +export interface SessionQuotaDelegateWarning { + /** + * User-facing guidance. + */ + text: string; + /** + * Link to upgrade the account. + */ + url: string; } /** - * Most-relevant session ID for the supplied context, or omitted when no sessions exist. + * The incumbent session-owned quota and account projection. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsGetLastForContextResult". + * via the `definition` "SessionQuotaProjection". */ /** @experimental */ -export interface SessionsGetLastForContextResult { +export interface SessionQuotaProjection { /** - * Most-relevant session ID for the supplied context, or omitted when no sessions exist + * Known quota snapshots, keyed by the provider's quota type. */ - sessionId?: string; + snapshots: { + [k: string]: SessionQuotaSnapshot | undefined; + }; + /** + * Provider-owned account quota state, including snapshots without numeric balances. + */ + providerQuotas?: ProviderQuotaState[]; + /** + * Whether the account uses the free limited Copilot plan. + */ + isFreeUser: boolean; + /** + * Whether the account uses token-based billing. + */ + isTbbUser: boolean; + planTier: SessionQuotaPlanTier; + /** + * Whether premium-request costs are billable. + */ + premiumRequestsBillable: boolean; + /** + * Whether model cost columns should be shown. + */ + modelCostColumnVisible: boolean; + /** + * Whether the account can delegate tasks to GitHub. + */ + delegateAvailable: boolean; + /** + * Whether the account can sign up for Copilot Free. + */ + canSignupForCopilotFree: boolean; + /** + * Whether dynamic workflows are enabled for the active account. + */ + dynamicWorkflowsEnabled: boolean; + /** + * Whether dynamic workflows are visible under the session's feature flags. + */ + dynamicWorkflowsUiVisible: boolean; + /** + * Upgrade link for a free account. + */ + upgradeUrl?: string; + delegateWarning?: SessionQuotaDelegateWarning; } /** - * Session ID whose persisted metadata should be read. + * Session quota snapshot, preserving the incumbent numeric units and reset metadata. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsGetMetadataRequest". + * via the `definition` "SessionQuotaSnapshot". */ /** @experimental */ -export interface SessionsGetMetadataRequest { +export interface SessionQuotaSnapshot { /** - * Session ID to inspect + * Whether the entitlement is unlimited. */ - sessionId: string; + isUnlimitedEntitlement: boolean; + /** + * Entitled quantity in this quota's units. + */ + entitlementRequests: number; + /** + * Consumed quantity in this quota's units. + */ + usedRequests: number; + /** + * Whether usage is allowed after quota exhaustion. + */ + usageAllowedWithExhaustedQuota: boolean; + /** + * Additional usage in this quota's units. + */ + overage: number; + /** + * Whether additional usage is allowed after quota exhaustion. + */ + overageAllowedWithExhaustedQuota: boolean; + /** + * Percentage of the entitlement remaining. + */ + remainingPercentage: number; + /** + * Quota reset time in milliseconds since the Unix epoch, when known. + */ + resetDateEpochMs?: number; + /** + * Whether the reset time is estimated. + */ + resetDateEstimated?: boolean; + /** + * Whether the provider reports available quota. + */ + hasQuota?: boolean; + /** + * Whether this quota uses token-based billing. + */ + tokenBasedBilling?: boolean; + /** + * Additional-usage budget cap, when provided. + */ + overageEntitlement?: number; } /** - * Persisted local session metadata when the session exists. + * Session IDs to close, deactivate, and delete from disk. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsGetMetadataResult". + * via the `definition` "SessionsBulkDeleteRequest". */ /** @experimental */ -export interface SessionsGetMetadataResult { - session?: LocalSessionMetadataValue; +export interface SessionsBulkDeleteRequest { + /** + * Session IDs to close, deactivate, and delete from disk + */ + sessionIds: string[]; } /** - * Session ID to look up the persisted remote-steerable flag for. + * Session IDs to test for live in-use locks. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsGetPersistedRemoteSteerableRequest". + * via the `definition` "SessionsCheckInUseRequest". */ /** @experimental */ -export interface SessionsGetPersistedRemoteSteerableRequest { +export interface SessionsCheckInUseRequest { /** - * Session ID to look up the persisted remote-steerable flag for + * Session IDs to test for live in-use locks */ - sessionId: string; + sessionIds: string[]; } /** - * The session's persisted remote-steerable flag, or omitted when no value has been persisted. + * Session IDs from the input set that are currently in use by another process. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsGetPersistedRemoteSteerableResult". + * via the `definition` "SessionsCheckInUseResult". */ /** @experimental */ -export interface SessionsGetPersistedRemoteSteerableResult { +export interface SessionsCheckInUseResult { /** - * The session's persisted remote-steerable flag if recorded; omitted when no value has been persisted + * Session IDs from the input set that are currently held by another running process via an alive lock file */ - remoteSteerable?: boolean; + inUse: string[]; } /** - * Map of sessionId -> on-disk size in bytes for each session's workspace directory. + * Session ID to close. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionSizes". + * via the `definition` "SessionsCloseRequest". */ /** @experimental */ -export interface SessionSizes { +export interface SessionsCloseRequest { /** - * Map of sessionId -> on-disk size in bytes for the session's workspace directory + * Session ID to close */ - sizes: { - [k: string]: number | undefined; - }; + sessionId: string; } /** - * Limit for non-empty local session IDs. + * Closes a session: emits shutdown, flushes pending events to disk, releases the in-use lock, disposes the active session. Idempotent: succeeds even if the session is not currently active. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsListNonEmptySessionIdsRequest". + * via the `definition` "SessionsCloseResult". */ /** @experimental */ -export interface SessionsListNonEmptySessionIdsRequest { - /** - * Maximum number of session IDs to return. - */ - limit?: number; -} +export interface SessionsCloseResult {} /** - * Recent local session IDs that contain user-visible history. + * Identity, state location and starting context for a workspace record. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsListNonEmptySessionIdsResult". + * via the `definition` "SessionsCreateWorkspaceRequest". */ /** @experimental */ -export interface SessionsListNonEmptySessionIdsResult { +export interface SessionsCreateWorkspaceRequest { /** - * Session IDs ordered newest-first. + * Session ID the workspace record belongs to */ - sessionIds: string[]; + sessionId: string; + /** + * Directory the session's state is written under when no session filesystem provider is configured. Ignored when a provider is configured; the provider's session state path is used instead. + */ + sessionStatePath: string; + /** + * `windows` (any letter case) selects Windows path rules. Any other value selects POSIX path rules. + */ + convention: string; + context?: SessionWorkingDirectoryContextWithClient; + /** + * User-supplied display name for the workspace + */ + name?: string; } /** - * Optional source filter, metadata-load limit, and context filter applied to the returned sessions. + * A working-directory context together with the client that produced it. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsListRequest". + * via the `definition` "SessionWorkingDirectoryContextWithClient". */ /** @experimental */ -export interface SessionsListRequest { - source?: SessionSource; +export interface SessionWorkingDirectoryContextWithClient { /** - * When provided, only the first N local sessions (sorted by modification time, newest first) load full metadata; remaining sessions return basic info only. Use 0 to return only basic info for every local session. Has no effect on remote entries (which always carry their full shape). + * Current working directory path */ - metadataLimit?: number; - filter?: SessionListFilter; + cwd: string; /** - * When true, include detached maintenance sessions. Defaults to false for user-facing session lists. + * Root directory of the git repository */ - includeDetached?: boolean; + gitRoot?: string; /** - * Only meaningful when `source` includes remote. When true, propagates errors from the remote service instead of silently returning an empty remote list. Defaults to false. + * Repository identifier derived from the git remote URL */ - throwOnError?: boolean; + repository?: string; + /** + * Hosting platform type of the repository + */ + hostType?: string; + /** + * Current git branch name + */ + branch?: string; + /** + * Raw host string from the git remote URL + */ + repositoryHost?: string; + /** + * Head commit of the current git branch + */ + headCommit?: string; + /** + * Merge-base commit SHA + */ + baseCommit?: string; + /** + * Name of the client that created the session + */ + clientName?: string; } /** - * Active session ID whose deferred repo-level hooks should be loaded. + * The workspace record that was written. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsLoadDeferredRepoHooksRequest". + * via the `definition` "SessionsCreateWorkspaceResult". */ /** @experimental */ -export interface SessionsLoadDeferredRepoHooksRequest { +export interface SessionsCreateWorkspaceResult { /** - * Active session ID whose deferred repo-level hooks should be loaded + * The created workspace record, as JSON */ - sessionId: string; + workspaceJson: string; } /** - * Where the session's state lives, as a root directory and the session ID under it. + * Session ID to delete from disk. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsLoadWorkspaceRequest". + * via the `definition` "SessionsDeleteRequest". */ /** @experimental */ -export interface SessionsLoadWorkspaceRequest { +export interface SessionsDeleteRequest { /** - * Root directory every session's state directory sits under + * Session ID to delete */ - sessionsHome: string; + sessionId: string; /** - * Session ID naming the state directory under the sessions home. Rejected when it is absolute or contains a parent component, so it cannot escape the sessions home. + * Internal resolved session directory path to delete */ - sessionId: string; + sessionPath?: string | null; } /** - * The workspace record on disk, omitted when the session has none. + * Session metadata records to enrich with summary and context information. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsLoadWorkspaceResult". + * via the `definition` "SessionsEnrichMetadataRequest". */ /** @experimental */ -export interface SessionsLoadWorkspaceResult { +export interface SessionsEnrichMetadataRequest { /** - * The workspace record, as JSON. Omitted when the record does not exist. + * Session metadata records to enrich. Records that already have summary and context are returned unchanged. */ - workspaceJson?: string; + sessions: LocalSessionMetadataValue[]; } /** - * Age threshold and optional flags controlling which old sessions are pruned (or simulated when dryRun is true). + * New auth credentials to install on the session. Omit to leave credentials unchanged. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsPruneOldRequest". + * via the `definition` "SessionSetCredentialsParams". */ /** @experimental */ -export interface SessionsPruneOldRequest { - /** - * Delete sessions whose modifiedTime is at least this many days old - */ - olderThanDays: number; - /** - * When true, only report what would be deleted without performing any deletion - */ - dryRun?: boolean; - /** - * When true, named sessions (set via /rename) are also eligible for pruning - */ - includeNamed?: boolean; - /** - * Session IDs that should never be considered for pruning - */ - excludeSessionIds?: string[]; +export interface SessionSetCredentialsParams { + credentials?: SettableAuthInfo; } /** - * Pagination options for reading an inactive or active local session's persisted event journal. + * Token authentication accepted by session.gitHubAuth.setCredentials. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsReadPersistedEventsRequest". + * via the `definition` "SettableTokenAuthInfo". */ /** @experimental */ -export interface SessionsReadPersistedEventsRequest { +export interface SettableTokenAuthInfo { /** - * Session ID whose persisted event journal should be read. + * SDK-side token authentication; the host configured the token directly via the SDK. */ - sessionId: string; + type: "token"; /** - * Opaque, process-local, single-use cursor returned by the previous persisted-event read. Omit on the first call and issue continuations sequentially; reusing the same cursor returns an expired terminal page. + * Authentication host. */ - cursor?: string; + host: string; /** - * Maximum number of events to return in this batch (1–1000, default 200). Pages may contain fewer events to keep the serialized event array within a soft 1 MiB budget including resolved binary assets; one oversized event is returned alone to guarantee progress. + * The token value itself. Treat as a secret. */ - max?: number; - direction?: EventsReadDirection; + token: string; + copilotUser?: CopilotUserResponse; } /** - * Session ID whose in-use lock should be released. + * Indicates whether the credential update succeeded. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsReleaseLockRequest". + * via the `definition` "SessionSetCredentialsResult". */ /** @experimental */ -export interface SessionsReleaseLockRequest { +export interface SessionSetCredentialsResult { /** - * Session ID whose in-use lock should be released + * Whether the operation succeeded */ - sessionId: string; -} -/** - * Release the in-use lock held by this process for the given session. No-op when this process does not currently hold a lock for the session. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsReleaseLockResult". - */ -/** @experimental */ -export interface SessionsReleaseLockResult {} -/** - * Active session ID and an optional flag for deferring repo-level hooks until folder trust. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsReloadPluginHooksRequest". - */ -/** @experimental */ -export interface SessionsReloadPluginHooksRequest { - /** - * Active session ID to reload hooks for - */ - sessionId: string; + success: boolean; /** - * When true, skip repo-level hooks. Use before folder trust is confirmed; loadDeferredRepoHooks loads them post-trust. + * Whether the session ended up with a populated `copilotUser` for the installed credentials. `true` when the supplied credential already carried `copilotUser` or it was successfully re-resolved server-side. `false` when the credential is installed without `copilotUser` — either re-resolution failed, or the variant cannot be re-resolved from the credential alone (only the raw-token variants `token`, `env`, and `gh-cli` can). In both `false` cases the token swap still applied, but plan/quota/billing metadata is degraded. Present whenever a credential was supplied; omitted only when no credential was supplied (no-op call). */ - deferRepoHooks?: boolean; + copilotUserResolved?: boolean; } /** - * Reload all hooks (user, plugin, optionally repo) and apply them to the active session. Call after installing or removing plugins so their hooks take effect immediately. No-op when no active session matches the given sessionId. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsReloadPluginHooksResult". - */ -/** @experimental */ -export interface SessionsReloadPluginHooksResult {} -/** - * Session ID whose pending events should be flushed to disk. + * Availability of built-in job tools surfaced to boundary consumers. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsSaveRequest". + * via the `definition` "SessionSettingsBuiltInToolAvailabilitySnapshot". */ /** @experimental */ -export interface SessionsSaveRequest { +export interface SessionSettingsBuiltInToolAvailabilitySnapshot { /** - * Session ID whose pending events should be flushed to disk + * Whether the report-progress tool is available. */ - sessionId: string; + reportProgress?: boolean; + /** + * Whether the create-pull-request tool is available. + */ + createPullRequest?: boolean; } /** - * Flush a session's pending events to disk. No-op when no writer exists for the session (e.g., already closed). - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsSaveResult". - */ -/** @experimental */ -export interface SessionsSaveResult {} -/** - * Manager-wide additional plugins to register; replaces any previously-configured set. + * Named Rust-owned settings predicate to evaluate for this session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsSetAdditionalPluginsRequest". + * via the `definition` "SessionSettingsEvaluatePredicateRequest". */ /** @experimental */ -export interface SessionsSetAdditionalPluginsRequest { +export interface SessionSettingsEvaluatePredicateRequest { + name: SessionSettingsPredicateName; /** - * Manager-wide additional plugins to register. Replaces any previously-configured set. Pass an empty array to clear. + * Tool name for tool-scoped predicates such as trivial-change handling. */ - plugins: InstalledPlugin[]; + toolName?: string; } /** - * Replace the manager-wide additional plugins. New session creations and subsequent hook reloads see the new set; already-running sessions keep their existing hook installation until the next reload. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsSetAdditionalPluginsResult". - */ -/** @experimental */ -export interface SessionsSetAdditionalPluginsResult {} -/** - * Patch for the singleton's steering state. + * Result of evaluating a Rust-owned settings predicate. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsSetRemoteControlSteeringRequest". + * via the `definition` "SessionSettingsEvaluatePredicateResult". */ /** @experimental */ -export interface SessionsSetRemoteControlSteeringRequest { +export interface SessionSettingsEvaluatePredicateResult { /** - * Target steering state. Today only `true` is actionable on the underlying exporter; `false` is reserved for future use. + * Whether the named settings predicate evaluated to enabled. */ enabled: boolean; } /** - * Parameters for attaching the remote-control singleton to a session. + * Redacted job settings for a session. The job nonce is excluded. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsStartRemoteControlRequest". + * via the `definition` "SessionSettingsJobSnapshot". */ /** @experimental */ -export interface SessionsStartRemoteControlRequest { - /** - * Local session id to attach remote control to. - */ - sessionId: string; - config: RemoteControlConfig; -} - -/** @experimental */ -export interface SessionsStopRemoteControlRequest { +export interface SessionSettingsJobSnapshot { /** - * When provided, the stop is rejected unless the singleton currently points at this session id (compare-and-swap semantics). + * GitHub Actions event type for the job. */ - expectedSessionId?: string; + eventType?: string; /** - * When true, the singleton is unconditionally torn down regardless of `expectedSessionId`. Use during shutdown or explicit `/remote off`. + * Whether this is the workflow's trigger job. */ - force?: boolean; + isTriggerJob?: boolean; + builtInToolAvailability?: SessionSettingsBuiltInToolAvailabilitySnapshot; } /** - * Parameters for atomically rebinding the remote-control singleton. + * Redacted model routing settings for a session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsTransferRemoteControlRequest". + * via the `definition` "SessionSettingsModelSnapshot". */ /** @experimental */ -export interface SessionsTransferRemoteControlRequest { - /** - * Local session id to point remote control at. - */ - toSessionId: string; +export interface SessionSettingsModelSnapshot { /** - * When provided, the transfer is rejected unless the singleton currently points at this session id (compare-and-swap semantics to avoid clobbering newer state). + * Selected model identifier. */ - expectedFromSessionId?: string; -} -/** - * Where the session's state lives, plus workspace-schema fields to merge into its workspace record. Stored keys outside the schema are not preserved, and a stored `fork_count` is never replaced. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsUpdateWorkspaceFieldsRequest". - */ -/** @experimental */ -export interface SessionsUpdateWorkspaceFieldsRequest { + model?: string; /** - * Root directory every session's state directory sits under + * Default reasoning effort for the selected model. */ - sessionsHome: string; + defaultReasoningEffort?: string; /** - * Session ID naming the state directory under the sessions home. Rejected when it is absolute or contains a parent component, so it cannot escape the sessions home. + * Agent job identifier for the session. */ - sessionId: string; + instanceId?: string; /** - * Workspace-schema fields to merge into the record, as a JSON object. Fields the object omits keep their stored values, except stored keys outside the schema are not preserved and a stored `fork_count` is never replaced. + * Agent service callback URL for job and progress updates. */ - fieldsJson: string; + callbackUrl?: string; } /** - * The merge completed. The record carries the supplied workspace-schema fields, but a stored `fork_count` stays. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionsUpdateWorkspaceFieldsResult". - */ -/** @experimental */ -export interface SessionsUpdateWorkspaceFieldsResult {} -/** - * Telemetry engagement ID for the session, when available. + * Online-evaluation settings safe to expose across the SDK boundary. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionTelemetryEngagement". + * via the `definition` "SessionSettingsOnlineEvaluationSnapshot". */ /** @experimental */ -export interface SessionTelemetryEngagement { +export interface SessionSettingsOnlineEvaluationSnapshot { /** - * Current telemetry engagement ID, when available. + * Whether online evaluation is disabled. */ - engagementId?: string; + disableOnlineEvaluation?: boolean; + /** + * Whether online-evaluation output-file generation is enabled. + */ + enableOnlineEvaluationOutputFile?: boolean; } /** - * Patch of mutable session options to apply to the running session. + * Redacted repository and GitHub host settings for a session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionUpdateOptionsParams". + * via the `definition` "SessionSettingsRepoSnapshot". */ /** @experimental */ -export interface SessionUpdateOptionsParams { - /** - * The model ID to use for assistant turns. - */ - model?: string; - modelCapabilitiesOverrides?: ModelCapabilitiesOverride; +export interface SessionSettingsRepoSnapshot { /** - * Reasoning effort for the selected model. CAPI values are model-defined and validated against the selected model; BYOK providers may define additional values. When omitted, no effort override is applied. + * Repository name. */ - reasoningEffort?: string; - reasoningSummary?: OptionsUpdateReasoningSummary; - verbosity?: Verbosity; + name?: string; /** - * Identifier of the client driving the session. + * GitHub repository database ID. */ - clientName?: string; + id?: number; /** - * Identifier sent to LSP-style integrations. + * Checked-out repository branch. */ - lspClientName?: string; + branch?: string; /** - * Stable integration identifier used for analytics and rate-limit attribution. + * Checked-out commit SHA. */ - integrationId?: string; + commit?: string; /** - * Map of feature-flag IDs to their boolean enabled state. + * Whether the repository is writable. */ - featureFlags?: { - [k: string]: boolean | undefined; - }; + readWrite?: boolean; /** - * Whether experimental capabilities are enabled. + * Repository owner login. */ - isExperimentalMode?: boolean; - provider?: ProviderConfig; - capi?: CapiSessionOptions; + ownerName?: string; /** - * Absolute working-directory path for shell tools. + * GitHub repository owner database ID. */ - workingDirectory?: string; + ownerId?: number; /** - * Allowlist of tool names available to this session. + * GitHub server base URL. */ - availableTools?: string[]; + serverUrl?: string; /** - * Denylist of tool names for this session. + * GitHub server host name. */ - excludedTools?: string[]; + host?: string; /** - * Built-in subagent names to include in this session. When specified, only these built-ins are available, subject to runtime availability and exclusions. Custom agents with the same name remain available. Set to null to remove the allowlist restriction. + * Protocol used to access the GitHub host. */ - includedBuiltinAgents?: string[] | null; + hostProtocol?: string; /** - * Built-in subagent names to exclude from this session. Excluded built-ins are hidden from agent discovery and cannot be dispatched unless a custom agent with the same name is available. + * GitHub secret-scanning service URL. */ - excludedBuiltinAgents?: string[]; - toolFilterPrecedence?: OptionsUpdateToolFilterPrecedence; + secretScanningUrl?: string; /** - * Whether shell-script safety heuristics are enabled. + * Number of commits in the pull request. */ - enableScriptSafety?: boolean; - shell?: ShellOptions; + prCommitCount?: number; +} +/** + * Redacted, serializable view of session runtime settings for SDK boundary consumers. Secrets and raw feature flags are intentionally excluded. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionSettingsSnapshot". + */ +/** @experimental */ +export interface SessionSettingsSnapshot { /** - * @deprecated - * Use shell.initProfile instead. Shell init profile (`None` or `NonInteractive`). + * Agent runtime version selector copied from the session settings, such as `latest` or a runtime release identifier. */ - shellInitProfile?: string; + version?: string; /** - * PowerShell process flags applied to built-in and user-requested shell commands. + * Name of the SDK client that created the session. */ - shellProcessFlags?: string[]; - sandboxConfig?: SandboxConfig; + clientName?: string; /** - * Origin of the sandbox choice. Settings-derived origins (never_configured, user_enabled, user_disabled, repository_policy) let managed policy floor a host preference; explicit below-floor changes remain policy conflicts unless a session opt-out is authorized. Also used for telemetry provenance. - * - * @experimental + * Session timeout in milliseconds. */ - sandboxConfigSource?: SandboxConfigSource; + timeoutMs?: number; /** - * Whether interactive shell sessions are logged. + * Session start time as Unix epoch milliseconds. */ - logInteractiveShells?: boolean; - envValueMode?: OptionsUpdateEnvValueMode; - /** - * Whether to include instructions from every MCP server in the system prompt instead of only allowlisted servers. - */ - allowAllMcpServerInstructions?: boolean; - /** - * Explicit discovery-only skill roots, not filesystem grants. Available without enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. - */ - skillDirectories?: string[]; - /** - * Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. - */ - agentDirectories?: string[]; - /** - * Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without enableConfigDiscovery, subject to instruction/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. - */ - instructionDirectories?: string[]; - /** - * Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without enableConfigDiscovery or enableFileHooks, which controls repository-origin hooks only; hook/managed disables still apply. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. - */ - hookDirectories?: string[]; - /** - * Skill scan directories and descendants excluded from discovery. Supports `~`-relative paths. - */ - ignoredSkillsLocations?: string[]; - /** - * Built-in skill names to include in this session. When specified, only these runtime-bundled skills are available. Skills from other sources with the same name remain available. Set to null to remove the allowlist restriction. - */ - includedBuiltinSkills?: string[] | null; - /** - * Skill IDs that should be excluded from this session. - */ - disabledSkills?: string[]; - /** - * Whether to discover custom instructions on demand after successful file views (AGENTS.md / CLAUDE.md / .github/copilot-instructions.md surfacing). Combined with `skipCustomInstructions`. - */ - enableOnDemandInstructionDiscovery?: boolean; - /** - * Maximum decoded byte size of a single model-facing binary tool result (e.g. an image) persisted inline in session events and re-presented to the model on later turns / resume. Larger results are persisted as a metadata-only marker and shown to the model as a short text note. Defaults to 10 MB. - */ - maxInlineBinaryBytes?: number; - /** - * Full set of installed plugins for the session. Replaces the existing list; the runtime invalidates the skills cache only when the list materially changes. - */ - installedPlugins?: SessionInstalledPlugin[]; - /** - * Whether to default custom agents to local-only execution. - */ - customAgentsLocalOnly?: boolean; - /** - * When true, the selected custom agent's prompt is not injected into the user message (skill context is still injected). Used by automation triggers where the agent prompt is already in the problem statement. - */ - suppressCustomAgentPrompt?: boolean; - /** - * Whether to skip loading custom instruction sources. - */ - skipCustomInstructions?: boolean; - /** - * Instruction source IDs to exclude from the system prompt. - */ - disabledInstructionSources?: string[]; - /** - * Whether to include the `Co-authored-by` trailer in commit messages. - */ - coauthorEnabled?: boolean; - /** - * Optional path for trajectory output. - */ - trajectoryFile?: string; - /** - * Whether to stream model responses. - */ - enableStreaming?: boolean; - /** - * Override URL for the Copilot API endpoint. - */ - copilotUrl?: string; - /** - * Whether to disable the `ask_user` tool (encourages autonomous behavior). - */ - askUserDisabled?: boolean; - /** - * Whether to allow auto-mode continuation across turns. - */ - continueOnAutoMode?: boolean; - /** - * Whether the session is running in an interactive UI. - */ - runningInInteractiveMode?: boolean; - /** - * Whether to surface reasoning-summary events from the model. - */ - enableReasoningSummaries?: boolean; - /** - * Runtime context discriminator (e.g., `cli`, `actions`). - */ - agentContext?: string; - /** - * Override directory for the session-events log. When unset, the runtime's default events log directory is used. - */ - eventsLogDirectory?: string; - /** - * Whether subagent callback events should be forwarded into the session event log sink. - */ - eventsLogIncludesSubagents?: boolean; - /** - * Additional content-exclusion policies to merge into the session's policy set. - * - * @experimental - */ - additionalContentExclusionPolicies?: OptionsUpdateAdditionalContentExclusionPolicy[]; + startTimeMs?: number; + repo: SessionSettingsRepoSnapshot; + model: SessionSettingsModelSnapshot; + validation: SessionSettingsValidationSnapshot; + job: SessionSettingsJobSnapshot; + onlineEvaluation: SessionSettingsOnlineEvaluationSnapshot; +} +/** + * Redacted validation and memory-tool settings for a session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionSettingsValidationSnapshot". + */ +/** @experimental */ +export interface SessionSettingsValidationSnapshot { /** - * Whether to expose the `manage_schedule` tool to the agent. The runtime always owns the per-session schedule registry; this flag only controls tool exposure (typically gated to staff users). + * General validation timeout budget in seconds. */ - manageScheduleEnabled?: boolean; + timeout?: number; /** - * Replaces the session's capability set with the given list. Use to enable or disable capabilities mid-session (e.g., remove `memory` for reproducible scripted runs). Omit the field to leave the existing capability set unchanged. + * Dependabot validation timeout budget in seconds. */ - sessionCapabilities?: SessionCapability[]; + dependabotTimeout?: number; /** - * Whether to skip embedding retrieval pipeline initialization and execution. + * Whether CodeQL validation is enabled. */ - skipEmbeddingRetrieval?: boolean; + codeqlEnabled?: boolean; /** - * Organization-level custom instructions to inject into the system prompt. + * Whether code-review validation is enabled. */ - organizationCustomInstructions?: string; + codeReviewEnabled?: boolean; /** - * Whether to enable repository-origin file hooks from `.github/hooks/` and trusted repository-configured roots. Does not control explicit hookDirectories or SDK callback hooks. + * Model used for code-review validation. */ - enableFileHooks?: boolean; + codeReviewModel?: string; /** - * Whether to enable host git operations (context resolution, child repo scanning, git info in system prompt). + * Whether advisory validation is enabled. */ - enableHostGitOperations?: boolean; + advisoryEnabled?: boolean; /** - * Whether to enable cross-session store writes and reads. + * Whether secret-scanning validation is enabled. */ - enableSessionStore?: boolean; + secretScanningEnabled?: boolean; /** - * Whether skill loading is enabled. Explicit false disables every source, including explicit SDK roots and a bound SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless explicit SDK skill roots or an SDK skill provider are supplied. + * Whether the memory-store tool is enabled. */ - enableSkills?: boolean; - contextTier?: OptionsUpdateContextTier; + memoryStoreEnabled?: boolean; /** - * Optional session limits. Pass null to clear the session limits. + * Whether the memory-vote tool is enabled. */ - sessionLimits?: SessionLimitsConfig | null; + memoryVoteEnabled?: boolean; } /** - * Indicates whether the session options patch was applied successfully. + * UUID prefix to resolve to a unique session ID. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionUpdateOptionsResult". + * via the `definition` "SessionsFindByPrefixRequest". */ /** @experimental */ -export interface SessionUpdateOptionsResult { - /** - * Whether the operation succeeded - */ - success: boolean; +export interface SessionsFindByPrefixRequest { /** - * Number of hooks loaded from installed plugins, returned when installedPlugins is updated + * UUID prefix (>=7 hex chars, <36 chars). Returns the unique session ID, or undefined when there is no match or the prefix matches multiple sessions. */ - pluginHookCount?: number; + prefix: string; } /** - * Outcome of an atomic user or repository settings edit. + * Session ID matching the prefix, omitted when no unique match exists. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SettingsEditResult". + * via the `definition` "SessionsFindByPrefixResult". */ /** @experimental */ -/** @internal */ -export interface SettingsEditResult { - status: SettingsEditStatus; +export interface SessionsFindByPrefixResult { + /** + * Omitted when no unique session matches the prefix (no match or ambiguous) + */ + sessionId?: string; } /** - * User-requested shell execution cancellation handle. + * GitHub task ID to look up. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ShellCancelUserRequestedRequest". + * via the `definition` "SessionsFindByTaskIDRequest". */ /** @experimental */ -export interface ShellCancelUserRequestedRequest { +export interface SessionsFindByTaskIDRequest { /** - * Request ID previously passed to executeUserRequested + * GitHub task ID to look up */ - requestId: string; + taskId: string; } /** - * Shell command to run, with optional working directory and timeout in milliseconds. Spawn failures return an RPC error. + * ID of the local session bound to the given GitHub task, or omitted when none. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ShellExecRequest". + * via the `definition` "SessionsFindByTaskIDResult". */ /** @experimental */ -export interface ShellExecRequest { - /** - * Shell command to execute - */ - command: string; - /** - * Working directory (defaults to session working directory) - */ - cwd?: string; +export interface SessionsFindByTaskIDResult { /** - * Timeout in milliseconds (default: 30000) + * Omitted when no local session is bound to that GitHub task */ - timeout?: number; + sessionId?: string; } /** - * Identifier of the spawned shell process, usable with shell.kill while the process is running. + * Source session identifier to fork from, optional event-ID boundary, and optional friendly name for the new session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ShellExecResult". + * via the `definition` "SessionsForkRequest". */ /** @experimental */ -export interface ShellExecResult { +export interface SessionsForkRequest { /** - * Identifier usable with shell.kill while the process is running + * Source session ID to fork from */ - processId: string; + sessionId: string; + /** + * Optional event ID boundary. When provided, the fork includes only events before this ID (exclusive). When omitted, all events are included. + */ + toEventId?: string; + /** + * Optional friendly name to assign to the forked session. + */ + name?: string; } /** - * User-requested shell command and cancellation handle. + * Identifier and optional friendly name assigned to the newly forked session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ShellExecuteUserRequestedRequest". + * via the `definition` "SessionsForkResult". */ /** @experimental */ -export interface ShellExecuteUserRequestedRequest { +export interface SessionsForkResult { /** - * Caller-provided cancellation handle for this execution + * The new forked session's ID */ - requestId: string; + sessionId: string; /** - * Shell command to execute + * Friendly name assigned to the forked session, if any. */ - command: string; + name?: string; } /** - * Identifier of a process previously returned by "shell.exec" and the signal to send. + * Session ID whose board entry count should be returned. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ShellKillRequest". + * via the `definition` "SessionsGetBoardEntryCountRequest". */ /** @experimental */ -export interface ShellKillRequest { +export interface SessionsGetBoardEntryCountRequest { /** - * Process identifier returned by shell.exec + * Session ID whose board entry count should be returned. */ - processId: string; - signal?: ShellKillSignal; + sessionId: string; } /** - * Indicates whether the signal was delivered; false if the process was unknown or already exited. + * Dynamic-context board entry count, when available. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ShellKillResult". + * via the `definition` "SessionsGetBoardEntryCountResult". */ /** @experimental */ -export interface ShellKillResult { +export interface SessionsGetBoardEntryCountResult { /** - * Whether the signal was sent successfully + * Board entry count, when available. */ - killed: boolean; + count?: number; } /** - * Parameters for shutting down the session + * Bounded batch request for client-owned metadata from persisted local sessions. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ShutdownRequest". + * via the `definition` "SessionsGetClientMetadataRequest". */ /** @experimental */ -export interface ShutdownRequest { - type?: ShutdownType; +export interface SessionsGetClientMetadataRequest { /** - * Optional human-readable reason. Typically the message of the error that triggered shutdown when type is 'error'. + * Session IDs to inspect. Results preserve this order. + * + * @maxItems 1000 */ - reason?: string; + sessionIds: string[]; /** - * Dispatch deferred sessionEnd hooks in the background with their full per-hook timeoutSec instead of awaiting them under the short shared shutdown budget. Set this when the host process keeps running after the session closes (for example the CLI's /clear), so a slow hook neither blocks the close nor is aborted. Hooks still detached when the process later exits are terminated with it. Defaults to false. + * Case-sensitive keys to project from each valid bag. Each key must be non-empty, at most 256 UTF-8 bytes, and outside the reserved `copilot/` and `github/` namespaces. Omit to return every entry. + * + * @maxItems 128 */ - detachSessionEndHooks?: boolean; + keys?: string[]; } /** - * Skill metadata available to a session, with name, description, source, enabled/invocable state, path, plugin, and argument hint. + * Session ID whose event-log file path to compute. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "Skill". + * via the `definition` "SessionsGetEventFilePathRequest". */ /** @experimental */ -export interface Skill { - /** - * Unique identifier for the skill - */ - name: string; - /** - * Canonical slash command name used to invoke the skill, without the leading '/' - */ - commandName?: string; - /** - * Description of what the skill does - */ - description: string; - source: SkillSource; - /** - * Whether the skill can be invoked by the user as a slash command - */ - userInvocable: boolean; - /** - * Whether the skill is currently enabled - */ - enabled: boolean; - /** - * Absolute path to the skill file - */ - path?: string; - /** - * Name of the plugin that provides the skill, when source is 'plugin' - */ - pluginName?: string; +export interface SessionsGetEventFilePathRequest { /** - * Optional freeform hint describing the skill's expected arguments, from the `argument-hint` frontmatter field + * Session ID whose event-log file path to compute */ - argumentHint?: string; + sessionId: string; } /** - * Applies exactly one retained verified Skill installation plan. + * Absolute path to the session's events.jsonl file on disk. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillApplyInstallRequest". + * via the `definition` "SessionsGetEventFilePathResult". */ /** @experimental */ -export interface SkillApplyInstallRequest { - contract: CatalogClientContract; - /** - * Opaque original plan, consumed once. - */ - planHandle: string; +export interface SessionsGetEventFilePathResult { /** - * Same existing selected session as planning. + * Absolute path to the session's events.jsonl file */ - policySessionId: string; + filePath: string; } /** - * One-use application of the exact retained Skill removal plan. + * Optional working-directory context used to score session relevance. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillApplyUninstallRequest". + * via the `definition` "SessionsGetLastForContextRequest". */ /** @experimental */ -export interface SkillApplyUninstallRequest { - contract: CatalogClientContract; - /** - * Opaque original removal plan, consumed once. - */ - planHandle: string; - /** - * Same existing selected session as removal preparation. - */ - policySessionId: string; +export interface SessionsGetLastForContextRequest { + context?: SessionContext; } /** - * Canonical directory where skills can be discovered or created, with scope, preference, and optional project path. + * Most-relevant session ID for the supplied context, or omitted when no sessions exist. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillDiscoveryPath". + * via the `definition` "SessionsGetLastForContextResult". */ /** @experimental */ -export interface SkillDiscoveryPath { - /** - * Absolute path of the create/discovery target (may not exist on disk yet) - */ - path: string; - scope: SkillDiscoveryScope; - /** - * Whether this is the canonical directory to create a new skill in its tier. At most one entry per tier is preferred; the `personal-agents` and `custom` scopes are never preferred. - */ - preferredForCreation: boolean; +export interface SessionsGetLastForContextResult { /** - * The input project path this directory was derived from (only for project scope) + * Most-relevant session ID for the supplied context, or omitted when no sessions exist */ - projectPath?: string; + sessionId?: string; } /** - * Canonical locations where skills can be created so the runtime will recognize them. + * Session ID whose persisted metadata should be read. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillDiscoveryPathList". + * via the `definition` "SessionsGetMetadataRequest". */ /** @experimental */ -export interface SkillDiscoveryPathList { +export interface SessionsGetMetadataRequest { /** - * Canonical skill create/discovery directories, in priority order + * Session ID to inspect */ - paths: SkillDiscoveryPath[]; + sessionId: string; } /** - * A computed Skill install plan. Nothing has been applied. + * Persisted local session metadata when the session exists. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillInstallPlan". + * via the `definition` "SessionsGetMetadataResult". */ /** @experimental */ -export interface SkillInstallPlan { - /** - * One-use plan handle, bound to the original candidate authority. - */ - planHandle: string; - /** - * Original operation identifier returned before confirmation. - */ - operationId: string; - /** - * Original wall-clock expiry as an ISO 8601 timestamp. - */ - expiresAt: string; - review: SkillInstallationReview; +export interface SessionsGetMetadataResult { + session?: LocalSessionMetadataValue; } /** - * A computed Skill uninstall plan. Nothing has been removed. + * Session ID to look up the persisted remote-steerable flag for. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillUninstallPlan". + * via the `definition` "SessionsGetPersistedRemoteSteerableRequest". */ /** @experimental */ -export interface SkillUninstallPlan { - /** - * One-use uninstall plan handle. - */ - planHandle: string; - /** - * Original removal operation identifier returned before confirmation. - */ - operationId: string; +export interface SessionsGetPersistedRemoteSteerableRequest { /** - * Original wall-clock expiry as an ISO 8601 timestamp. + * Session ID to look up the persisted remote-steerable flag for */ - expiresAt: string; - installation: SkillInstallationSummary; - review: SkillInstallationReview; + sessionId: string; } /** - * Existing-operation control. A new session selector is deliberately not accepted. + * The session's persisted remote-steerable flag, or omitted when no value has been persisted. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillInstallationOperationRequest". + * via the `definition` "SessionsGetPersistedRemoteSteerableResult". */ /** @experimental */ -export interface SkillInstallationOperationRequest { - contract: CatalogClientContract; +export interface SessionsGetPersistedRemoteSteerableResult { /** - * Exact runtime-issued operation ID on the original connection. + * The session's persisted remote-steerable flag if recorded; omitted when no value has been persisted */ - operationId: string; + remoteSteerable?: boolean; } /** - * Inventory request under an explicitly selected existing session. + * Map of sessionId -> on-disk size in bytes for each session's workspace directory. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillInstallationsRequest". + * via the `definition` "SessionSizes". */ /** @experimental */ -export interface SkillInstallationsRequest { - contract: CatalogClientContract; +export interface SessionSizes { /** - * Existing selected local session on this connection. + * Map of sessionId -> on-disk size in bytes for the session's workspace directory */ - policySessionId: string; + sizes: { + [k: string]: number | undefined; + }; } /** - * Skills available to the session, with their enabled state. + * Limit for non-empty local session IDs. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillList". + * via the `definition` "SessionsListNonEmptySessionIdsRequest". */ /** @experimental */ -export interface SkillList { +export interface SessionsListNonEmptySessionIdsRequest { /** - * Available skills + * Maximum number of session IDs to return. */ - skills: Skill[]; + limit?: number; } /** - * Side-effect-free planning of one verified Agent Finder Skill candidate. + * Recent local session IDs that contain user-visible history. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillPlanInstallRequest". + * via the `definition` "SessionsListNonEmptySessionIdsResult". */ /** @experimental */ -export interface SkillPlanInstallRequest { - contract: CatalogClientContract; - /** - * Fresh single-use AI skill candidate handle returned by a bound catalogue search. - */ - candidateHandle: string; +export interface SessionsListNonEmptySessionIdsResult { /** - * Existing local session attached to this connection. + * Session IDs ordered newest-first. */ - policySessionId: string; + sessionIds: string[]; } /** - * Read-only preparation of one owned Skill removal under fresh selected-session authority. + * Optional source filter, metadata-load limit, and context filter applied to the returned sessions. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillPlanUninstallRequest". + * via the `definition` "SessionsListRequest". */ /** @experimental */ -export interface SkillPlanUninstallRequest { - contract: CatalogClientContract; +export interface SessionsListRequest { + source?: SessionSource; /** - * Exact receipt to inspect. + * When provided, only the first N local sessions (sorted by modification time, newest first) load full metadata; remaining sessions return basic info only. Use 0 to return only basic info for every local session. Has no effect on remote entries (which always carry their full shape). */ - installationId: string; + metadataLimit?: number; + filter?: SessionListFilter; /** - * Existing selected local session on this connection. + * When true, include detached maintenance sessions. Defaults to false for user-facing session lists. */ - policySessionId: string; + includeDetached?: boolean; + /** + * Only meaningful when `source` includes remote. When true, propagates errors from the remote service instead of silently returning an empty remote list. Defaults to false. + */ + throwOnError?: boolean; } /** - * Authoritative catalog metadata for one SDK-provided skill. The skill's SKILL.md text is fetched separately and lazily. + * Active session ID whose deferred repo-level hooks should be loaded. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillProviderDescriptor". + * via the `definition` "SessionsLoadDeferredRepoHooksRequest". */ /** @experimental */ -export interface SkillProviderDescriptor { - /** - * Invocation and display name. - */ - name: string; +export interface SessionsLoadDeferredRepoHooksRequest { /** - * Description used in skill catalogs without fetching content. + * Active session ID whose deferred repo-level hooks should be loaded */ - description: string; - /** - * Whether users may invoke the skill directly. Defaults to true. - */ - userInvocable?: boolean; + sessionId: string; +} +/** + * Where the session's state lives, as a root directory and the session ID under it. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsLoadWorkspaceRequest". + */ +/** @experimental */ +export interface SessionsLoadWorkspaceRequest { /** - * Whether model invocation is disabled. Defaults to false. + * Root directory every session's state directory sits under */ - disableModelInvocation?: boolean; + sessionsHome: string; /** - * Optional freeform argument hint used by slash-command catalogs. + * Session ID naming the state directory under the sessions home. Rejected when it is absolute or contains a parent component, so it cannot escape the sessions home. */ - argumentHint?: string; + sessionId: string; } /** - * Catalog metadata returned by an SDK session's skill provider. Catalogs are limited to 1024 descriptors and 1 MiB of aggregate metadata. + * The workspace record on disk, omitted when the session has none. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillProviderListResult". + * via the `definition` "SessionsLoadWorkspaceResult". */ /** @experimental */ -/** @internal */ -export interface SkillProviderListResult { +export interface SessionsLoadWorkspaceResult { /** - * Skill descriptors in provider order. Invocation names must be unique under case-insensitive comparison. - * - * @maxItems 1024 + * The workspace record, as JSON. Omitted when the record does not exist. */ - skills: SkillProviderDescriptor[]; + workspaceJson?: string; } /** - * Identifies one SDK-provided skill by invocation name. + * Age threshold and optional flags controlling which old sessions are pruned (or simulated when dryRun is true). * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillProviderReadRequest". + * via the `definition` "SessionsPruneOldRequest". */ /** @experimental */ -/** @internal */ -export interface SkillProviderReadRequest { +export interface SessionsPruneOldRequest { /** - * Target session identifier + * Delete sessions whose modifiedTime is at least this many days old */ - sessionId: string; + olderThanDays: number; /** - * Invocation name of the skill to read. + * When true, only report what would be deleted without performing any deletion */ - name: string; + dryRun?: boolean; + /** + * When true, named sessions (set via /rename) are also eligible for pruning + */ + includeNamed?: boolean; + /** + * Session IDs that should never be considered for pruning + */ + excludeSessionIds?: string[]; } /** - * Text-only SKILL.md content returned by an SDK session's skill provider. YAML frontmatter is optional: fields it omits come from the catalog descriptor, fields it declares must match the descriptor, and `allowed-tools` is read only from frontmatter. Related files and assets are not supported. + * Pagination options for reading an inactive or active local session's persisted event journal. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillProviderReadResult". + * via the `definition` "SessionsReadPersistedEventsRequest". */ /** @experimental */ -/** @internal */ -export interface SkillProviderReadResult { +export interface SessionsReadPersistedEventsRequest { /** - * SKILL.md text, with or without YAML frontmatter, or null when the provider has no skill with the requested name. The runtime enforces a 1 MiB UTF-8 byte limit. + * Session ID whose persisted event journal should be read. */ - markdown: string | null; + sessionId: string; + /** + * Opaque, process-local, single-use cursor returned by the previous persisted-event read. Omit on the first call and issue continuations sequentially; reusing the same cursor returns an expired terminal page. + */ + cursor?: string; + /** + * Maximum number of events to return in this batch (1–1000, default 200). Pages may contain fewer events to keep the serialized event array within a soft 1 MiB budget including resolved binary assets; one oversized event is returned alone to guarantee progress. + */ + max?: number; + direction?: EventsReadDirection; } /** - * Skill names to mark as disabled in global configuration, replacing any previous list. + * Session ID whose in-use lock should be released. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillsConfigSetDisabledSkillsRequest". + * via the `definition` "SessionsReleaseLockRequest". */ /** @experimental */ -export interface SkillsConfigSetDisabledSkillsRequest { +export interface SessionsReleaseLockRequest { /** - * List of skill names to disable + * Session ID whose in-use lock should be released */ - disabledSkills: string[]; + sessionId: string; } /** - * Adds or removes a single skill from the global disabled list, leaving every other entry untouched. + * Release the in-use lock held by this process for the given session. No-op when this process does not currently hold a lock for the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillsConfigSetSkillDisabledRequest". + * via the `definition` "SessionsReleaseLockResult". */ /** @experimental */ -export interface SkillsConfigSetSkillDisabledRequest { +export interface SessionsReleaseLockResult {} +/** + * Active session ID and an optional flag for deferring repo-level hooks until folder trust. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsReloadPluginHooksRequest". + */ +/** @experimental */ +export interface SessionsReloadPluginHooksRequest { /** - * Name of the skill to add to or remove from the disabled list + * Active session ID to reload hooks for */ - name: string; + sessionId: string; /** - * True to disable the skill, false to enable it + * When true, skip repo-level hooks. Use before folder trust is confirmed; loadDeferredRepoHooks loads them post-trust. */ - disabled: boolean; + deferRepoHooks?: boolean; } /** - * Name of the skill to disable for the session. + * Reload all hooks (user, plugin, optionally repo) and apply them to the active session. Call after installing or removing plugins so their hooks take effect immediately. No-op when no active session matches the given sessionId. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillsDisableRequest". + * via the `definition` "SessionsReloadPluginHooksResult". */ /** @experimental */ -export interface SkillsDisableRequest { +export interface SessionsReloadPluginHooksResult {} +/** + * Session ID whose pending events should be flushed to disk. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsSaveRequest". + */ +/** @experimental */ +export interface SessionsSaveRequest { /** - * Name of the skill to disable + * Session ID whose pending events should be flushed to disk */ - name: string; + sessionId: string; } /** - * Optional project paths and additional skill directories to include in discovery. + * Flush a session's pending events to disk. No-op when no writer exists for the session (e.g., already closed). * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillsDiscoverRequest". + * via the `definition` "SessionsSaveResult". */ /** @experimental */ -export interface SkillsDiscoverRequest { - /** - * Optional list of project directory paths to scan for project-scoped skills - */ - projectPaths?: string[]; - /** - * Explicit discovery-only skill roots, not filesystem grants. Available without ambient discovery, subject to skill/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. - */ - skillDirectories?: string[]; - /** - * Optional skill scan paths to exclude from discovery. - */ - ignoredSkillsLocations?: string[]; +export interface SessionsSaveResult {} +/** + * Manager-wide additional plugins to register; replaces any previously-configured set. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsSetAdditionalPluginsRequest". + */ +/** @experimental */ +export interface SessionsSetAdditionalPluginsRequest { /** - * When true, omit skills from the host's global sources (personal, custom, plugin, and built-in), returning only project-scoped skills. For multitenant deployments. + * Manager-wide additional plugins to register. Replaces any previously-configured set. Pass an empty array to clear. */ - excludeHostSkills?: boolean; + plugins: InstalledPlugin[]; } /** - * Name of the skill to enable for the session. + * Replace the manager-wide additional plugins. New session creations and subsequent hook reloads see the new set; already-running sessions keep their existing hook installation until the next reload. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillsEnableRequest". + * via the `definition` "SessionsSetAdditionalPluginsResult". */ /** @experimental */ -export interface SkillsEnableRequest { +export interface SessionsSetAdditionalPluginsResult {} +/** + * Patch for the singleton's steering state. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsSetRemoteControlSteeringRequest". + */ +/** @experimental */ +export interface SessionsSetRemoteControlSteeringRequest { /** - * Name of the skill to enable + * Target steering state. Today only `true` is actionable on the underlying exporter; `false` is reserved for future use. */ - name: string; + enabled: boolean; } /** - * Persisted enablement update for one owned Skill installation. + * Parameters for attaching the remote-control singleton to a session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillSetEnabledRequest". + * via the `definition` "SessionsStartRemoteControlRequest". */ /** @experimental */ -export interface SkillSetEnabledRequest { - contract: CatalogClientContract; +export interface SessionsStartRemoteControlRequest { /** - * Exact receipt identity to update. + * Local session id to attach remote control to. */ - installationId: string; + sessionId: string; + config: RemoteControlConfig; +} + +/** @experimental */ +export interface SessionsStopRemoteControlRequest { /** - * Persisted enablement value. + * When provided, the stop is rejected unless the singleton currently points at this session id (compare-and-swap semantics). */ - enabled: boolean; + expectedSessionId?: string; /** - * Existing selected local session to reconcile after persistence. + * When true, the singleton is unconditionally torn down regardless of `expectedSessionId`. Use during shutdown or explicit `/remote off`. */ - policySessionId: string; + force?: boolean; } /** - * Optional project paths to enumerate. + * Parameters for atomically rebinding the remote-control singleton. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillsGetDiscoveryPathsRequest". + * via the `definition` "SessionsTransferRemoteControlRequest". */ /** @experimental */ -export interface SkillsGetDiscoveryPathsRequest { +export interface SessionsTransferRemoteControlRequest { /** - * Explicit discovery-only skill roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. + * Local session id to point remote control at. */ - skillDirectories?: string[]; + toSessionId: string; /** - * Optional list of project directory paths. When omitted or empty, only personal and custom directories are returned. + * When provided, the transfer is rejected unless the singleton currently points at this session id (compare-and-swap semantics to avoid clobbering newer state). */ - projectPaths?: string[]; + expectedFromSessionId?: string; +} +/** + * Where the session's state lives, plus workspace-schema fields to merge into its workspace record. Stored keys outside the schema are not preserved, and a stored `fork_count` is never replaced. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionsUpdateWorkspaceFieldsRequest". + */ +/** @experimental */ +export interface SessionsUpdateWorkspaceFieldsRequest { /** - * Optional skill scan paths to exclude from discovery. + * Root directory every session's state directory sits under */ - ignoredSkillsLocations?: string[]; + sessionsHome: string; /** - * When true, omit the host's personal and custom skill directories, leaving only project directories. For multitenant deployments. + * Session ID naming the state directory under the sessions home. Rejected when it is absolute or contains a parent component, so it cannot escape the sessions home. */ - excludeHostSkills?: boolean; + sessionId: string; + /** + * Workspace-schema fields to merge into the record, as a JSON object. Fields the object omits keep their stored values, except stored keys outside the schema are not preserved and a stored `fork_count` is never replaced. + */ + fieldsJson: string; } /** - * Skills invoked during this session, ordered by invocation time (most recent last). + * The merge completed. The record carries the supplied workspace-schema fields, but a stored `fork_count` stays. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillsGetInvokedResult". + * via the `definition` "SessionsUpdateWorkspaceFieldsResult". */ /** @experimental */ -export interface SkillsGetInvokedResult { - /** - * Skills invoked during this session, ordered by invocation time (most recent last) - */ - skills: SkillsInvokedSkill[]; -} +export interface SessionsUpdateWorkspaceFieldsResult {} /** - * Skill invocation record with name, path, content, allowed tools, and turn number. + * Telemetry engagement ID for the session, when available. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillsInvokedSkill". + * via the `definition` "SessionTelemetryEngagement". */ /** @experimental */ -export interface SkillsInvokedSkill { +export interface SessionTelemetryEngagement { /** - * Unique identifier for the skill + * Current telemetry engagement ID, when available. */ - name: string; - /** - * Path to the SKILL.md file, or an empty string for an SDK-provided skill without a filesystem identity - */ - path: string; - /** - * Full content of the skill file - */ - content: string; - /** - * Tools that should be auto-approved when this skill is active, captured at invocation time - */ - allowedTools?: string[]; - /** - * Whether model invocation was disabled when this skill was invoked - */ - disableModelInvocation?: boolean; - /** - * Turn number when the skill was invoked - */ - invokedAtTurn: number; + engagementId?: string; } /** - * Diagnostics from reloading skill definitions, with warnings and errors as separate lists. + * Patch of mutable session options to apply to the running session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillsLoadDiagnostics". + * via the `definition` "SessionUpdateOptionsParams". */ /** @experimental */ -export interface SkillsLoadDiagnostics { +export interface SessionUpdateOptionsParams { /** - * Warnings emitted while loading skills (e.g. skills that loaded but had issues) + * The model ID to use for assistant turns. */ - warnings: string[]; + model?: string; + modelCapabilitiesOverrides?: ModelCapabilitiesOverride; /** - * Errors emitted while loading skills (e.g. skills that failed to load entirely) + * Reasoning effort for the selected model. CAPI values are model-defined and validated against the selected model; BYOK providers may define additional values. When omitted, no effort override is applied. */ - errors: string[]; -} - -/** @experimental */ -export interface SlashCommandAddTimelineEntryResult { + reasoningEffort?: string; + reasoningSummary?: OptionsUpdateReasoningSummary; + verbosity?: Verbosity; /** - * Discriminator for an add-timeline-entry result. + * Identifier of the client driving the session. */ - kind: "add-timeline-entry"; - entry: SlashCommandTimelineEntry; + clientName?: string; /** - * Optional text the host should prefill into the input editor. + * Identifier sent to LSP-style integrations. */ - prefillInput?: string; + lspClientName?: string; /** - * Whether command execution changed persisted runtime settings. + * Stable integration identifier used for analytics and rate-limit attribution. */ - runtimeSettingsChanged?: boolean; -} - -/** @experimental */ -export interface SlashCommandTimelineEntry { + integrationId?: string; /** - * Timeline entry presentation type. + * Map of feature-flag IDs to their boolean enabled state. */ - type: string; + featureFlags?: { + [k: string]: boolean | undefined; + }; /** - * Text displayed for the timeline entry. + * Whether experimental capabilities are enabled. */ - text: string; + isExperimentalMode?: boolean; + provider?: ProviderConfig; + capi?: CapiSessionOptions; /** - * Optional URL associated with the timeline entry. + * Absolute working-directory path for shell tools. */ - url?: string; - remediation?: RemediationAction; -} -/** - * Slash-command invocation result that submits an agent prompt, with display prompt, optional mode, optional user-facing notice, and settings-change flag. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SlashCommandAgentPromptResult". - */ -/** @experimental */ -export interface SlashCommandAgentPromptResult { + workingDirectory?: string; /** - * Agent prompt result discriminator + * Allowlist of tool names available to this session. */ - kind: "agent-prompt"; + availableTools?: string[]; /** - * Prompt to submit to the agent + * Denylist of tool names for this session. */ - prompt: string; + excludedTools?: string[]; /** - * Prompt text to display to the user + * Built-in subagent names to include in this session. When specified, only these built-ins are available, subject to runtime availability and exclusions. Custom agents with the same name remain available. Set to null to remove the allowlist restriction. */ - displayPrompt: string; - mode?: SessionMode; + includedBuiltinAgents?: string[] | null; /** - * Optional user-facing notice to show before the prompt is submitted + * Built-in subagent names to exclude from this session. Excluded built-ins are hidden from agent discovery and cannot be dispatched unless a custom agent with the same name is available. */ - notice?: string; + excludedBuiltinAgents?: string[]; + toolFilterPrecedence?: OptionsUpdateToolFilterPrecedence; /** - * True when the invocation mutated user runtime settings; consumers caching settings should refresh + * Whether shell-script safety heuristics are enabled. */ - runtimeSettingsChanged?: boolean; -} -/** - * Slash-command invocation result indicating completion, with optional message and settings-change flag. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SlashCommandCompletedResult". - */ -/** @experimental */ -export interface SlashCommandCompletedResult { + enableScriptSafety?: boolean; + shell?: ShellOptions; /** - * Completed result discriminator + * @deprecated + * Use shell.initProfile instead. Shell init profile (`None` or `NonInteractive`). */ - kind: "completed"; + shellInitProfile?: string; /** - * Optional user-facing message describing the completed command + * PowerShell process flags applied to built-in and user-requested shell commands. */ - message?: string; - mode?: SessionMode; + shellProcessFlags?: string[]; + sandboxConfig?: SandboxConfig; /** - * True when the invocation mutated user runtime settings; consumers caching settings should refresh + * Origin of the sandbox choice. Settings-derived origins (never_configured, user_enabled, user_disabled, repository_policy) let managed policy floor a host preference; explicit below-floor changes remain policy conflicts unless a session opt-out is authorized. Also used for telemetry provenance. + * + * @experimental */ - runtimeSettingsChanged?: boolean; -} -/** - * Slash-command invocation result containing text output plus Markdown/ANSI rendering flags. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SlashCommandTextResult". - */ -/** @experimental */ -export interface SlashCommandTextResult { + sandboxConfigSource?: SandboxConfigSource; /** - * Text result discriminator + * Whether interactive shell sessions are logged. */ - kind: "text"; + logInteractiveShells?: boolean; + envValueMode?: OptionsUpdateEnvValueMode; /** - * Text output for the client to render + * Whether to include instructions from every MCP server in the system prompt instead of only allowlisted servers. */ - text: string; + allowAllMcpServerInstructions?: boolean; /** - * Whether text contains Markdown + * Explicit discovery-only skill roots, not filesystem grants. Available without enableConfigDiscovery, subject to skill/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ - markdown?: boolean; + skillDirectories?: string[]; /** - * Whether ANSI sequences should be preserved + * Explicit discovery-only agent roots, separate from customAgents and filesystem grants. Available without enableConfigDiscovery, subject to managed/source disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ - preserveAnsi?: boolean; + agentDirectories?: string[]; /** - * True when the invocation mutated user runtime settings; consumers caching settings should refresh + * Explicit discovery-only instruction roots using existing SDK instruction formats, not filesystem grants. Available without enableConfigDiscovery, subject to instruction/managed disables. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ - runtimeSettingsChanged?: boolean; - sandboxSessionChange?: SandboxSessionChange; -} -/** - * Slash-command invocation result asking the client to present subcommand options for a parent command. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SlashCommandSelectSubcommandResult". - */ -/** @experimental */ -export interface SlashCommandSelectSubcommandResult { + instructionDirectories?: string[]; /** - * Select subcommand result discriminator + * Explicit discovery-only file-hook roots, separate from callback hooks and filesystem grants. Available without enableConfigDiscovery or enableFileHooks, which controls repository-origin hooks only; hook/managed disables still apply. Relative SDK paths resolve once when supplied against the request's effective workingDirectory; retained roots do not move on cwd changes. Null and omission are equivalent; [] clears only the explicit SDK contribution. */ - kind: "select-subcommand"; + hookDirectories?: string[]; /** - * Parent command name that requires subcommand selection + * Skill scan directories and descendants excluded from discovery. Supports `~`-relative paths. */ - command: string; + ignoredSkillsLocations?: string[]; /** - * Human-readable title for the selection UI + * Built-in skill names to include in this session. When specified, only these runtime-bundled skills are available. Skills from other sources with the same name remain available. Set to null to remove the allowlist restriction. */ - title: string; + includedBuiltinSkills?: string[] | null; /** - * Available subcommand options for the client to present + * Skill IDs that should be excluded from this session. */ - options: SlashCommandSelectSubcommandOption[]; + disabledSkills?: string[]; /** - * True when the invocation mutated user runtime settings; consumers caching settings should refresh + * Whether to discover custom instructions on demand after successful file views (AGENTS.md / CLAUDE.md / .github/copilot-instructions.md surfacing). Combined with `skipCustomInstructions`. */ - runtimeSettingsChanged?: boolean; -} -/** - * Selectable slash-command subcommand option with name, description, and optional group label. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SlashCommandSelectSubcommandOption". - */ -/** @experimental */ -export interface SlashCommandSelectSubcommandOption { + enableOnDemandInstructionDiscovery?: boolean; /** - * Subcommand name to invoke + * Maximum decoded byte size of a single model-facing binary tool result (e.g. an image) persisted inline in session events and re-presented to the model on later turns / resume. Larger results are persisted as a metadata-only marker and shown to the model as a short text note. Defaults to 10 MB. */ - name: string; + maxInlineBinaryBytes?: number; /** - * Human-readable description of the subcommand + * Full set of installed plugins for the session. Replaces the existing list; the runtime invalidates the skills cache only when the list materially changes. */ - description: string; + installedPlugins?: SessionInstalledPlugin[]; /** - * Optional group label for organizing options + * Whether to default custom agents to local-only execution. */ - group?: string; -} - -/** @experimental */ -export interface SlashCommandShowDialogResult { + customAgentsLocalOnly?: boolean; /** - * Discriminator for a show-dialog result. + * When true, the selected custom agent's prompt is not injected into the user message (skill context is still injected). Used by automation triggers where the agent prompt is already in the problem statement. */ - kind: "show-dialog"; - dialog: SlashCommandModelPickerDialog; + suppressCustomAgentPrompt?: boolean; /** - * Whether command execution changed persisted runtime settings. + * Whether to skip loading custom instruction sources. */ - runtimeSettingsChanged?: boolean; -} - -/** @experimental */ -export interface SlashCommandModelPickerDialog { + skipCustomInstructions?: boolean; /** - * Discriminator for a model-picker dialog. + * Instruction source IDs to exclude from the system prompt. */ - kind: "model-picker"; + disabledInstructionSources?: string[]; /** - * Model that should be enabled before it can be selected. + * Whether to include the `Co-authored-by` trailer in commit messages. */ - modelToEnable?: string; + coauthorEnabled?: boolean; /** - * Settings scope the picker should modify. + * Optional path for trajectory output. */ - scope?: string; + trajectoryFile?: string; /** - * Model-selection target represented by the picker. + * Whether to stream model responses. */ - target?: string; -} - -/** @experimental */ -export interface SlashCommandSetModelResult { + enableStreaming?: boolean; /** - * Discriminator for a set-model result. + * Override URL for the Copilot API endpoint. */ - kind: "set-model"; + copilotUrl?: string; /** - * Model selected by the command. + * Whether to disable the `ask_user` tool (encourages autonomous behavior). */ - model: string; - autoTier?: AutoTier; + askUserDisabled?: boolean; /** - * Settings scope modified by the command. + * Whether to allow auto-mode continuation across turns. */ - scope?: string; + continueOnAutoMode?: boolean; /** - * User-facing warning produced while selecting the model. + * Whether the session is running in an interactive UI. */ - warning?: string; + runningInInteractiveMode?: boolean; /** - * Reasoning effort selected for the model. + * Whether to surface reasoning-summary events from the model. */ - reasoningEffort?: string; + enableReasoningSummaries?: boolean; /** - * User-settings snapshot to restore if the host cancels the model switch. + * Runtime context discriminator (e.g., `cli`, `actions`). */ - revertOnCancel?: {}; + agentContext?: string; /** - * Repository settings scope modified by the command. + * Override directory for the session-events log. When unset, the runtime's default events log directory is used. */ - repoScope?: string; + eventsLogDirectory?: string; /** - * Whether command execution changed persisted runtime settings. + * Whether subagent callback events should be forwarded into the session event log sink. */ - runtimeSettingsChanged?: boolean; -} - -/** @experimental */ -export interface SlashCommandSetPlanModelResult { + eventsLogIncludesSubagents?: boolean; /** - * Discriminator for a set-plan-model result. + * Additional content-exclusion policies to merge into the session's policy set. + * + * @experimental */ - kind: "set-plan-model"; + additionalContentExclusionPolicies?: OptionsUpdateAdditionalContentExclusionPolicy[]; /** - * Dedicated model selected for plan mode. + * Whether to expose the `manage_schedule` tool to the agent. The runtime always owns the per-session schedule registry; this flag only controls tool exposure (typically gated to staff users). */ - planModel?: string; + manageScheduleEnabled?: boolean; /** - * User-facing confirmation message for the plan-model selection. + * Replaces the session's capability set with the given list. Use to enable or disable capabilities mid-session (e.g., remove `memory` for reproducible scripted runs). Omit the field to leave the existing capability set unchanged. */ - message: string; + sessionCapabilities?: SessionCapability[]; /** - * Whether command execution changed persisted runtime settings. + * Whether to skip embedding retrieval pipeline initialization and execution. */ - runtimeSettingsChanged?: boolean; + skipEmbeddingRetrieval?: boolean; + /** + * Organization-level custom instructions to inject into the system prompt. + */ + organizationCustomInstructions?: string; + /** + * Whether to enable repository-origin file hooks from `.github/hooks/` and trusted repository-configured roots. Does not control explicit hookDirectories or SDK callback hooks. + */ + enableFileHooks?: boolean; + /** + * Whether to enable host git operations (context resolution, child repo scanning, git info in system prompt). + */ + enableHostGitOperations?: boolean; + /** + * Whether to enable cross-session store writes and reads. + */ + enableSessionStore?: boolean; + /** + * Whether skill loading is enabled. Explicit false disables every source, including explicit SDK roots and a bound SDK provider; changing the value invalidates the loaded skill snapshot. When omitted, creation falls back to enableConfigDiscovery unless explicit SDK skill roots or an SDK skill provider are supplied. + */ + enableSkills?: boolean; + contextTier?: OptionsUpdateContextTier; + /** + * Optional session limits. Pass null to clear the session limits. + */ + sessionLimits?: SessionLimitsConfig | null; } /** - * Subagent model, reasoning effort, context tier, and auto-invocation settings + * Indicates whether the session options patch was applied successfully. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SubagentSettingsEntry". + * via the `definition` "SessionUpdateOptionsResult". */ /** @experimental */ -export interface SubagentSettingsEntry { +export interface SessionUpdateOptionsResult { /** - * Model override for matching subagents + * Whether the operation succeeded */ - model?: string; - modelPolicy?: AgentModelPolicy; + success: boolean; /** - * Reasoning effort override for matching subagents + * Number of hooks loaded from installed plugins, returned when installedPlugins is updated */ - effortLevel?: string; - contextTier?: SubagentSettingsEntryContextTier; + pluginHookCount?: number; +} +/** + * Outcome of an atomic user or repository settings edit. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SettingsEditResult". + */ +/** @experimental */ +/** @internal */ +export interface SettingsEditResult { + status: SettingsEditStatus; +} +/** + * User-requested shell execution cancellation handle. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ShellCancelUserRequestedRequest". + */ +/** @experimental */ +export interface ShellCancelUserRequestedRequest { /** - * Whether this agent's runtime-defined proactive invocation prompting is enabled, if supported. Currently consumed by the built-in rubber-duck agent. + * Request ID previously passed to executeUserRequested */ - autoInvoke?: boolean; + requestId: string; } /** - * Tracked background agent task metadata, including IDs, status, timing, agent type, prompt, model, result, and latest response. + * Shell command to run, with optional working directory and timeout in milliseconds. Spawn failures return an RPC error. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TaskAgentInfo". + * via the `definition` "ShellExecRequest". */ /** @experimental */ -export interface TaskAgentInfo { +export interface ShellExecRequest { /** - * Task kind + * Shell command to execute */ - type: "agent"; + command: string; /** - * Unique task identifier + * Working directory (defaults to session working directory) */ - id: string; + cwd?: string; /** - * Tool call ID associated with this agent task + * Timeout in milliseconds (default: 30000) */ - toolCallId: string; + timeout?: number; +} +/** + * Identifier of the spawned shell process, usable with shell.kill while the process is running. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ShellExecResult". + */ +/** @experimental */ +export interface ShellExecResult { /** - * Friendly, non-unique name intended for display + * Identifier usable with shell.kill while the process is running */ - displayName?: string; + processId: string; +} +/** + * User-requested shell command and cancellation handle. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ShellExecuteUserRequestedRequest". + */ +/** @experimental */ +export interface ShellExecuteUserRequestedRequest { /** - * Short description of the task + * Caller-provided cancellation handle for this execution */ - description: string; - status: TaskStatus; + requestId: string; /** - * ISO 8601 timestamp when the task was started + * Shell command to execute */ - startedAt: string; + command: string; +} +/** + * Identifier of a process previously returned by "shell.exec" and the signal to send. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ShellKillRequest". + */ +/** @experimental */ +export interface ShellKillRequest { /** - * ISO 8601 timestamp when the task finished + * Process identifier returned by shell.exec */ - completedAt?: string; + processId: string; + signal?: ShellKillSignal; +} +/** + * Indicates whether the signal was delivered; false if the process was unknown or already exited. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ShellKillResult". + */ +/** @experimental */ +export interface ShellKillResult { /** - * Accumulated active execution time in milliseconds + * Whether the signal was sent successfully */ - activeTimeMs?: number; + killed: boolean; +} +/** + * Parameters for shutting down the session + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ShutdownRequest". + */ +/** @experimental */ +export interface ShutdownRequest { + type?: ShutdownType; /** - * ISO 8601 timestamp when the current active period began + * Optional human-readable reason. Typically the message of the error that triggered shutdown when type is 'error'. */ - activeStartedAt?: string; + reason?: string; /** - * Error message when the task failed + * Dispatch deferred sessionEnd hooks in the background with their full per-hook timeoutSec instead of awaiting them under the short shared shutdown budget. Set this when the host process keeps running after the session closes (for example the CLI's /clear), so a slow hook neither blocks the close nor is aborted. Hooks still detached when the process later exits are terminated with it. Defaults to false. */ - error?: string; + detachSessionEndHooks?: boolean; +} +/** + * Skill metadata available to a session, with name, description, source, enabled/invocable state, path, plugin, and argument hint. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "Skill". + */ +/** @experimental */ +export interface Skill { /** - * Type of agent running this task + * Unique identifier for the skill */ - agentType: string; + name: string; /** - * Most recent prompt delivered to the agent. Updated whenever the agent receives a follow-up message. + * Canonical slash command name used to invoke the skill, without the leading '/' */ - prompt: string; + commandName?: string; /** - * Result text from the task when available + * Description of what the skill does */ - result?: string; + description: string; + source: SkillSource; /** - * Requested model override for the task when specified + * Whether the skill can be invoked by the user as a slash command */ - model?: string; + userInvocable: boolean; /** - * Runtime model resolved for the task when available + * Whether the skill is currently enabled */ - resolvedModel?: string; - executionMode?: TaskExecutionMode; + enabled: boolean; /** - * Whether the task is currently in the original sync wait and can be moved to background mode. False once it is already backgrounded, idle, finished, or no longer has a promotable sync waiter. + * Absolute path to the skill file */ - canPromoteToBackground?: boolean; + path?: string; /** - * Most recent response text from the agent + * Name of the plugin that provides the skill, when source is 'plugin' */ - latestResponse?: string; + pluginName?: string; /** - * ISO 8601 timestamp when the agent entered idle state + * Optional freeform hint describing the skill's expected arguments, from the `argument-hint` frontmatter field */ - idleSince?: string; + argumentHint?: string; } /** - * Progress snapshot for an agent task, with recent activity lines and optional latest intent. + * Applies exactly one retained verified Skill installation plan. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TaskAgentProgress". + * via the `definition` "SkillApplyInstallRequest". */ /** @experimental */ -export interface TaskAgentProgress { - /** - * Progress kind - */ - type: "agent"; +export interface SkillApplyInstallRequest { + contract: CatalogClientContract; /** - * Recent tool execution events converted to display lines + * Opaque original plan, consumed once. */ - recentActivity: TaskProgressLine[]; + planHandle: string; /** - * The most recent intent reported by the agent + * Same existing selected session as planning. */ - latestIntent?: string; + policySessionId: string; } /** - * Timestamped display line for task progress output or recent agent activity. + * One-use application of the exact retained Skill removal plan. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TaskProgressLine". + * via the `definition` "SkillApplyUninstallRequest". */ /** @experimental */ -export interface TaskProgressLine { +export interface SkillApplyUninstallRequest { + contract: CatalogClientContract; /** - * Display message, e.g., "▸ bash", "✓ edit src/foo.ts" + * Opaque original removal plan, consumed once. */ - message: string; + planHandle: string; /** - * ISO 8601 timestamp when this event occurred + * Same existing selected session as removal preparation. */ - timestamp: string; + policySessionId: string; } /** - * Tracked client-owned task metadata. + * Canonical directory where skills can be discovered or created, with scope, preference, and optional project path. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TaskClientInfo". + * via the `definition` "SkillDiscoveryPath". */ /** @experimental */ -export interface TaskClientInfo { - type: TaskClientType; - /** - * Canonical runtime-generated task identifier - */ - id: string; +export interface SkillDiscoveryPath { /** - * Owner-scoped registration and reclaim key + * Absolute path of the create/discovery target (may not exist on disk yet) */ - clientTaskId: string; + path: string; + scope: SkillDiscoveryScope; /** - * Optional task display name + * Whether this is the canonical directory to create a new skill in its tier. At most one entry per tier is preferred; the `personal-agents` and `custom` scopes are never preferred. */ - displayName?: string; + preferredForCreation: boolean; /** - * Task description + * The input project path this directory was derived from (only for project scope) */ - description: string; - status: TaskClientStatus; - owner: TaskClientOwner; + projectPath?: string; +} +/** + * Canonical locations where skills can be created so the runtime will recognize them. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SkillDiscoveryPathList". + */ +/** @experimental */ +export interface SkillDiscoveryPathList { /** - * ISO 8601 timestamp when the task started + * Canonical skill create/discovery directories, in priority order */ - startedAt: string; + paths: SkillDiscoveryPath[]; +} +/** + * A computed Skill install plan. Nothing has been applied. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SkillInstallPlan". + */ +/** @experimental */ +export interface SkillInstallPlan { /** - * ISO 8601 timestamp of the latest accepted lifecycle change + * One-use plan handle, bound to the original candidate authority. */ - updatedAt: string; + planHandle: string; /** - * ISO 8601 timestamp when the task reached a terminal status + * Original operation identifier returned before confirmation. */ - completedAt?: string; + operationId: string; /** - * Accumulated active execution time in milliseconds + * Original wall-clock expiry as an ISO 8601 timestamp. */ - activeTimeMs: number; + expiresAt: string; + review: SkillInstallationReview; +} +/** + * A computed Skill uninstall plan. Nothing has been removed. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SkillUninstallPlan". + */ +/** @experimental */ +export interface SkillUninstallPlan { /** - * ISO 8601 timestamp when the current active segment started + * One-use uninstall plan handle. */ - activeStartedAt?: string; + planHandle: string; /** - * ISO 8601 timestamp when the connected owner entered idle status + * Original removal operation identifier returned before confirmation. */ - idleSince?: string; + operationId: string; /** - * ISO 8601 timestamp of the most recent orphan transition + * Original wall-clock expiry as an ISO 8601 timestamp. */ - orphanedAt?: string; + expiresAt: string; + installation: SkillInstallationSummary; + review: SkillInstallationReview; +} +/** + * Existing-operation control. A new session selector is deliberately not accepted. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SkillInstallationOperationRequest". + */ +/** @experimental */ +export interface SkillInstallationOperationRequest { + contract: CatalogClientContract; /** - * ISO 8601 timestamp of the most recent successful reclaim + * Exact runtime-issued operation ID on the original connection. */ - reclaimedAt?: string; - executionMode: TaskClientExecutionMode; + operationId: string; +} +/** + * Inventory request under an explicitly selected existing session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SkillInstallationsRequest". + */ +/** @experimental */ +export interface SkillInstallationsRequest { + contract: CatalogClientContract; /** - * Whether the currently bound owner can receive a cancellation request + * Existing selected local session on this connection. */ - canCancel: boolean; + policySessionId: string; +} +/** + * Skills available to the session, with their enabled state. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SkillList". + */ +/** @experimental */ +export interface SkillList { /** - * Sequence number of the latest accepted owner update + * Available skills */ - sequence: number; + skills: Skill[]; +} +/** + * Side-effect-free planning of one verified Agent Finder Skill candidate. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SkillPlanInstallRequest". + */ +/** @experimental */ +export interface SkillPlanInstallRequest { + contract: CatalogClientContract; /** - * Opaque successful terminal result supplied by the task owner + * Fresh single-use AI skill candidate handle returned by a bound catalogue search. */ - result?: JsonValue; + candidateHandle: string; /** - * Human-readable terminal failure message + * Existing local session attached to this connection. */ - error?: string; + policySessionId: string; +} +/** + * Read-only preparation of one owned Skill removal under fresh selected-session authority. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SkillPlanUninstallRequest". + */ +/** @experimental */ +export interface SkillPlanUninstallRequest { + contract: CatalogClientContract; /** - * Optional owner-supplied terminal failure code + * Exact receipt to inspect. */ - errorCode?: string; + installationId: string; /** - * Human-readable reason for terminal cancellation + * Existing selected local session on this connection. */ - cancellationReason?: string; + policySessionId: string; } /** - * Public owner attribution for a client-owned task. Identifiers are opaque and never authorize requests. + * Authoritative catalog metadata for one SDK-provided skill. The skill's SKILL.md text is fetched separately and lazily. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TaskClientOwner". + * via the `definition` "SkillProviderDescriptor". */ /** @experimental */ -export interface TaskClientOwner { +export interface SkillProviderDescriptor { /** - * Opaque session-scoped participant identity + * Invocation and display name. */ - participantId: string; + name: string; /** - * Opaque identity of the currently or most recently bound session join + * Description used in skill catalogs without fetching content. */ - joinId: string; - kind: TaskClientOwnerKind; + description: string; /** - * Display-only owner name + * Whether users may invoke the skill directly. Defaults to true. */ - displayName?: string; + userInvocable?: boolean; /** - * Display-only owner source + * Whether model invocation is disabled. Defaults to false. */ - source?: string; - presence: TaskClientOwnerPresence; + disableModelInvocation?: boolean; /** - * ISO 8601 timestamp when the bound join disconnected + * Optional freeform argument hint used by slash-command catalogs. */ - disconnectedAt?: string; + argumentHint?: string; } /** - * Generic progress for a client-owned task. + * Catalog metadata returned by an SDK session's skill provider. Catalogs are limited to 1024 descriptors and 1 MiB of aggregate metadata. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TaskClientProgress". + * via the `definition` "SkillProviderListResult". */ /** @experimental */ -export interface TaskClientProgress { - type: TaskClientType; - status: TaskClientStatus; - /** - * Sequence number of the latest accepted owner update - */ - sequence: number; +/** @internal */ +export interface SkillProviderListResult { /** - * ISO 8601 timestamp of the latest accepted lifecycle change + * Skill descriptors in provider order. Invocation names must be unique under case-insensitive comparison. + * + * @maxItems 1024 */ - updatedAt: string; + skills: SkillProviderDescriptor[]; +} +/** + * Identifies one SDK-provided skill by invocation name. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SkillProviderReadRequest". + */ +/** @experimental */ +/** @internal */ +export interface SkillProviderReadRequest { /** - * Current owner-defined progress phase + * Target session identifier */ - phase?: string; + sessionId: string; /** - * Current completion percentage from zero through one hundred + * Invocation name of the skill to read. */ - percentage?: number; - /** - * Most recent nonempty progress message - */ - lastMessage?: string; - /** - * Recent server-timestamped progress messages - */ - recentActivity: TaskProgressLine[]; -} - -/** @experimental */ -export interface TaskCompletionDecision { - outcome: TaskCompletionOutcome; - /** - * Rationale for the completion decision, when one is available. - */ - reason?: string; - /** - * Whether the rationale was derived from completion-reviewer output. - */ - reviewerDerived?: boolean; - /** - * Information-flow metadata captured from the completion reviewer. - */ - reviewerResultMeta?: JsonValue; - /** - * Active autopilot objective evaluated by the completion reviewer. - */ - objectiveId?: number; - /** - * Whether completion was accepted after the reviewer-rejection budget was exhausted. - */ - completionRejectionBudgetExhausted?: boolean; - /** - * Objective eligibility token captured when the decision was evaluated. - */ - completionEligibilityToken?: number; + name: string; } /** - * Tracked shell task metadata, including ID, command, status, timing, attachment/execution mode, log path, and PID. + * Text-only SKILL.md content returned by an SDK session's skill provider. YAML frontmatter is optional: fields it omits come from the catalog descriptor, fields it declares must match the descriptor, and `allowed-tools` is read only from frontmatter. Related files and assets are not supported. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TaskShellInfo". + * via the `definition` "SkillProviderReadResult". */ /** @experimental */ -export interface TaskShellInfo { - /** - * Task kind - */ - type: "shell"; - /** - * Unique task identifier - */ - id: string; - /** - * Short description of the task - */ - description: string; - status: TaskStatus; - /** - * ISO 8601 timestamp when the task was started - */ - startedAt: string; - /** - * ISO 8601 timestamp when the task finished - */ - completedAt?: string; - /** - * Command being executed - */ - command: string; - attachmentMode: TaskShellInfoAttachmentMode; - executionMode?: TaskExecutionMode; - /** - * Whether this shell task can be promoted to background mode - */ - canPromoteToBackground?: boolean; - /** - * Path to the detached shell log, when available - */ - logPath?: string; +/** @internal */ +export interface SkillProviderReadResult { /** - * Process ID when available + * SKILL.md text, with or without YAML frontmatter, or null when the provider has no skill with the requested name. The runtime enforces a 1 MiB UTF-8 byte limit. */ - pid?: number; + markdown: string | null; } /** - * Background tasks currently tracked by the session. + * Skill names to mark as disabled in global configuration, replacing any previous list. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TaskList". + * via the `definition` "SkillsConfigSetDisabledSkillsRequest". */ /** @experimental */ -export interface TaskList { +export interface SkillsConfigSetDisabledSkillsRequest { /** - * Currently tracked tasks + * List of skill names to disable */ - tasks: TaskInfo[]; + disabledSkills: string[]; } /** - * Progress snapshot for a shell task, with recent stdout/stderr output and optional process ID. + * Adds or removes a single skill from the global disabled list, leaving every other entry untouched. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TaskShellProgress". + * via the `definition` "SkillsConfigSetSkillDisabledRequest". */ /** @experimental */ -export interface TaskShellProgress { - /** - * Progress kind - */ - type: "shell"; +export interface SkillsConfigSetSkillDisabledRequest { /** - * Recent stdout/stderr lines from the running shell command + * Name of the skill to add to or remove from the disabled list */ - recentOutput: string; + name: string; /** - * Process ID when available + * True to disable the skill, false to enable it */ - pid?: number; + disabled: boolean; } /** - * Identifier of the background task to cancel. + * Name of the skill to disable for the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksCancelRequest". + * via the `definition` "SkillsDisableRequest". */ /** @experimental */ -export interface TasksCancelRequest { +export interface SkillsDisableRequest { /** - * Task identifier + * Name of the skill to disable */ - id: string; + name: string; } /** - * Indicates whether the background task was successfully cancelled. + * Optional project paths and additional skill directories to include in discovery. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksCancelResult". + * via the `definition` "SkillsDiscoverRequest". */ /** @experimental */ -export interface TasksCancelResult { +export interface SkillsDiscoverRequest { /** - * Whether the task was successfully cancelled + * Optional list of project directory paths to scan for project-scoped skills */ - cancelled: boolean; -} -/** - * The first sync-waiting task that can currently be promoted to background mode. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksGetCurrentPromotableResult". - */ -/** @experimental */ -export interface TasksGetCurrentPromotableResult { - task?: TaskInfo; -} -/** - * Identifier of the background task to fetch progress for. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksGetProgressRequest". - */ -/** @experimental */ -export interface TasksGetProgressRequest { + projectPaths?: string[]; /** - * Task identifier (agent ID or shell ID) + * Explicit discovery-only skill roots, not filesystem grants. Available without ambient discovery, subject to skill/managed disables. Relative paths resolve against the request's effective working directory when supplied. Null and omission are equivalent; an empty array contributes no explicit roots. */ - id: string; + skillDirectories?: string[]; + /** + * Optional skill scan paths to exclude from discovery. + */ + ignoredSkillsLocations?: string[]; + /** + * When true, omit skills from the host's global sources (personal, custom, plugin, and built-in), returning only project-scoped skills. For multitenant deployments. + */ + excludeHostSkills?: boolean; } /** - * Progress information for the task, or null when no task with that ID is tracked. + * Name of the skill to enable for the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksGetProgressResult". + * via the `definition` "SkillsEnableRequest". */ /** @experimental */ -export interface TasksGetProgressResult { +export interface SkillsEnableRequest { /** - * Progress information for the task, discriminated by type. Returns null when no task with this ID is currently tracked. + * Name of the skill to enable */ - progress?: TaskProgress | null; + name: string; } /** - * The promoted task as it now exists in background mode, omitted if no promotable task was waiting. + * Persisted enablement update for one owned Skill installation. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksPromoteCurrentToBackgroundResult". + * via the `definition` "SkillSetEnabledRequest". */ /** @experimental */ -export interface TasksPromoteCurrentToBackgroundResult { - task?: TaskInfo; +export interface SkillSetEnabledRequest { + contract: CatalogClientContract; + /** + * Exact receipt identity to update. + */ + installationId: string; + /** + * Persisted enablement value. + */ + enabled: boolean; + /** + * Existing selected local session to reconcile after persistence. + */ + policySessionId: string; } /** - * Identifier of the task to promote to background mode. + * Optional project paths to enumerate. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksPromoteToBackgroundRequest". + * via the `definition` "SkillsGetDiscoveryPathsRequest". */ /** @experimental */ -export interface TasksPromoteToBackgroundRequest { +export interface SkillsGetDiscoveryPathsRequest { /** - * Task identifier + * Explicit discovery-only skill roots to enumerate, including configured missing directories. Relative paths resolve against the request's effective working directory when supplied. These are not filesystem grants or preferred creation targets. Null and omission are equivalent. */ - id: string; + skillDirectories?: string[]; + /** + * Optional list of project directory paths. When omitted or empty, only personal and custom directories are returned. + */ + projectPaths?: string[]; + /** + * Optional skill scan paths to exclude from discovery. + */ + ignoredSkillsLocations?: string[]; + /** + * When true, omit the host's personal and custom skill directories, leaving only project directories. For multitenant deployments. + */ + excludeHostSkills?: boolean; } /** - * Indicates whether the task was successfully promoted to background mode. + * Skills invoked during this session, ordered by invocation time (most recent last). * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksPromoteToBackgroundResult". + * via the `definition` "SkillsGetInvokedResult". */ /** @experimental */ -export interface TasksPromoteToBackgroundResult { +export interface SkillsGetInvokedResult { /** - * Whether the task was successfully promoted to background mode + * Skills invoked during this session, ordered by invocation time (most recent last) */ - promoted: boolean; + skills: SkillsInvokedSkill[]; } /** - * Refresh metadata for any detached background shells the runtime knows about. Use after a long pause to pick up exit/output state for shells running outside the agent loop. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksRefreshResult". - */ -/** @experimental */ -export interface TasksRefreshResult {} -/** - * Registers or reclaims a client-owned task. + * Skill invocation record with name, path, content, allowed tools, and turn number. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksRegisterRequest". + * via the `definition` "SkillsInvokedSkill". */ /** @experimental */ -export interface TasksRegisterRequest { - type: TaskClientType; +export interface SkillsInvokedSkill { /** - * Owner-scoped idempotency key used for registration and reclaim + * Unique identifier for the skill */ - clientTaskId: string; + name: string; /** - * Human-readable description of the external work + * Path to the SKILL.md file, or an empty string for an SDK-provided skill without a filesystem identity */ - description: string; + path: string; /** - * Optional short display name for the external work + * Full content of the skill file */ - displayName?: string; + content: string; /** - * Whether the owner supports runtime cancellation requests + * Tools that should be auto-approved when this skill is active, captured at invocation time */ - cancellable: boolean; + allowedTools?: string[]; /** - * Expected current sequence for idempotent registration or orphan reclaim - */ - expectedSequence?: number; -} -/** - * Result of registering or reclaiming a client-owned task. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksRegisterResult". - */ -/** @experimental */ -export interface TasksRegisterResult { - task: TaskClientInfo; - /** - * True only when this invocation created a new task + * Whether model invocation was disabled when this skill was invoked */ - created: boolean; + disableModelInvocation?: boolean; /** - * True only when this invocation reclaimed an orphaned task + * Turn number when the skill was invoked */ - reclaimed: boolean; + invokedAtTurn: number; } /** - * Identifier of the completed or cancelled task to remove from tracking. + * Diagnostics from reloading skill definitions, with warnings and errors as separate lists. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksRemoveRequest". + * via the `definition` "SkillsLoadDiagnostics". */ /** @experimental */ -export interface TasksRemoveRequest { +export interface SkillsLoadDiagnostics { /** - * Task identifier + * Warnings emitted while loading skills (e.g. skills that loaded but had issues) */ - id: string; -} -/** - * Indicates whether the task was removed. False when the task does not exist or is still running/idle. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksRemoveResult". - */ -/** @experimental */ -export interface TasksRemoveResult { + warnings: string[]; /** - * Whether the task was removed. Returns false if the task does not exist or is still running/idle (cancel it first). + * Errors emitted while loading skills (e.g. skills that failed to load entirely) */ - removed: boolean; + errors: string[]; } -/** - * Identifier of the target agent task, message content, and optional sender agent ID. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksSendMessageRequest". - */ + /** @experimental */ -export interface TasksSendMessageRequest { +export interface SlashCommandAddTimelineEntryResult { /** - * Agent task identifier + * Discriminator for an add-timeline-entry result. */ - id: string; + kind: "add-timeline-entry"; + entry: SlashCommandTimelineEntry; /** - * Message content to send to the agent + * Optional text the host should prefill into the input editor. */ - message: string; + prefillInput?: string; /** - * Agent ID of the sender, if sent on behalf of another agent + * Whether command execution changed persisted runtime settings. */ - fromAgentId?: string; + runtimeSettingsChanged?: boolean; } -/** - * Indicates whether the message was delivered, with an error message when delivery failed. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksSendMessageResult". - */ + /** @experimental */ -export interface TasksSendMessageResult { +export interface SlashCommandTimelineEntry { /** - * Whether the message was successfully delivered or steered + * Timeline entry presentation type. */ - sent: boolean; + type: string; /** - * Error message if delivery failed + * Text displayed for the timeline entry. */ - error?: string; + text: string; + /** + * Optional URL associated with the timeline entry. + */ + url?: string; + remediation?: RemediationAction; } /** - * Agent type, prompt, name, and optional description and model override for the new task. + * Slash-command invocation result that submits an agent prompt, with display prompt, optional mode, optional user-facing notice, and settings-change flag. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksStartAgentRequest". + * via the `definition` "SlashCommandAgentPromptResult". */ /** @experimental */ -export interface TasksStartAgentRequest { +export interface SlashCommandAgentPromptResult { /** - * Type of agent to start (e.g., 'explore', 'task', 'general-purpose') + * Agent prompt result discriminator */ - agentType: string; + kind: "agent-prompt"; /** - * Task prompt for the agent + * Prompt to submit to the agent */ prompt: string; /** - * Friendly, non-unique name used when displaying the agent + * Prompt text to display to the user */ - name: string; + displayPrompt: string; + mode?: SessionMode; /** - * Short description of the task + * Optional user-facing notice to show before the prompt is submitted */ - description?: string; + notice?: string; /** - * Optional model override + * True when the invocation mutated user runtime settings; consumers caching settings should refresh */ - model?: string; + runtimeSettingsChanged?: boolean; } /** - * Identifier assigned to the newly started background agent task. + * Slash-command invocation result indicating completion, with optional message and settings-change flag. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksStartAgentResult". + * via the `definition` "SlashCommandCompletedResult". */ /** @experimental */ -export interface TasksStartAgentResult { +export interface SlashCommandCompletedResult { /** - * Generated agent ID for the background task + * Completed result discriminator */ - agentId: string; -} -/** - * Updates a client-owned task. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksUpdateRequest". - */ -/** @experimental */ -export interface TasksUpdateRequest { + kind: "completed"; /** - * Canonical runtime-generated task identifier + * Optional user-facing message describing the completed command */ - id: string; + message?: string; + mode?: SessionMode; /** - * Owner update sequence to apply + * True when the invocation mutated user runtime settings; consumers caching settings should refresh */ - sequence: number; - update: TaskClientUpdate; + runtimeSettingsChanged?: boolean; } /** - * Result of publishing a client-owned task update. + * Slash-command invocation result containing text output plus Markdown/ANSI rendering flags. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksUpdateResult". + * via the `definition` "SlashCommandTextResult". */ /** @experimental */ -export interface TasksUpdateResult { - task: TaskClientInfo; +export interface SlashCommandTextResult { /** - * Whether this invocation changed task state + * Text result discriminator */ - applied: boolean; + kind: "text"; /** - * Whether this invocation repeated the latest accepted update + * Text output for the client to render */ - duplicate: boolean; -} -/** - * Wait until all in-flight background tasks (agents + shells) and any follow-up turns scheduled by their completions have settled. Returns when the runtime is fully drained or after an internal timeout (default 10 minutes; configurable via COPILOT_TASK_WAIT_TIMEOUT_SECONDS). - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TasksWaitForPendingResult". - */ -/** @experimental */ -export interface TasksWaitForPendingResult {} -/** - * Feature override key/value pairs to attach to subsequent telemetry events from this session. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "TelemetrySetFeatureOverridesRequest". - */ -/** @experimental */ -export interface TelemetrySetFeatureOverridesRequest { + text: string; /** - * Override key/value pairs to attach to subsequent telemetry events from this session. Replaces any previously-set overrides. + * Whether text contains Markdown */ - features: { - [k: string]: string | undefined; - }; + markdown?: boolean; + /** + * Whether ANSI sequences should be preserved + */ + preserveAnsi?: boolean; + /** + * True when the invocation mutated user runtime settings; consumers caching settings should refresh + */ + runtimeSettingsChanged?: boolean; + sandboxSessionChange?: SandboxSessionChange; } /** - * Built-in tool metadata with identifier, optional namespaced name, description, input-parameter schema, and usage instructions. + * Slash-command invocation result asking the client to present subcommand options for a parent command. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "Tool". + * via the `definition` "SlashCommandSelectSubcommandResult". */ /** @experimental */ -export interface Tool { - /** - * Tool identifier (e.g., "bash", "grep", "str_replace_editor") - */ - name: string; +export interface SlashCommandSelectSubcommandResult { /** - * Optional namespaced name for declarative filtering (e.g., "playwright/navigate" for MCP tools) + * Select subcommand result discriminator */ - namespacedName?: string; + kind: "select-subcommand"; /** - * Description of what the tool does + * Parent command name that requires subcommand selection */ - description: string; + command: string; /** - * JSON Schema for the tool's input parameters + * Human-readable title for the selection UI */ - parameters?: { - [k: string]: JsonValue | undefined; - }; + title: string; /** - * Optional instructions for how to use this tool effectively + * Available subcommand options for the client to present */ - instructions?: string; + options: SlashCommandSelectSubcommandOption[]; /** - * Telemetry-safety policy for the tool name and input names, not input values. Treat omitted metadata as unsafe. - * - * @experimental + * True when the invocation mutated user runtime settings; consumers caching settings should refresh */ - safeForTelemetry?: BuiltinToolSafeForTelemetry; + runtimeSettingsChanged?: boolean; } /** - * Built-in tools available for the requested model, with their parameters and instructions. + * Selectable slash-command subcommand option with name, description, and optional group label. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ToolList". + * via the `definition` "SlashCommandSelectSubcommandOption". */ /** @experimental */ -export interface ToolList { +export interface SlashCommandSelectSubcommandOption { /** - * List of available built-in tools with metadata + * Subcommand name to invoke */ - tools: Tool[]; -} -/** - * Expanded canonical result returned by a session tool. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ToolResultExpanded". - */ -/** @experimental */ -export interface ToolResultExpanded { + name: string; /** - * Text result returned to the model. + * Human-readable description of the subcommand */ - textResultForLlm: string; - resultType: ToolResultType; + description: string; /** - * Base64-encoded binary results returned to the model. + * Optional group label for organizing options */ - binaryResultsForLlm?: ExternalToolTextResultForLlmBinaryResultsForLlm[]; + group?: string; +} + +/** @experimental */ +export interface SlashCommandShowDialogResult { /** - * Detailed log content available for session display. + * Discriminator for a show-dialog result. */ - sessionLog?: string; + kind: "show-dialog"; + dialog: SlashCommandModelPickerDialog; /** - * Error message for an unsuccessful execution. + * Whether command execution changed persisted runtime settings. */ - error?: string; + runtimeSettingsChanged?: boolean; +} + +/** @experimental */ +export interface SlashCommandModelPickerDialog { /** - * Tool-specific telemetry payload. + * Discriminator for a model-picker dialog. */ - toolTelemetry?: JsonValue; + kind: "model-picker"; /** - * Whether large-output post-processing should be skipped. + * Model that should be enabled before it can be selected. */ - skipLargeOutputProcessing?: boolean; + modelToEnable?: string; /** - * Messages to inject after the tool result. + * Settings scope the picker should modify. */ - newMessages?: ToolResultNewMessage[]; + scope?: string; /** - * Structured content blocks returned to the model. + * Model-selection target represented by the picker. */ - contents?: ExternalToolTextResultForLlmContent[]; + target?: string; +} + +/** @experimental */ +export interface SlashCommandSetModelResult { /** - * Deferred tool names made available by this result. + * Discriminator for a set-model result. */ - toolReferences?: string[]; + kind: "set-model"; /** - * Sources returned by the tool that the model may cite. + * Model selected by the command. */ - citableSources?: JsonValue[]; + model: string; + autoTier?: AutoTier; /** - * Skill invocation metadata produced by the tool. + * Settings scope modified by the command. */ - skillInvocation?: JsonValue; + scope?: string; /** - * Whether post-tool-use failure hooks have already processed this result. + * User-facing warning produced while selecting the model. */ - postToolUseFailureHooksProcessed?: boolean; + warning?: string; /** - * Optional UI resource produced by the tool. + * Reasoning effort selected for the model. */ - uiResource?: JsonValue; + reasoningEffort?: string; /** - * Metadata propagated with the tool result, including information-flow labels. + * User-settings snapshot to restore if the host cancels the model switch. */ - mcpMeta?: { - [k: string]: JsonValue | undefined; - }; + revertOnCancel?: {}; /** - * Structured result content in addition to the model-facing text. + * Repository settings scope modified by the command. */ - structuredContent?: JsonValue; - taskCompletionDecision?: TaskCompletionDecision; + repoScope?: string; + /** + * Whether command execution changed persisted runtime settings. + */ + runtimeSettingsChanged?: boolean; } -/** - * A message injected by a tool result. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ToolResultNewMessage". - */ + /** @experimental */ -export interface ToolResultNewMessage { +export interface SlashCommandSetPlanModelResult { /** - * Message content to inject after the tool result. + * Discriminator for a set-plan-model result. */ - content: string; + kind: "set-plan-model"; /** - * Source attributed to the injected message. + * Dedicated model selected for plan mode. */ - source: string; + planModel?: string; + /** + * User-facing confirmation message for the plan-model selection. + */ + message: string; + /** + * Whether command execution changed persisted runtime settings. + */ + runtimeSettingsChanged?: boolean; } /** - * A tool name and arguments to execute through the session's native invocation pipeline. + * Subagent model, reasoning effort, context tier, and auto-invocation settings * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ToolsExecuteRequest". + * via the `definition` "SubagentSettingsEntry". */ /** @experimental */ -export interface ToolsExecuteRequest { +export interface SubagentSettingsEntry { /** - * Name of the currently offered tool to execute. + * Model override for matching subagents */ - name: string; + model?: string; + modelPolicy?: AgentModelPolicy; /** - * Arguments supplied to the tool. + * Reasoning effort override for matching subagents */ - arguments: JsonValue; + effortLevel?: string; + contextTier?: SubagentSettingsEntryContextTier; /** - * Optional identifier used to correlate this invocation with its tool call. + * Whether this agent's runtime-defined proactive invocation prompting is enabled, if supported. Currently consumed by the built-in rubber-duck agent. */ - toolCallId?: string; + autoInvoke?: boolean; } /** - * Options controlling how Rust-owned built-in tool descriptors are materialized. + * Tracked background agent task metadata, including IDs, status, timing, agent type, prompt, model, result, and latest response. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ToolsGetBuiltinDescriptorsRequest". + * via the `definition` "TaskAgentInfo". */ /** @experimental */ -export interface ToolsGetBuiltinDescriptorsRequest { +export interface TaskAgentInfo { /** - * Whether descriptors should favor fewer user-intervention prompts. + * Task kind */ - reduceUserIntervention?: boolean; + type: "agent"; /** - * Whether tool descriptors should include authoring metadata. + * Unique task identifier */ - includeAuthor?: boolean; + id: string; /** - * Whether semantic skill lookup is available. + * Tool call ID associated with this agent task */ - skillEmbeddingEnabled?: boolean; - shellConfig?: ToolsShellDescriptorConfig; + toolCallId: string; /** - * Whether the configured shell supports PowerShell 7 syntax. + * Friendly, non-unique name intended for display */ - shellSupportsPowerShell7Syntax?: boolean; + displayName?: string; /** - * Default shell timeout in milliseconds. + * Short description of the task */ - shellTimeoutMs?: number; + description: string; + status: TaskStatus; /** - * Whether background task completion notifications are enabled. + * ISO 8601 timestamp when the task was started */ - backgroundTaskNotificationsEnabled?: boolean; -} -/** - * Shell-specific names and description lines used to materialize built-in shell tool descriptors. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ToolsShellDescriptorConfig". - */ -/** @experimental */ -export interface ToolsShellDescriptorConfig { + startedAt: string; /** - * Stable shell type identifier. + * ISO 8601 timestamp when the task finished */ - shellType: string; + completedAt?: string; /** - * Human-readable shell name. + * Accumulated active execution time in milliseconds */ - displayName: string; + activeTimeMs?: number; /** - * Tool name used to start shell commands. + * ISO 8601 timestamp when the current active period began */ - shellToolName: string; + activeStartedAt?: string; /** - * Tool name used to read shell output. + * Error message when the task failed */ - readShellToolName: string; + error?: string; /** - * Tool name used to stop shell commands. + * Type of agent running this task */ - stopShellToolName: string; + agentType: string; /** - * Tool name used to list active shells. + * Most recent prompt delivered to the agent. Updated whenever the agent receives a follow-up message. */ - listShellsToolName: string; + prompt: string; /** - * Additional model-facing shell description lines. + * Result text from the task when available */ - descriptionLines: string[]; + result?: string; + /** + * Requested model override for the task when specified + */ + model?: string; + /** + * Runtime model resolved for the task when available + */ + resolvedModel?: string; + executionMode?: TaskExecutionMode; + /** + * Whether the task is currently in the original sync wait and can be moved to background mode. False once it is already backgrounded, idle, finished, or no longer has a promotable sync waiter. + */ + canPromoteToBackground?: boolean; + /** + * Most recent response text from the agent + */ + latestResponse?: string; + /** + * ISO 8601 timestamp when the agent entered idle state + */ + idleSince?: string; } /** - * Rust-owned built-in tool descriptors for the session. + * Progress snapshot for an agent task, with recent activity lines and optional latest intent. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ToolsGetBuiltinDescriptorsResult". + * via the `definition` "TaskAgentProgress". */ /** @experimental */ -export interface ToolsGetBuiltinDescriptorsResult { +export interface TaskAgentProgress { /** - * Built-in tool descriptors materialized for the session. + * Progress kind */ - tools: BuiltinToolDescriptor[]; + type: "agent"; + /** + * Recent tool execution events converted to display lines + */ + recentActivity: TaskProgressLine[]; + /** + * The most recent intent reported by the agent + */ + latestIntent?: string; } /** - * Current lightweight tool metadata snapshot for the session. + * Timestamped display line for task progress output or recent agent activity. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ToolsGetCurrentMetadataResult". + * via the `definition` "TaskProgressLine". */ /** @experimental */ -export interface ToolsGetCurrentMetadataResult { +export interface TaskProgressLine { /** - * Current tool metadata, or null when tools have not been initialized yet + * Display message, e.g., "▸ bash", "✓ edit src/foo.ts" */ - tools: CurrentToolMetadata[] | null; + message: string; + /** + * ISO 8601 timestamp when this event occurred + */ + timestamp: string; } /** - * Resolve, build, and validate the runtime tool list for this session. Subagent sessions and consumer flows that need an initialized tool set before `send` invoke this. Default base-class implementation is a no-op for sessions that don't support tool validation. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ToolsInitializeAndValidateResult". - */ -/** @experimental */ -export interface ToolsInitializeAndValidateResult {} -/** - * No parameters; returns the external tool calls of the session and its sub-agents that are still waiting for a result. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ToolsListPendingRequestsRequest". - */ -/** @experimental */ -export interface ToolsListPendingRequestsRequest {} -/** - * Optional model identifier whose tool overrides should be applied to the listing. + * Tracked client-owned task metadata. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ToolsListRequest". + * via the `definition` "TaskClientInfo". */ /** @experimental */ -export interface ToolsListRequest { +export interface TaskClientInfo { + type: TaskClientType; /** - * Optional model ID — when provided, the returned tool list reflects model-specific overrides + * Canonical runtime-generated task identifier */ - model?: string; -} -/** - * Complete externally implemented tool list for the calling connection. An empty list removes every tool previously supplied by that connection. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ToolsSetRequest". - */ -/** @experimental */ -export interface ToolsSetRequest { + id: string; /** - * Complete replacement list for the calling connection. + * Owner-scoped registration and reclaim key */ - tools: ProtocolExternalToolDefinition[]; -} -/** - * Empty result after replacing the calling connection's externally implemented tools. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ToolsSetResult". - */ -/** @experimental */ -export interface ToolsSetResult {} -/** - * Task-completion tool arguments and final result used to build a label-safe session event payload. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ToolsTaskCompleteEventDataRequest". - */ -/** @experimental */ -export interface ToolsTaskCompleteEventDataRequest { + clientTaskId: string; /** - * Arguments supplied to the completed task_complete tool call. + * Optional task display name */ - toolArgs: JsonValue; - finalResult: ToolResultExpanded; -} -/** - * Empty result after applying subagent settings - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ToolsUpdateSubagentSettingsResult". - */ -/** @experimental */ -export interface ToolsUpdateSubagentSettingsResult {} -/** - * Multi-select string field where each option pairs a value with a display label. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationArrayAnyOfField". - */ -/** @experimental */ -export interface UIElicitationArrayAnyOfField { + displayName?: string; /** - * Type discriminator. Always "array". + * Task description */ - type: "array"; + description: string; + status: TaskClientStatus; + owner: TaskClientOwner; /** - * Human-readable label for the field. + * ISO 8601 timestamp when the task started */ - title?: string; + startedAt: string; /** - * Help text describing the field. + * ISO 8601 timestamp of the latest accepted lifecycle change */ - description?: string; + updatedAt: string; /** - * Minimum number of items the user must select. + * ISO 8601 timestamp when the task reached a terminal status */ - minItems?: number; + completedAt?: string; /** - * Maximum number of items the user may select. + * Accumulated active execution time in milliseconds */ - maxItems?: number; - items: UIElicitationArrayAnyOfFieldItems; + activeTimeMs: number; /** - * Default values selected when the form is first shown. + * ISO 8601 timestamp when the current active segment started */ - default?: string[]; -} -/** - * Schema applied to each item in the array. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationArrayAnyOfFieldItems". - */ -/** @experimental */ -export interface UIElicitationArrayAnyOfFieldItems { + activeStartedAt?: string; /** - * Selectable options, each with a value and a display label. + * ISO 8601 timestamp when the connected owner entered idle status */ - anyOf: UIElicitationArrayAnyOfFieldItemsAnyOf[]; -} -/** - * Selectable option for a UI elicitation multi-select array item, with submitted value and display label. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationArrayAnyOfFieldItemsAnyOf". - */ -/** @experimental */ -export interface UIElicitationArrayAnyOfFieldItemsAnyOf { + idleSince?: string; /** - * Value submitted when this option is selected. + * ISO 8601 timestamp of the most recent orphan transition */ - const: string; + orphanedAt?: string; /** - * Display label for this option. + * ISO 8601 timestamp of the most recent successful reclaim */ - title: string; -} -/** - * Multi-select string field whose allowed values are defined inline. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationArrayEnumField". - */ -/** @experimental */ -export interface UIElicitationArrayEnumField { + reclaimedAt?: string; + executionMode: TaskClientExecutionMode; /** - * Type discriminator. Always "array". + * Whether the currently bound owner can receive a cancellation request */ - type: "array"; + canCancel: boolean; /** - * Human-readable label for the field. + * Sequence number of the latest accepted owner update */ - title?: string; + sequence: number; /** - * Help text describing the field. + * Opaque successful terminal result supplied by the task owner */ - description?: string; + result?: JsonValue; /** - * Minimum number of items the user must select. + * Human-readable terminal failure message */ - minItems?: number; + error?: string; /** - * Maximum number of items the user may select. + * Optional owner-supplied terminal failure code */ - maxItems?: number; - items: UIElicitationArrayEnumFieldItems; + errorCode?: string; /** - * Default values selected when the form is first shown. + * Human-readable reason for terminal cancellation */ - default?: string[]; + cancellationReason?: string; } /** - * Schema applied to each item in the array. + * Public owner attribution for a client-owned task. Identifiers are opaque and never authorize requests. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationArrayEnumFieldItems". + * via the `definition` "TaskClientOwner". */ /** @experimental */ -export interface UIElicitationArrayEnumFieldItems { +export interface TaskClientOwner { /** - * Type discriminator. Always "string". + * Opaque session-scoped participant identity */ - type: "string"; + participantId: string; /** - * Allowed string values for each selected item. + * Opaque identity of the currently or most recently bound session join */ - enum: string[]; -} -/** - * Prompt message and JSON schema describing the form fields to elicit from the user. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationRequest". - */ -/** @experimental */ -export interface UIElicitationRequest { - mode?: McpElicitationFormMode; + joinId: string; + kind: TaskClientOwnerKind; /** - * Message describing what information is needed from the user + * Display-only owner name */ - message: string; - requestedSchema: UIElicitationSchema; + displayName?: string; /** - * MCP request metadata. + * Display-only owner source */ - _meta?: { - [k: string]: unknown | undefined; - }; - task?: McpTaskMetadata; - [k: string]: unknown | undefined; + source?: string; + presence: TaskClientOwnerPresence; + /** + * ISO 8601 timestamp when the bound join disconnected + */ + disconnectedAt?: string; } /** - * JSON Schema describing the form fields to present to the user + * Generic progress for a client-owned task. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationSchema". + * via the `definition` "TaskClientProgress". */ /** @experimental */ -export interface UIElicitationSchema { +export interface TaskClientProgress { + type: TaskClientType; + status: TaskClientStatus; /** - * Schema type indicator (always 'object') + * Sequence number of the latest accepted owner update */ - type: "object"; + sequence: number; /** - * Form field definitions, keyed by field name + * ISO 8601 timestamp of the latest accepted lifecycle change */ - properties: { - [k: string]: UIElicitationSchemaProperty | undefined; - }; + updatedAt: string; /** - * List of required field names + * Current owner-defined progress phase */ - required?: string[]; -} -/** - * Single-select string field whose allowed values are defined inline. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationStringEnumField". - */ -/** @experimental */ -export interface UIElicitationStringEnumField { + phase?: string; /** - * Type discriminator. Always "string". + * Current completion percentage from zero through one hundred */ - type: "string"; + percentage?: number; /** - * Human-readable label for the field. + * Most recent nonempty progress message */ - title?: string; + lastMessage?: string; /** - * Help text describing the field. + * Recent server-timestamped progress messages */ - description?: string; + recentActivity: TaskProgressLine[]; +} + +/** @experimental */ +export interface TaskCompletionDecision { + outcome: TaskCompletionOutcome; /** - * Allowed string values. + * Rationale for the completion decision, when one is available. */ - enum: string[]; + reason?: string; /** - * Optional display labels for each enum value, in the same order as `enum`. + * Whether the rationale was derived from completion-reviewer output. */ - enumNames?: string[]; + reviewerDerived?: boolean; /** - * Default value selected when the form is first shown. + * Information-flow metadata captured from the completion reviewer. */ - default?: string; -} -/** - * Single-select string field where each option pairs a value with a display label. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationStringOneOfField". - */ -/** @experimental */ -export interface UIElicitationStringOneOfField { - /** - * Type discriminator. Always "string". - */ - type: "string"; - /** - * Human-readable label for the field. - */ - title?: string; - /** - * Help text describing the field. - */ - description?: string; - /** - * Selectable options, each with a value and a display label. - */ - oneOf: UIElicitationStringOneOfFieldOneOf[]; + reviewerResultMeta?: JsonValue; /** - * Default value selected when the form is first shown. + * Active autopilot objective evaluated by the completion reviewer. */ - default?: string; -} -/** - * Selectable option for a UI elicitation single-select string field, with submitted value and display label. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationStringOneOfFieldOneOf". - */ -/** @experimental */ -export interface UIElicitationStringOneOfFieldOneOf { + objectiveId?: number; /** - * Value submitted when this option is selected. + * Whether completion was accepted after the reviewer-rejection budget was exhausted. */ - const: string; + completionRejectionBudgetExhausted?: boolean; /** - * Display label for this option. + * Objective eligibility token captured when the decision was evaluated. */ - title: string; + completionEligibilityToken?: number; } /** - * Boolean field rendered as a yes/no toggle. + * Tracked shell task metadata, including ID, command, status, timing, attachment/execution mode, log path, and PID. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationSchemaPropertyBoolean". + * via the `definition` "TaskShellInfo". */ /** @experimental */ -export interface UIElicitationSchemaPropertyBoolean { - /** - * Type discriminator. Always "boolean". - */ - type: "boolean"; +export interface TaskShellInfo { /** - * Human-readable label for the field. + * Task kind */ - title?: string; + type: "shell"; /** - * Help text describing the field. + * Unique task identifier */ - description?: string; + id: string; /** - * Default value selected when the form is first shown. + * Short description of the task */ - default?: boolean; -} -/** - * Free-text string field with optional length and format constraints. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationSchemaPropertyString". - */ -/** @experimental */ -export interface UIElicitationSchemaPropertyString { + description: string; + status: TaskStatus; /** - * Type discriminator. Always "string". + * ISO 8601 timestamp when the task was started */ - type: "string"; + startedAt: string; /** - * Human-readable label for the field. + * ISO 8601 timestamp when the task finished */ - title?: string; + completedAt?: string; /** - * Help text describing the field. + * Command being executed */ - description?: string; + command: string; + attachmentMode: TaskShellInfoAttachmentMode; + executionMode?: TaskExecutionMode; /** - * Minimum number of characters required. + * Whether this shell task can be promoted to background mode */ - minLength?: number; + canPromoteToBackground?: boolean; /** - * Maximum number of characters allowed. + * Path to the detached shell log, when available */ - maxLength?: number; - format?: UIElicitationSchemaPropertyStringFormat; + logPath?: string; /** - * Default value populated in the input when the form is first shown. + * Process ID when available */ - default?: string; + pid?: number; } /** - * Numeric field accepting either a number or an integer. + * Background tasks currently tracked by the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationSchemaPropertyNumber". + * via the `definition` "TaskList". */ /** @experimental */ -export interface UIElicitationSchemaPropertyNumber { - type: UIElicitationSchemaPropertyNumberType; - /** - * Human-readable label for the field. - */ - title?: string; +export interface TaskList { /** - * Help text describing the field. + * Currently tracked tasks */ - description?: string; + tasks: TaskInfo[]; +} +/** + * Progress snapshot for a shell task, with recent stdout/stderr output and optional process ID. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "TaskShellProgress". + */ +/** @experimental */ +export interface TaskShellProgress { /** - * Minimum allowed value (inclusive). + * Progress kind */ - minimum?: number; + type: "shell"; /** - * Maximum allowed value (inclusive). + * Recent stdout/stderr lines from the running shell command */ - maximum?: number; + recentOutput: string; /** - * Default value populated in the input when the form is first shown. + * Process ID when available */ - default?: number; + pid?: number; } /** - * The elicitation response (accept with form values, decline, or cancel) + * Identifier of the background task to cancel. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationResponse". + * via the `definition` "TasksCancelRequest". */ /** @experimental */ -export interface UIElicitationResponse { - action: UIElicitationResponseAction; - content?: UIElicitationResponseContent; +export interface TasksCancelRequest { /** - * MCP response metadata. + * Task identifier */ - _meta?: { - [k: string]: unknown | undefined; - }; - [k: string]: unknown | undefined; + id: string; } /** - * The form values submitted by the user (present when action is 'accept') + * Indicates whether the background task was successfully cancelled. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationResponseContent". + * via the `definition` "TasksCancelResult". */ /** @experimental */ -export interface UIElicitationResponseContent { - [k: string]: UIElicitationFieldValue; +export interface TasksCancelResult { + /** + * Whether the task was successfully cancelled + */ + cancelled: boolean; } /** - * Indicates whether the elicitation response was accepted; false if it was already resolved by another client. + * The first sync-waiting task that can currently be promoted to background mode. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIElicitationResult". + * via the `definition` "TasksGetCurrentPromotableResult". */ /** @experimental */ -export interface UIElicitationResult { - /** - * Whether the response was accepted. False if the request was already resolved by another client. - */ - success: boolean; +export interface TasksGetCurrentPromotableResult { + task?: TaskInfo; } /** - * Transient question to answer without adding it to conversation history. + * Identifier of the background task to fetch progress for. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIEphemeralQueryRequest". + * via the `definition` "TasksGetProgressRequest". */ /** @experimental */ -export interface UIEphemeralQueryRequest { - /** - * Question to answer from the current conversation context. - */ - question: string; - /** - * In-process streaming callback `(text) => void` invoked with each token as the model emits it. Internal and excluded from the public SDK surface. - * - * @internal - */ - onChunk?: OpaqueInProcessValue; +export interface TasksGetProgressRequest { /** - * In-process `AbortSignal` forwarded to the model client to cancel an in-flight request. Internal and excluded from the public SDK surface. - * - * @internal + * Task identifier (agent ID or shell ID) */ - abortSignal?: OpaqueInProcessValue; + id: string; } /** - * Completed transient query. Ordered chunks and the terminal outcome are also delivered through `ui.ephemeral_query` session events while it runs. + * Progress information for the task, or null when no task with that ID is tracked. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIEphemeralQueryResult". + * via the `definition` "TasksGetProgressResult". */ /** @experimental */ -export interface UIEphemeralQueryResult { +export interface TasksGetProgressResult { /** - * Answer returned by the model + * Progress information for the task, discriminated by type. Returns null when no task with this ID is currently tracked. */ - answer: string; + progress?: TaskProgress | null; } /** - * User response for a pending exit-plan-mode request, with approval state, selected action, auto-approve flag, and feedback. + * The promoted task as it now exists in background mode, omitted if no promotable task was waiting. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIExitPlanModeResponse". + * via the `definition` "TasksPromoteCurrentToBackgroundResult". */ /** @experimental */ -export interface UIExitPlanModeResponse { - /** - * Whether the plan was approved. - */ - approved: boolean; - selectedAction?: UIExitPlanModeAction; - /** - * Whether subsequent edits should be auto-approved without confirmation. - */ - autoApproveEdits?: boolean; - /** - * Feedback from the user when they declined the plan or requested changes. - */ - feedback?: string; - /** - * When true, the agent is instructed to end its turn without starting implementation so the client can restore the session model and auto-submit a fresh implementation turn on it. Set only when a distinct plan configuration (a different model, reasoning effort, or context tier) actually ran the planning turn. - */ - deferImplementation?: boolean; +export interface TasksPromoteCurrentToBackgroundResult { + task?: TaskInfo; } /** - * Request ID of a pending `auto_mode_switch.requested` event and the user's response. + * Identifier of the task to promote to background mode. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIHandlePendingAutoModeSwitchRequest". + * via the `definition` "TasksPromoteToBackgroundRequest". */ /** @experimental */ -export interface UIHandlePendingAutoModeSwitchRequest { +export interface TasksPromoteToBackgroundRequest { /** - * The unique request ID from the auto_mode_switch.requested event + * Task identifier */ - requestId: string; - response: UIAutoModeSwitchResponse; + id: string; } /** - * Pending elicitation request ID and the user's response (accept/decline/cancel + form values). + * Indicates whether the task was successfully promoted to background mode. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIHandlePendingElicitationRequest". + * via the `definition` "TasksPromoteToBackgroundResult". */ /** @experimental */ -export interface UIHandlePendingElicitationRequest { +export interface TasksPromoteToBackgroundResult { /** - * The unique request ID from the elicitation.requested event + * Whether the task was successfully promoted to background mode */ - requestId: string; - result: UIElicitationResponse; + promoted: boolean; } /** - * Request ID of a pending `exit_plan_mode.requested` event and the user's response. + * Refresh metadata for any detached background shells the runtime knows about. Use after a long pause to pick up exit/output state for shells running outside the agent loop. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIHandlePendingExitPlanModeRequest". + * via the `definition` "TasksRefreshResult". */ /** @experimental */ -export interface UIHandlePendingExitPlanModeRequest { - /** - * The unique request ID from the exit_plan_mode.requested event - */ - requestId: string; - response: UIExitPlanModeResponse; -} +export interface TasksRefreshResult {} /** - * Indicates whether the pending UI request was resolved by this call. + * Registers or reclaims a client-owned task. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIHandlePendingResult". + * via the `definition` "TasksRegisterRequest". */ /** @experimental */ -export interface UIHandlePendingResult { +export interface TasksRegisterRequest { + type: TaskClientType; /** - * True if the request was still pending and was resolved by this call. False if the request ID was unknown, already resolved by another client (e.g. GitHub), expired, or otherwise no longer pending. + * Owner-scoped idempotency key used for registration and reclaim */ - success: boolean; + clientTaskId: string; + /** + * Human-readable description of the external work + */ + description: string; + /** + * Optional short display name for the external work + */ + displayName?: string; + /** + * Whether the owner supports runtime cancellation requests + */ + cancellable: boolean; + /** + * Expected current sequence for idempotent registration or orphan reclaim + */ + expectedSequence?: number; } /** - * Request ID of a pending `sampling.requested` event and an optional sampling result payload (omit to reject). + * Result of registering or reclaiming a client-owned task. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIHandlePendingSamplingRequest". + * via the `definition` "TasksRegisterResult". */ /** @experimental */ -export interface UIHandlePendingSamplingRequest { +export interface TasksRegisterResult { + task: TaskClientInfo; /** - * The unique request ID from the sampling.requested event + * True only when this invocation created a new task */ - requestId: string; - response?: UIHandlePendingSamplingResponse; + created: boolean; + /** + * True only when this invocation reclaimed an orphaned task + */ + reclaimed: boolean; } /** - * Optional sampling result payload. Omit to reject/cancel the sampling request without providing a result. + * Identifier of the completed or cancelled task to remove from tracking. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIHandlePendingSamplingResponse". + * via the `definition` "TasksRemoveRequest". */ /** @experimental */ -export interface UIHandlePendingSamplingResponse { - [k: string]: unknown | undefined; +export interface TasksRemoveRequest { + /** + * Task identifier + */ + id: string; } /** - * Request ID of a pending `session_limits_exhausted.requested` event and the user's selected limit action. + * Indicates whether the task was removed. False when the task does not exist or is still running/idle. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIHandlePendingSessionLimitsExhaustedRequest". + * via the `definition` "TasksRemoveResult". */ /** @experimental */ -export interface UIHandlePendingSessionLimitsExhaustedRequest { +export interface TasksRemoveResult { /** - * The unique request ID from the session_limits_exhausted.requested event + * Whether the task was removed. Returns false if the task does not exist or is still running/idle (cancel it first). */ - requestId: string; - response: UISessionLimitsExhaustedResponse; + removed: boolean; } /** - * The user's selected action for an exhausted session limit. + * Identifier of the target agent task, message content, and optional sender agent ID. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UISessionLimitsExhaustedResponse". + * via the `definition` "TasksSendMessageRequest". */ /** @experimental */ -export interface UISessionLimitsExhaustedResponse { - action: UISessionLimitsExhaustedResponseAction; +export interface TasksSendMessageRequest { /** - * AI Credits to add to the current max when action is 'add'. + * Agent task identifier */ - additionalAiCredits?: number; + id: string; /** - * New absolute max AI Credits when action is 'set'. + * Message content to send to the agent */ - maxAiCredits?: number; + message: string; + /** + * Agent ID of the sender, if sent on behalf of another agent + */ + fromAgentId?: string; } /** - * Request ID of a pending `user_input.requested` event and the user's response. + * Indicates whether the message was delivered, with an error message when delivery failed. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIHandlePendingUserInputRequest". + * via the `definition` "TasksSendMessageResult". */ /** @experimental */ -export interface UIHandlePendingUserInputRequest { +export interface TasksSendMessageResult { /** - * The unique request ID from the user_input.requested event + * Whether the message was successfully delivered or steered */ - requestId: string; - response: UIUserInputResponse; + sent: boolean; + /** + * Error message if delivery failed + */ + error?: string; } /** - * User response for a pending user-input request, with answer text and whether it was typed freeform. + * Agent type, prompt, name, and optional description and model override for the new task. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIUserInputResponse". + * via the `definition` "TasksStartAgentRequest". */ /** @experimental */ -export interface UIUserInputResponse { +export interface TasksStartAgentRequest { /** - * The user's answer text + * Type of agent to start (e.g., 'explore', 'task', 'general-purpose') */ - answer: string; + agentType: string; /** - * True if the user typed a freeform response, false if they selected a presented choice. Used by telemetry to differentiate between free text input and choice selection. + * Task prompt for the agent */ - wasFreeform: boolean; + prompt: string; + /** + * Friendly, non-unique name used when displaying the agent + */ + name: string; + /** + * Short description of the task + */ + description?: string; + /** + * Optional model override + */ + model?: string; } /** - * Register an in-process handler for `auto_mode_switch.requested` events. The caller still attaches the actual listener via the standard event-subscription mechanism; this registration solely tells the server bridge to skip its own dispatch (so a remote client doesn't race the in-process handler for the same requestId). + * Identifier assigned to the newly started background agent task. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIRegisterDirectAutoModeSwitchHandlerResult". + * via the `definition` "TasksStartAgentResult". */ /** @experimental */ -export interface UIRegisterDirectAutoModeSwitchHandlerResult { +export interface TasksStartAgentResult { /** - * Opaque handle representing the registration. Pass this same handle to `unregisterDirectAutoModeSwitchHandler` when the in-process handler is no longer active. Multiple registrations are reference-counted; the server bridge will only dispatch auto-mode-switch requests when no handles are active. + * Generated agent ID for the background task */ - handle: string; + agentId: string; } /** - * Opaque handle previously returned by `registerDirectAutoModeSwitchHandler` to release. + * Updates a client-owned task. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIUnregisterDirectAutoModeSwitchHandlerRequest". + * via the `definition` "TasksUpdateRequest". */ /** @experimental */ -export interface UIUnregisterDirectAutoModeSwitchHandlerRequest { +export interface TasksUpdateRequest { /** - * Handle previously returned by `registerDirectAutoModeSwitchHandler` + * Canonical runtime-generated task identifier */ - handle: string; + id: string; + /** + * Owner update sequence to apply + */ + sequence: number; + update: TaskClientUpdate; } /** - * Indicates whether the handle was active and the registration count was decremented. + * Result of publishing a client-owned task update. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UIUnregisterDirectAutoModeSwitchHandlerResult". + * via the `definition` "TasksUpdateResult". */ /** @experimental */ -export interface UIUnregisterDirectAutoModeSwitchHandlerResult { +export interface TasksUpdateResult { + task: TaskClientInfo; /** - * True if the handle was active and decremented the counter; false if the handle was unknown. + * Whether this invocation changed task state */ - unregistered: boolean; + applied: boolean; + /** + * Whether this invocation repeated the latest accepted update + */ + duplicate: boolean; } /** - * Subagent settings to apply to the current session + * Wait until all in-flight background tasks (agents + shells) and any follow-up turns scheduled by their completions have settled. Returns when the runtime is fully drained or after an internal timeout (default 10 minutes; configurable via COPILOT_TASK_WAIT_TIMEOUT_SECONDS). * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UpdateSubagentSettingsRequest". + * via the `definition` "TasksWaitForPendingResult". */ /** @experimental */ -export interface UpdateSubagentSettingsRequest { - /** - * Subagent settings to apply, or null to clear the live session override - */ - subagents?: SubagentSettings | null; -} +export interface TasksWaitForPendingResult {} /** - * Internal absolute code-change totals reported by the owning host. + * Feature override key/value pairs to attach to subsequent telemetry events from this session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UsageSetCodeChangesRequest". + * via the `definition` "TelemetrySetFeatureOverridesRequest". */ /** @experimental */ -/** @internal */ -export interface UsageSetCodeChangesRequest { - /** - * Absolute added-line total, replacing the previous reading. - */ - linesAdded: number; - /** - * Absolute removed-line total, replacing the previous reading. - */ - linesRemoved: number; +export interface TelemetrySetFeatureOverridesRequest { /** - * Absolute changed-file count; omission preserves the previous count. + * Override key/value pairs to attach to subsequent telemetry events from this session. Replaces any previously-set overrides. */ - filesCount?: number; + features: { + [k: string]: string | undefined; + }; } /** - * Result of a user-requested shell command. + * Built-in tool metadata with identifier, optional namespaced name, description, input-parameter schema, and usage instructions. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserRequestedShellCommandResult". + * via the `definition` "Tool". */ /** @experimental */ -export interface UserRequestedShellCommandResult { +export interface Tool { /** - * Tool call id emitted for the shell execution + * Tool identifier (e.g., "bash", "grep", "str_replace_editor") */ - toolCallId: string; + name: string; /** - * Whether the command completed successfully + * Optional namespaced name for declarative filtering (e.g., "playwright/navigate" for MCP tools) */ - success: boolean; + namespacedName?: string; /** - * Captured command output + * Description of what the tool does */ - output: string; + description: string; /** - * Process exit code, when available + * JSON Schema for the tool's input parameters */ - exitCode?: number | null; + parameters?: { + [k: string]: JsonValue | undefined; + }; /** - * Error output when the execution failed + * Optional instructions for how to use this tool effectively */ - error?: string; + instructions?: string; + /** + * Telemetry-safety policy for the tool name and input names, not input values. Treat omitted metadata as unsafe. + * + * @experimental + */ + safeForTelemetry?: BuiltinToolSafeForTelemetry; } /** - * A single user setting's effective value alongside its default, so consumers can render settings left at their default. + * Built-in tools available for the requested model, with their parameters and instructions. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingMetadata". + * via the `definition` "ToolList". */ /** @experimental */ -export interface UserSettingMetadata { - /** - * The effective value: the user's value if set, otherwise the default. - */ - value: JsonValue; +export interface ToolList { /** - * The centrally-known default for this setting (null when no default is registered). + * List of available built-in tools with metadata */ - default: JsonValue; - /** - * True when the user has not set an explicit value for this setting (i.e. it is left at its default). Reflects whether the user has overridden the key, not whether the effective value happens to equal the default — a key explicitly set to a value identical to the default still reports false. - */ - isDefault: boolean; + tools: Tool[]; } /** - * A single top-level setting subtree to validate and write. + * Expanded canonical result returned by a session tool. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingsApplyTopKeyRequest". + * via the `definition` "ToolResultExpanded". */ /** @experimental */ -export interface UserSettingsApplyTopKeyRequest { +export interface ToolResultExpanded { /** - * Canonical path of the setting the caller is editing. Currently informational only. + * Text result returned to the model. */ - canonicalPath: string[]; + textResultForLlm: string; + resultType: ToolResultType; /** - * Top-level setting name to write. + * Base64-encoded binary results returned to the model. */ - topKey: string; + binaryResultsForLlm?: ExternalToolTextResultForLlmBinaryResultsForLlm[]; /** - * Value to write for the whole top-level key. Omitted when `delete` is true. Explicit null is preserved and validated as null. + * Detailed log content available for session display. */ - value?: JsonValue | null; + sessionLog?: string; /** - * True to remove the top-level key instead of writing it. + * Error message for an unsuccessful execution. */ - delete?: boolean; + error?: string; /** - * Records that the user chose an update channel explicitly, so the one-time staff channel migration stops reapplying. Honored only for the `autoUpdatesChannel` key. + * Tool-specific telemetry payload. */ - completeStaffUpdateChannelMigration?: boolean; -} -/** - * Outcome of validating and writing one top-level setting subtree. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingsApplyTopKeyResult". - */ -/** @experimental */ -export interface UserSettingsApplyTopKeyResult { + toolTelemetry?: JsonValue; /** - * `ok` when the value was written, `validation-error` when it was rejected before any write, `write-error` when validation passed but the write failed. + * Whether large-output post-processing should be skipped. */ - status: string; + skipLargeOutputProcessing?: boolean; /** - * Problems found, present only when `status` is `validation-error`. + * Messages to inject after the tool result. */ - issues?: UserSettingsValidationIssue[]; + newMessages?: ToolResultNewMessage[]; /** - * Why the write failed, present only when `status` is `write-error`. + * Structured content blocks returned to the model. */ - error?: string | null; + contents?: ExternalToolTextResultForLlmContent[]; + /** + * Deferred tool names made available by this result. + */ + toolReferences?: string[]; + /** + * Sources returned by the tool that the model may cite. + */ + citableSources?: JsonValue[]; + /** + * Skill invocation metadata produced by the tool. + */ + skillInvocation?: JsonValue; + /** + * Whether post-tool-use failure hooks have already processed this result. + */ + postToolUseFailureHooksProcessed?: boolean; + /** + * Optional UI resource produced by the tool. + */ + uiResource?: JsonValue; + /** + * Metadata propagated with the tool result, including information-flow labels. + */ + mcpMeta?: { + [k: string]: JsonValue | undefined; + }; + /** + * Structured result content in addition to the model-facing text. + */ + structuredContent?: JsonValue; + taskCompletionDecision?: TaskCompletionDecision; } /** - * One problem found while validating a setting value. + * A message injected by a tool result. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingsValidationIssue". + * via the `definition` "ToolResultNewMessage". */ /** @experimental */ -export interface UserSettingsValidationIssue { +export interface ToolResultNewMessage { /** - * Where in the settings tree the problem sits, as object keys and array indices. The first element is the top-level key; a whole-value problem is reported as that single key. + * Message content to inject after the tool result. */ - path: JsonValue[]; + content: string; /** - * Human-readable description of the problem. + * Source attributed to the injected message. */ - message: string; + source: string; } /** - * One atomic edit of a canonical setting in settings.json. + * A tool name and arguments to execute through the session's native invocation pipeline. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingsEditRequest". + * via the `definition` "ToolsExecuteRequest". */ /** @experimental */ -/** @internal */ -export interface UserSettingsEditRequest { +export interface ToolsExecuteRequest { /** - * Configuration directory to edit. Omitted or empty resolves the server's own home, as in `user.settings.loadForConfigDir`. + * Name of the currently offered tool to execute. */ - configDir?: string; + name: string; /** - * Nonempty canonical path segments of the setting to edit, starting with its top-level key. - * - * @minItems 1 + * Arguments supplied to the tool. */ - canonicalPath: [string, ...string[]]; - operation: SettingsEditOperation; + arguments: JsonValue; /** - * Required boolean, string or number for set, required string for add-item and remove-item, and forbidden for remove. The runtime rejects all other JSON values. + * Optional identifier used to correlate this invocation with its tool call. */ - value?: JsonValue; + toolCallId?: string; } /** - * Selects which settings file paths to resolve. + * Options controlling how Rust-owned built-in tool descriptors are materialized. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingsGetPathsRequest". + * via the `definition` "ToolsGetBuiltinDescriptorsRequest". */ /** @experimental */ -export interface UserSettingsGetPathsRequest { +export interface ToolsGetBuiltinDescriptorsRequest { /** - * Absolute path of a repository root. Supply it to also resolve that repository's two settings file paths; omit it to resolve only the user path. + * Whether descriptors should favor fewer user-intervention prompts. */ - repoRoot?: string; + reduceUserIntervention?: boolean; + /** + * Whether tool descriptors should include authoring metadata. + */ + includeAuthor?: boolean; + /** + * Whether semantic skill lookup is available. + */ + skillEmbeddingEnabled?: boolean; + shellConfig?: ToolsShellDescriptorConfig; + /** + * Whether the configured shell supports PowerShell 7 syntax. + */ + shellSupportsPowerShell7Syntax?: boolean; + /** + * Default shell timeout in milliseconds. + */ + shellTimeoutMs?: number; + /** + * Whether background task completion notifications are enabled. + */ + backgroundTaskNotificationsEnabled?: boolean; } /** - * On-disk locations of the settings files this runtime reads. A path is reported whether or not the file exists. + * Shell-specific names and description lines used to materialize built-in shell tool descriptors. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingsGetPathsResult". + * via the `definition` "ToolsShellDescriptorConfig". */ /** @experimental */ -export interface UserSettingsGetPathsResult { +export interface ToolsShellDescriptorConfig { /** - * The user settings file: `settings.json` under the resolved Copilot home. This is the file `user.settings.get`, `user.settings.load`, and `user.settings.set` read and write. + * Stable shell type identifier. */ - userSettings: string; + shellType: string; /** - * The repository's checked-in settings file, or null when no repository root was supplied. + * Human-readable shell name. */ - repoSettings?: string | null; + displayName: string; /** - * The repository's local, untracked settings file, or null when no repository root was supplied. + * Tool name used to start shell commands. */ - repoLocalSettings?: string | null; + shellToolName: string; + /** + * Tool name used to read shell output. + */ + readShellToolName: string; + /** + * Tool name used to stop shell commands. + */ + stopShellToolName: string; + /** + * Tool name used to list active shells. + */ + listShellsToolName: string; + /** + * Additional model-facing shell description lines. + */ + descriptionLines: string[]; } /** - * Per-key metadata for every known user setting in settings.json, including settings left at their default. Excludes repository- and enterprise-managed overrides. + * Rust-owned built-in tool descriptors for the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingsGetResult". + * via the `definition` "ToolsGetBuiltinDescriptorsResult". */ /** @experimental */ -export interface UserSettingsGetResult { +export interface ToolsGetBuiltinDescriptorsResult { /** - * Every known user setting keyed by setting name, each with its effective value, default, and whether it is at the default. + * Built-in tool descriptors materialized for the session. */ - settings: { - [k: string]: UserSettingMetadata; - }; + tools: BuiltinToolDescriptor[]; } /** - * Top-level user-setting keys grouped by who may govern them. + * Current lightweight tool metadata snapshot for the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingsGovernanceKeysResult". + * via the `definition` "ToolsGetCurrentMetadataResult". */ /** @experimental */ -export interface UserSettingsGovernanceKeysResult { - /** - * Top-level keys a repository may override through `.github/copilot/settings.json` or `.github/copilot/settings.local.json`. - */ - repo: string[]; - /** - * Top-level keys a repository may override through a Claude-compatible repository config. - */ - claudeRepo: string[]; +export interface ToolsGetCurrentMetadataResult { /** - * Top-level keys an enterprise policy may fix through managed settings. + * Current tool metadata, or null when tools have not been initialized yet */ - managed: string[]; + tools: CurrentToolMetadata[] | null; } /** - * Contents of settings.json as stored, for a caller about to rewrite it. + * Resolve, build, and validate the runtime tool list for this session. Subagent sessions and consumer flows that need an initialized tool set before `send` invoke this. Default base-class implementation is a no-op for sessions that don't support tool validation. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingsLoadForEditResult". + * via the `definition` "ToolsInitializeAndValidateResult". */ /** @experimental */ -export interface UserSettingsLoadForEditResult { - /** - * `ok` when the file parsed, `missing` when there is no file yet, `invalid` when the file exists but will not parse. - */ - status: string; - /** - * Parsed contents, present only when `status` is `ok`. - */ - settings?: JsonValue; -} +export interface ToolsInitializeAndValidateResult {} /** - * Settings object whose key names should be canonicalized. + * No parameters; returns the external tool calls of the session and its sub-agents that are still waiting for a result. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingsNormalizeRequest". + * via the `definition` "ToolsListPendingRequestsRequest". */ /** @experimental */ -export interface UserSettingsNormalizeRequest { - /** - * Free-form settings object, possibly using legacy or snake_case key names. - */ - settings: JsonValue; -} +export interface ToolsListPendingRequestsRequest {} /** - * Settings object with canonical key names. + * Optional model identifier whose tool overrides should be applied to the listing. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingsNormalizeResult". + * via the `definition` "ToolsListRequest". */ /** @experimental */ -export interface UserSettingsNormalizeResult { +export interface ToolsListRequest { /** - * The same settings with every legacy or snake_case key renamed to its canonical spelling. + * Optional model ID — when provided, the returned tool list reflects model-specific overrides */ - settings: JsonValue; + model?: string; } /** - * One setting that will not take effect, and why. + * Complete externally implemented tool list for the calling connection. An empty list removes every tool previously supplied by that connection. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingsProblem". + * via the `definition` "ToolsSetRequest". */ /** @experimental */ -export interface UserSettingsProblem { +export interface ToolsSetRequest { /** - * Stable identifier for this problem within the reported set, so a caller can track a selection across refreshes. - */ - id: string; - /** - * What is wrong in machine-readable form, for a caller that wants to branch rather than display. - */ - kind: string; - /** - * Coarse grouping for the problem, for a caller that presents problems in sections. - */ - category: string; - source: UserSettingsProblemLocation; - /** - * The offending key as written in the file, when the problem is attributable to a single key. Absent when the whole file is at fault. - */ - rawKey?: string; - /** - * Why the setting will not take effect. Never contains the setting's value, which may be a token or another secret. + * Complete replacement list for the calling connection. */ - explanation: string; + tools: ProtocolExternalToolDefinition[]; } /** - * The settings layer a problem was found in. + * Empty result after replacing the calling connection's externally implemented tools. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingsProblemLocation". + * via the `definition` "ToolsSetResult". */ /** @experimental */ -export interface UserSettingsProblemLocation { - /** - * Which layer this is: `user`, `repo`, or `local`. - */ - kind: string; - /** - * The caller-supplied display label for the layer. - */ - label: string; +export interface ToolsSetResult {} +/** + * Task-completion tool arguments and final result used to build a label-safe session event payload. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ToolsTaskCompleteEventDataRequest". + */ +/** @experimental */ +export interface ToolsTaskCompleteEventDataRequest { /** - * Absolute path of the file backing this layer. + * Arguments supplied to the completed task_complete tool call. */ - filePath: string; + toolArgs: JsonValue; + finalResult: ToolResultExpanded; } /** - * One already-loaded settings layer to diagnose. + * Empty result after applying subagent settings * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingsProblemSource". + * via the `definition` "ToolsUpdateSubagentSettingsResult". */ /** @experimental */ -export interface UserSettingsProblemSource { +export interface ToolsUpdateSubagentSettingsResult {} +/** + * Multi-select string field where each option pairs a value with a display label. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIElicitationArrayAnyOfField". + */ +/** @experimental */ +export interface UIElicitationArrayAnyOfField { /** - * Which layer this is: `user`, `repo`, or `local`. + * Type discriminator. Always "array". */ - kind: string; + type: "array"; /** - * Caller-chosen display label for the layer, echoed back on each problem so a caller can group by layer without re-deriving its own naming. + * Human-readable label for the field. */ - label: string; + title?: string; /** - * Absolute path of the file backing this layer. + * Help text describing the field. */ - filePath: string; + description?: string; /** - * The layer's settings exactly as loaded, unnormalized. Empty when the file is missing or failed to parse. + * Minimum number of items the user must select. */ - config?: { - [k: string]: unknown | undefined; - }; + minItems?: number; /** - * True when the file itself failed to parse, so its keys could not be read at all. + * Maximum number of items the user may select. */ - invalid?: boolean; -} -/** - * The settings layers to diagnose. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingsProblemsRequest". - */ -/** @experimental */ -export interface UserSettingsProblemsRequest { + maxItems?: number; + items: UIElicitationArrayAnyOfFieldItems; /** - * Layers to diagnose, in the precedence order the caller applies them. + * Default values selected when the form is first shown. */ - sources?: UserSettingsProblemSource[]; + default?: string[]; } /** - * The settings that will not take effect across the given layers. + * Schema applied to each item in the array. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingsProblemsResult". + * via the `definition` "UIElicitationArrayAnyOfFieldItems". */ /** @experimental */ -export interface UserSettingsProblemsResult { +export interface UIElicitationArrayAnyOfFieldItems { /** - * Each setting that will not take effect, and why. Empty when every layer is healthy. + * Selectable options, each with a value and a display label. */ - problems?: UserSettingsProblem[]; + anyOf: UIElicitationArrayAnyOfFieldItemsAnyOf[]; } /** - * Partial user settings to write to settings.json. Each top-level key is written individually, replacing the existing value; a key whose value is null is removed. + * Selectable option for a UI elicitation multi-select array item, with submitted value and display label. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingsSetRequest". + * via the `definition` "UIElicitationArrayAnyOfFieldItemsAnyOf". */ /** @experimental */ -export interface UserSettingsSetRequest { +export interface UIElicitationArrayAnyOfFieldItemsAnyOf { /** - * Partial user settings to write, as a free-form object keyed by setting name + * Value submitted when this option is selected. */ - settings: JsonValue; + const: string; + /** + * Display label for this option. + */ + title: string; } /** - * Names the user setting to merge into, and the partial object to merge. + * Multi-select string field whose allowed values are defined inline. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingsUpdateRequest". + * via the `definition` "UIElicitationArrayEnumField". */ /** @experimental */ -/** @internal */ -export interface UserSettingsUpdateRequest { +export interface UIElicitationArrayEnumField { /** - * Top-level user-setting key to merge into, such as `extensions`. + * Type discriminator. Always "array". */ - key: string; + type: "array"; /** - * Value to store for `key`. When both the stored value and this value are objects, their fields are shallow-merged and fields this object does not name are preserved. Otherwise this value replaces the stored value. + * Human-readable label for the field. */ - value: JsonValue; + title?: string; /** - * Copilot configuration directory to write the settings document in, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to use the directory the server resolved for itself. + * Help text describing the field. */ - configDir?: string; + description?: string; /** - * Single-component name for the settings document at `/settings/.json`; path separators, `.` and `..` are rejected. Omit it, or pass an empty string, to use the main settings document. + * Minimum number of items the user must select. */ - subDir?: string; -} -/** - * The stored value of the user setting after the merge. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingsUpdateResult". - */ -/** @experimental */ -/** @internal */ -export interface UserSettingsUpdateResult { + minItems?: number; /** - * The key's stored value after the write: the merged object when both the stored value and the supplied value are objects, otherwise the supplied value. + * Maximum number of items the user may select. */ - value: JsonValue; + maxItems?: number; + items: UIElicitationArrayEnumFieldItems; + /** + * Default values selected when the form is first shown. + */ + default?: string[]; } /** - * A single top-level setting subtree to validate. + * Schema applied to each item in the array. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingsValidateRequest". + * via the `definition` "UIElicitationArrayEnumFieldItems". */ /** @experimental */ -export interface UserSettingsValidateRequest { - /** - * Top-level setting name to validate. - */ - topKey: string; +export interface UIElicitationArrayEnumFieldItems { /** - * Value to validate. Omitted when `delete` is true. + * Type discriminator. Always "string". */ - value?: JsonValue; + type: "string"; /** - * True to validate a removal of this key. The current settings file is not read. + * Allowed string values for each selected item. */ - delete?: boolean; + enum: string[]; } /** - * Outcome of validating one top-level setting subtree. + * Prompt message and JSON schema describing the form fields to elicit from the user. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingsValidateResult". + * via the `definition` "UIElicitationRequest". */ /** @experimental */ -export interface UserSettingsValidateResult { +export interface UIElicitationRequest { + mode?: McpElicitationFormMode; /** - * True when the subtree is valid. + * Message describing what information is needed from the user */ - ok: boolean; + message: string; + requestedSchema: UIElicitationSchema; /** - * Problems found, empty when `ok` is true. + * MCP request metadata. */ - issues?: UserSettingsValidationIssue[]; + _meta?: { + [k: string]: unknown | undefined; + }; + task?: McpTaskMetadata; + [k: string]: unknown | undefined; } /** - * The whole content to store in the user settings file. + * JSON Schema describing the form fields to present to the user * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "UserSettingsWriteAllRequest". + * via the `definition` "UIElicitationSchema". */ /** @experimental */ -export interface UserSettingsWriteAllRequest { +export interface UIElicitationSchema { /** - * The settings object to store. It replaces the file's entire content, so a key absent here is removed. + * Schema type indicator (always 'object') */ - settings: JsonValue; + type: "object"; + /** + * Form field definitions, keyed by field name + */ + properties: { + [k: string]: UIElicitationSchemaProperty | undefined; + }; + /** + * List of required field names + */ + required?: string[]; } /** - * Current sharing status and shareable GitHub URL for a session. + * Single-select string field whose allowed values are defined inline. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "VisibilityGetResult". + * via the `definition` "UIElicitationStringEnumField". */ /** @experimental */ -export interface VisibilityGetResult { +export interface UIElicitationStringEnumField { /** - * Whether the session has been synced to Mission Control (i.e. has a GitHub task). When false, the session cannot be shared and `status`/`shareUrl` are absent. + * Type discriminator. Always "string". */ - synced: boolean; - status?: SessionVisibilityStatus; + type: "string"; /** - * Shareable GitHub URL for the session. Present when the session is synced and the URL can be resolved. + * Human-readable label for the field. */ - shareUrl?: string; + title?: string; + /** + * Help text describing the field. + */ + description?: string; + /** + * Allowed string values. + */ + enum: string[]; + /** + * Optional display labels for each enum value, in the same order as `enum`. + */ + enumNames?: string[]; + /** + * Default value selected when the form is first shown. + */ + default?: string; } /** - * Desired sharing status for the session. + * Single-select string field where each option pairs a value with a display label. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "VisibilitySetRequest". + * via the `definition` "UIElicitationStringOneOfField". */ /** @experimental */ -export interface VisibilitySetRequest { - status: SessionVisibilityStatus; -} -/** - * Effective sharing status and shareable GitHub URL after updating session visibility. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "VisibilitySetResult". - */ -/** @experimental */ -export interface VisibilitySetResult { +export interface UIElicitationStringOneOfField { /** - * Whether the session has been synced to Mission Control (i.e. has a GitHub task). When false, the visibility change could not be applied and `status`/`shareUrl` are absent. + * Type discriminator. Always "string". */ - synced: boolean; - status?: SessionVisibilityStatus; + type: "string"; /** - * Shareable GitHub URL for the session. Present when the session is synced and the URL can be resolved. + * Human-readable label for the field. */ - shareUrl?: string; -} -/** - * Parameters for cooperatively aborting a workflow body. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowAbortRequest". - */ -/** @experimental */ -export interface WorkflowAbortRequest { + title?: string; /** - * Target session identifier + * Help text describing the field. */ - sessionId: string; + description?: string; /** - * Workflow run identifier. + * Selectable options, each with a value and a display label. */ - runId: string; + oneOf: UIElicitationStringOneOfFieldOneOf[]; /** - * Opaque token identifying the execution attempt to abort. + * Default value selected when the form is first shown. */ - executionToken: string; + default?: string; } /** - * Acknowledgement that a workflow request was accepted. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowAckResult". - */ -/** @experimental */ -export interface WorkflowAckResult {} -/** - * Options for one workflow-scoped subagent call. + * Selectable option for a UI elicitation single-select string field, with submitted value and display label. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowAgentOptions". + * via the `definition` "UIElicitationStringOneOfFieldOneOf". */ /** @experimental */ -export interface WorkflowAgentOptions { - /** - * Optional label distinguishing otherwise identical memoized agent calls. - */ - label?: string; - /** - * Optional JSON Schema for structured agent output. - */ - schema?: JsonValue; - /** - * Optional model identifier for the subagent. - */ - model?: string; +export interface UIElicitationStringOneOfFieldOneOf { /** - * Optional reasoning effort override for the subagent. + * Value submitted when this option is selected. */ - reasoningEffort?: string; - contextTier?: ContextTier; + const: string; /** - * Optional built-in or custom agent name whose definition configures the subagent. + * Display label for this option. */ - agent?: string; + title: string; } /** - * Parameters for one workflow-scoped subagent call. + * Boolean field rendered as a yes/no toggle. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowAgentRequest". + * via the `definition` "UIElicitationSchemaPropertyBoolean". */ /** @experimental */ -export interface WorkflowAgentRequest { +export interface UIElicitationSchemaPropertyBoolean { /** - * Workflow run identifier that owns the subagent. + * Type discriminator. Always "boolean". */ - workflowRunId: string; + type: "boolean"; /** - * Opaque token identifying the current workflow execution attempt. + * Human-readable label for the field. */ - executionToken: string; + title?: string; /** - * Prompt to send to the subagent. + * Help text describing the field. */ - prompt: string; - opts: WorkflowAgentOptions; -} -/** - * Result of one workflow-scoped subagent call. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowAgentResult". - */ -/** @experimental */ -export interface WorkflowAgentResult { + description?: string; /** - * Agent result, omitted when the agent produced no result. + * Default value selected when the form is first shown. */ - result?: JsonValue; + default?: boolean; } /** - * Prompt-safe durable identity and live status for a direct workflow agent. + * Free-text string field with optional length and format constraints. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowAgentSummary". + * via the `definition` "UIElicitationSchemaPropertyString". */ /** @experimental */ -export interface WorkflowAgentSummary { - /** - * Stable direct-agent identifier. - */ - agentId: string; - /** - * Tool-call identifier that launched the agent. - */ - toolCallId: string; - /** - * Owning workflow run identifier. - */ - runId: string; +export interface UIElicitationSchemaPropertyString { /** - * Phase identifier active when the agent was launched, or null. + * Type discriminator. Always "string". */ - phaseId: string | null; + type: "string"; /** - * Friendly, non-unique name intended for display + * Human-readable label for the field. */ - label: string; + title?: string; /** - * Friendly, non-unique name intended for display + * Help text describing the field. */ - displayName?: string; + description?: string; /** - * Registered agent type. + * Minimum number of characters required. */ - agentType: string; + minLength?: number; /** - * Current durable or live agent status. + * Maximum number of characters allowed. */ - status: string; + maxLength?: number; + format?: UIElicitationSchemaPropertyStringFormat; /** - * Model requested when the agent was launched. + * Default value populated in the input when the form is first shown. */ - requestedModel?: string; + default?: string; +} +/** + * Numeric field accepting either a number or an integer. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIElicitationSchemaPropertyNumber". + */ +/** @experimental */ +export interface UIElicitationSchemaPropertyNumber { + type: UIElicitationSchemaPropertyNumberType; /** - * Concrete model resolved for the agent. + * Human-readable label for the field. */ - resolvedModel?: string; + title?: string; /** - * Epoch milliseconds when the agent started. + * Help text describing the field. */ - startedAt?: number; + description?: string; /** - * Epoch milliseconds when the agent completed. + * Minimum allowed value (inclusive). */ - completedAt?: number; + minimum?: number; /** - * Accumulated active agent time in milliseconds. + * Maximum allowed value (inclusive). */ - activeMs: number; + maximum?: number; /** - * Prompt-safe live activity text. + * Default value populated in the input when the form is first shown. */ - activity?: string; + default?: number; } /** - * Parameters for cancelling a workflow run. + * The elicitation response (accept with form values, decline, or cancel) * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowCancelRequest". + * via the `definition` "UIElicitationResponse". */ /** @experimental */ -export interface WorkflowCancelRequest { +export interface UIElicitationResponse { + action: UIElicitationResponseAction; + content?: UIElicitationResponseContent; /** - * Workflow run identifier. + * MCP response metadata. */ - runId: string; + _meta?: { + [k: string]: unknown | undefined; + }; + [k: string]: unknown | undefined; } /** - * Current workflow phase identity. + * The form values submitted by the user (present when action is 'accept') * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowCurrentPhase". + * via the `definition` "UIElicitationResponseContent". */ /** @experimental */ -export interface WorkflowCurrentPhase { - /** - * Current phase identifier. - */ - id: string; - /** - * Zero-based declared phase ordinal, or null for an undeclared phase. - */ - ordinal: number | null; +export interface UIElicitationResponseContent { + [k: string]: UIElicitationFieldValue; } /** - * Declared or approved workflow resource ceilings. + * Indicates whether the elicitation response was accepted; false if it was already resolved by another client. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowDeclaredLimits". + * via the `definition` "UIElicitationResult". */ /** @experimental */ -export interface WorkflowDeclaredLimits { +export interface UIElicitationResult { /** - * Maximum concurrently active subagents. + * Whether the response was accepted. False if the request was already resolved by another client. */ - maxConcurrentSubagents?: number; + success: boolean; +} +/** + * Transient question to answer without adding it to conversation history. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIEphemeralQueryRequest". + */ +/** @experimental */ +export interface UIEphemeralQueryRequest { /** - * Maximum total subagents spawned by the run. + * Question to answer from the current conversation context. */ - maxTotalSubagents?: number; + question: string; /** - * Maximum accumulated active execution time in seconds. + * In-process streaming callback `(text) => void` invoked with each token as the model emits it. Internal and excluded from the public SDK surface. + * + * @internal */ - timeoutSeconds?: number; + onChunk?: OpaqueInProcessValue; /** - * Maximum AI credits consumed by subagents and descendants. + * In-process `AbortSignal` forwarded to the model client to cancel an in-flight request. Internal and excluded from the public SDK surface. + * + * @internal */ - maxAiCredits?: number; + abortSignal?: OpaqueInProcessValue; } /** - * Parameters sent to the owning extension to execute a workflow closure. + * Completed transient query. Ordered chunks and the terminal outcome are also delivered through `ui.ephemeral_query` session events while it runs. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowExecuteRequest". + * via the `definition` "UIEphemeralQueryResult". */ /** @experimental */ -export interface WorkflowExecuteRequest { +export interface UIEphemeralQueryResult { /** - * Target session identifier + * Answer returned by the model */ - sessionId: string; + answer: string; +} +/** + * User response for a pending exit-plan-mode request, with approval state, selected action, auto-approve flag, and feedback. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIExitPlanModeResponse". + */ +/** @experimental */ +export interface UIExitPlanModeResponse { /** - * Registered workflow name. + * Whether the plan was approved. */ - name: string; + approved: boolean; + selectedAction?: UIExitPlanModeAction; /** - * Workflow run identifier. + * Whether subsequent edits should be auto-approved without confirmation. */ - runId: string; + autoApproveEdits?: boolean; /** - * Opaque token identifying this workflow execution attempt. + * Feedback from the user when they declined the plan or requested changes. */ - executionToken: string; + feedback?: string; /** - * Workflow input value. + * When true, the agent is instructed to end its turn without starting implementation so the client can restore the session model and auto-submit a fresh implementation turn on it. Set only when a distinct plan configuration (a different model, reasoning effort, or context tier) actually ran the planning turn. */ - args: JsonValue; + deferImplementation?: boolean; } /** - * Result returned by an extension workflow closure. + * Request ID of a pending `auto_mode_switch.requested` event and the user's response. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowExecuteResult". + * via the `definition` "UIHandlePendingAutoModeSwitchRequest". */ /** @experimental */ -export interface WorkflowExecuteResult { +export interface UIHandlePendingAutoModeSwitchRequest { /** - * Workflow result value. + * The unique request ID from the auto_mode_switch.requested event */ - result?: JsonValue; + requestId: string; + response: UIAutoModeSwitchResponse; } /** - * Parameters for paging workflow progress. + * Pending elicitation request ID and the user's response (accept/decline/cancel + form values). * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowGetRunProgressRequest". + * via the `definition` "UIHandlePendingElicitationRequest". */ /** @experimental */ -export interface WorkflowGetRunProgressRequest { - /** - * Workflow run identifier. - */ - runId: string; +export interface UIHandlePendingElicitationRequest { /** - * Optional phase identifier used to scope records and cursors. + * The unique request ID from the elicitation.requested event */ - phaseId?: string; + requestId: string; + result: UIElicitationResponse; +} +/** + * Request ID of a pending `exit_plan_mode.requested` event and the user's response. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIHandlePendingExitPlanModeRequest". + */ +/** @experimental */ +export interface UIHandlePendingExitPlanModeRequest { /** - * Exclusive forward cursor. + * The unique request ID from the exit_plan_mode.requested event */ - afterSeq?: number; + requestId: string; + response: UIExitPlanModeResponse; +} +/** + * Indicates whether the pending UI request was resolved by this call. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIHandlePendingResult". + */ +/** @experimental */ +export interface UIHandlePendingResult { /** - * Exclusive backward cursor. + * True if the request was still pending and was resolved by this call. False if the request ID was unknown, already resolved by another client (e.g. GitHub), expired, or otherwise no longer pending. */ - beforeSeq?: number; + success: boolean; +} +/** + * Request ID of a pending `sampling.requested` event and an optional sampling result payload (omit to reject). + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIHandlePendingSamplingRequest". + */ +/** @experimental */ +export interface UIHandlePendingSamplingRequest { /** - * Maximum records to return. Defaults to 200 and is capped at 500. + * The unique request ID from the sampling.requested event */ - limit?: number; + requestId: string; + response?: UIHandlePendingSamplingResponse; } /** - * Parameters for retrieving a workflow run. + * Optional sampling result payload. Omit to reject/cancel the sampling request without providing a result. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowGetRunRequest". + * via the `definition` "UIHandlePendingSamplingResponse". */ /** @experimental */ -export interface WorkflowGetRunRequest { +export interface UIHandlePendingSamplingResponse { + [k: string]: unknown | undefined; +} +/** + * Request ID of a pending `session_limits_exhausted.requested` event and the user's selected limit action. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIHandlePendingSessionLimitsExhaustedRequest". + */ +/** @experimental */ +export interface UIHandlePendingSessionLimitsExhaustedRequest { /** - * Workflow run identifier. + * The unique request ID from the session_limits_exhausted.requested event */ - runId: string; + requestId: string; + response: UISessionLimitsExhaustedResponse; } /** - * Parameters for reading a workflow journal entry. + * The user's selected action for an exhausted session limit. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowJournalGetRequest". + * via the `definition` "UISessionLimitsExhaustedResponse". */ /** @experimental */ -export interface WorkflowJournalGetRequest { +export interface UISessionLimitsExhaustedResponse { + action: UISessionLimitsExhaustedResponseAction; /** - * Workflow run identifier. + * AI Credits to add to the current max when action is 'add'. */ - runId: string; + additionalAiCredits?: number; /** - * Opaque token identifying the current workflow execution attempt. + * New absolute max AI Credits when action is 'set'. */ - executionToken: string; + maxAiCredits?: number; +} +/** + * Request ID of a pending `user_input.requested` event and the user's response. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIHandlePendingUserInputRequest". + */ +/** @experimental */ +export interface UIHandlePendingUserInputRequest { /** - * Namespaced journal key. + * The unique request ID from the user_input.requested event */ - key: string; + requestId: string; + response: UIUserInputResponse; } /** - * Result of reading a workflow journal entry. + * User response for a pending user-input request, with answer text and whether it was typed freeform. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowJournalGetResult". + * via the `definition` "UIUserInputResponse". */ /** @experimental */ -export interface WorkflowJournalGetResult { +export interface UIUserInputResponse { /** - * Whether the journal contained the requested key. + * The user's answer text */ - hit: boolean; + answer: string; /** - * Cached JSON result. The hit field distinguishes a cached JSON null from a miss. + * True if the user typed a freeform response, false if they selected a presented choice. Used by telemetry to differentiate between free text input and choice selection. */ - resultJson?: JsonValue; + wasFreeform: boolean; } /** - * Parameters for storing a workflow journal entry. + * Register an in-process handler for `auto_mode_switch.requested` events. The caller still attaches the actual listener via the standard event-subscription mechanism; this registration solely tells the server bridge to skip its own dispatch (so a remote client doesn't race the in-process handler for the same requestId). * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowJournalPutRequest". + * via the `definition` "UIRegisterDirectAutoModeSwitchHandlerResult". */ /** @experimental */ -export interface WorkflowJournalPutRequest { +export interface UIRegisterDirectAutoModeSwitchHandlerResult { /** - * Workflow run identifier. + * Opaque handle representing the registration. Pass this same handle to `unregisterDirectAutoModeSwitchHandler` when the in-process handler is no longer active. Multiple registrations are reference-counted; the server bridge will only dispatch auto-mode-switch requests when no handles are active. */ - runId: string; + handle: string; +} +/** + * Opaque handle previously returned by `registerDirectAutoModeSwitchHandler` to release. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIUnregisterDirectAutoModeSwitchHandlerRequest". + */ +/** @experimental */ +export interface UIUnregisterDirectAutoModeSwitchHandlerRequest { /** - * Opaque token identifying the current workflow execution attempt. + * Handle previously returned by `registerDirectAutoModeSwitchHandler` */ - executionToken: string; + handle: string; +} +/** + * Indicates whether the handle was active and the registration count was decremented. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UIUnregisterDirectAutoModeSwitchHandlerResult". + */ +/** @experimental */ +export interface UIUnregisterDirectAutoModeSwitchHandlerResult { /** - * Namespaced journal key. + * True if the handle was active and decremented the counter; false if the handle was unknown. */ - key: string; + unregistered: boolean; +} +/** + * Subagent settings to apply to the current session + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UpdateSubagentSettingsRequest". + */ +/** @experimental */ +export interface UpdateSubagentSettingsRequest { /** - * JSON result to memoize. + * Subagent settings to apply, or null to clear the live session override */ - resultJson: JsonValue; + subagents?: SubagentSettings | null; } /** - * Parameters for paging workflow runs. + * Internal absolute code-change totals reported by the owning host. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowListRunsRequest". + * via the `definition` "UsageSetCodeChangesRequest". */ /** @experimental */ -export interface WorkflowListRunsRequest { +/** @internal */ +export interface UsageSetCodeChangesRequest { /** - * Exclusive forward cursor. + * Absolute added-line total, replacing the previous reading. */ - afterSeq?: number; + linesAdded: number; /** - * Exclusive backward cursor. + * Absolute removed-line total, replacing the previous reading. */ - beforeSeq?: number; + linesRemoved: number; /** - * Maximum terminal runs to return. Defaults to 200 and is capped at 500. + * Absolute changed-file count; omission preserves the previous count. */ - limit?: number; + filesCount?: number; } /** - * A page of workflow runs in durable creation order. + * Result of a user-requested shell command. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowListRunsResult". + * via the `definition` "UserRequestedShellCommandResult". */ /** @experimental */ -export interface WorkflowListRunsResult { +export interface UserRequestedShellCommandResult { /** - * Workflow run summaries in durable creation order. + * Tool call id emitted for the shell execution */ - runs: WorkflowRunSummary[]; + toolCallId: string; /** - * Oldest terminal-run cursor in this page, or null when the terminal window is empty. + * Whether the command completed successfully */ - oldestSeq?: number | null; + success: boolean; /** - * Newest terminal-run cursor in this page, or null when the terminal window is empty. + * Captured command output */ - newestSeq?: number | null; + output: string; /** - * Whether terminal runs newer than this page exist. + * Process exit code, when available */ - hasMoreNewer?: boolean; + exitCode?: number | null; /** - * Number of terminal runs older than this page. + * Error output when the execution failed */ - omittedOlder?: number; + error?: string; } /** - * Durable workflow run summary with read-time live overlays. + * A single user setting's effective value alongside its default, so consumers can render settings left at their default. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowRunSummary". + * via the `definition` "UserSettingMetadata". */ /** @experimental */ -export interface WorkflowRunSummary { +export interface UserSettingMetadata { /** - * Workflow run identifier. + * The effective value: the user's value if set, otherwise the default. */ - runId: string; + value: JsonValue; /** - * Registered workflow name. + * The centrally-known default for this setting (null when no default is registered). */ - workflowName: string; + default: JsonValue; /** - * Human-readable workflow description. + * True when the user has not set an explicit value for this setting (i.e. it is left at its default). Reflects whether the user has overridden the key, not whether the effective value happens to equal the default — a key explicitly set to a value identical to the default still reports false. */ - description: string; - status: WorkflowRunStatus; + isDefault: boolean; +} +/** + * A single top-level setting subtree to validate and write. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsApplyTopKeyRequest". + */ +/** @experimental */ +export interface UserSettingsApplyTopKeyRequest { /** - * Monotonic durable run revision. + * Canonical path of the setting the caller is editing. Currently informational only. */ - revision: number; + canonicalPath: string[]; /** - * Epoch milliseconds when the run was created. + * Top-level setting name to write. */ - createdAt: number; + topKey: string; /** - * Epoch milliseconds when execution first started, or null before start. + * Value to write for the whole top-level key. Omitted when `delete` is true. Explicit null is preserved and validated as null. */ - startedAt: number | null; + value?: JsonValue | null; /** - * Epoch milliseconds when the durable run was last updated. + * True to remove the top-level key instead of writing it. */ - updatedAt: number; + delete?: boolean; /** - * Epoch milliseconds when the run completed, or null while nonterminal. + * Records that the user chose an update channel explicitly, so the one-time staff channel migration stops reapplying. Honored only for the `autoUpdatesChannel` key. */ - completedAt: number | null; + completeStaffUpdateChannelMigration?: boolean; +} +/** + * Outcome of validating and writing one top-level setting subtree. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsApplyTopKeyResult". + */ +/** @experimental */ +export interface UserSettingsApplyTopKeyResult { /** - * Current phase identity, or null before any phase is entered. + * `ok` when the value was written, `validation-error` when it was rejected before any write, `write-error` when validation passed but the write failed. */ - currentPhase: WorkflowCurrentPhase | null; + status: string; /** - * Number of phases declared by the workflow. + * Problems found, present only when `status` is `validation-error`. */ - declaredPhaseCount: number; + issues?: UserSettingsValidationIssue[]; /** - * Number of direct workflow agents currently live. + * Why the write failed, present only when `status` is `write-error`. */ - liveAgentCount: number; + error?: string | null; +} +/** + * One problem found while validating a setting value. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsValidationIssue". + */ +/** @experimental */ +export interface UserSettingsValidationIssue { /** - * Total direct workflow agents spawned across all attempts. + * Where in the settings tree the problem sits, as object keys and array indices. The first element is the top-level key; a whole-value problem is reported as that single key. */ - totalSpawnedAgentCount: number; - consumed: WorkflowRunConsumed; - declaredLimits: WorkflowDeclaredLimits; + path: JsonValue[]; /** - * Approved effective resource ceilings, or null until approved. + * Human-readable description of the problem. */ - approved: WorkflowDeclaredLimits | null; + message: string; +} +/** + * The overrides and host context to resolve effective runtime settings from. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsBuildRuntimeRequest". + */ +/** @experimental */ +/** @internal */ +export interface UserSettingsBuildRuntimeRequest { /** - * Epoch milliseconds when this live-overlay snapshot was observed. + * Settings that take precedence over every document and environment layer, such as the values a host derived from its own command line. Keyed by setting name, with each value carried verbatim, so a host may pass keys this runtime does not recognize. Absent when the host contributes no overrides of its own. */ - observedAt: number; + overrides?: { + [k: string]: JsonValue | undefined; + }; /** - * Epoch milliseconds when the current active segment started, or null while inactive. + * The directory the settings are being resolved for. This selects the repository-scoped document, so a host resolving settings for a directory other than its own process working directory must pass that directory here. */ - activeSegmentStartedAt: number | null; + workingDirectory: string; /** - * Terminal run outcome, or null while nonterminal. + * The environment to read settings-bearing variables from. Passed explicitly rather than read from the server process so a host can resolve settings for an environment it is about to create rather than the one it runs in. */ - terminal: WorkflowRunTerminal | null; + environment: { + [k: string]: string | undefined; + }; /** - * Whether the durable run state currently passes runtime resume eligibility checks. + * The platform to apply platform-specific defaults for, in the same spelling the host's own runtime reports. */ - canResume: boolean; + platform: string; } /** - * Durable workflow resource consumption. + * One atomic edit of a canonical setting in settings.json. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowRunConsumed". + * via the `definition` "UserSettingsEditRequest". */ /** @experimental */ -export interface WorkflowRunConsumed { +/** @internal */ +export interface UserSettingsEditRequest { /** - * Accumulated active execution time in milliseconds. + * Configuration directory to edit. Omitted or empty resolves the server's own home, as in `user.settings.loadForConfigDir`. */ - activeMs: number; + configDir?: string; /** - * Total subagents spawned by the run. + * Nonempty canonical path segments of the setting to edit, starting with its top-level key. + * + * @minItems 1 */ - subagents: number; + canonicalPath: [string, ...string[]]; + operation: SettingsEditOperation; /** - * AI usage consumed by the run in nano-AIU. + * Required boolean, string or number for set, required string for add-item and remove-item, and forbidden for remove. The runtime rejects all other JSON values. */ - nanoAiu: number; + value?: JsonValue; } /** - * Prompt-safe terminal workflow outcome. + * Selects which settings file paths to resolve. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowRunTerminal". + * via the `definition` "UserSettingsGetPathsRequest". */ /** @experimental */ -export interface WorkflowRunTerminal { +export interface UserSettingsGetPathsRequest { /** - * Human-readable terminal reason. + * Absolute path of a repository root. Supply it to also resolve that repository's two settings file paths; omit it to resolve only the user path. */ - reason?: string; - failure?: WorkflowRunFailure; + repoRoot?: string; +} +/** + * On-disk locations of the settings files this runtime reads. A path is reported whether or not the file exists. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsGetPathsResult". + */ +/** @experimental */ +export interface UserSettingsGetPathsResult { /** - * Human-readable terminal error. + * The user settings file: `settings.json` under the resolved Copilot home. This is the file `user.settings.get`, `user.settings.load`, and `user.settings.set` read and write. */ - error?: string; + userSettings: string; /** - * Prompt-safe preview of the completed result. + * The repository's checked-in settings file, or null when no repository root was supplied. */ - resultPreview?: string; + repoSettings?: string | null; /** - * Pause initiator metadata, or null when the run did not pause. + * The repository's local, untracked settings file, or null when no repository root was supplied. */ - pauseInfo: WorkflowPauseInfo | null; + repoLocalSettings?: string | null; } /** - * One ordered workflow progress line. + * Per-key metadata for every known user setting in settings.json, including settings left at their default. Excludes repository- and enterprise-managed overrides. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowLogLine". + * via the `definition` "UserSettingsGetResult". */ /** @experimental */ -export interface WorkflowLogLine { - /** - * Monotonic sequence number within the workflow run. - */ - seq: number; - kind: WorkflowLogLineKind; +export interface UserSettingsGetResult { /** - * Progress text. + * Every known user setting keyed by setting name, each with its effective value, default, and whether it is at the default. */ - text: string; + settings: { + [k: string]: UserSettingMetadata; + }; } /** - * Parameters for recording workflow progress. + * Top-level user-setting keys grouped by who may govern them. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowLogRequest". + * via the `definition` "UserSettingsGovernanceKeysResult". */ /** @experimental */ -export interface WorkflowLogRequest { +export interface UserSettingsGovernanceKeysResult { /** - * Workflow run identifier. + * Top-level keys a repository may override through `.github/copilot/settings.json` or `.github/copilot/settings.local.json`. */ - runId: string; + repo: string[]; /** - * Opaque token identifying the current workflow execution attempt. + * Top-level keys a repository may override through a Claude-compatible repository config. */ - executionToken: string; + claudeRepo: string[]; /** - * Ordered progress lines to append. + * Top-level keys an enterprise policy may fix through managed settings. */ - lines: WorkflowLogLine[]; + managed: string[]; } /** - * Parameters for an owned durable pause checkpoint. + * The filesystem and environment facts a user-settings file is resolved from. Passed explicitly rather than read from the runtime's own process, so a host whose configuration directory differs from its process environment resolves the file it means. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowPauseCheckpointRequest". + * via the `definition` "UserSettingsHostContext". */ /** @experimental */ -export interface WorkflowPauseCheckpointRequest { +export interface UserSettingsHostContext { /** - * Workflow run identifier. + * The Copilot configuration directory, when the host set one. Takes precedence over `COPILOT_HOME` and the home directory. */ - runId: string; + configDir?: string; /** - * Opaque token identifying the execution attempt that reached the checkpoint. + * The user's home directory, used when neither a configuration directory nor `COPILOT_HOME` is set. */ - executionToken: string; + homeDirectory: string; /** - * Stable author-defined checkpoint key. + * The host's environment variables. `COPILOT_HOME` is read from here, as are the variables a settings hook may expand. */ - key: string; -} - -/** @experimental */ -export interface WorkflowPauseCheckpointResult { - action: WorkflowPauseCheckpointAction; + environment: {}; } /** - * Parameters for pausing a running workflow. + * A repository to read settings from, and the user layer they are merged over. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowPauseRequest". + * via the `definition` "UserSettingsLoadAndMergeRepoRequest". */ /** @experimental */ -export interface WorkflowPauseRequest { +/** @internal */ +export interface UserSettingsLoadAndMergeRepoRequest { /** - * Workflow run identifier. + * Absolute path of the repository root whose settings to read. When this is the user's home directory, the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as if it were repository policy. */ - runId: string; + repoRoot: string; + /** + * The user's own settings, keyed by setting name. The repository layer is merged over this; a repository may only add to the collection settings it is allowed to influence, so a user setting it does not name survives unchanged. + */ + userSettings: { + [k: string]: JsonValue | undefined; + }; } /** - * Durable lifecycle and timing for one workflow phase. + * The settings a consumer should act on inside a repository, together with any diagnostic raised while reading the repository layer. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowPhaseObservation". + * via the `definition` "UserSettingsLoadAndMergeRepoResult". */ /** @experimental */ -export interface WorkflowPhaseObservation { +/** @internal */ +export interface UserSettingsLoadAndMergeRepoResult { /** - * Phase identifier. + * The merged settings document, keyed by setting name. Equals the supplied user layer when the repository declares no settings. */ - id: string; + settings: { + [k: string]: JsonValue | undefined; + }; /** - * Zero-based declared phase ordinal, or null for an undeclared phase. + * Why part of the repository document was ignored, as a single human-readable string joining every diagnostic with `; `. Null when it loaded cleanly. The settings that did load are still merged, so a consumer should surface this and continue rather than treat it as a failure. */ - ordinal: number | null; + warning?: string | null; +} +/** + * Selects the configuration directory whose user settings to read. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsLoadForConfigDirRequest". + */ +/** @experimental */ +/** @internal */ +export interface UserSettingsLoadForConfigDirRequest { /** - * Human-readable phase title. + * Copilot configuration directory to read the settings document from, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to read the directory the server resolved for itself. */ - title: string; + configDir?: string; +} +/** + * Contents of settings.json as stored, for a caller about to rewrite it. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsLoadForEditResult". + */ +/** @experimental */ +export interface UserSettingsLoadForEditResult { /** - * Optional human-readable phase detail. + * `ok` when the file parsed, `missing` when there is no file yet, `invalid` when the file exists but will not parse. */ - detail?: string; - status: WorkflowPhaseStatus; - /** - * Most recent run attempt that entered this phase, or `0` if the phase has never been entered. - */ - lastEnteredRunAttempt: number; - /** - * Number of times execution entered this phase. - */ - entryCount: number; - /** - * Epoch milliseconds when this phase first started; for a skipped phase, the synthetic skip timestamp (equal to `completedAt`). - */ - startedAt?: number; - /** - * Epoch milliseconds when this phase completed; for a skipped phase, the synthetic skip timestamp (equal to `startedAt`). - */ - completedAt?: number; - /** - * Completed active time accumulated by this phase in milliseconds. - */ - accumulatedActiveMs: number; - /** - * Current live active time for this phase in milliseconds. - */ - currentActiveMs: number; - /** - * Total direct agents associated with this phase. - */ - totalAgentCount: number; + status: string; /** - * Direct agents in this phase that are currently live. + * Parsed contents, present only when `status` is `ok`. */ - liveAgentCount: number; + settings?: JsonValue; } /** - * One durable workflow progress record. + * Selects the repository whose checked-in settings to read. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowProgressLine". + * via the `definition` "UserSettingsLoadRepoRequest". */ /** @experimental */ -export interface WorkflowProgressLine { +export interface UserSettingsLoadRepoRequest { /** - * Global monotonic sequence number within the run. + * Absolute path of the repository root whose settings to read. When this is the user's home directory, the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as if it were repository policy. */ - seq: number; + repoRoot: string; +} +/** + * A repository's settings as stored, together with any diagnostic raised while reading them. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsLoadRepoResult". + */ +/** @experimental */ +export interface UserSettingsLoadRepoResult { /** - * Resume attempt that emitted this record. + * The repository's settings document, keyed by setting name, with each value carried verbatim. Null when the repository declares no settings. */ - attempt: number; + settings?: { + [k: string]: JsonValue | undefined; + } | null; /** - * Phase active when the record was emitted, or null before any phase. + * Why part of the document was ignored, as a single human-readable string joining every diagnostic with `; `. Null when the document loaded cleanly. The settings that did load are still reported, so a consumer should surface this and continue rather than treat it as a failure. */ - phaseId: string | null; + warning?: string | null; +} +/** + * The user's stored settings, together with any diagnostic raised while reading them. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsLoadWithWarningResult". + */ +/** @experimental */ +export interface UserSettingsLoadWithWarningResult { /** - * Epoch milliseconds when the record was persisted. + * The stored user settings document, keyed by setting name, with each value carried verbatim. Empty when the file could not be read at all. */ - recordedAt: number; - kind: WorkflowLogLineKind; + settings: { + [k: string]: JsonValue | undefined; + }; /** - * Prompt-safe progress text. + * Why part of the document was ignored, phrased for display to the user. Null when the document loaded cleanly. The settings that did load are still reported, so a consumer may surface this and continue rather than treat it as a failure. */ - text: string; + warning?: string | null; } /** - * A bidirectional page of workflow progress. + * The managed (enterprise policy) layer and the user layer to fold together. The field names carry the layer identity: nothing about a settings object identifies which layer produced it, so a generic base/override pair would let a caller transpose them and silently resolve the governance keys in the user's favour. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowProgressPage". + * via the `definition` "UserSettingsMergeManagedAndUserParams". */ /** @experimental */ -export interface WorkflowProgressPage { - /** - * Progress records in sequence order. - */ - records: WorkflowProgressLine[]; +/** @internal */ +export interface UserSettingsMergeManagedAndUserParams { /** - * Oldest sequence number in this page, or null when empty. + * The managed layer. Its governance keys win, and the per-entry `enabledPlugins` and `extraKnownMarketplaces` control maps are stamped back from it after the union. Omitted when the host is unmanaged. */ - oldestSeq: number | null; + managed?: JsonValue; /** - * Newest sequence number in this page, or null when empty. + * The user's own settings layer. Wins on every key the managed layer does not govern. Omitted when the user has no settings yet. */ - newestSeq: number | null; + user?: JsonValue; +} +/** + * The user layer folded over the managed layer. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsMergeManagedAndUserResult". + */ +/** @experimental */ +export interface UserSettingsMergeManagedAndUserResult { /** - * Whether progress records older than this page exist. + * The merged settings. An empty object when neither layer was supplied, so an unmanaged host with no user settings governs nothing. */ - hasMoreOlder: boolean; + settingsJson: JsonValue; +} +/** + * The user layer and the repository layer to fold together. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsMergeRepoValueParams". + */ +/** @experimental */ +/** @internal */ +export interface UserSettingsMergeRepoValueParams { /** - * Whether progress records newer than this page exist. + * The user's settings, already resolved against any managed layer. */ - hasMoreNewer: boolean; + userSettings: JsonValue; /** - * Run revision reflected by this page. + * The repository's checked-in settings layer. */ - revision: number; + repoSettings: JsonValue; } /** - * Parameters for resuming a workflow run from its persisted identity. + * The repository layer folded into the user layer. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowResumeRequest". + * via the `definition` "UserSettingsMergeRepoValueResult". */ /** @experimental */ -export interface WorkflowResumeRequest { +export interface UserSettingsMergeRepoValueResult { /** - * Workflow run identifier. + * The merged settings, with the per-entry managed control maps re-stamped from the runtime's ambient managed policy. */ - runId: string; - limits?: WorkflowRunLimits; + settingsJson: JsonValue; +} +/** + * Selects the configuration directory whose settings document to clean. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsMigrateObsoleteOnDiskRequest". + */ +/** @experimental */ +/** @internal */ +export interface UserSettingsMigrateObsoleteOnDiskRequest { /** - * Whether to notify the originating session when the workflow completes. + * The configuration directory holding the settings document to clean. A host that scopes a session to its own Copilot home passes that directory here; omit it to clean the document under the home the server resolved for itself. The home directory and environment are deliberately not caller-supplied: they decide only the settings path root and the two hook-parsing flags, and those describe the process doing the reading rather than the caller. */ - notifyOnComplete?: boolean; + configDir?: string; +} +/** + * The outcome of the one-time obsolete-settings cleanup. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsMigrateObsoleteOnDiskResult". + */ +/** @experimental */ +/** @internal */ +export interface UserSettingsMigrateObsoleteOnDiskResult { + status: UserSettingsMigrateObsoleteOnDiskStatus; +} +/** + * Selects the configuration directory to run the one-time staff log-level migration against, and supplies the caller's record of whether it has already run. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsMigrateStaffLogLevelOnceRequest". + */ +/** @experimental */ +/** @internal */ +export interface UserSettingsMigrateStaffLogLevelOnceRequest { + context: UserSettingsHostContext; /** - * Whether to emit workflow phase names to the session transcript. + * When the caller last recorded this migration, as an ISO-8601 timestamp. Supplying it lets the runtime answer `current` without re-running the evaluation. */ - logPhaseNames?: boolean; + cachedCompletedAt?: string; } /** - * Wire-only per-invocation workflow resource ceiling overrides. + * The outcome of the one-time staff log-level migration. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowRunLimits". + * via the `definition` "UserSettingsMigrateStaffLogLevelOnceResult". */ /** @experimental */ -export interface WorkflowRunLimits { +/** @internal */ +export interface UserSettingsMigrateStaffLogLevelOnceResult { + status: StaffLogLevelMigrationStatus; /** - * Maximum number of workflow subagents that may run concurrently. + * When the migration was recorded as done, as an ISO-8601 timestamp. Absent only for `ineligible`, which records nothing. */ - maxConcurrentSubagents?: number | null; + completedAt?: string; /** - * Maximum total number of workflow subagents that may be admitted. + * The settings document as it stands after the migration, keyed by setting name. Present only for `refreshed`, and only when the document could be re-read cleanly. */ - maxTotalSubagents?: number | null; + settings?: {}; +} +/** + * The outcome of the one-time staff update-channel migration. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsMigrateStaffUpdateChannelOnceResult". + */ +/** @experimental */ +/** @internal */ +export interface UserSettingsMigrateStaffUpdateChannelOnceResult { + status: StaffUpdateChannelMigrationStatus; /** - * Maximum accumulated active-execution time in seconds. Active execution includes the entire extension body, subprocess waits, queued-agent waits, and sleeps; time between resumed attempts is not counted. + * When the migration was recorded as done, as an ISO-8601 timestamp. Absent only for `ineligible`, which records nothing. */ - timeoutSeconds?: number | null; + completedAt?: string; +} +/** + * Settings object whose key names should be canonicalized. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsNormalizeRequest". + */ +/** @experimental */ +export interface UserSettingsNormalizeRequest { /** - * Maximum AI credits consumed by workflow subagents and their descendants. The post-paid ceiling is soft: parallel turns can settle beyond it before the run stops. + * Free-form settings object, possibly using legacy or snake_case key names. */ - maxAiCredits?: number | null; + settings: JsonValue; } /** - * Resolved persisted workflow identity and resumed run envelope. + * Settings object with canonical key names. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowResumeResult". + * via the `definition` "UserSettingsNormalizeResult". */ /** @experimental */ -export interface WorkflowResumeResult { +export interface UserSettingsNormalizeResult { /** - * Persisted workflow name resolved for the resumed run. + * The same settings with every legacy or snake_case key renamed to its canonical spelling. */ - workflowName: string; - run: WorkflowRunResult; + settings: JsonValue; } /** - * Complete current or terminal workflow run envelope. + * The on-disk location of the user's settings document. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowRunResult". + * via the `definition` "UserSettingsPathResult". */ /** @experimental */ -export interface WorkflowRunResult { +export interface UserSettingsPathResult { /** - * Workflow run identifier. + * Absolute path to the settings file this runtime reads and writes. Normally `settings.json` under the Copilot configuration directory; an extensionless legacy `settings` file is reported instead when it exists and `settings.json` does not. */ - runId: string; + path: string; +} +/** + * One setting that will not take effect, and why. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsProblem". + */ +/** @experimental */ +export interface UserSettingsProblem { /** - * One-based execution attempt represented by this envelope. Absent before the first attempt starts or when returned by an older runtime. + * Stable identifier for this problem within the reported set, so a caller can track a selection across refreshes. */ - attempt?: number; - status: WorkflowRunStatus; + id: string; /** - * Completed workflow result. + * What is wrong in machine-readable form, for a caller that wants to branch rather than display. */ - result?: JsonValue; + kind: string; /** - * Error message for an errored run. + * Coarse grouping for the problem, for a caller that presents problems in sections. */ - error?: string; - failure?: WorkflowRunFailure; + category: string; + source: UserSettingsProblemLocation; /** - * Reason for a halted or cancelled run. + * The offending key as written in the file, when the problem is attributable to a single key. Absent when the whole file is at fault. */ - reason?: string; + rawKey?: string; /** - * Partial journal and progress snapshot for a halted, cancelled, or errored run. + * Why the setting will not take effect. Never contains the setting's value, which may be a token or another secret. */ - snapshot?: JsonValue; - pauseInfo?: WorkflowPauseInfo; + explanation: string; } /** - * Full workflow run observability detail. + * The settings layer a problem was found in. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowRunDetail". + * via the `definition` "UserSettingsProblemLocation". */ /** @experimental */ -export interface WorkflowRunDetail { +export interface UserSettingsProblemLocation { /** - * Workflow run identifier. + * Which layer this is: `user`, `repo`, or `local`. */ - runId: string; + kind: string; /** - * Registered workflow name. + * The caller-supplied display label for the layer. */ - workflowName: string; + label: string; /** - * Human-readable workflow description. + * Absolute path of the file backing this layer. */ - description: string; - status: WorkflowRunStatus; + filePath: string; +} +/** + * One already-loaded settings layer to diagnose. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsProblemSource". + */ +/** @experimental */ +export interface UserSettingsProblemSource { /** - * Monotonic durable run revision. + * Which layer this is: `user`, `repo`, or `local`. */ - revision: number; + kind: string; /** - * Epoch milliseconds when the run was created. + * Caller-chosen display label for the layer, echoed back on each problem so a caller can group by layer without re-deriving its own naming. */ - createdAt: number; + label: string; /** - * Epoch milliseconds when execution first started, or null before start. + * Absolute path of the file backing this layer. */ - startedAt: number | null; + filePath: string; /** - * Epoch milliseconds when the durable run was last updated. + * The layer's settings exactly as loaded, unnormalized. Empty when the file is missing or failed to parse. */ - updatedAt: number; + config?: { + [k: string]: unknown | undefined; + }; /** - * Epoch milliseconds when the run completed, or null while nonterminal. + * True when the file itself failed to parse, so its keys could not be read at all. */ - completedAt: number | null; + invalid?: boolean; +} +/** + * The settings layers to diagnose. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsProblemsRequest". + */ +/** @experimental */ +export interface UserSettingsProblemsRequest { /** - * Current phase identity, or null before any phase is entered. + * Layers to diagnose, in the precedence order the caller applies them. */ - currentPhase: WorkflowCurrentPhase | null; + sources?: UserSettingsProblemSource[]; +} +/** + * The settings that will not take effect across the given layers. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsProblemsResult". + */ +/** @experimental */ +export interface UserSettingsProblemsResult { /** - * Number of phases declared by the workflow. + * Each setting that will not take effect, and why. Empty when every layer is healthy. */ - declaredPhaseCount: number; + problems?: UserSettingsProblem[]; +} +/** + * Selects the configuration directory to run the one-time staff model-selection reset against, and supplies the caller's record of whether it has already run. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsResetStaffModelSelectionOnceRequest". + */ +/** @experimental */ +/** @internal */ +export interface UserSettingsResetStaffModelSelectionOnceRequest { + context: UserSettingsHostContext; /** - * Number of direct workflow agents currently live. + * Whether the signed-in account is a staff account. The reset applies only to staff, so anything other than `true` returns `didReset: false` without touching the settings document. */ - liveAgentCount: number; + staff?: boolean; /** - * Total direct workflow agents spawned across all attempts. + * When the caller last recorded this reset, as an ISO-8601 timestamp. A timestamp at or after the cutoff means the reset already ran and is returned unchanged. */ - totalSpawnedAgentCount: number; - consumed: WorkflowRunConsumed; - declaredLimits: WorkflowDeclaredLimits; + staffModelResetAt?: string; +} +/** + * The outcome of the one-time staff model-selection reset. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsResetStaffModelSelectionOnceResult". + */ +/** @experimental */ +/** @internal */ +export interface UserSettingsResetStaffModelSelectionOnceResult { /** - * Approved effective resource ceilings, or null until approved. + * Whether the persisted model selection was cleared. Only `true` means the settings document changed and the host should adopt the returned settings. */ - approved: WorkflowDeclaredLimits | null; + didReset: boolean; /** - * Epoch milliseconds when this live-overlay snapshot was observed. + * The timestamp the host should now record, as an ISO-8601 timestamp. Carries the caller's own value back unchanged when nothing was reset. */ - observedAt: number; + resetAt?: string; /** - * Epoch milliseconds when the current active segment started, or null while inactive. + * The cutoff this reset is gated on, as an ISO-8601 timestamp. A recorded timestamp at or after it means the reset is already done. */ - activeSegmentStartedAt: number | null; + cutoff: string; /** - * Terminal run outcome, or null while nonterminal. + * The settings document as it stands after the reset, keyed by setting name. Present only when `didReset` is true. */ - terminal: WorkflowRunTerminal | null; + settings?: {}; +} +/** + * One hook to disable or re-enable. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsSetHookDisabledRequest". + */ +/** @experimental */ +/** @internal */ +export interface UserSettingsSetHookDisabledRequest { /** - * Whether the durable run state currently passes runtime resume eligibility checks. + * Path of the settings.json to rewrite. */ - canResume: boolean; + settingsPath: string; /** - * Lifecycle and timing observations for each workflow phase. + * Durable content-hash key of the hook, as `hooks.loadResources` reports it. */ - phases: WorkflowPhaseObservation[]; + disableKey: string; /** - * Durable identities and live statuses for direct workflow agents. + * True adds the key to `disabledHooks`, false removes it. */ - agents: WorkflowAgentSummary[]; - progress: WorkflowProgressPage; + disabled: boolean; } /** - * Options controlling workflow invocation. + * Outcome of rewriting the `disabledHooks` setting. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowRunOptions". + * via the `definition` "UserSettingsSetHookDisabledResult". */ /** @experimental */ -export interface WorkflowRunOptions { - limits?: WorkflowRunLimits; - /** - * Whether to notify the originating session when the workflow completes. - */ - notifyOnComplete?: boolean; +/** @internal */ +export interface UserSettingsSetHookDisabledResult { /** - * Whether to emit workflow phase names to the session transcript. + * `ok` when the setting was written, `invalid` when settings.json could not be parsed and was left alone, `error` when the write itself failed. */ - logPhaseNames?: boolean; + status: string; /** - * Run identifier whose journal and progress should seed this resumed run. + * Why the write failed. Absent when the status is `ok`. */ - resumeFromRunId?: string; + errorMessage?: string; } /** - * Parameters for invoking a registered workflow. + * Partial user settings to write to settings.json. Each top-level key is written individually, replacing the existing value; a key whose value is null is removed. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowRunRequest". + * via the `definition` "UserSettingsSetRequest". */ /** @experimental */ -export interface WorkflowRunRequest { - /** - * Registered workflow name. - */ - name: string; +export interface UserSettingsSetRequest { /** - * Workflow input value. + * Partial user settings to write, as a free-form object keyed by setting name */ - args: JsonValue; - options?: WorkflowRunOptions; + settings: JsonValue; } /** - * Internal parameters for resuming a workflow run from a tool. + * Selects the configuration directory whose user settings document should be inspected for unrecognized top-level keys. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowToolResumeRequest". + * via the `definition` "UserSettingsUnknownKeysWarningRequest". */ /** @experimental */ /** @internal */ -export interface WorkflowToolResumeRequest { - /** - * Workflow run identifier. - */ - runId: string; - limits?: WorkflowRunLimits; - /** - * Opaque identifier of the originating tool call. - */ - toolCallId?: string; +export interface UserSettingsUnknownKeysWarningRequest { + context: UserSettingsHostContext; } /** - * Options for an internal tool-originated workflow invocation. + * The unrecognized top-level keys found in the user settings document, already phrased for display. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowToolRunOptions". + * via the `definition` "UserSettingsUnknownKeysWarningResult". */ /** @experimental */ /** @internal */ -export interface WorkflowToolRunOptions { - limits?: WorkflowRunLimits; +export interface UserSettingsUnknownKeysWarningResult { /** - * Run identifier whose journal and progress should seed this resumed run. + * The warning to show the user, naming the unrecognized keys and the file they were found in. Absent when every top-level key is recognized, and also when the document is missing or could not be read, because an unknown-key list taken from a document the runtime could not load would name keys that may not be there. */ - resumeFromRunId?: string; + warning?: string; } /** - * Internal parameters for invoking a registered workflow from a tool. + * Names the user setting to merge into, and the partial object to merge. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkflowToolRunRequest". + * via the `definition` "UserSettingsUpdateRequest". */ /** @experimental */ /** @internal */ -export interface WorkflowToolRunRequest { +export interface UserSettingsUpdateRequest { /** - * Registered workflow name. + * Top-level user-setting key to merge into, such as `extensions`. */ - name: string; + key: string; /** - * Workflow input value. + * Value to store for `key`. When both the stored value and this value are objects, their fields are shallow-merged and fields this object does not name are preserved. Otherwise this value replaces the stored value. */ - args: JsonValue; - options?: WorkflowToolRunOptions; + value: JsonValue; /** - * Opaque identifier of the originating tool call. + * Copilot configuration directory to write the settings document in, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to use the directory the server resolved for itself. */ - toolCallId?: string; + configDir?: string; + /** + * Single-component name for the settings document at `/settings/.json`; path separators, `.` and `..` are rejected. Omit it, or pass an empty string, to use the main settings document. + */ + subDir?: string; } /** - * Complete text used to generate one session diff. These are display contents, with the same text decoding as the patch, not a file-restore contract. + * The stored value of the user setting after the merge. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspaceDiffContents". + * via the `definition` "UserSettingsUpdateResult". */ /** @experimental */ -export interface WorkspaceDiffContents { - /** - * Complete text before the session first changed the file. Omitted when the file did not exist; an empty string represents an existing empty file. - */ - before?: string; +/** @internal */ +export interface UserSettingsUpdateResult { /** - * Complete current text read when computing the diff. Omitted for a deleted file; an empty string represents an existing empty file. + * The key's stored value after the write: the merged object when both the stored value and the supplied value are objects, otherwise the supplied value. */ - after?: string; + value: JsonValue; } /** - * A single changed file and its unified diff. + * A single top-level setting subtree to validate. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspaceDiffFileChange". + * via the `definition` "UserSettingsValidateRequest". */ /** @experimental */ -export interface WorkspaceDiffFileChange { - /** - * Path to the changed file, relative to the workspace root when the file lives under it. A file changed outside the workspace root keeps a `../`-relative path, or an absolute path when no relative path exists (for example a different Windows drive). - */ - path: string; +export interface UserSettingsValidateRequest { /** - * Unified diff content for the file. Empty when the diff was truncated. + * Top-level setting name to validate. */ - diff: string; - changeType: WorkspaceDiffFileChangeType; + topKey: string; /** - * Original file path for renamed files. + * Value to validate. Omitted when `delete` is true. */ - oldPath?: string; + value?: JsonValue; /** - * Whether the diff content was omitted because it exceeded the per-file size limit. + * True to validate a removal of this key. The current settings file is not read. */ - isTruncated?: boolean; - contents?: WorkspaceDiffContents; + delete?: boolean; } /** - * Workspace diff result for the requested mode. + * Outcome of validating one top-level setting subtree. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspaceDiffResult". + * via the `definition` "UserSettingsValidateResult". */ /** @experimental */ -export interface WorkspaceDiffResult { - requestedMode: WorkspaceDiffMode; - mode: WorkspaceDiffMode; - /** - * Changed files and their unified diffs. - */ - changes: WorkspaceDiffFileChange[]; +export interface UserSettingsValidateResult { /** - * Default branch used for a branch diff, when branch mode was requested. + * True when the subtree is valid. */ - baseBranch?: string; + ok: boolean; /** - * Whether the requested diff fell back to unstaged changes, either because branch diff failed or session diff was unavailable. + * Problems found, empty when `ok` is true. */ - isFallback: boolean; - unavailableReason?: HistoryRewindUnavailableReason; + issues?: UserSettingsValidationIssue[]; } /** - * Compaction summary checkpoint to persist. + * The whole content to store in the user settings file. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesAddSummaryRequest". + * via the `definition` "UserSettingsWriteAllRequest". */ /** @experimental */ -export interface WorkspacesAddSummaryRequest { - /** - * Summary title shown in checkpoint listings. - */ - title: string; +export interface UserSettingsWriteAllRequest { /** - * Markdown summary content to persist. + * The settings object to store. It replaces the file's entire content, so a key absent here is removed. */ - content: string; + settings: JsonValue; } /** - * Persisted summary metadata and refreshed workspace metadata. + * Current sharing status and shareable GitHub URL for a session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesAddSummaryResult". + * via the `definition` "VisibilityGetResult". */ /** @experimental */ -export interface WorkspacesAddSummaryResult { +export interface VisibilityGetResult { /** - * Metadata for the persisted summary. + * Whether the session has been synced to Mission Control (i.e. has a GitHub task). When false, the session cannot be shared and `status`/`shareUrl` are absent. */ - summary?: {}; + synced: boolean; + status?: SessionVisibilityStatus; /** - * Refreshed metadata for the containing workspace. + * Shareable GitHub URL for the session. Present when the session is synced and the URL can be resolved. */ - workspace?: {}; - [k: string]: unknown | undefined; + shareUrl?: string; } /** - * Whether the autopilot objective file exists. + * Desired sharing status for the session. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesAutopilotObjectiveExistsResult". + * via the `definition` "VisibilitySetRequest". */ /** @experimental */ -export interface WorkspacesAutopilotObjectiveExistsResult { - /** - * True when the objective file exists. - */ - exists: boolean; +export interface VisibilitySetRequest { + status: SessionVisibilityStatus; } /** - * Workspace checkpoint metadata with assigned number, human-readable title, and checkpoint filename. + * Effective sharing status and shareable GitHub URL after updating session visibility. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesCheckpoints". + * via the `definition` "VisibilitySetResult". */ /** @experimental */ -export interface WorkspacesCheckpoints { +export interface VisibilitySetResult { /** - * Checkpoint number assigned by the workspace manager + * Whether the session has been synced to Mission Control (i.e. has a GitHub task). When false, the visibility change could not be applied and `status`/`shareUrl` are absent. */ - number: number; - /** - * Human-readable checkpoint title - */ - title: string; + synced: boolean; + status?: SessionVisibilityStatus; /** - * Filename of the checkpoint within the workspace checkpoints directory + * Shareable GitHub URL for the session. Present when the session is synced and the URL can be resolved. */ - filename: string; + shareUrl?: string; } /** - * Directory to create within the session workspace files directory. + * Parameters for cooperatively aborting a workflow body. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesCreateDirectoryRequest". + * via the `definition` "WorkflowAbortRequest". */ /** @experimental */ -export interface WorkspacesCreateDirectoryRequest { +export interface WorkflowAbortRequest { /** - * Slash-separated relative path within the workspace files directory + * Target session identifier */ - path: string; + sessionId: string; /** - * Whether to create missing parent directories. Defaults to false. + * Workflow run identifier. */ - recursive?: boolean; + runId: string; + /** + * Opaque token identifying the execution attempt to abort. + */ + executionToken: string; } /** - * Relative path and UTF-8 content for the workspace file to create or overwrite. + * Acknowledgement that a workflow request was accepted. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesCreateFileRequest". + * via the `definition` "WorkflowAckResult". */ /** @experimental */ -export interface WorkspacesCreateFileRequest { - /** - * Slash-separated relative path within the workspace files directory - */ - path: string; - /** - * File content to write as a UTF-8 string - */ - content: string; -} +export interface WorkflowAckResult {} /** - * Result of deleting the autopilot objective file. + * Options for one workflow-scoped subagent call. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesDeleteAutopilotObjectiveResult". + * via the `definition` "WorkflowAgentOptions". */ /** @experimental */ -export interface WorkspacesDeleteAutopilotObjectiveResult { +export interface WorkflowAgentOptions { /** - * True when a file was deleted. + * Optional label distinguishing otherwise identical memoized agent calls. */ - deleted: boolean; + label?: string; + /** + * Optional JSON Schema for structured agent output. + */ + schema?: JsonValue; + /** + * Optional model identifier for the subagent. + */ + model?: string; + /** + * Optional reasoning effort override for the subagent. + */ + reasoningEffort?: string; + contextTier?: ContextTier; + /** + * Optional built-in or custom agent name whose definition configures the subagent. + */ + agent?: string; } /** - * Parameters for computing a workspace diff. + * Parameters for one workflow-scoped subagent call. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesDiffRequest". + * via the `definition` "WorkflowAgentRequest". */ /** @experimental */ -export interface WorkspacesDiffRequest { - mode: WorkspaceDiffMode; +export interface WorkflowAgentRequest { /** - * When true, ignore whitespace-only changes (git `--ignore-all-space`). Defaults to false. + * Workflow run identifier that owns the subagent. */ - ignoreWhitespace?: boolean; + workflowRunId: string; /** - * Include the full before/after text used to compute each session diff. Defaults to false; true is accepted only for session mode. Existing capture/read limits still apply, and binary or unavailable contents are not returned. This can substantially increase response size. + * Opaque token identifying the current workflow execution attempt. */ - includeContents?: boolean; + executionToken: string; + /** + * Prompt to send to the subagent. + */ + prompt: string; + opts: WorkflowAgentOptions; } /** - * Optional session context used when creating a local workspace. + * Result of one workflow-scoped subagent call. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesEnsureRequest". + * via the `definition` "WorkflowAgentResult". */ /** @experimental */ -export interface WorkspacesEnsureRequest { +export interface WorkflowAgentResult { /** - * Opaque workspace context supplied by the session host. + * Agent result, omitted when the agent produced no result. */ - context?: JsonValue; + result?: JsonValue; } /** - * Current workspace metadata for the session, including its absolute filesystem path when available. + * Prompt-safe durable identity and live status for a direct workflow agent. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesGetWorkspaceResult". + * via the `definition` "WorkflowAgentSummary". */ /** @experimental */ -export interface WorkspacesGetWorkspaceResult { +export interface WorkflowAgentSummary { /** - * Current workspace metadata, or null if not available + * Stable direct-agent identifier. */ - workspace: { - /** - * Stable workspace identifier. - */ - id: string; - /** - * Current working directory associated with the workspace. - */ - cwd?: string; - /** - * Git repository root associated with the workspace. - */ - git_root?: string; - /** - * Repository identifier associated with the workspace. - */ - repository?: string; - host_type?: WorkspacesWorkspaceDetailsHostType; - /** - * Current Git branch. - */ - branch?: string; - /** - * Workspace display name. - */ - name?: string; - /** - * Name of the client that created the workspace. - */ - client_name?: string; - /** - * Whether the workspace name was explicitly chosen by the user. - */ - user_named?: boolean; - /** - * Number of persisted summaries in the workspace. - */ - summary_count?: number; - /** - * Timestamp when the workspace was created. - */ - created_at?: string; - /** - * Timestamp when the workspace was last updated. - */ - updated_at?: string; - /** - * Whether the workspace session can be steered remotely. - */ - remote_steerable?: boolean; - /** - * Mission Control task identifier associated with the workspace. - */ - mc_task_id?: string; - /** - * Mission Control session identifier associated with the workspace. - */ - mc_session_id?: string; - /** - * Most recent Mission Control event identifier observed for the workspace. - */ - mc_last_event_id?: string; - /** - * Whether the per-session Chronicle upgrade prompt was dismissed for the workspace. - */ - chronicle_sync_dismissed?: boolean; - } | null; + agentId: string; /** - * Absolute filesystem path to the workspace directory. Omitted when the session has no workspace (e.g. remote sessions). + * Tool-call identifier that launched the agent. */ - path?: string; + toolCallId: string; + /** + * Owning workflow run identifier. + */ + runId: string; + /** + * Phase identifier active when the agent was launched, or null. + */ + phaseId: string | null; + /** + * Friendly, non-unique name intended for display + */ + label: string; + /** + * Friendly, non-unique name intended for display + */ + displayName?: string; + /** + * Registered agent type. + */ + agentType: string; + /** + * Current durable or live agent status. + */ + status: string; + /** + * Model requested when the agent was launched. + */ + requestedModel?: string; + /** + * Concrete model resolved for the agent. + */ + resolvedModel?: string; + /** + * Epoch milliseconds when the agent started. + */ + startedAt?: number; + /** + * Epoch milliseconds when the agent completed. + */ + completedAt?: number; + /** + * Accumulated active agent time in milliseconds. + */ + activeMs: number; + /** + * Prompt-safe live activity text. + */ + activity?: string; } /** - * Workspace checkpoints in chronological order; empty when the workspace is not enabled. + * Parameters for cancelling a workflow run. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesListCheckpointsResult". + * via the `definition` "WorkflowCancelRequest". */ /** @experimental */ -export interface WorkspacesListCheckpointsResult { +export interface WorkflowCancelRequest { /** - * Workspace checkpoints in chronological order. Empty when workspace is not enabled. + * Workflow run identifier. */ - checkpoints: WorkspacesCheckpoints[]; + runId: string; } /** - * Relative paths of files stored in the session workspace files directory. + * Current workflow phase identity. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesListFilesResult". + * via the `definition` "WorkflowCurrentPhase". */ /** @experimental */ -export interface WorkspacesListFilesResult { +export interface WorkflowCurrentPhase { /** - * Slash-separated relative file paths in the workspace files directory + * Current phase identifier. */ - files: string[]; + id: string; + /** + * Zero-based declared phase ordinal, or null for an undeclared phase. + */ + ordinal: number | null; } /** - * Autopilot objective file content, or null when missing. + * Declared or approved workflow resource ceilings. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesReadAutopilotObjectiveResult". + * via the `definition` "WorkflowDeclaredLimits". */ /** @experimental */ -export interface WorkspacesReadAutopilotObjectiveResult { +export interface WorkflowDeclaredLimits { /** - * Autopilot objective file content, or null when missing. + * Maximum concurrently active subagents. */ - content: string | null; -} -/** - * Checkpoint number to read. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesReadCheckpointRequest". - */ -/** @experimental */ -export interface WorkspacesReadCheckpointRequest { + maxConcurrentSubagents?: number; /** - * Checkpoint number to read + * Maximum total subagents spawned by the run. */ - number: number; -} -/** - * Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesReadCheckpointResult". - */ -/** @experimental */ -export interface WorkspacesReadCheckpointResult { + maxTotalSubagents?: number; /** - * Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing + * Maximum accumulated active execution time in seconds. */ - content: string | null; + timeoutSeconds?: number; + /** + * Maximum AI credits consumed by subagents and descendants. + */ + maxAiCredits?: number; } /** - * Relative path of the workspace file to read. + * Parameters sent to the owning extension to execute a workflow closure. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesReadFileRequest". + * via the `definition` "WorkflowExecuteRequest". */ /** @experimental */ -export interface WorkspacesReadFileRequest { +export interface WorkflowExecuteRequest { /** - * Slash-separated relative path within the workspace files directory + * Target session identifier */ - path: string; + sessionId: string; + /** + * Registered workflow name. + */ + name: string; + /** + * Workflow run identifier. + */ + runId: string; + /** + * Opaque token identifying this workflow execution attempt. + */ + executionToken: string; + /** + * Workflow input value. + */ + args: JsonValue; } /** - * Contents of the requested workspace file as a UTF-8 string. + * Result returned by an extension workflow closure. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesReadFileResult". + * via the `definition` "WorkflowExecuteResult". */ /** @experimental */ -export interface WorkspacesReadFileResult { +export interface WorkflowExecuteResult { /** - * File content as a UTF-8 string + * Workflow result value. */ - content: string; + result?: JsonValue; } /** - * File or directory to remove from the session workspace files directory. + * Parameters for paging workflow progress. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesRemovePathRequest". + * via the `definition` "WorkflowGetRunProgressRequest". */ /** @experimental */ -export interface WorkspacesRemovePathRequest { +export interface WorkflowGetRunProgressRequest { /** - * Slash-separated relative path within the workspace files directory + * Workflow run identifier. */ - path: string; + runId: string; /** - * Whether to remove directory contents recursively. Defaults to false. + * Optional phase identifier used to scope records and cursors. */ - recursive?: boolean; + phaseId?: string; /** - * Whether a missing path should be treated as success. Defaults to false. + * Exclusive forward cursor. */ - force?: boolean; -} -/** - * Source and destination paths for a rename within the session workspace files directory. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesRenamePathRequest". - */ -/** @experimental */ -export interface WorkspacesRenamePathRequest { + afterSeq?: number; /** - * Slash-separated source path relative to the workspace files directory + * Exclusive backward cursor. */ - source: string; + beforeSeq?: number; /** - * Slash-separated destination path relative to the workspace files directory + * Maximum records to return. Defaults to 200 and is capped at 500. */ - destination: string; + limit?: number; } /** - * Pasted content to save as a UTF-8 file in the session workspace. + * Parameters for retrieving a workflow run. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesSaveLargePasteRequest". + * via the `definition` "WorkflowGetRunRequest". */ /** @experimental */ -export interface WorkspacesSaveLargePasteRequest { +export interface WorkflowGetRunRequest { /** - * Pasted content to save as a UTF-8 file + * Workflow run identifier. */ - content: string; + runId: string; } /** - * Descriptor for the saved paste file, or null when the workspace is unavailable. + * Parameters for reading a workflow journal entry. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesSaveLargePasteResult". + * via the `definition` "WorkflowJournalGetRequest". */ /** @experimental */ -export interface WorkspacesSaveLargePasteResult { +export interface WorkflowJournalGetRequest { /** - * Saved-paste descriptor, or null when the workspace is unavailable (e.g. CCA runtime, non-infinite sessions, remote sessions) + * Workflow run identifier. */ - saved: { - /** - * Absolute filesystem path to the saved paste file - */ - filePath: string; - /** - * Filename within the workspace files directory - */ - filename: string; - /** - * Size of the saved file in bytes - */ - sizeBytes: number; - } | null; + runId: string; + /** + * Opaque token identifying the current workflow execution attempt. + */ + executionToken: string; + /** + * Namespaced journal key. + */ + key: string; } /** - * Relative path of the workspace file or directory to inspect. + * Result of reading a workflow journal entry. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesStatFileRequest". + * via the `definition` "WorkflowJournalGetResult". */ /** @experimental */ -export interface WorkspacesStatFileRequest { +export interface WorkflowJournalGetResult { /** - * Slash-separated relative path within the workspace files directory + * Whether the journal contained the requested key. */ - path: string; + hit: boolean; + /** + * Cached JSON result. The hit field distinguishes a cached JSON null from a miss. + */ + resultJson?: JsonValue; } /** - * Filesystem metadata for a path in the session workspace files directory. + * Parameters for storing a workflow journal entry. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesStatFileResult". + * via the `definition` "WorkflowJournalPutRequest". */ /** @experimental */ -export interface WorkspacesStatFileResult { - /** - * Whether the path identifies a regular file - */ - isFile: boolean; +export interface WorkflowJournalPutRequest { /** - * Whether the path identifies a directory + * Workflow run identifier. */ - isDirectory: boolean; + runId: string; /** - * Size in bytes + * Opaque token identifying the current workflow execution attempt. */ - size: number; + executionToken: string; /** - * Last modification time in Unix epoch milliseconds + * Namespaced journal key. */ - mtimeMs: number; + key: string; /** - * Creation time in Unix epoch milliseconds + * JSON result to memoize. */ - birthtimeMs: number; + resultJson: JsonValue; } /** - * Rollback point for local workspace summaries. + * Parameters for paging workflow runs. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesTruncateSummariesRequest". + * via the `definition` "WorkflowListRunsRequest". */ /** @experimental */ -export interface WorkspacesTruncateSummariesRequest { +export interface WorkflowListRunsRequest { /** - * Number of newest summaries to keep. + * Exclusive forward cursor. */ - keepCount: number; -} -/** - * Workspace metadata fields to update. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesUpdateMetadataRequest". - */ -/** @experimental */ -export interface WorkspacesUpdateMetadataRequest { + afterSeq?: number; /** - * Opaque workspace context supplied by the session host. + * Exclusive backward cursor. */ - context?: JsonValue; + beforeSeq?: number; /** - * Optional workspace display name override. + * Maximum terminal runs to return. Defaults to 200 and is capped at 500. */ - name?: string; + limit?: number; } /** - * Autopilot objective file content to persist. + * A page of workflow runs in durable creation order. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesWriteAutopilotObjectiveRequest". + * via the `definition` "WorkflowListRunsResult". */ /** @experimental */ -export interface WorkspacesWriteAutopilotObjectiveRequest { +export interface WorkflowListRunsResult { /** - * Autopilot objective file content. + * Workflow run summaries in durable creation order. */ - content: string; -} -/** - * Result of writing the autopilot objective file. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "WorkspacesWriteAutopilotObjectiveResult". - */ -/** @experimental */ -export interface WorkspacesWriteAutopilotObjectiveResult { + runs: WorkflowRunSummary[]; /** - * Filesystem operation performed. + * Oldest terminal-run cursor in this page, or null when the terminal window is empty. */ - operation: string; + oldestSeq?: number | null; + /** + * Newest terminal-run cursor in this page, or null when the terminal window is empty. + */ + newestSeq?: number | null; + /** + * Whether terminal runs newer than this page exist. + */ + hasMoreNewer?: boolean; + /** + * Number of terminal runs older than this page. + */ + omittedOlder?: number; } /** - * The resident session the application has materialized on its own connection. + * Durable workflow run summary with read-time live overlays. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "HostCreateSessionResult". + * via the `definition` "WorkflowRunSummary". */ /** @experimental */ -export interface HostCreateSessionResult { +export interface WorkflowRunSummary { /** - * Runtime session UUID materialized on the application's SDK connection. + * Workflow run identifier. */ - sessionId: string; -} -/** - * One application-owned session handoff, requested by the supervised hosting participant. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "HostCreateSessionRequest". - */ -/** @experimental */ -export interface HostCreateSessionRequest { + runId: string; /** - * Unique identity for this participation, independent of the session lifetime. + * Registered workflow name. */ - handoffId: string; + workflowName: string; /** - * Resume an app-owned durable session instead of creating a new session. + * Human-readable workflow description. */ - resume?: boolean; + description: string; + status: WorkflowRunStatus; /** - * For an explicit publication, borrow an existing owning-connection resident - * instead of invoking the resume factory. Cold sessions still use the factory. + * Monotonic durable run revision. */ - preferResident?: boolean; + revision: number; /** - * Host-selected SDK creation or resume settings, without executable callbacks or tools. + * Epoch milliseconds when the run was created. */ - config: { - [k: string]: unknown | undefined; - }; + createdAt: number; + /** + * Epoch milliseconds when execution first started, or null before start. + */ + startedAt: number | null; + /** + * Epoch milliseconds when the durable run was last updated. + */ + updatedAt: number; + /** + * Epoch milliseconds when the run completed, or null while nonterminal. + */ + completedAt: number | null; + /** + * Current phase identity, or null before any phase is entered. + */ + currentPhase: WorkflowCurrentPhase | null; + /** + * Number of phases declared by the workflow. + */ + declaredPhaseCount: number; + /** + * Number of direct workflow agents currently live. + */ + liveAgentCount: number; + /** + * Total direct workflow agents spawned across all attempts. + */ + totalSpawnedAgentCount: number; + consumed: WorkflowRunConsumed; + declaredLimits: WorkflowDeclaredLimits; + /** + * Approved effective resource ceilings, or null until approved. + */ + approved: WorkflowDeclaredLimits | null; + /** + * Epoch milliseconds when this live-overlay snapshot was observed. + */ + observedAt: number; + /** + * Epoch milliseconds when the current active segment started, or null while inactive. + */ + activeSegmentStartedAt: number | null; + /** + * Terminal run outcome, or null while nonterminal. + */ + terminal: WorkflowRunTerminal | null; + /** + * Whether the durable run state currently passes runtime resume eligibility checks. + */ + canResume: boolean; } /** - * Empty acknowledgement for a completed host lifecycle operation. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "HostReleaseSessionResult". - */ -/** @experimental */ -export interface HostReleaseSessionResult {} -/** - * Ends one participation, not the application's session lifetime. + * Durable workflow resource consumption. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "HostReleaseSessionRequest". + * via the `definition` "WorkflowRunConsumed". */ /** @experimental */ -export interface HostReleaseSessionRequest { +export interface WorkflowRunConsumed { /** - * Identity of the participation to release without destroying the session. + * Accumulated active execution time in milliseconds. */ - handoffId: string; + activeMs: number; + /** + * Total subagents spawned by the run. + */ + subagents: number; + /** + * AI usage consumed by the run in nano-AIU. + */ + nanoAiu: number; } /** - * Empty acknowledgement for a completed host lifecycle operation. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "HostDisposeResult". - */ -/** @experimental */ -export interface HostDisposeResult {} -/** - * Private credentials delivered only to a runtime-owned Mission Control hosting participant. + * Prompt-safe terminal workflow outcome. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "HostGetEnvironmentCredentialsResult". + * via the `definition` "WorkflowRunTerminal". */ /** @experimental */ -export interface HostGetEnvironmentCredentialsResult { +export interface WorkflowRunTerminal { /** - * Current bearer token for the authenticated GitHub identity. + * Human-readable terminal reason. */ - token: string; + reason?: string; + failure?: WorkflowRunFailure; /** - * Hostname of the authenticated GitHub service. + * Human-readable terminal error. */ - githubHost: string; + error?: string; /** - * GitHub API base URL for the authenticated service. + * Prompt-safe preview of the completed result. */ - githubApiUrl: string; + resultPreview?: string; /** - * Mission Control API origin for environment registration and management. + * Pause initiator metadata, or null when the run did not pause. */ - missionControlUrl: string; + pauseInfo: WorkflowPauseInfo | null; } /** - * Normalized listener settings delivered only to the supervised hosting participant. + * One ordered workflow progress line. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "HostGetConfigurationResult". + * via the `definition` "WorkflowLogLine". */ /** @experimental */ -export interface HostGetConfigurationResult { - localServer?: HostLocalServerConfiguration; - githubEnvironment?: HostGitHubEnvironmentOptions; +export interface WorkflowLogLine { /** - * Whether session materialization is delegated to the owning application. + * Monotonic sequence number within the workflow run. */ - sessionFactory: boolean; + seq: number; + kind: WorkflowLogLineKind; /** - * Whether app-owned durable sessions are resumed by the owning application. + * Progress text. */ - resumeFactory: boolean; + text: string; } /** - * Empty acknowledgement for a completed host lifecycle operation. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "HostReadyResult". - */ -/** @experimental */ -export interface HostReadyResult {} -/** - * The resolved feature flags, keyed by flag name. + * Parameters for recording workflow progress. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "FeatureFlagsResolveResult". + * via the `definition` "WorkflowLogRequest". */ /** @experimental */ -export interface FeatureFlagsResolveResult { +export interface WorkflowLogRequest { /** - * Whether the flag is enabled for this population. + * Workflow run identifier. */ - [k: string]: boolean | undefined; -} -/** - * Ordered managed permission verdicts and the supplied policy's fail-closed posture. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ManagedSettingsPermissionsEvaluateResult". - */ -/** @experimental */ -export interface ManagedSettingsPermissionsEvaluateResult { + runId: string; /** - * One verdict per input operation, in the same order, including duplicates. + * Opaque token identifying the current workflow execution attempt. */ - results: ManagedPermissionEvaluation[]; + executionToken: string; /** - * Managed permission policy could not be determined; every operation is denied. + * Ordered progress lines to append. */ - failClosed: boolean; + lines: WorkflowLogLine[]; } /** - * Managed policy context and ordered operations for pure, sessionless evaluation. + * Parameters for an owned durable pause checkpoint. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ManagedSettingsPermissionsEvaluateRequest". + * via the `definition` "WorkflowPauseCheckpointRequest". */ /** @experimental */ -export interface ManagedSettingsPermissionsEvaluateRequest { - context: ManagedPermissionsContext; +export interface WorkflowPauseCheckpointRequest { /** - * Operations to evaluate, preserving input order and duplicates. An empty batch is valid. + * Workflow run identifier. */ - operations: ManagedPermissionOperation[]; -} - -/** @experimental */ -export interface SessionWorkflowPauseAtCheckpointResult { - action: WorkflowPauseCheckpointAction; -} - -/** @experimental */ -export interface SessionModelClearStartupSeedResult { - cleared: boolean; -} - -/** @experimental */ -export interface SessionModelClearStartupSeedRequest { - expectedModel: string; + runId: string; /** - * Provider captured with the startup seed; omission matches only an unqualified seed. + * Opaque token identifying the execution attempt that reached the checkpoint. */ - expectedProviderId?: string; -} - -/** @experimental */ -export interface SessionModelListRequest { + executionToken: string; /** - * If true, bypasses the per-session model list cache and re-fetches from CAPI. + * Stable author-defined checkpoint key. */ - skipCache?: boolean; + key: string; } /** @experimental */ -export interface SessionAgentListRequest { - /** - * When true, request the session's configured built-in agents alongside custom agents. Listing applies feature, context, inclusion, exclusion, and user-disabled-agent policy, but does not evaluate transient invocation requirements such as model availability. Built-in metadata may be omitted when the session cannot project it, such as a relay session. - */ - includeBuiltInAgents?: boolean; - /** - * When true, request authored base prompt text on each AgentInfo. Prompt text may be omitted when unavailable, such as for agents projected through a relay session. - */ - includePrompt?: boolean; +export interface WorkflowPauseCheckpointResult { + action: WorkflowPauseCheckpointAction; } /** - * An inert runtime-issued login handle. Preparation alone performs no activation or OAuth work. + * Parameters for pausing a running workflow. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionMcpOauthPrepareLoginResult". + * via the `definition` "WorkflowPauseRequest". */ /** @experimental */ -export interface SessionMcpOauthPrepareLoginResult { - /** - * Retain with the original requester and use for one login or cancellation. - */ - loginId: string; +export interface WorkflowPauseRequest { /** - * Original expiry, not extended by consumption, retries or cancellation. + * Workflow run identifier. */ - expiresAt: string; + runId: string; } /** - * Effect-free preparation bound to the existing local session, requester and installation, with frozen options. + * Durable lifecycle and timing for one workflow phase. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionMcpOauthPrepareLoginRequest". + * via the `definition` "WorkflowPhaseObservation". */ /** @experimental */ -export interface SessionMcpOauthPrepareLoginRequest { +export interface WorkflowPhaseObservation { /** - * Name recorded by the authoritative owned installation receipt. + * Phase identifier. */ - serverName: string; + id: string; /** - * Exact installation identity from owned inventory, never a server-name alias. + * Zero-based declared phase ordinal, or null for an undeclared phase. */ - expectedInstallationId: string; + ordinal: number | null; /** - * Request a new authorisation rather than accepting a usable cached grant. + * Human-readable phase title. */ - forceReauth?: boolean; + title: string; /** - * Display name used by the incumbent OAuth client-registration flow. + * Optional human-readable phase detail. */ - clientName?: string; + detail?: string; + status: WorkflowPhaseStatus; /** - * Text shown on the loopback callback page after successful authorisation. + * Most recent run attempt that entered this phase, or `0` if the phase has never been entered. */ - callbackSuccessMessage?: string; -} -/** - * Honest terminal cancellation result; persistence or recovery failures remain RPC errors. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionMcpOauthCancelLoginResult". - */ -/** @experimental */ -export interface SessionMcpOauthCancelLoginResult { + lastEnteredRunAttempt: number; /** - * True after cancellation settles, false when the original login already connected successfully. + * Number of times execution entered this phase. */ - cancelled: boolean; -} -/** - * Targets only the original prepared/applying owned login on this exact session requester. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionMcpOauthCancelLoginRequest". - */ -/** @experimental */ -export interface SessionMcpOauthCancelLoginRequest { + entryCount: number; /** - * The same authoritative installation identity supplied during preparation. + * Epoch milliseconds when this phase first started; for a skipped phase, the synthetic skip timestamp (equal to `completedAt`). */ - expectedInstallationId: string; + startedAt?: number; /** - * Runtime-issued login handle known before the effectful login request begins. + * Epoch milliseconds when this phase completed; for a skipped phase, the synthetic skip timestamp (equal to `startedAt`). */ - loginId: string; + completedAt?: number; + /** + * Completed active time accumulated by this phase in milliseconds. + */ + accumulatedActiveMs: number; + /** + * Current live active time for this phase in milliseconds. + */ + currentActiveMs: number; + /** + * Total direct agents associated with this phase. + */ + totalAgentCount: number; + /** + * Direct agents in this phase that are currently live. + */ + liveAgentCount: number; } /** - * Standard MCP CallToolResult + * One durable workflow progress record. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionMcpAppsCallToolResult". + * via the `definition` "WorkflowProgressLine". */ /** @experimental */ -export interface SessionMcpAppsCallToolResult { - [k: string]: JsonValue | undefined; -} - -/** @experimental */ -export interface SessionPluginsMarketplacesRefreshRequest { - /** - * Marketplace name to refresh. When omitted, every registered marketplace is refreshed. - */ - name?: string; -} - -/** @experimental */ -export interface SessionPluginsReloadRequest { - /** - * Reload MCP server connections after refreshing plugins. Defaults to true. - */ - reloadMcp?: boolean; +export interface WorkflowProgressLine { /** - * Re-run custom-agent discovery after refreshing plugins. Defaults to true. + * Global monotonic sequence number within the run. */ - reloadCustomAgents?: boolean; + seq: number; /** - * Re-load user, plugin, and (subject to `deferRepoHooks`) repo hooks. Defaults to true. Has no effect when the host has not registered a hook reloader (e.g. remote sessions). + * Resume attempt that emitted this record. */ - reloadHooks?: boolean; + attempt: number; /** - * Re-discover and relaunch subprocess extensions (including plugin-shipped extensions) after refreshing plugins. Defaults to true. Has no effect when the session has no active extension controller (e.g. extensions were not requested for the session). + * Phase active when the record was emitted, or null before any phase. */ - reloadExtensions?: boolean; + phaseId: string | null; /** - * When true, skip repo-level hooks during the hook reload. Use before folder trust is confirmed; load them post-trust via `sessions.loadDeferredRepoHooks`. + * Epoch milliseconds when the record was persisted. */ - deferRepoHooks?: boolean; -} - -/** @experimental */ -export interface SessionProviderGetEndpointRequest { + recordedAt: number; + kind: WorkflowLogLineKind; /** - * Model identifier the caller intends to use against the returned endpoint. Used to pick the correct wire shape. Omit to use whichever model the session is currently using. + * Prompt-safe progress text. */ - modelId?: string; + text: string; } - +/** + * A bidirectional page of workflow progress. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkflowProgressPage". + */ /** @experimental */ -export interface SessionCommandsListRequest { +export interface WorkflowProgressPage { /** - * Include runtime built-in commands + * Progress records in sequence order. */ - includeBuiltins?: boolean; + records: WorkflowProgressLine[]; /** - * Include enabled user-invocable skills and commands + * Oldest sequence number in this page, or null when empty. */ - includeSkills?: boolean; + oldestSeq: number | null; /** - * Include commands registered by protocol clients, including SDK clients and extensions + * Newest sequence number in this page, or null when empty. */ - includeClientCommands?: boolean; -} - -/** @experimental */ -export interface SessionHistoryCompactRequest { + newestSeq: number | null; /** - * Optional user-provided instructions to focus the compaction summary + * Whether progress records older than this page exist. */ - customInstructions?: string; + hasMoreOlder: boolean; /** - * What initiated this compaction request, recorded as the `trigger` on the persisted `session.compaction_start` / `session.compaction_complete` events. When absent, the compaction is persisted without trigger attribution (initiator unknown). + * Whether progress records newer than this page exist. */ - trigger?: /** User-requested compaction, e.g. the /compact command or a direct history.compact call. */ - | "manual" - /** Compaction requested while switching to a model with a smaller context window. */ - | "model_switch"; + hasMoreNewer: boolean; /** - * Context window token limit this compaction is targeting, recorded as the `tokenLimit` on the persisted `session.compaction_start` / `session.compaction_complete` events. Set it when the compaction targets a window other than the compacting model's own, e.g. switching to a model with a smaller context window: the compaction still runs on the current model, so the limit that motivated it would otherwise be lost. When absent, the events record the compacting model's own resolved limit. Attribution metadata only - it does not change how much the compaction removes. + * Run revision reflected by this page. */ - tokenLimit?: number; + revision: number; } /** - * Internal absolute code-change totals reported by the owning host. + * Parameters for resuming a workflow run from its persisted identity. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionUsageSetCodeChangesRequest". + * via the `definition` "WorkflowResumeRequest". */ /** @experimental */ -export interface SessionUsageSetCodeChangesRequest { +export interface WorkflowResumeRequest { /** - * Absolute added-line total, replacing the previous reading. + * Workflow run identifier. */ - linesAdded: number; + runId: string; + limits?: WorkflowRunLimits; /** - * Absolute removed-line total, replacing the previous reading. + * Whether to notify the originating session when the workflow completes. */ - linesRemoved: number; + notifyOnComplete?: boolean; /** - * Absolute changed-file count; omission preserves the previous count. + * Whether to emit workflow phase names to the session transcript. */ - filesCount?: number; + logPhaseNames?: boolean; } /** - * The incumbent session-owned quota and account projection. + * Wire-only per-invocation workflow resource ceiling overrides. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionQuotaGetResult". + * via the `definition` "WorkflowRunLimits". */ /** @experimental */ -export interface SessionQuotaGetResult { +export interface WorkflowRunLimits { /** - * Known quota snapshots, keyed by the provider's quota type. + * Maximum number of workflow subagents that may run concurrently. */ - snapshots: { - [k: string]: SessionQuotaSnapshot | undefined; - }; + maxConcurrentSubagents?: number | null; /** - * Provider-owned account quota state, including snapshots without numeric balances. + * Maximum total number of workflow subagents that may be admitted. */ - providerQuotas?: ProviderQuotaState[]; + maxTotalSubagents?: number | null; /** - * Whether the account uses the free limited Copilot plan. + * Maximum accumulated active-execution time in seconds. Active execution includes the entire extension body, subprocess waits, queued-agent waits, and sleeps; time between resumed attempts is not counted. */ - isFreeUser: boolean; + timeoutSeconds?: number | null; /** - * Whether the account uses token-based billing. + * Maximum AI credits consumed by workflow subagents and their descendants. The post-paid ceiling is soft: parallel turns can settle beyond it before the run stops. */ - isTbbUser: boolean; - planTier: SessionQuotaPlanTier; + maxAiCredits?: number | null; +} +/** + * Resolved persisted workflow identity and resumed run envelope. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkflowResumeResult". + */ +/** @experimental */ +export interface WorkflowResumeResult { /** - * Whether premium-request costs are billable. + * Persisted workflow name resolved for the resumed run. */ - premiumRequestsBillable: boolean; + workflowName: string; + run: WorkflowRunResult; +} +/** + * Complete current or terminal workflow run envelope. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkflowRunResult". + */ +/** @experimental */ +export interface WorkflowRunResult { /** - * Whether model cost columns should be shown. + * Workflow run identifier. */ - modelCostColumnVisible: boolean; + runId: string; /** - * Whether the account can delegate tasks to GitHub. + * One-based execution attempt represented by this envelope. Absent before the first attempt starts or when returned by an older runtime. */ - delegateAvailable: boolean; + attempt?: number; + status: WorkflowRunStatus; /** - * Whether the account can sign up for Copilot Free. + * Completed workflow result. */ - canSignupForCopilotFree: boolean; + result?: JsonValue; /** - * Whether dynamic workflows are enabled for the active account. + * Error message for an errored run. */ - dynamicWorkflowsEnabled: boolean; + error?: string; + failure?: WorkflowRunFailure; /** - * Whether dynamic workflows are visible under the session's feature flags. + * Reason for a halted or cancelled run. */ - dynamicWorkflowsUiVisible: boolean; + reason?: string; /** - * Upgrade link for a free account. + * Partial journal and progress snapshot for a halted, cancelled, or errored run. */ - upgradeUrl?: string; - delegateWarning?: SessionQuotaDelegateWarning; + snapshot?: JsonValue; + pauseInfo?: WorkflowPauseInfo; } /** - * The incumbent session-owned quota and account projection. + * Full workflow run observability detail. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionQuotaRefreshResult". + * via the `definition` "WorkflowRunDetail". */ /** @experimental */ -export interface SessionQuotaRefreshResult { +export interface WorkflowRunDetail { /** - * Known quota snapshots, keyed by the provider's quota type. + * Workflow run identifier. */ - snapshots: { - [k: string]: SessionQuotaSnapshot | undefined; - }; + runId: string; /** - * Provider-owned account quota state, including snapshots without numeric balances. + * Registered workflow name. */ - providerQuotas?: ProviderQuotaState[]; + workflowName: string; /** - * Whether the account uses the free limited Copilot plan. + * Human-readable workflow description. */ - isFreeUser: boolean; + description: string; + status: WorkflowRunStatus; /** - * Whether the account uses token-based billing. + * Monotonic durable run revision. */ - isTbbUser: boolean; - planTier: SessionQuotaPlanTier; + revision: number; /** - * Whether premium-request costs are billable. + * Epoch milliseconds when the run was created. */ - premiumRequestsBillable: boolean; + createdAt: number; /** - * Whether model cost columns should be shown. + * Epoch milliseconds when execution first started, or null before start. */ - modelCostColumnVisible: boolean; + startedAt: number | null; /** - * Whether the account can delegate tasks to GitHub. + * Epoch milliseconds when the durable run was last updated. */ - delegateAvailable: boolean; + updatedAt: number; /** - * Whether the account can sign up for Copilot Free. + * Epoch milliseconds when the run completed, or null while nonterminal. */ - canSignupForCopilotFree: boolean; + completedAt: number | null; /** - * Whether dynamic workflows are enabled for the active account. + * Current phase identity, or null before any phase is entered. */ - dynamicWorkflowsEnabled: boolean; + currentPhase: WorkflowCurrentPhase | null; /** - * Whether dynamic workflows are visible under the session's feature flags. + * Number of phases declared by the workflow. */ - dynamicWorkflowsUiVisible: boolean; + declaredPhaseCount: number; /** - * Upgrade link for a free account. + * Number of direct workflow agents currently live. */ - upgradeUrl?: string; - delegateWarning?: SessionQuotaDelegateWarning; -} - -/** @experimental */ -export interface SessionLimitPredictionPredictRequest { + liveAgentCount: number; /** - * Optional model identifier override. If omitted, the session's current model is used. + * Total direct workflow agents spawned across all attempts. */ - modelId?: string; - clientType?: SessionLimitPredictionClientType; + totalSpawnedAgentCount: number; + consumed: WorkflowRunConsumed; + declaredLimits: WorkflowDeclaredLimits; + /** + * Approved effective resource ceilings, or null until approved. + */ + approved: WorkflowDeclaredLimits | null; + /** + * Epoch milliseconds when this live-overlay snapshot was observed. + */ + observedAt: number; + /** + * Epoch milliseconds when the current active segment started, or null while inactive. + */ + activeSegmentStartedAt: number | null; + /** + * Terminal run outcome, or null while nonterminal. + */ + terminal: WorkflowRunTerminal | null; + /** + * Whether the durable run state currently passes runtime resume eligibility checks. + */ + canResume: boolean; + /** + * Lifecycle and timing observations for each workflow phase. + */ + phases: WorkflowPhaseObservation[]; + /** + * Durable identities and live statuses for direct workflow agents. + */ + agents: WorkflowAgentSummary[]; + progress: WorkflowProgressPage; } /** - * Identifies the target session. + * Options controlling workflow invocation. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SkillProviderListRequest". + * via the `definition` "WorkflowRunOptions". */ /** @experimental */ -export interface SkillProviderListRequest { +export interface WorkflowRunOptions { + limits?: WorkflowRunLimits; /** - * Target session identifier + * Whether to notify the originating session when the workflow completes. */ - sessionId: string; + notifyOnComplete?: boolean; + /** + * Whether to emit workflow phase names to the session transcript. + */ + logPhaseNames?: boolean; + /** + * Run identifier whose journal and progress should seed this resumed run. + */ + resumeFromRunId?: string; } /** - * Identifies the target session. + * Parameters for invoking a registered workflow. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "SessionFsSqliteExistsRequest". + * via the `definition` "WorkflowRunRequest". */ /** @experimental */ -export interface SessionFsSqliteExistsRequest { +export interface WorkflowRunRequest { /** - * Target session identifier + * Registered workflow name. */ - sessionId: string; + name: string; + /** + * Workflow input value. + */ + args: JsonValue; + options?: WorkflowRunOptions; } /** - * The existing runtime identity and its resource on the listener. + * Internal parameters for resuming a workflow run from a tool. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "HostRegisterSessionResult". + * via the `definition` "WorkflowToolResumeRequest". */ /** @experimental */ -export interface HostRegisterSessionResult { +/** @internal */ +export interface WorkflowToolResumeRequest { /** - * Canonical runtime ID of the published session. + * Workflow run identifier. */ - sessionId: string; + runId: string; + limits?: WorkflowRunLimits; /** - * AHP resource URI for the session on this listener. + * Opaque identifier of the originating tool call. */ - sessionUri: string; + toolCallId?: string; } /** - * The resident session the application has materialized on its own connection. + * Options for an internal tool-originated workflow invocation. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "HostMaterializeSessionResult". + * via the `definition` "WorkflowToolRunOptions". */ /** @experimental */ -export interface HostMaterializeSessionResult { +/** @internal */ +export interface WorkflowToolRunOptions { + limits?: WorkflowRunLimits; /** - * Runtime session UUID materialized on the application's SDK connection. + * Run identifier whose journal and progress should seed this resumed run. */ - sessionId: string; + resumeFromRunId?: string; } /** - * Application callback routed over its existing SDK connection. + * Internal parameters for invoking a registered workflow from a tool. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "HostMaterializeSessionRequest". + * via the `definition` "WorkflowToolRunRequest". */ /** @experimental */ -export interface HostMaterializeSessionRequest { - /** - * Listener UUID identifying the owning application's host. - */ - hostId: string; +/** @internal */ +export interface WorkflowToolRunRequest { /** - * Unique identity of the session participation being requested. + * Registered workflow name. */ - handoffId: string; + name: string; /** - * Resume an app-owned durable session instead of creating a new session. + * Workflow input value. */ - resume?: boolean; + args: JsonValue; + options?: WorkflowToolRunOptions; /** - * Host-selected SDK creation or resume settings, without executable callbacks or tools. + * Opaque identifier of the originating tool call. */ - config: { - [k: string]: unknown | undefined; - }; + toolCallId?: string; } /** - * Releases the original application session object retained for one handoff. + * Complete text used to generate one session diff. These are display contents, with the same text decoding as the patch, not a file-restore contract. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "HostSessionReleasedRequest". + * via the `definition` "WorkspaceDiffContents". */ /** @experimental */ -export interface HostSessionReleasedRequest { +export interface WorkspaceDiffContents { /** - * Listener UUID whose application session participation ended. + * Complete text before the session first changed the file. Omitted when the file did not exist; an empty string represents an existing empty file. */ - hostId: string; + before?: string; /** - * Identity of the handoff retaining the original application session object. + * Complete current text read when computing the diff. Omitted for a deleted file; an empty string represents an existing empty file. */ - handoffId: string; + after?: string; } /** - * Empty acknowledgement for a completed host lifecycle operation. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "HostShutdownResult". - */ -/** @experimental */ -export interface HostShutdownResult {} -/** - * Reports a supervised listener's hosting-task termination and cleanup outcome. + * A single changed file and its unified diff. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "HostExitedRequest". + * via the `definition` "WorkspaceDiffFileChange". */ /** @experimental */ -export interface HostExitedRequest { +export interface WorkspaceDiffFileChange { /** - * Listener UUID. + * Path to the changed file, relative to the workspace root when the file lives under it. A file changed outside the workspace root keeps a `../`-relative path, or an absolute path when no relative path exists (for example a different Windows drive). */ - hostId: string; - reason: HostExitReason; + path: string; /** - * Process exit status when available; absent for in-process listener tasks. + * Unified diff content for the file. Empty when the diff was truncated. */ - exitCode?: number | null; + diff: string; + changeType: WorkspaceDiffFileChangeType; /** - * Explicit startup or teardown failure, when present. + * Original file path for renamed files. */ - error?: string | null; + oldPath?: string; + /** + * Whether the diff content was omitted because it exceeded the per-file size limit. + */ + isTruncated?: boolean; + contents?: WorkspaceDiffContents; } /** - * A response is meaningful only on the connection and request that issued its challenge. + * Workspace diff result for the requested mode. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "InstallationsConfirmResult". + * via the `definition` "WorkspaceDiffResult". */ /** @experimental */ -export interface InstallationsConfirmResult { +export interface WorkspaceDiffResult { + requestedMode: WorkspaceDiffMode; + mode: WorkspaceDiffMode; /** - * Exact challenge from the request. + * Changed files and their unified diffs. */ - confirmationId: string; + changes: WorkspaceDiffFileChange[]; /** - * Exact review commitment from the request. + * Default branch used for a branch diff, when branch mode was requested. */ - reviewFingerprint: string; - decision: InstallationDecision; + baseBranch?: string; + /** + * Whether the requested diff fell back to unstaged changes, either because branch diff failed or session diff was unavailable. + */ + isFallback: boolean; + unavailableReason?: HistoryRewindUnavailableReason; } /** - * One connection-owned, expiring request for a trusted host's explicit user decision. + * Compaction summary checkpoint to persist. * * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "InstallationsConfirmRequest". + * via the `definition` "WorkspacesAddSummaryRequest". + */ +/** @experimental */ +export interface WorkspacesAddSummaryRequest { + /** + * Summary title shown in checkpoint listings. + */ + title: string; + /** + * Markdown summary content to persist. + */ + content: string; +} +/** + * Persisted summary metadata and refreshed workspace metadata. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesAddSummaryResult". + */ +/** @experimental */ +export interface WorkspacesAddSummaryResult { + /** + * Metadata for the persisted summary. + */ + summary?: {}; + /** + * Refreshed metadata for the containing workspace. + */ + workspace?: {}; + [k: string]: unknown | undefined; +} +/** + * Whether the autopilot objective file exists. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesAutopilotObjectiveExistsResult". + */ +/** @experimental */ +export interface WorkspacesAutopilotObjectiveExistsResult { + /** + * True when the objective file exists. + */ + exists: boolean; +} +/** + * Workspace checkpoint metadata with assigned number, human-readable title, and checkpoint filename. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesCheckpoints". + */ +/** @experimental */ +export interface WorkspacesCheckpoints { + /** + * Checkpoint number assigned by the workspace manager + */ + number: number; + /** + * Human-readable checkpoint title + */ + title: string; + /** + * Filename of the checkpoint within the workspace checkpoints directory + */ + filename: string; +} +/** + * Directory to create within the session workspace files directory. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesCreateDirectoryRequest". + */ +/** @experimental */ +export interface WorkspacesCreateDirectoryRequest { + /** + * Slash-separated relative path within the workspace files directory + */ + path: string; + /** + * Whether to create missing parent directories. Defaults to false. + */ + recursive?: boolean; +} +/** + * Relative path and UTF-8 content for the workspace file to create or overwrite. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesCreateFileRequest". + */ +/** @experimental */ +export interface WorkspacesCreateFileRequest { + /** + * Slash-separated relative path within the workspace files directory + */ + path: string; + /** + * File content to write as a UTF-8 string + */ + content: string; +} +/** + * Result of deleting the autopilot objective file. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesDeleteAutopilotObjectiveResult". + */ +/** @experimental */ +export interface WorkspacesDeleteAutopilotObjectiveResult { + /** + * True when a file was deleted. + */ + deleted: boolean; +} +/** + * Parameters for computing a workspace diff. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesDiffRequest". + */ +/** @experimental */ +export interface WorkspacesDiffRequest { + mode: WorkspaceDiffMode; + /** + * When true, ignore whitespace-only changes (git `--ignore-all-space`). Defaults to false. + */ + ignoreWhitespace?: boolean; + /** + * Include the full before/after text used to compute each session diff. Defaults to false; true is accepted only for session mode. Existing capture/read limits still apply, and binary or unavailable contents are not returned. This can substantially increase response size. + */ + includeContents?: boolean; +} +/** + * Optional session context used when creating a local workspace. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesEnsureRequest". + */ +/** @experimental */ +export interface WorkspacesEnsureRequest { + /** + * Opaque workspace context supplied by the session host. + */ + context?: JsonValue; +} +/** + * Current workspace metadata for the session, including its absolute filesystem path when available. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesGetWorkspaceResult". + */ +/** @experimental */ +export interface WorkspacesGetWorkspaceResult { + /** + * Current workspace metadata, or null if not available + */ + workspace: { + /** + * Stable workspace identifier. + */ + id: string; + /** + * Current working directory associated with the workspace. + */ + cwd?: string; + /** + * Git repository root associated with the workspace. + */ + git_root?: string; + /** + * Repository identifier associated with the workspace. + */ + repository?: string; + host_type?: WorkspacesWorkspaceDetailsHostType; + /** + * Current Git branch. + */ + branch?: string; + /** + * Workspace display name. + */ + name?: string; + /** + * Name of the client that created the workspace. + */ + client_name?: string; + /** + * Whether the workspace name was explicitly chosen by the user. + */ + user_named?: boolean; + /** + * Number of persisted summaries in the workspace. + */ + summary_count?: number; + /** + * Timestamp when the workspace was created. + */ + created_at?: string; + /** + * Timestamp when the workspace was last updated. + */ + updated_at?: string; + /** + * Whether the workspace session can be steered remotely. + */ + remote_steerable?: boolean; + /** + * Mission Control task identifier associated with the workspace. + */ + mc_task_id?: string; + /** + * Mission Control session identifier associated with the workspace. + */ + mc_session_id?: string; + /** + * Most recent Mission Control event identifier observed for the workspace. + */ + mc_last_event_id?: string; + /** + * Whether the per-session Chronicle upgrade prompt was dismissed for the workspace. + */ + chronicle_sync_dismissed?: boolean; + } | null; + /** + * Absolute filesystem path to the workspace directory. Omitted when the session has no workspace (e.g. remote sessions). + */ + path?: string; +} +/** + * Workspace checkpoints in chronological order; empty when the workspace is not enabled. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesListCheckpointsResult". + */ +/** @experimental */ +export interface WorkspacesListCheckpointsResult { + /** + * Workspace checkpoints in chronological order. Empty when workspace is not enabled. + */ + checkpoints: WorkspacesCheckpoints[]; +} +/** + * Relative paths of files stored in the session workspace files directory. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesListFilesResult". + */ +/** @experimental */ +export interface WorkspacesListFilesResult { + /** + * Slash-separated relative file paths in the workspace files directory + */ + files: string[]; +} +/** + * Autopilot objective file content, or null when missing. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesReadAutopilotObjectiveResult". + */ +/** @experimental */ +export interface WorkspacesReadAutopilotObjectiveResult { + /** + * Autopilot objective file content, or null when missing. + */ + content: string | null; +} +/** + * Checkpoint number to read. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesReadCheckpointRequest". + */ +/** @experimental */ +export interface WorkspacesReadCheckpointRequest { + /** + * Checkpoint number to read + */ + number: number; +} +/** + * Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesReadCheckpointResult". + */ +/** @experimental */ +export interface WorkspacesReadCheckpointResult { + /** + * Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace is missing + */ + content: string | null; +} +/** + * Relative path of the workspace file to read. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesReadFileRequest". + */ +/** @experimental */ +export interface WorkspacesReadFileRequest { + /** + * Slash-separated relative path within the workspace files directory + */ + path: string; +} +/** + * Contents of the requested workspace file as a UTF-8 string. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesReadFileResult". + */ +/** @experimental */ +export interface WorkspacesReadFileResult { + /** + * File content as a UTF-8 string + */ + content: string; +} +/** + * File or directory to remove from the session workspace files directory. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesRemovePathRequest". + */ +/** @experimental */ +export interface WorkspacesRemovePathRequest { + /** + * Slash-separated relative path within the workspace files directory + */ + path: string; + /** + * Whether to remove directory contents recursively. Defaults to false. + */ + recursive?: boolean; + /** + * Whether a missing path should be treated as success. Defaults to false. + */ + force?: boolean; +} +/** + * Source and destination paths for a rename within the session workspace files directory. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesRenamePathRequest". + */ +/** @experimental */ +export interface WorkspacesRenamePathRequest { + /** + * Slash-separated source path relative to the workspace files directory + */ + source: string; + /** + * Slash-separated destination path relative to the workspace files directory + */ + destination: string; +} +/** + * Pasted content to save as a UTF-8 file in the session workspace. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesSaveLargePasteRequest". + */ +/** @experimental */ +export interface WorkspacesSaveLargePasteRequest { + /** + * Pasted content to save as a UTF-8 file + */ + content: string; +} +/** + * Descriptor for the saved paste file, or null when the workspace is unavailable. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesSaveLargePasteResult". + */ +/** @experimental */ +export interface WorkspacesSaveLargePasteResult { + /** + * Saved-paste descriptor, or null when the workspace is unavailable (e.g. CCA runtime, non-infinite sessions, remote sessions) + */ + saved: { + /** + * Absolute filesystem path to the saved paste file + */ + filePath: string; + /** + * Filename within the workspace files directory + */ + filename: string; + /** + * Size of the saved file in bytes + */ + sizeBytes: number; + } | null; +} +/** + * Relative path of the workspace file or directory to inspect. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesStatFileRequest". + */ +/** @experimental */ +export interface WorkspacesStatFileRequest { + /** + * Slash-separated relative path within the workspace files directory + */ + path: string; +} +/** + * Filesystem metadata for a path in the session workspace files directory. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesStatFileResult". + */ +/** @experimental */ +export interface WorkspacesStatFileResult { + /** + * Whether the path identifies a regular file + */ + isFile: boolean; + /** + * Whether the path identifies a directory + */ + isDirectory: boolean; + /** + * Size in bytes + */ + size: number; + /** + * Last modification time in Unix epoch milliseconds + */ + mtimeMs: number; + /** + * Creation time in Unix epoch milliseconds + */ + birthtimeMs: number; +} +/** + * Rollback point for local workspace summaries. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesTruncateSummariesRequest". + */ +/** @experimental */ +export interface WorkspacesTruncateSummariesRequest { + /** + * Number of newest summaries to keep. + */ + keepCount: number; +} +/** + * Workspace metadata fields to update. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesUpdateMetadataRequest". + */ +/** @experimental */ +export interface WorkspacesUpdateMetadataRequest { + /** + * Opaque workspace context supplied by the session host. + */ + context?: JsonValue; + /** + * Optional workspace display name override. + */ + name?: string; +} +/** + * Autopilot objective file content to persist. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesWriteAutopilotObjectiveRequest". + */ +/** @experimental */ +export interface WorkspacesWriteAutopilotObjectiveRequest { + /** + * Autopilot objective file content. + */ + content: string; +} +/** + * Result of writing the autopilot objective file. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "WorkspacesWriteAutopilotObjectiveResult". + */ +/** @experimental */ +export interface WorkspacesWriteAutopilotObjectiveResult { + /** + * Filesystem operation performed. + */ + operation: string; +} +/** + * The effective sandbox settings, with every unset value resolved to its default. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SandboxSettingsApplyDefaultsResult". + */ +/** @experimental */ +export interface SandboxSettingsApplyDefaultsResult { + /** + * One resolved sandbox setting's value, carried verbatim. + */ + [k: string]: JsonValue | undefined; +} +/** + * The stored user settings document, keyed by setting name. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsLoadForConfigDirResult". + */ +/** @experimental */ +export interface UserSettingsLoadForConfigDirResult { + /** + * One setting's stored value, carried verbatim. + */ + [k: string]: JsonValue | undefined; +} +/** + * The effective runtime settings, keyed by setting name. Keys this runtime does not recognize are preserved rather than dropped, so a caller reading a document written by a newer runtime keeps every value. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "UserSettingsBuildRuntimeResult". + */ +/** @experimental */ +export interface UserSettingsBuildRuntimeResult { + /** + * One resolved setting's effective value, carried verbatim. + */ + [k: string]: JsonValue | undefined; +} +/** + * The resolved gates, keyed by flag name. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "FeatureFlagsResolveStartupGatesResult". + */ +/** @experimental */ +export interface FeatureFlagsResolveStartupGatesResult { + /** + * Whether the gate is on for this installation. + */ + [k: string]: boolean | undefined; +} +/** + * The resolved feature flags, keyed by flag name. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "FeatureFlagsResolveResult". + */ +/** @experimental */ +export interface FeatureFlagsResolveResult { + /** + * Whether the flag is enabled for this population. + */ + [k: string]: boolean | undefined; +} +/** + * Ordered managed permission verdicts and the supplied policy's fail-closed posture. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ManagedSettingsPermissionsEvaluateResult". + */ +/** @experimental */ +export interface ManagedSettingsPermissionsEvaluateResult { + /** + * One verdict per input operation, in the same order, including duplicates. + */ + results: ManagedPermissionEvaluation[]; + /** + * Managed permission policy could not be determined; every operation is denied. + */ + failClosed: boolean; +} +/** + * Managed policy context and ordered operations for pure, sessionless evaluation. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "ManagedSettingsPermissionsEvaluateRequest". + */ +/** @experimental */ +export interface ManagedSettingsPermissionsEvaluateRequest { + context: ManagedPermissionsContext; + /** + * Operations to evaluate, preserving input order and duplicates. An empty batch is valid. + */ + operations: ManagedPermissionOperation[]; +} +/** + * The resident session the application has materialized on its own connection. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "HostCreateSessionResult". + */ +/** @experimental */ +export interface HostCreateSessionResult { + /** + * Runtime session UUID materialized on the application's SDK connection. + */ + sessionId: string; +} +/** + * One application-owned session handoff, requested by the supervised hosting participant. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "HostCreateSessionRequest". + */ +/** @experimental */ +export interface HostCreateSessionRequest { + /** + * Unique identity for this participation, independent of the session lifetime. + */ + handoffId: string; + /** + * Resume an app-owned durable session instead of creating a new session. + */ + resume?: boolean; + /** + * For an explicit publication, borrow an existing owning-connection resident + * instead of invoking the resume factory. Cold sessions still use the factory. + */ + preferResident?: boolean; + /** + * Host-selected SDK creation or resume settings, without executable callbacks or tools. + */ + config: { + [k: string]: unknown | undefined; + }; +} +/** + * Empty acknowledgement for a completed host lifecycle operation. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "HostReleaseSessionResult". + */ +/** @experimental */ +export interface HostReleaseSessionResult {} +/** + * Ends one participation, not the application's session lifetime. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "HostReleaseSessionRequest". + */ +/** @experimental */ +export interface HostReleaseSessionRequest { + /** + * Identity of the participation to release without destroying the session. + */ + handoffId: string; +} +/** + * Empty acknowledgement for a completed host lifecycle operation. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "HostDisposeResult". + */ +/** @experimental */ +export interface HostDisposeResult {} +/** + * Private credentials delivered only to a runtime-owned Mission Control hosting participant. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "HostGetEnvironmentCredentialsResult". + */ +/** @experimental */ +export interface HostGetEnvironmentCredentialsResult { + /** + * Current bearer token for the authenticated GitHub identity. + */ + token: string; + /** + * Hostname of the authenticated GitHub service. + */ + githubHost: string; + /** + * GitHub API base URL for the authenticated service. + */ + githubApiUrl: string; + /** + * Mission Control API origin for environment registration and management. + */ + missionControlUrl: string; +} +/** + * Normalized listener settings delivered only to the supervised hosting participant. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "HostGetConfigurationResult". + */ +/** @experimental */ +export interface HostGetConfigurationResult { + localServer?: HostLocalServerConfiguration; + githubEnvironment?: HostGitHubEnvironmentOptions; + /** + * Whether session materialization is delegated to the owning application. + */ + sessionFactory: boolean; + /** + * Whether app-owned durable sessions are resumed by the owning application. + */ + resumeFactory: boolean; +} +/** + * Empty acknowledgement for a completed host lifecycle operation. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "HostReadyResult". + */ +/** @experimental */ +export interface HostReadyResult {} + +/** @experimental */ +export interface SessionWorkflowPauseAtCheckpointResult { + action: WorkflowPauseCheckpointAction; +} + +/** @experimental */ +export interface SessionModelClearStartupSeedResult { + cleared: boolean; +} + +/** @experimental */ +export interface SessionModelClearStartupSeedRequest { + expectedModel: string; + /** + * Provider captured with the startup seed; omission matches only an unqualified seed. + */ + expectedProviderId?: string; +} + +/** @experimental */ +export interface SessionModelListRequest { + /** + * If true, bypasses the per-session model list cache and re-fetches from CAPI. + */ + skipCache?: boolean; +} + +/** @experimental */ +export interface SessionAgentListRequest { + /** + * When true, request the session's configured built-in agents alongside custom agents. Listing applies feature, context, inclusion, exclusion, and user-disabled-agent policy, but does not evaluate transient invocation requirements such as model availability. Built-in metadata may be omitted when the session cannot project it, such as a relay session. + */ + includeBuiltInAgents?: boolean; + /** + * When true, request authored base prompt text on each AgentInfo. Prompt text may be omitted when unavailable, such as for agents projected through a relay session. + */ + includePrompt?: boolean; +} +/** + * An inert runtime-issued login handle. Preparation alone performs no activation or OAuth work. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionMcpOauthPrepareLoginResult". + */ +/** @experimental */ +export interface SessionMcpOauthPrepareLoginResult { + /** + * Retain with the original requester and use for one login or cancellation. + */ + loginId: string; + /** + * Original expiry, not extended by consumption, retries or cancellation. + */ + expiresAt: string; +} +/** + * Effect-free preparation bound to the existing local session, requester and installation, with frozen options. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionMcpOauthPrepareLoginRequest". + */ +/** @experimental */ +export interface SessionMcpOauthPrepareLoginRequest { + /** + * Name recorded by the authoritative owned installation receipt. + */ + serverName: string; + /** + * Exact installation identity from owned inventory, never a server-name alias. + */ + expectedInstallationId: string; + /** + * Request a new authorisation rather than accepting a usable cached grant. + */ + forceReauth?: boolean; + /** + * Display name used by the incumbent OAuth client-registration flow. + */ + clientName?: string; + /** + * Text shown on the loopback callback page after successful authorisation. + */ + callbackSuccessMessage?: string; +} +/** + * Honest terminal cancellation result; persistence or recovery failures remain RPC errors. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionMcpOauthCancelLoginResult". + */ +/** @experimental */ +export interface SessionMcpOauthCancelLoginResult { + /** + * True after cancellation settles, false when the original login already connected successfully. + */ + cancelled: boolean; +} +/** + * Targets only the original prepared/applying owned login on this exact session requester. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionMcpOauthCancelLoginRequest". + */ +/** @experimental */ +export interface SessionMcpOauthCancelLoginRequest { + /** + * The same authoritative installation identity supplied during preparation. + */ + expectedInstallationId: string; + /** + * Runtime-issued login handle known before the effectful login request begins. + */ + loginId: string; +} +/** + * Standard MCP CallToolResult + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionMcpAppsCallToolResult". + */ +/** @experimental */ +export interface SessionMcpAppsCallToolResult { + [k: string]: JsonValue | undefined; +} + +/** @experimental */ +export interface SessionPluginsMarketplacesRefreshRequest { + /** + * Marketplace name to refresh. When omitted, every registered marketplace is refreshed. + */ + name?: string; +} + +/** @experimental */ +export interface SessionPluginsReloadRequest { + /** + * Reload MCP server connections after refreshing plugins. Defaults to true. + */ + reloadMcp?: boolean; + /** + * Re-run custom-agent discovery after refreshing plugins. Defaults to true. + */ + reloadCustomAgents?: boolean; + /** + * Re-load user, plugin, and (subject to `deferRepoHooks`) repo hooks. Defaults to true. Has no effect when the host has not registered a hook reloader (e.g. remote sessions). + */ + reloadHooks?: boolean; + /** + * Re-discover and relaunch subprocess extensions (including plugin-shipped extensions) after refreshing plugins. Defaults to true. Has no effect when the session has no active extension controller (e.g. extensions were not requested for the session). + */ + reloadExtensions?: boolean; + /** + * When true, skip repo-level hooks during the hook reload. Use before folder trust is confirmed; load them post-trust via `sessions.loadDeferredRepoHooks`. + */ + deferRepoHooks?: boolean; +} + +/** @experimental */ +export interface SessionProviderGetEndpointRequest { + /** + * Model identifier the caller intends to use against the returned endpoint. Used to pick the correct wire shape. Omit to use whichever model the session is currently using. + */ + modelId?: string; +} + +/** @experimental */ +export interface SessionCommandsListRequest { + /** + * Include runtime built-in commands + */ + includeBuiltins?: boolean; + /** + * Include enabled user-invocable skills and commands + */ + includeSkills?: boolean; + /** + * Include commands registered by protocol clients, including SDK clients and extensions + */ + includeClientCommands?: boolean; +} + +/** @experimental */ +export interface SessionHistoryCompactRequest { + /** + * Optional user-provided instructions to focus the compaction summary + */ + customInstructions?: string; + /** + * What initiated this compaction request, recorded as the `trigger` on the persisted `session.compaction_start` / `session.compaction_complete` events. When absent, the compaction is persisted without trigger attribution (initiator unknown). + */ + trigger?: /** User-requested compaction, e.g. the /compact command or a direct history.compact call. */ + | "manual" + /** Compaction requested while switching to a model with a smaller context window. */ + | "model_switch"; + /** + * Context window token limit this compaction is targeting, recorded as the `tokenLimit` on the persisted `session.compaction_start` / `session.compaction_complete` events. Set it when the compaction targets a window other than the compacting model's own, e.g. switching to a model with a smaller context window: the compaction still runs on the current model, so the limit that motivated it would otherwise be lost. When absent, the events record the compacting model's own resolved limit. Attribution metadata only - it does not change how much the compaction removes. + */ + tokenLimit?: number; +} +/** + * Internal absolute code-change totals reported by the owning host. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionUsageSetCodeChangesRequest". + */ +/** @experimental */ +export interface SessionUsageSetCodeChangesRequest { + /** + * Absolute added-line total, replacing the previous reading. + */ + linesAdded: number; + /** + * Absolute removed-line total, replacing the previous reading. + */ + linesRemoved: number; + /** + * Absolute changed-file count; omission preserves the previous count. + */ + filesCount?: number; +} +/** + * The incumbent session-owned quota and account projection. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionQuotaGetResult". + */ +/** @experimental */ +export interface SessionQuotaGetResult { + /** + * Known quota snapshots, keyed by the provider's quota type. + */ + snapshots: { + [k: string]: SessionQuotaSnapshot | undefined; + }; + /** + * Provider-owned account quota state, including snapshots without numeric balances. + */ + providerQuotas?: ProviderQuotaState[]; + /** + * Whether the account uses the free limited Copilot plan. + */ + isFreeUser: boolean; + /** + * Whether the account uses token-based billing. + */ + isTbbUser: boolean; + planTier: SessionQuotaPlanTier; + /** + * Whether premium-request costs are billable. + */ + premiumRequestsBillable: boolean; + /** + * Whether model cost columns should be shown. + */ + modelCostColumnVisible: boolean; + /** + * Whether the account can delegate tasks to GitHub. + */ + delegateAvailable: boolean; + /** + * Whether the account can sign up for Copilot Free. + */ + canSignupForCopilotFree: boolean; + /** + * Whether dynamic workflows are enabled for the active account. + */ + dynamicWorkflowsEnabled: boolean; + /** + * Whether dynamic workflows are visible under the session's feature flags. + */ + dynamicWorkflowsUiVisible: boolean; + /** + * Upgrade link for a free account. + */ + upgradeUrl?: string; + delegateWarning?: SessionQuotaDelegateWarning; +} +/** + * The incumbent session-owned quota and account projection. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionQuotaRefreshResult". + */ +/** @experimental */ +export interface SessionQuotaRefreshResult { + /** + * Known quota snapshots, keyed by the provider's quota type. + */ + snapshots: { + [k: string]: SessionQuotaSnapshot | undefined; + }; + /** + * Provider-owned account quota state, including snapshots without numeric balances. + */ + providerQuotas?: ProviderQuotaState[]; + /** + * Whether the account uses the free limited Copilot plan. + */ + isFreeUser: boolean; + /** + * Whether the account uses token-based billing. + */ + isTbbUser: boolean; + planTier: SessionQuotaPlanTier; + /** + * Whether premium-request costs are billable. + */ + premiumRequestsBillable: boolean; + /** + * Whether model cost columns should be shown. + */ + modelCostColumnVisible: boolean; + /** + * Whether the account can delegate tasks to GitHub. + */ + delegateAvailable: boolean; + /** + * Whether the account can sign up for Copilot Free. + */ + canSignupForCopilotFree: boolean; + /** + * Whether dynamic workflows are enabled for the active account. + */ + dynamicWorkflowsEnabled: boolean; + /** + * Whether dynamic workflows are visible under the session's feature flags. + */ + dynamicWorkflowsUiVisible: boolean; + /** + * Upgrade link for a free account. + */ + upgradeUrl?: string; + delegateWarning?: SessionQuotaDelegateWarning; +} + +/** @experimental */ +export interface SessionLimitPredictionPredictRequest { + /** + * Optional model identifier override. If omitted, the session's current model is used. + */ + modelId?: string; + clientType?: SessionLimitPredictionClientType; +} +/** + * Identifies the target session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SkillProviderListRequest". + */ +/** @experimental */ +export interface SkillProviderListRequest { + /** + * Target session identifier + */ + sessionId: string; +} +/** + * Identifies the target session. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "SessionFsSqliteExistsRequest". + */ +/** @experimental */ +export interface SessionFsSqliteExistsRequest { + /** + * Target session identifier + */ + sessionId: string; +} +/** + * The existing runtime identity and its resource on the listener. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "HostRegisterSessionResult". + */ +/** @experimental */ +export interface HostRegisterSessionResult { + /** + * Canonical runtime ID of the published session. + */ + sessionId: string; + /** + * AHP resource URI for the session on this listener. + */ + sessionUri: string; +} +/** + * The resident session the application has materialized on its own connection. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "HostMaterializeSessionResult". + */ +/** @experimental */ +export interface HostMaterializeSessionResult { + /** + * Runtime session UUID materialized on the application's SDK connection. + */ + sessionId: string; +} +/** + * Application callback routed over its existing SDK connection. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "HostMaterializeSessionRequest". + */ +/** @experimental */ +export interface HostMaterializeSessionRequest { + /** + * Listener UUID identifying the owning application's host. + */ + hostId: string; + /** + * Unique identity of the session participation being requested. + */ + handoffId: string; + /** + * Resume an app-owned durable session instead of creating a new session. + */ + resume?: boolean; + /** + * Host-selected SDK creation or resume settings, without executable callbacks or tools. + */ + config: { + [k: string]: unknown | undefined; + }; +} +/** + * Releases the original application session object retained for one handoff. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "HostSessionReleasedRequest". + */ +/** @experimental */ +export interface HostSessionReleasedRequest { + /** + * Listener UUID whose application session participation ended. + */ + hostId: string; + /** + * Identity of the handoff retaining the original application session object. + */ + handoffId: string; +} +/** + * Empty acknowledgement for a completed host lifecycle operation. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "HostShutdownResult". + */ +/** @experimental */ +export interface HostShutdownResult {} +/** + * Reports a supervised listener's hosting-task termination and cleanup outcome. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "HostExitedRequest". + */ +/** @experimental */ +export interface HostExitedRequest { + /** + * Listener UUID. + */ + hostId: string; + reason: HostExitReason; + /** + * Process exit status when available; absent for in-process listener tasks. + */ + exitCode?: number | null; + /** + * Explicit startup or teardown failure, when present. + */ + error?: string | null; +} +/** + * A response is meaningful only on the connection and request that issued its challenge. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "InstallationsConfirmResult". + */ +/** @experimental */ +export interface InstallationsConfirmResult { + /** + * Exact challenge from the request. + */ + confirmationId: string; + /** + * Exact review commitment from the request. + */ + reviewFingerprint: string; + decision: InstallationDecision; +} +/** + * One connection-owned, expiring request for a trusted host's explicit user decision. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "InstallationsConfirmRequest". */ /** @experimental */ export interface InstallationsConfirmRequest { @@ -33176,6 +35031,159 @@ export interface InstallationsConfirmRequest { /** Create typed server-scoped RPC methods (no session required). */ export function createServerRpc(connection: MessageConnection) { return { + /** @experimental */ + sandbox: { + /** @experimental */ + proxyCa: { + /** + * Reports whether this runtime process can offer installing the sandbox credential-proxy certificate authority into OS trust. + * + * @returns True when this process can offer installing the sandbox credential-proxy certificate authority into OS trust. + */ + checkInstallationSupport: async (): Promise => + connection.sendRequest("sandbox.proxyCa.checkInstallationSupport", {}), + /** + * Reports whether this sandbox configuration uses the credential proxy and can need certificate-authority setup. + * + * @param params Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. + * + * @returns True when the sandbox configuration uses the credential proxy and can need certificate-authority setup. + */ + checkRelevance: async (params: SandboxProxyCaRequest): Promise => + connection.sendRequest("sandbox.proxyCa.checkRelevance", params), + /** + * Reports whether the persistent certificate authority of the sandbox credential proxy exists, whether OS trust includes it, and whether it must be rotated. Changes nothing. + * + * @param params Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. + * + * @returns Status of the persistent certificate authority of the sandbox credential proxy. + */ + getStatus: async (params: SandboxProxyCaRequest): Promise => + connection.sendRequest("sandbox.proxyCa.getStatus", params), + /** + * Creates the persistent certificate authority of the sandbox credential proxy if none is stored, without changing OS trust, and returns the path of its public certificate. Keeps an existing certificate authority, even one that must be rotated. Fails where OS trust is unsupported. Trust it with sandbox.proxyCa.trust: the CLI trusts only the hosts in the saved user settings, so it refuses a certificate authority that also covers hosts from sandboxConfig. + * + * @param params Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. + * + * @returns Result of creating the persistent certificate authority of the sandbox credential proxy. + */ + create: async (params: SandboxProxyCaRequest): Promise => + connection.sendRequest("sandbox.proxyCa.create", params), + /** + * Replaces the persistent certificate authority of the sandbox credential proxy with a new one for the current credential hosts. If OS trust included the old one, removes it and trusts the new one, which can show an OS authentication prompt. Running sandboxed tools keep the old certificate authority until they restart. + * + * @param params Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. + * + * @returns Status of the persistent certificate authority of the sandbox credential proxy. + */ + rotate: async (params: SandboxProxyCaRequest): Promise => + connection.sendRequest("sandbox.proxyCa.rotate", params), + /** + * Adds the persistent certificate authority of the sandbox credential proxy to OS trust, so sandboxed clients that read only OS trust accept the proxy. Call create first. Refuses a certificate authority that is not constrained to the current credential hosts. Can show an OS authentication prompt. + * + * @param params Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. + * + * @returns Status of the persistent certificate authority of the sandbox credential proxy. + */ + trust: async (params: SandboxProxyCaRequest): Promise => + connection.sendRequest("sandbox.proxyCa.trust", params), + /** + * Removes the persistent certificate authority of the sandbox credential proxy from OS trust. Keeps the stored certificate authority. Can show an OS authentication prompt. Sandboxed clients that read only OS trust then reject the proxy; clients that read the per-process certificate bundle continue to work. + * + * @returns Status of the persistent certificate authority of the sandbox credential proxy. + */ + remove: async (): Promise => + connection.sendRequest("sandbox.proxyCa.remove", {}), + }, + /** + * Reports whether the host running this runtime can run the command sandbox, without starting a session or spawning a sandboxed command. + * + * @returns Whether the host running this runtime can run the command sandbox. The runtime checks `supported` once per process. A capability answer can change while the process runs, for example after the user installs a missing package. + */ + getHostSupport: async (): Promise => + connection.sendRequest("sandbox.getHostSupport", {}), + }, + /** @experimental */ + user: { + /** @experimental */ + settings: { + /** + * Lists every known user setting from settings.json, each with its effective value, its default, and whether it is at the default — so settings the user has never set still appear with their default value. Does not include repository- or enterprise-managed overrides that the runtime layers on top at session time. + * + * @returns Per-key metadata for every known user setting in settings.json, including settings left at their default. Excludes repository- and enterprise-managed overrides. + */ + get: async (): Promise => + connection.sendRequest("user.settings.get", {}), + /** + * Writes one or more user settings to settings.json, replacing each provided top-level key. A key whose value is null is removed. + * + * @param params Partial user settings to write to settings.json. Each top-level key is written individually, replacing the existing value; a key whose value is null is removed. + */ + set: async (params: UserSettingsSetRequest): Promise => + connection.sendRequest("user.settings.set", params), + }, + }, + /** @experimental */ + managedSettings: { + /** + * Discovers device-managed settings from production MDM and managed-file sources, validates them against the runtime-owned managed-settings schema, and returns the canonical JSON without requiring a session. `managedSettings.resolve` returns the same device settings together with the account's server policy. + * + * @returns Validated device-managed settings discovered before a session exists. + */ + read: async (): Promise => + connection.sendRequest("managedSettings.read", {}), + /** + * Force-refreshes enterprise managed settings for every account: wipes the persistent server-policy cache (the whole `/managed-settings` directory) and drops this runtime process's in-memory retained server policy. It does not itself fetch policy — the effect is that the next time a session resolves managed settings for an account, that resolution re-fetches the account's org policy from the network instead of serving a cached response. Note that `managedSettings.read` returns only device/MDM settings and never triggers the account server-policy fetch, so a host implementing "sync account policy" should call `managedSettings.resolve` or start a fresh session resolution rather than treat a subsequent `managedSettings.read` as the refreshed org policy. Mirrors the invalidation a sign-out performs, broadened from the one signing-out account to all of them; device/MDM layers describe the machine, not the account, and are left untouched. Rejects if the on-disk cache cannot be removed. + */ + clearCache: async (): Promise => + connection.sendRequest("managedSettings.clearCache", {}), + /** + * Resolves the effective enterprise managed settings without a session, from the device channel and, when an account is available, the account's server policy through the same per-account cache sessions use. A cached server policy less than an hour old is used without a fetch; otherwise the policy is fetched, and when the fetch fails a cached policy up to 24 hours old is used instead, unless `forceRemoteSettingsRefresh` requires a live fetch. With no account requested or signed in, it reports device policy only; signing out removes the account's cached policy. It can fetch server policy over the network when the cache is stale, so call it off latency-critical paths such as startup rather than before listing models. The policy helper is not run. `layers` lists each channel's document before merging, and `values` and `meta` carry typed effective values and their lock state for the keys typed so far. + * + * @param params Optional opaque account selection or GitHub token whose managed settings are resolved. + * + * @returns Effective enterprise managed settings for an account, resolved without a session. + */ + resolve: async (params: ManagedSettingsResolveRequest): Promise => + connection.sendRequest("managedSettings.resolve", params), + /** @experimental */ + permissions: { + /** + * Pure, sessionless evaluation of operations against a supplied permissionsContext. Performs no policy discovery, I/O, prompting, navigation, permission grants, or sandbox changes. Obtain the context from managedSettings.resolve or session.managedSettings.get, or reuse an in-memory context. Results preserve input order and duplicates. Consumers must block deny, obtain approval for ask, and use their normal permission flow for unmanaged. Unknown policy returns failClosed with every operation denied. This is not a substitute for user permissions or other security controls. + * + * @param params Managed policy context and ordered operations for pure, sessionless evaluation. + * + * @returns Ordered managed permission verdicts and the supplied policy's fail-closed posture. + */ + evaluate: async (params: ManagedSettingsPermissionsEvaluateRequest): Promise => + connection.sendRequest("managedSettings.permissions.evaluate", params), + }, + /** + * Returns the managed-settings authoring JSON schema with descriptive `x-composition` annotations aligned with the shared settings-engine vocabulary. These annotations are not a complete runtime composition contract: model, effortLevel, and contextTier remain coupled. Use `managedSettings.compose` for the runtime's effective result. Performs no I/O. + * + * @returns The authoring JSON schema for managed settings recognized by this runtime. + */ + schema: async (): Promise => + connection.sendRequest("managedSettings.schema", {}), + /** + * Validates a candidate managed-settings document the way the runtime validates delivered policy, without applying it. Reports errors that would reject the document, warnings for content the runtime ignores, and the canonical document it would apply. Document text nested more than 64 levels deep is rejected. Performs no I/O. + * + * @param params A candidate managed-settings document to validate without applying it. + * + * @returns Result of validating a managed-settings document. + */ + validate: async (params: ManagedSettingsValidateRequest): Promise => + connection.sendRequest("managedSettings.validate", params), + /** + * Merges candidate managed-settings documents for the device, server, and policy-helper channels into the effective settings the runtime would enforce on this host, using the same precedence and composition rules as live resolution, without applying them. Like live resolution, a server's advisory sandbox force-enable is declined on a host that cannot run the sandbox. Does not fetch policy or read policy files, but may perform blocking OS or subprocess probes for sandbox support. Preview documents are limited to 1 MiB and 64 levels of nesting. + * + * @param params Candidate managed-settings documents to merge without applying them. + * + * @returns The effective managed settings the runtime would enforce for the given documents, in the same shape `managedSettings.resolve` returns. + */ + compose: async (params: ManagedSettingsComposeRequest): Promise => + connection.sendRequest("managedSettings.compose", params), + }, /** @experimental */ environments: { /** @@ -33288,62 +35296,6 @@ export function createServerRpc(connection: MessageConnection) { connection.sendRequest("models.getBuiltInCatalog", {}), }, /** @experimental */ - sandbox: { - /** - * Reports whether the host running this runtime can run the command sandbox, without starting a session or spawning a sandboxed command. - * - * @returns Whether the host running this runtime can run the command sandbox. The runtime checks `supported` once per process. A capability answer can change while the process runs, for example after the user installs a missing package. - */ - getHostSupport: async (): Promise => - connection.sendRequest("sandbox.getHostSupport", {}), - /** @experimental */ - proxyCa: { - /** - * Reports whether the persistent certificate authority of the sandbox credential proxy exists, whether OS trust includes it, and whether it must be rotated. Changes nothing. - * - * @param params Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. - * - * @returns Status of the persistent certificate authority of the sandbox credential proxy. - */ - getStatus: async (params: SandboxProxyCaRequest): Promise => - connection.sendRequest("sandbox.proxyCa.getStatus", params), - /** - * Creates the persistent certificate authority of the sandbox credential proxy if none is stored, without changing OS trust, and returns the path of its public certificate. Keeps an existing certificate authority, even one that must be rotated. Fails where OS trust is unsupported. Trust it with sandbox.proxyCa.trust: the CLI trusts only the hosts in the saved user settings, so it refuses a certificate authority that also covers hosts from sandboxConfig. - * - * @param params Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. - * - * @returns Result of creating the persistent certificate authority of the sandbox credential proxy. - */ - create: async (params: SandboxProxyCaRequest): Promise => - connection.sendRequest("sandbox.proxyCa.create", params), - /** - * Replaces the persistent certificate authority of the sandbox credential proxy with a new one for the current credential hosts. If OS trust included the old one, removes it and trusts the new one, which can show an OS authentication prompt. Running sandboxed tools keep the old certificate authority until they restart. - * - * @param params Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. - * - * @returns Status of the persistent certificate authority of the sandbox credential proxy. - */ - rotate: async (params: SandboxProxyCaRequest): Promise => - connection.sendRequest("sandbox.proxyCa.rotate", params), - /** - * Adds the persistent certificate authority of the sandbox credential proxy to OS trust, so sandboxed clients that read only OS trust accept the proxy. Call create first. Refuses a certificate authority that is not constrained to the current credential hosts. Can show an OS authentication prompt. - * - * @param params Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. - * - * @returns Status of the persistent certificate authority of the sandbox credential proxy. - */ - trust: async (params: SandboxProxyCaRequest): Promise => - connection.sendRequest("sandbox.proxyCa.trust", params), - /** - * Removes the persistent certificate authority of the sandbox credential proxy from OS trust. Keeps the stored certificate authority. Can show an OS authentication prompt. Sandboxed clients that read only OS trust then reject the proxy; clients that read the per-process certificate bundle continue to work. - * - * @returns Status of the persistent certificate authority of the sandbox credential proxy. - */ - remove: async (): Promise => - connection.sendRequest("sandbox.proxyCa.remove", {}), - }, - }, - /** @experimental */ tools: { /** * Lists built-in tools available for a model. @@ -33896,87 +35848,6 @@ export function createServerRpc(connection: MessageConnection) { connection.sendRequest("commands.list", {}), }, /** @experimental */ - user: { - /** @experimental */ - settings: { - /** - * Lists every known user setting from settings.json, each with its effective value, its default, and whether it is at the default — so settings the user has never set still appear with their default value. Does not include repository- or enterprise-managed overrides that the runtime layers on top at session time. - * - * @returns Per-key metadata for every known user setting in settings.json, including settings left at their default. Excludes repository- and enterprise-managed overrides. - */ - get: async (): Promise => - connection.sendRequest("user.settings.get", {}), - /** - * Writes one or more user settings to settings.json, replacing each provided top-level key. A key whose value is null is removed. - * - * @param params Partial user settings to write to settings.json. Each top-level key is written individually, replacing the existing value; a key whose value is null is removed. - */ - set: async (params: UserSettingsSetRequest): Promise => - connection.sendRequest("user.settings.set", params), - }, - }, - /** @experimental */ - managedSettings: { - /** - * Discovers device-managed settings from production MDM and managed-file sources, validates them against the runtime-owned managed-settings schema, and returns the canonical JSON without requiring a session. `managedSettings.resolve` returns the same device settings together with the account's server policy. - * - * @returns Validated device-managed settings discovered before a session exists. - */ - read: async (): Promise => - connection.sendRequest("managedSettings.read", {}), - /** - * Force-refreshes enterprise managed settings for every account: wipes the persistent server-policy cache (the whole `/managed-settings` directory) and drops this runtime process's in-memory retained server policy. It does not itself fetch policy — the effect is that the next time a session resolves managed settings for an account, that resolution re-fetches the account's org policy from the network instead of serving a cached response. Note that `managedSettings.read` returns only device/MDM settings and never triggers the account server-policy fetch, so a host implementing "sync account policy" should call `managedSettings.resolve` or start a fresh session resolution rather than treat a subsequent `managedSettings.read` as the refreshed org policy. Mirrors the invalidation a sign-out performs, broadened from the one signing-out account to all of them; device/MDM layers describe the machine, not the account, and are left untouched. Rejects if the on-disk cache cannot be removed. - */ - clearCache: async (): Promise => - connection.sendRequest("managedSettings.clearCache", {}), - /** - * Resolves the effective enterprise managed settings without a session, from the device channel and, when an account is available, the account's server policy through the same per-account cache sessions use. A cached server policy less than an hour old is used without a fetch; otherwise the policy is fetched, and when the fetch fails a cached policy up to 24 hours old is used instead, unless `forceRemoteSettingsRefresh` requires a live fetch. With no account requested or signed in, it reports device policy only; signing out removes the account's cached policy. It can fetch server policy over the network when the cache is stale, so call it off latency-critical paths such as startup rather than before listing models. The policy helper is not run. `layers` lists each channel's document before merging, and `values` and `meta` carry typed effective values and their lock state for the keys typed so far. - * - * @param params Optional opaque account selection or GitHub token whose managed settings are resolved. - * - * @returns Effective enterprise managed settings for an account, resolved without a session. - */ - resolve: async (params: ManagedSettingsResolveRequest): Promise => - connection.sendRequest("managedSettings.resolve", params), - /** @experimental */ - permissions: { - /** - * Pure, sessionless evaluation of operations against a supplied permissionsContext. Performs no policy discovery, I/O, prompting, navigation, permission grants, or sandbox changes. Obtain the context from managedSettings.resolve or session.managedSettings.get, or reuse an in-memory context. Results preserve input order and duplicates. Consumers must block deny, obtain approval for ask, and use their normal permission flow for unmanaged. Unknown policy returns failClosed with every operation denied. This is not a substitute for user permissions or other security controls. - * - * @param params Managed policy context and ordered operations for pure, sessionless evaluation. - * - * @returns Ordered managed permission verdicts and the supplied policy's fail-closed posture. - */ - evaluate: async (params: ManagedSettingsPermissionsEvaluateRequest): Promise => - connection.sendRequest("managedSettings.permissions.evaluate", params), - }, - /** - * Returns the managed-settings authoring JSON schema with descriptive `x-composition` annotations aligned with the shared settings-engine vocabulary. These annotations are not a complete runtime composition contract: model, effortLevel, and contextTier remain coupled. Use `managedSettings.compose` for the runtime's effective result. Performs no I/O. - * - * @returns The authoring JSON schema for managed settings recognized by this runtime. - */ - schema: async (): Promise => - connection.sendRequest("managedSettings.schema", {}), - /** - * Validates a candidate managed-settings document the way the runtime validates delivered policy, without applying it. Reports errors that would reject the document, warnings for content the runtime ignores, and the canonical document it would apply. Document text nested more than 64 levels deep is rejected. Performs no I/O. - * - * @param params A candidate managed-settings document to validate without applying it. - * - * @returns Result of validating a managed-settings document. - */ - validate: async (params: ManagedSettingsValidateRequest): Promise => - connection.sendRequest("managedSettings.validate", params), - /** - * Merges candidate managed-settings documents for the device, server, and policy-helper channels into the effective settings the runtime would enforce on this host, using the same precedence and composition rules as live resolution, without applying them. Like live resolution, a server's advisory sandbox force-enable is declined on a host that cannot run the sandbox. Does not fetch policy or read policy files, but may perform blocking OS or subprocess probes for sandbox support. Preview documents are limited to 1 MiB and 64 levels of nesting. - * - * @param params Candidate managed-settings documents to merge without applying them. - * - * @returns The effective managed settings the runtime would enforce for the given documents, in the same shape `managedSettings.resolve` returns. - */ - compose: async (params: ManagedSettingsComposeRequest): Promise => - connection.sendRequest("managedSettings.compose", params), - }, - /** @experimental */ runtime: { /** * Gracefully shuts down an SDK-owned runtime. The response is sent only after cleanup completes; callers may then terminate the owned runtime process. @@ -34063,248 +35934,796 @@ export function createServerRpc(connection: MessageConnection) { list: async (params: SessionsListRequest): Promise => connection.sendRequest("sessions.list", params), /** - * Reads client-owned metadata for multiple persisted local sessions without opening them. Results preserve request order and report missing, corrupt, unsupported, or temporarily unavailable sessions independently. + * Reads client-owned metadata for multiple persisted local sessions without opening them. Results preserve request order and report missing, corrupt, unsupported, or temporarily unavailable sessions independently. + * + * @param params Bounded batch request for client-owned metadata from persisted local sessions. + * + * @returns Ordered client metadata outcomes for the requested local sessions. + */ + getClientMetadata: async (params: SessionsGetClientMetadataRequest): Promise => + connection.sendRequest("sessions.getClientMetadata", params), + /** + * Reads a page of durable events directly from a local session's persisted journal without creating, resuming, or activating the session. The first read pins the currently opened journal generation and its byte-length boundary; opaque cursor continuations remain on that generation across runtime-owned compaction, truncation, and rewrite operations, which replace the live path atomically, and events appended after the boundary are excluded. For cold hydration, await the first successful page before activation and establish lossless live-event buffering before resume; merge subsequent live events by ID, preserving persisted order and letting live payloads win. Continuations are process-local, single-use capabilities bound to the originating session and storage context and must be paged sequentially; concurrent or repeated use of the same cursor expires that duplicate read rather than reading the generation twice. A complete snapshot has cursorStatus 'ok' and hasMore false. Snapshots expire after five idle minutes, with at most eight retained per process and idle-only eviction under pressure; completion and cancelled-worker exit release their handles. No transcript copy is created, but retained handles may keep replaced files' disk blocks alive until release. Pages have a soft 1 MiB serialized event-array budget including resolved binary assets; one oversized event is returned alone to guarantee progress. Working memory also includes a record/lookahead and asset resolution; resolving the first binary reference may scan the full pinned generation to build a bounded offset index. If the snapshot expires, is evicted, is cancelled before a continuation is established, or becomes unreadable after an observable unsupported in-place shortening, the continuation returns cursorStatus 'expired' with an empty terminal page and never falls back to a different generation. A missing or initially unreadable journal is an RPC error. Persisted history excludes ephemeral events and may omit payloads that are reconstructed only for an active session; use the active session event stream for post-resume live events. + * + * @param params Pagination options for reading an inactive or active local session's persisted event journal. + * + * @returns Batch of session events returned by a read, with cursor and continuation metadata. + */ + readPersistedEvents: async (params: SessionsReadPersistedEventsRequest): Promise => + connection.sendRequest("sessions.readPersistedEvents", params), + /** + * Finds the local session bound to a GitHub task ID, if any. + * + * @param params GitHub task ID to look up. + * + * @returns ID of the local session bound to the given GitHub task, or omitted when none. + */ + findByTaskId: async (params: SessionsFindByTaskIDRequest): Promise => + connection.sendRequest("sessions.findByTaskId", params), + /** + * Resolves a UUID prefix to a unique session ID, if exactly one session matches. + * + * @param params UUID prefix to resolve to a unique session ID. + * + * @returns Session ID matching the prefix, omitted when no unique match exists. + */ + findByPrefix: async (params: SessionsFindByPrefixRequest): Promise => + connection.sendRequest("sessions.findByPrefix", params), + /** + * Returns the most-relevant prior session for a given working-directory context. + * + * @param params Optional working-directory context used to score session relevance. + * + * @returns Most-relevant session ID for the supplied context, or omitted when no sessions exist. + */ + getLastForContext: async (params: SessionsGetLastForContextRequest): Promise => + connection.sendRequest("sessions.getLastForContext", params), + /** + * Returns the on-disk byte size of each session's workspace directory. + * + * @returns Map of sessionId -> on-disk size in bytes for each session's workspace directory. + */ + getSizes: async (): Promise => + connection.sendRequest("sessions.getSizes", {}), + /** + * Returns the subset of the supplied session IDs that are currently held by another running process. + * + * @param params Session IDs to test for live in-use locks. + * + * @returns Session IDs from the input set that are currently in use by another process. + */ + checkInUse: async (params: SessionsCheckInUseRequest): Promise => + connection.sendRequest("sessions.checkInUse", params), + /** + * Closes a session: emits shutdown, flushes pending events, releases the in-use lock, and disposes the active session. + * + * @param params Session ID to close. + * + * @returns Closes a session: emits shutdown, flushes pending events to disk, releases the in-use lock, disposes the active session. Idempotent: succeeds even if the session is not currently active. + */ + close: async (params: SessionsCloseRequest): Promise => + connection.sendRequest("sessions.close", params), + /** + * Closes, deactivates, and deletes a set of sessions, returning the bytes freed per session. + * + * @param params Session IDs to close, deactivate, and delete from disk. + * + * @returns Map of sessionId -> bytes freed by removing the session's workspace directory. + */ + bulkDelete: async (params: SessionsBulkDeleteRequest): Promise => + connection.sendRequest("sessions.bulkDelete", params), + /** + * Deletes sessions older than the given threshold, with optional dry-run and exclusion list. + * + * @param params Age threshold and optional flags controlling which old sessions are pruned (or simulated when dryRun is true). + * + * @returns Outcome of the prune operation: deleted IDs, dry-run candidates, skipped IDs, total bytes freed, and the dry-run flag. + */ + pruneOld: async (params: SessionsPruneOldRequest): Promise => + connection.sendRequest("sessions.pruneOld", params), + /** + * Flushes a session's pending events to disk. + * + * @param params Session ID whose pending events should be flushed to disk. + * + * @returns Flush a session's pending events to disk. No-op when no writer exists for the session (e.g., already closed). + */ + save: async (params: SessionsSaveRequest): Promise => + connection.sendRequest("sessions.save", params), + /** + * Releases the in-use lock held by this process for a session. + * + * @param params Session ID whose in-use lock should be released. + * + * @returns Release the in-use lock held by this process for the given session. No-op when this process does not currently hold a lock for the session. + */ + releaseLock: async (params: SessionsReleaseLockRequest): Promise => + connection.sendRequest("sessions.releaseLock", params), + /** + * Backfills missing summary and context fields on the supplied session metadata records. + * + * @param params Session metadata records to enrich with summary and context information. + * + * @returns The enriched metadata records, with summary and context fields backfilled where available. Sessions confirmed empty and unnamed are omitted. + */ + enrichMetadata: async (params: SessionsEnrichMetadataRequest): Promise => + connection.sendRequest("sessions.enrichMetadata", params), + /** + * Reloads user, plugin, and (optionally) repo hooks on the active session. + * + * @param params Active session ID and an optional flag for deferring repo-level hooks until folder trust. + * + * @returns Reload all hooks (user, plugin, optionally repo) and apply them to the active session. Call after installing or removing plugins so their hooks take effect immediately. No-op when no active session matches the given sessionId. + */ + reloadPluginHooks: async (params: SessionsReloadPluginHooksRequest): Promise => + connection.sendRequest("sessions.reloadPluginHooks", params), + /** + * Loads previously-deferred repo-level hooks on the active session, returning queued startup prompts. + * + * @param params Active session ID whose deferred repo-level hooks should be loaded. + * + * @returns Queued repo-level startup prompts and the total hook command count after loading. + */ + loadDeferredRepoHooks: async (params: SessionsLoadDeferredRepoHooksRequest): Promise => + connection.sendRequest("sessions.loadDeferredRepoHooks", params), + /** + * Replaces the manager-wide additional plugins registered with the session manager. + * + * @param params Manager-wide additional plugins to register; replaces any previously-configured set. + * + * @returns Replace the manager-wide additional plugins. New session creations and subsequent hook reloads see the new set; already-running sessions keep their existing hook installation until the next reload. + */ + setAdditionalPlugins: async (params: SessionsSetAdditionalPluginsRequest): Promise => + connection.sendRequest("sessions.setAdditionalPlugins", params), + /** + * Attaches the runtime-managed remote-control singleton to a session, awaiting initial setup. If remote control is already attached to a different session, the singleton is transferred (preserving the underlying Mission Control connection). Returns the final status. + * + * @param params Parameters for attaching the remote-control singleton to a session. + * + * @returns Wrapper for the singleton's current status. + */ + startRemoteControl: async (params: SessionsStartRemoteControlRequest): Promise => + connection.sendRequest("sessions.startRemoteControl", params), + /** + * Atomically rebinds the remote-control singleton to a different session, preserving the underlying Mission Control connection. When `expectedFromSessionId` is provided and does not match the singleton's current `attachedSessionId`, the transfer is rejected with `transferred: false` and the current status is returned unchanged. + * + * @param params Parameters for atomically rebinding the remote-control singleton. + * + * @returns Outcome of a transferRemoteControl call. + */ + transferRemoteControl: async (params: SessionsTransferRemoteControlRequest): Promise => + connection.sendRequest("sessions.transferRemoteControl", params), + /** + * Patches the steering state of the active remote-control singleton. When remote control is off, this is a no-op and the off status is returned. Today only `enabled: true` is actionable on the underlying exporter; passing `false` is reserved for future use. + * + * @param params Patch for the singleton's steering state. + * + * @returns Wrapper for the singleton's current status. + */ + setRemoteControlSteering: async (params: SessionsSetRemoteControlSteeringRequest): Promise => + connection.sendRequest("sessions.setRemoteControlSteering", params), + /** + * Stops the remote-control singleton. When `expectedSessionId` is provided and does not match the singleton's current `attachedSessionId`, the stop is rejected with `stopped: false` and the current status is returned unchanged (unless `force` is set, in which case the singleton is unconditionally torn down). + * + * @param params Parameters for stopping the remote-control singleton. + * + * @returns Outcome of a stopRemoteControl call. + */ + stopRemoteControl: async (params: SessionsStopRemoteControlRequest): Promise => + connection.sendRequest("sessions.stopRemoteControl", params), + /** + * Returns the current state of the remote-control singleton, including the attached session id and frontend URL when active. + * + * @returns Wrapper for the singleton's current status. + */ + getRemoteControlStatus: async (): Promise => + connection.sendRequest("sessions.getRemoteControlStatus", {}), + }, + /** @experimental */ + agentRegistry: { + /** + * Spawns a managed-server child with the supplied configuration and returns a discriminated-union result. The caller (typically the CLI controller) is responsible for attaching to the spawned child and sending any follow-up prompt. When the controller-local spawn gate is closed the server returns JSON-RPC MethodNotFound. + * + * @param params Inputs to spawn a managed-server child via the controller's spawn delegate. + * + * @returns Outcome of an agentRegistry.spawn call. + */ + spawn: async (params: AgentRegistrySpawnRequest): Promise => + connection.sendRequest("agentRegistry.spawn", params), + }, + /** @experimental */ + connectors: { + /** + * Returns feature availability. + * + * @returns Feature availability. + */ + getCapabilities: async (): Promise => + connection.sendRequest("connectors.getCapabilities", {}), + /** + * Returns eligible accounts. + * + * @returns Eligible accounts. + */ + getAccounts: async (): Promise => + connection.sendRequest("connectors.getAccounts", {}), + /** + * Lists entries for the selected account. + * + * @param params Selected account. + * + * @returns Entries for the selected account. + */ + list: async (params: ConnectorDiscoveryAccountRequest): Promise => + connection.sendRequest("connectors.list", params), + /** + * Refreshes entries for the selected account. + * + * @param params Selected account. + * + * @returns Entries for the selected account. + */ + refresh: async (params: ConnectorDiscoveryAccountRequest): Promise => + connection.sendRequest("connectors.refresh", params), + }, + }; +} + +/** + * Create typed server-scoped RPC methods that are part of the SDK's internal + * surface (e.g. handshake helpers). Not exported on the public client API. + * @internal + */ +export function createInternalServerRpc(connection: MessageConnection) { + return { + /** @experimental */ + sandbox: { + /** @experimental */ + proxySecret: { + /** + * Reports where this runtime keeps the sandbox proxy password: the credential store directory and the entry identifier within it. Both are derived from the configuration directory this runtime was started with, so a host does not resolve them itself. Read this to recognize a `${secret:…}` value in stored sandbox settings as this runtime's own proxy password rather than a reference the user wrote by hand. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. + * + * @returns Where this runtime keeps the sandbox proxy password. + */ + getLocation: async (): Promise => + connection.sendRequest("sandbox.proxySecret.getLocation", {}), + /** + * Reads the stored sandbox proxy password from the credential store `sandbox.proxySecret.getLocation` names, preferring the OS keychain and falling back to the on-disk store. Reports an absent value rather than failing when no entry exists. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. + * + * @returns The stored sandbox proxy password, if one is present. + */ + get: async (): Promise => + connection.sendRequest("sandbox.proxySecret.get", {}), + /** + * Stores the sandbox proxy password in the credential store `sandbox.proxySecret.getLocation` names, replacing any existing entry. Reports whether the OS keychain accepted it or it fell back to the on-disk store. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. + * + * @param params The sandbox proxy password to store. + * + * @returns Where the sandbox proxy password was stored. + */ + save: async (params: SandboxProxySecretSaveRequest): Promise => + connection.sendRequest("sandbox.proxySecret.save", params), + /** + * Removes the stored sandbox proxy password from the credential store `sandbox.proxySecret.getLocation` names. Succeeds when no entry exists, so it is safe to call while clearing a proxy password whose origin is unknown. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. + */ + delete: async (): Promise => + connection.sendRequest("sandbox.proxySecret.delete", {}), + }, + /** @experimental */ + settings: { + /** + * Resolves a stored sandbox settings object into the effective one, filling every value the user left unset with its default. Read this to render or reason about the sandbox configuration a session would actually run under, rather than the sparse document the user wrote. + * + * @param params The stored sandbox settings to resolve against the defaults. + * + * @returns The effective sandbox settings, with every unset value resolved to its default. + */ + applyDefaults: async (params: SandboxApplyDefaultsRequest): Promise => + connection.sendRequest("sandbox.settings.applyDefaults", params), + }, + /** + * Raises a user's sandbox settings to an administrator's managed sandbox floor and returns the result a session should actually run under. The floor can only tighten: an enterprise force-on is reflected even when the user's own `enabled` is false, and a user cannot lower a setting the floor raised. The result is normalized through the declared sandbox shape, so a key reorder or an undeclared passthrough key is not mistaken for a policy change by callers that diff two results. A host must call this rather than merge the two layers itself, because reimplementing the direction of the fold is what turns an administrator's floor into a suggestion. * - * @param params Bounded batch request for client-owned metadata from persisted local sessions. + * @param params The user's sandbox settings and the managed sandbox floor to raise them to. * - * @returns Ordered client metadata outcomes for the requested local sessions. + * @returns The user's sandbox settings raised to the managed floor. */ - getClientMetadata: async (params: SessionsGetClientMetadataRequest): Promise => - connection.sendRequest("sessions.getClientMetadata", params), + resolveFlooredConfig: async (params: SandboxResolveFlooredConfigParams): Promise => + connection.sendRequest("sandbox.resolveFlooredConfig", params), /** - * Reads a page of durable events directly from a local session's persisted journal without creating, resuming, or activating the session. The first read pins the currently opened journal generation and its byte-length boundary; opaque cursor continuations remain on that generation across runtime-owned compaction, truncation, and rewrite operations, which replace the live path atomically, and events appended after the boundary are excluded. For cold hydration, await the first successful page before activation and establish lossless live-event buffering before resume; merge subsequent live events by ID, preserving persisted order and letting live payloads win. Continuations are process-local, single-use capabilities bound to the originating session and storage context and must be paged sequentially; concurrent or repeated use of the same cursor expires that duplicate read rather than reading the generation twice. A complete snapshot has cursorStatus 'ok' and hasMore false. Snapshots expire after five idle minutes, with at most eight retained per process and idle-only eviction under pressure; completion and cancelled-worker exit release their handles. No transcript copy is created, but retained handles may keep replaced files' disk blocks alive until release. Pages have a soft 1 MiB serialized event-array budget including resolved binary assets; one oversized event is returned alone to guarantee progress. Working memory also includes a record/lookahead and asset resolution; resolving the first binary reference may scan the full pinned generation to build a bounded offset index. If the snapshot expires, is evicted, is cancelled before a continuation is established, or becomes unreadable after an observable unsupported in-place shortening, the continuation returns cursorStatus 'expired' with an empty terminal page and never falls back to a different generation. A missing or initially unreadable journal is an RPC error. Persisted history excludes ephemeral events and may omit payloads that are reconstructed only for an active session; use the active session event stream for post-resume live events. + * Builds the effective filesystem policy one `@`-file picker checks its suggestions against, so Git discovery and grant canonicalization run once for the picker's lifetime instead of on every debounced keystroke. Returns no policy when the sandbox is absent or disabled, which the paired filter reads as "keep every candidate". A host must pair this with `sandbox.filterPickerCandidates` rather than resolve a grant list itself, because the picker's grants are narrower than a file tool's — the same path a built-in tool may read can be one the picker must not offer. * - * @param params Pagination options for reading an inactive or active local session's persisted event journal. + * @param params The working directory and sandbox settings to build a file-picker policy from. * - * @returns Batch of session events returned by a read, with cursor and continuation metadata. + * @returns The prepared file-picker policy, or none when the sandbox is disabled. */ - readPersistedEvents: async (params: SessionsReadPersistedEventsRequest): Promise => - connection.sendRequest("sessions.readPersistedEvents", params), + preparePickerPolicy: async (params: SandboxPreparePickerPolicyParams): Promise => + connection.sendRequest("sandbox.preparePickerPolicy", params), /** - * Finds the local session bound to a GitHub task ID, if any. + * Checks a batch of `@`-file picker suggestions against a policy prepared by `sandbox.preparePickerPolicy` and returns one allow decision per candidate, positionally aligned with the request. Batched deliberately: each check canonicalizes a path component-by-component through the real filesystem, so one call amortizes that over a single hop rather than dozens while the user types. A directory the policy does not itself allow can still be kept as a waypoint to an allowed subtree. An absent policy keeps every candidate. * - * @param params GitHub task ID to look up. + * @param params A batch of file-picker candidates to check against a prepared policy. * - * @returns ID of the local session bound to the given GitHub task, or omitted when none. + * @returns Per-candidate allow decisions, positionally aligned with the request. */ - findByTaskId: async (params: SessionsFindByTaskIDRequest): Promise => - connection.sendRequest("sessions.findByTaskId", params), + filterPickerCandidates: async (params: SandboxFilterPickerCandidatesParams): Promise => + connection.sendRequest("sandbox.filterPickerCandidates", params), /** - * Resolves a UUID prefix to a unique session ID, if exactly one session matches. + * The sandbox a single named feature actually launches under, which is not the same as the session's sandbox. A feature is routed out of the sandbox by its own flag — `sandboxMcpServers`, `sandboxLspServers` — so an enabled session can still start one server confined and another free. Returns a disabled sandbox rather than an error when the host has no sandbox slice at all, so an absent config and an opted-out feature read alike at the launch site. A host must ask per feature rather than reuse the session config, because reading only `enabled` confines a server the user opted out of, or reports as sandboxed one that is not. * - * @param params UUID prefix to resolve to a unique session ID. + * @param params A sandbox config and the per-feature routing flag to resolve it for. * - * @returns Session ID matching the prefix, omitted when no unique match exists. + * @returns The sandbox a named feature actually launches under. */ - findByPrefix: async (params: SessionsFindByPrefixRequest): Promise => - connection.sendRequest("sessions.findByPrefix", params), + resolveForOptional: async (params: SandboxEffectiveForOptionalParams): Promise => + connection.sendRequest("sandbox.resolveForOptional", params), /** - * Returns the most-relevant prior session for a given working-directory context. - * - * @param params Optional working-directory context used to score session relevance. + * Reports whether this machine can run an OS-level command sandbox at all. A host must ask before it offers sandboxing, because the answer is a property of the machine rather than of any setting: on Linux it depends on bubblewrap being installed, and on Windows on the OS build supporting BaseContainer. Probing it requires spawning a process the first time, so the answer is cached for the life of the runtime. A host that assumes support and enables the sandbox anyway produces a session in which every shell command fails. * - * @returns Most-relevant session ID for the supplied context, or omitted when no sessions exist. + * @returns True when an OS-level sandbox can run on this host. */ - getLastForContext: async (params: SessionsGetLastForContextRequest): Promise => - connection.sendRequest("sessions.getLastForContext", params), + checkPlatformSupport: async (): Promise => + connection.sendRequest("sandbox.checkPlatformSupport", {}), /** - * Returns the on-disk byte size of each session's workspace directory. + * Reports whether this Windows host's BaseContainer implementation can reach the host's loopback interface directly, which is what a local-network policy needs to avoid routing through the egress proxy. Like `sandbox.checkPlatformSupport`, the answer is a property of the machine's OS build rather than of any setting, and resolving it the first time spawns a platform probe. A host that offers the direct local-network option on a machine that lacks the capability produces a session whose sandboxed commands cannot reach local services. Always false off Windows. * - * @returns Map of sessionId -> on-disk size in bytes for each session's workspace directory. + * @returns True when the sandbox on this host can reach host loopback directly. */ - getSizes: async (): Promise => - connection.sendRequest("sessions.getSizes", {}), + checkWindowsHostLoopbackSupport: async (): Promise => + connection.sendRequest("sandbox.checkWindowsHostLoopbackSupport", {}), /** - * Returns the subset of the supplied session IDs that are currently held by another running process. - * - * @param params Session IDs to test for live in-use locks. + * The explanation a host shows when it refuses an explicit request to turn the sandbox on for a machine that cannot run one. Carries the platform-specific remedy — install bubblewrap, update Windows — and the documentation link, so a host that got `false` from `sandbox.checkPlatformSupport` does not have to compose its own reason and cannot describe the same machine differently from the runtime's own spawn path. * - * @returns Session IDs from the input set that are currently in use by another process. + * @returns The user-facing refusal, including the platform remedy and the documentation link. */ - checkInUse: async (params: SessionsCheckInUseRequest): Promise => - connection.sendRequest("sessions.checkInUse", params), + getUnsupportedMessage: async (): Promise => + connection.sendRequest("sandbox.getUnsupportedMessage", {}), /** - * Closes a session: emits shutdown, flushes pending events, releases the in-use lock, and disposes the active session. - * - * @param params Session ID to close. + * The notice a host shows when a stored `sandbox` setting is being ignored for this session because the machine cannot enforce it. Distinct from `sandbox.getUnsupportedMessage`, which refuses an explicit request: this one reports that a setting the user already saved is inert, states that commands will run unsandboxed, and confirms the stored setting itself is left alone. A host that stays silent here leaves the user believing a sandbox is active. * - * @returns Closes a session: emits shutdown, flushes pending events to disk, releases the in-use lock, disposes the active session. Idempotent: succeeds even if the session is not currently active. + * @returns The user-facing notice that a saved sandbox setting is inert for this session. */ - close: async (params: SessionsCloseRequest): Promise => - connection.sendRequest("sessions.close", params), + getUnsupportedSettingDisabledNotice: async (): Promise => + connection.sendRequest("sandbox.getUnsupportedSettingDisabledNotice", {}), /** - * Closes, deactivates, and deletes a set of sessions, returning the bytes freed per session. + * The warning a host prints at startup when a session asked for a sandbox on a machine that cannot run one. The third of the unsupported notices, and the only one that depends on the policy in force: it names the remedy the reader can actually act on, which is the stored setting for an unmanaged host, an administrator for a managed one, and waiting for the policy to resolve when the sandbox stayed on only because the policy could not be determined. Returns no notice when the machine does support a sandbox, so a host can call it unconditionally on the startup path. A host that composes its own warning tells a managed user to change a setting their policy will overwrite. * - * @param params Session IDs to close, deactivate, and delete from disk. + * @param params The managed sandbox policy in force, which selects which remedy the notice offers. * - * @returns Map of sessionId -> bytes freed by removing the session's workspace directory. + * @returns The startup warning, absent when the machine can run a sandbox. */ - bulkDelete: async (params: SessionsBulkDeleteRequest): Promise => - connection.sendRequest("sessions.bulkDelete", params), + getUnsupportedStartupNotice: async (params: SandboxUnsupportedStartupNoticeParams): Promise => + connection.sendRequest("sandbox.getUnsupportedStartupNotice", params), /** - * Deletes sessions older than the given threshold, with optional dry-run and exclusion list. + * Whether one slash command stays reachable while sandbox enforcement is unavailable and the session is otherwise blocked. The permitted set is deliberately narrow — commands that only report state, and the few that let the user repair or leave the situation — and it is keyed on the arguments as well as the name, so `/sandbox status` is admitted where `/sandbox enable` is not. A host must ask rather than keep its own list: a command this returns false for is one the runtime would refuse anyway, and a divergent list either strands the user with no way out or admits a command that acts on an unenforced session. * - * @param params Age threshold and optional flags controlling which old sessions are pruned (or simulated when dryRun is true). + * @param params One slash command, as typed, to test against the enforcement-block allowlist. * - * @returns Outcome of the prune operation: deleted IDs, dry-run candidates, skipped IDs, total bytes freed, and the dry-run flag. + * @returns True when the command stays available while enforcement is blocked. */ - pruneOld: async (params: SessionsPruneOldRequest): Promise => - connection.sendRequest("sessions.pruneOld", params), + checkEnforcementCommand: async (params: SandboxEnforcementCommandAllowedParams): Promise => + connection.sendRequest("sandbox.checkEnforcementCommand", params), /** - * Flushes a session's pending events to disk. - * - * @param params Session ID whose pending events should be flushed to disk. + * Returns the documentation URL a host should point a user at when it declines or downgrades a sandbox setting. The runtime owns the address so every surface cites the same page and a host does not hard-code a link that later moves. * - * @returns Flush a session's pending events to disk. No-op when no writer exists for the session (e.g., already closed). + * @returns The documentation URL a host cites when it declines or downgrades a sandbox setting. */ - save: async (params: SessionsSaveRequest): Promise => - connection.sendRequest("sessions.save", params), + getDocsUrl: async (): Promise => + connection.sendRequest("sandbox.getDocsUrl", {}), + }, + /** @experimental */ + persistence: { /** - * Releases the in-use lock held by this process for a session. + * Atomically replaces a JSON file's entire contents while holding the runtime's per-path lock. The lock lives in the runtime process, so a host that writes these files itself takes no part in it and can tear a concurrent runtime write; route the write here instead. Unlike a merging write this never reads or parses the existing file, so a previously corrupted snapshot is replaced wholesale rather than failing every later write. Use it only for callers that always persist a complete snapshot. * - * @param params Session ID whose in-use lock should be released. + * @param params A complete JSON snapshot to write under the runtime's per-path file lock. * - * @returns Release the in-use lock held by this process for the given session. No-op when this process does not currently hold a lock for the session. + * @returns The outcome of a locked snapshot write. */ - releaseLock: async (params: SessionsReleaseLockRequest): Promise => - connection.sendRequest("sessions.releaseLock", params), + writeRawJsonLocked: async (params: PersistenceWriteRawJsonLockedRequest): Promise => + connection.sendRequest("persistence.writeRawJsonLocked", params), + }, + /** @experimental */ + user: { + /** @experimental */ + settings: { + /** + * Adds or removes one hook key in the user `disabledHooks` setting, rewriting settings.json in place and leaving every other setting untouched. Reports a typed outcome rather than failing the call, so a host can tell an unparseable settings file apart from a write that could not complete. + * + * @param params One hook to disable or re-enable. + * + * @returns Outcome of rewriting the `disabledHooks` setting. + */ + setHookDisabled: async (params: UserSettingsSetHookDisabledRequest): Promise => + connection.sendRequest("user.settings.setHookDisabled", params), + /** + * Reads the user's settings document exactly as `user.settings.load` does, but from a caller-supplied configuration directory instead of the one the server resolved for itself. Use this when a consumer scopes a session to its own Copilot home — the SDK's per-session `configDir` override — so the settings read match the directory that session actually uses. An absent or empty `configDir` resolves the server's own home, making this identical to `user.settings.load`. Hook-validation relaxations are deliberately not caller-supplied: they continue to come from the server's environment, so a consumer cannot widen the host's hook policy through this method. + * + * @param params Selects the configuration directory whose user settings to read. + * + * @returns The stored user settings document, keyed by setting name. + */ + loadForConfigDir: async (params: UserSettingsLoadForConfigDirRequest): Promise => + connection.sendRequest("user.settings.loadForConfigDir", params), + /** + * Reads a repository's checked-in settings document as stored, normalized, together with any diagnostic raised while reading it. This is the repository half of the layering `user.settings.get` reports: `user.settings.load` reads the user's own document, and this reads the one a repository checks in to govern the keys `user.settings.governanceKeys` lists as repo-governable. A document that fails to parse, or that sets a key a repository may not govern, is reported through `warning` while the settings that did load are still returned, so a consumer surfaces the diagnostic and continues rather than failing the session. When `repoRoot` is the user's home directory the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as repository policy. + * + * @param params Selects the repository whose checked-in settings to read. + * + * @returns A repository's settings as stored, together with any diagnostic raised while reading them. + */ + loadRepo: async (params: UserSettingsLoadRepoRequest): Promise => + connection.sendRequest("user.settings.loadRepo", params), + /** + * Reads a repository's settings and merges them over a supplied user layer in one step, returning the settings a consumer should act on inside that repository. Use this rather than reading the two layers separately: the merge is per setting and collection-aware, so a repository adds to the collections it is allowed to influence without replacing the user's own entries, and a whole-document overlay would get that wrong. Any diagnostic raised while reading the repository layer is returned rather than printed, so the consumer decides how to surface it; the settings that did load are merged regardless. + * + * @param params A repository to read settings from, and the user layer they are merged over. + * + * @returns The settings a consumer should act on inside a repository, together with any diagnostic raised while reading the repository layer. + */ + loadAndMergeRepo: async (params: UserSettingsLoadAndMergeRepoRequest): Promise => + connection.sendRequest("user.settings.loadAndMergeRepo", params), + /** + * Reports the on-disk path of the settings document `user.settings.load` and `user.settings.set` read and write. Resolved the same way those methods resolve it, so a host that shows or opens the settings file names the file the runtime actually uses, including the extensionless legacy `settings` file when that is what is present. + * + * @returns The on-disk location of the user's settings document. + */ + getPath: async (): Promise => + connection.sendRequest("user.settings.getPath", {}), + /** + * Reads the user's stored settings together with the diagnostic raised while reading them. This is `user.settings.load` plus the reason part of the document was ignored: that one answers the document alone, so a caller cannot tell a clean read from a salvaged one. Read this when the caller is about to write the file back, where accepting a partial parse would discard every value the loader could not read. The settings that did load are still reported alongside the warning, so a consumer may surface it and continue instead of failing. + * + * @returns The user's stored settings, together with any diagnostic raised while reading them. + */ + loadWithWarning: async (): Promise => + connection.sendRequest("user.settings.loadWithWarning", {}), + /** + * Folds a user settings layer over a managed (enterprise policy) layer and returns the merged settings. The managed layer's governance keys win, `autoTier` resolves through its overridable form, and the two per-entry control maps (`enabledPlugins`, `extraKnownMarketplaces`) union across the layers and are then stamped back from the managed layer, so each entry an administrator declares wins while the user keeps control of the rest. The parameters are named for their layers rather than being a generic base/override pair: nothing about a settings object identifies which layer produced it, so the runtime cannot detect a transposed call, and transposing one resolves the governance keys in the user's favour instead of the administrator's. Supplying only one layer returns it unchanged, and supplying neither returns an empty object. Rejects a managed `autoTier` that is neither a user-configurable tier nor a single-key overridable form, rather than silently dropping it. + * + * @param params The managed (enterprise policy) layer and the user layer to fold together. The field names carry the layer identity: nothing about a settings object identifies which layer produced it, so a generic base/override pair would let a caller transpose them and silently resolve the governance keys in the user's favour. + * + * @returns The user layer folded over the managed layer. + */ + mergeManagedAndUser: async (params: UserSettingsMergeManagedAndUserParams): Promise => + connection.sendRequest("user.settings.mergeManagedAndUser", params), + /** + * Folds a repository's settings layer into the user layer. Each repo-overridable key carries a directional policy chosen so a repository can only add restrictions and never relax the user's own. The two per-entry managed control maps are the exception those directional rules cannot express — a repository may legitimately enable plugins and declare marketplaces — so they are re-stamped afterwards from the runtime's ambient managed policy. That makes the result depend on the runtime process's managed state and not on the arguments alone: a host must call this rather than reimplement the fold, or a repository could relax a restriction the administrator imposed. Rejects when either layer is not a JSON object. + * + * @param params The user layer and the repository layer to fold together. + * + * @returns The repository layer folded into the user layer. + */ + mergeRepoValue: async (params: UserSettingsMergeRepoValueParams): Promise => + connection.sendRequest("user.settings.mergeRepoValue", params), + /** + * Runs the one-time migration that moves a staff account's update channel to stable, and records that it ran. Idempotent and self-gating: it takes a lock over the global-state file, re-reads the completion stamp inside it, and returns `current` rather than migrating twice, so two hosts racing at startup cannot both migrate. Only a `migrated` status means the persisted settings changed and the caller should reload them. An account on the experimental channel is deliberately left alone and reported as `excluded-experimental`. + * + * @param params The filesystem and environment facts a user-settings file is resolved from. Passed explicitly rather than read from the runtime's own process, so a host whose configuration directory differs from its process environment resolves the file it means. + * + * @returns The outcome of the one-time staff update-channel migration. + */ + migrateStaffUpdateChannelOnce: async (params: UserSettingsHostContext): Promise => + connection.sendRequest("user.settings.migrateStaffUpdateChannelOnce", params), + /** + * Runs the one-time reset that clears a staff account's pinned model selection, and reports the timestamp the host should record. Idempotent and self-gating: the reset is gated on a fixed cutoff, so a caller that passes back the timestamp it recorded gets `didReset: false` rather than a second reset. It applies to staff accounts only; any other account is reported as not reset without the settings document being opened. Only `didReset: true` means the persisted settings changed, and only then are the updated settings returned for the host to adopt. + * + * @param params Selects the configuration directory to run the one-time staff model-selection reset against, and supplies the caller's record of whether it has already run. + * + * @returns The outcome of the one-time staff model-selection reset. + */ + resetStaffModelSelectionOnce: async (params: UserSettingsResetStaffModelSelectionOnceRequest): Promise => + connection.sendRequest("user.settings.resetStaffModelSelectionOnce", params), + /** + * Reports the top-level keys in the user settings document that the runtime does not recognize, phrased for display to the user. This is a separate question from the warning `user.settings.loadWithWarning` returns: that one describes parts of the document the loader had to ignore to load the rest, whereas an unknown key parses cleanly and is simply not a setting, so a host that surfaces only the load warning silently accepts a misspelled key that will never take effect. Nothing is reported when the document is absent, unreadable, or failed to load, because an unknown-key list derived from a document the runtime could not read would be misleading rather than helpful. Inspection never modifies the document. + * + * @param params Selects the configuration directory whose user settings document should be inspected for unrecognized top-level keys. + * + * @returns The unrecognized top-level keys found in the user settings document, already phrased for display. + */ + getUnknownKeysWarning: async (params: UserSettingsUnknownKeysWarningRequest): Promise => + connection.sendRequest("user.settings.getUnknownKeysWarning", params), + /** + * Resolves the effective runtime settings for a host that is about to start a session, layering the given overrides over the settings documents, the environment and the platform defaults. A host cannot assemble this itself: the precedence between a user document, a repository document, the managed layers and the environment is the runtime's own rule, and a host that re-implements it drifts from the server it is configuring. The working directory, environment and platform are taken as arguments rather than read from the server process, so a host resolving settings for a directory other than its own gets that directory's answer. Nothing is written; this only computes. + * + * @param params The overrides and host context to resolve effective runtime settings from. + * + * @returns The effective runtime settings, keyed by setting name. Keys this runtime does not recognize are preserved rather than dropped, so a caller reading a document written by a newer runtime keeps every value. + */ + buildRuntime: async (params: UserSettingsBuildRuntimeRequest): Promise => + connection.sendRequest("user.settings.buildRuntime", params), + /** + * Runs the one-time migration that moves a staff account's log level to the current default, and records that it ran. Idempotent and self-gating: it takes a lock over the global-state file and re-reads the completion stamp inside it, so two hosts racing at startup cannot both migrate. Only `refreshed` can have changed the persisted settings, and the settings it returns are the document re-read after the write, so a host should adopt them rather than reloading separately and racing the next writer. + * + * @param params Selects the configuration directory to run the one-time staff log-level migration against, and supplies the caller's record of whether it has already run. + * + * @returns The outcome of the one-time staff log-level migration. + */ + migrateStaffLogLevelOnce: async (params: UserSettingsMigrateStaffLogLevelOnceRequest): Promise => + connection.sendRequest("user.settings.migrateStaffLogLevelOnce", params), + /** + * Runs the one-time cleanup that removes obsolete CLI-owned settings and legacy rubber-duck keys from the user's settings document, and reports what it did. Idempotent and safe to call on every startup: with nothing obsolete left it reports `unchanged` and writes nothing. The cleanup preserves every key it does not recognize, so a setting written by a newer host is never dropped by an older one, and a document that fails to parse is reported `invalid` and left untouched rather than rewritten from a partial read. The cleaned document is not returned: it is written before this replies, so `user.settings.load` reads it authoritatively. A host that surfaces unrecognized keys through `user.settings.unknownKeys` wants this first, because the keys this retires would otherwise be shown to the user as if they were misspelled settings. + * + * @param params Selects the configuration directory whose settings document to clean. + * + * @returns The outcome of the one-time obsolete-settings cleanup. + */ + migrateObsoleteOnDisk: async (params: UserSettingsMigrateObsoleteOnDiskRequest): Promise => + connection.sendRequest("user.settings.migrateObsoleteOnDisk", params), + /** + * Resolves the on-disk locations of the settings files this runtime reads, so a consumer can show or open them. The user path is the same file `user.settings.get`, `user.settings.load`, and `user.settings.set` operate on. Supply `repoRoot` to also resolve that repository's checked-in and local settings paths. A path is reported whether or not the file exists. + * + * @param params Selects which settings file paths to resolve. + * + * @returns On-disk locations of the settings files this runtime reads. A path is reported whether or not the file exists. + */ + getPaths: async (params: UserSettingsGetPathsRequest): Promise => + connection.sendRequest("user.settings.getPaths", params), + /** + * Lists the top-level user-setting keys by who is allowed to govern them: `repo` keys a repository may override through `.github/copilot/settings.json`, `claudeRepo` keys a repository may override through a Claude-compatible config, and `managed` keys an enterprise policy may fix. The lists are static for a given runtime build and fail closed: a key absent from a list cannot be governed that way. + * + * @returns Top-level user-setting keys grouped by who may govern them. + */ + listGovernanceKeys: async (): Promise => + connection.sendRequest("user.settings.listGovernanceKeys", {}), + /** + * Atomically edits one canonical user setting inside its settings-file lock. Reads, canonicalizes touched aliases, applies the edit, validates the resulting top-level setting and writes before releasing the lock. An explicit autoUpdatesChannel set completes the staff migration in the same transaction. Only a malformed existing file returns `invalid`; refused keys, invalid values and I/O errors reject the call. + * + * @param params One atomic edit of a canonical setting in settings.json. + * + * @returns Outcome of an atomic user or repository settings edit. + */ + edit: async (params: UserSettingsEditRequest): Promise => + connection.sendRequest("user.settings.edit", params), + /** + * Rewrites legacy and snake_case setting names in a settings object to their canonical spelling. A caller editing settings.json must normalize before writing: a legacy key left in place survives the write, is re-normalized on the next load, and silently shadows the canonical value the write just stored. + * + * @param params Settings object whose key names should be canonicalized. + * + * @returns Settings object with canonical key names. + */ + normalize: async (params: UserSettingsNormalizeRequest): Promise => + connection.sendRequest("user.settings.normalize", params), + /** + * Diagnoses a set of already-loaded settings layers, reporting each key that will not take effect and why. Settings load tolerantly so that one bad key does not stop a session from starting; this method surfaces what was dropped so a caller can report it instead of silently ignoring the user's intent. Takes the layers as given rather than reading them, so a caller can diagnose exactly the content it is showing, including unsaved edits. Never echoes a setting's value, because a value may be a token or another secret. Marked internal because it exists to carry a CLI call site off the native addon, not to serve a consumer-facing need; it becomes public once an SDK consumer needs to inspect settings health itself. + * + * @param params The settings layers to diagnose. + * + * @returns The settings that will not take effect across the given layers. + */ + diagnoseProblems: async (params: UserSettingsProblemsRequest): Promise => + connection.sendRequest("user.settings.diagnoseProblems", params), + /** + * Validates one top-level setting subtree and writes just that key to settings.json as a single step. Doing both here closes the race a caller cannot close itself: between a separate preflight read and the write, the file may change. Rewriting only the touched key keeps legacy siblings out of settings.json. Answers a status rather than failing, so a validation problem and a write problem stay distinguishable. + * + * @param params A single top-level setting subtree to validate and write. + * + * @returns Outcome of validating and writing one top-level setting subtree. + */ + applyTopKey: async (params: UserSettingsApplyTopKeyRequest): Promise => + connection.sendRequest("user.settings.applyTopKey", params), + /** + * Replaces the user settings file's entire content in one write. A key absent from `settings` is removed, which is what distinguishes this from `user.settings.set`: that one merges, so it can never clear a key the caller has dropped. For a caller saving the result of a raw edit, a merge would silently resurrect every key the user deleted. Records the same one-time mutation marks a per-key write records, so a setting the user has now chosen explicitly stops being migrated for them. + * + * @param params The whole content to store in the user settings file. + */ + writeAll: async (params: UserSettingsWriteAllRequest): Promise => + connection.sendRequest("user.settings.writeAll", params), + /** + * Merges a partial object into one top-level user setting, re-reading the stored value inside this runtime process's settings.json write lock so that concurrent writers in this process to different sub-fields of the same key do not clobber each other. Unlike `user.settings.set`, which replaces a key's whole value with what the caller last read, this keeps sub-fields the caller did not name when both the stored value and supplied value are objects; otherwise the supplied value replaces the stored value. Use it whenever two independent surfaces own different sub-fields of one setting. Returns the key's stored value after the write, in `value`. + * + * @param params Names the user setting to merge into, and the partial object to merge. + * + * @returns The stored value of the user setting after the merge. + */ + update: async (params: UserSettingsUpdateRequest): Promise => + connection.sendRequest("user.settings.update", params), + /** + * Reads settings.json as stored for a caller that is about to edit it. Unlike `user.settings.get`, this returns file values rather than per-key metadata and defaults. Reports `missing` for an absent file and `invalid` when the existing file will not parse. Retired config.json and extensionless files are not read. + * + * @returns Contents of settings.json as stored, for a caller about to rewrite it. + */ + loadForEdit: async (): Promise => + connection.sendRequest("user.settings.loadForEdit", {}), + /** + * Validates one top-level setting subtree without writing it, reporting each problem with the path it applies to. Scoped to a single top-level key on purpose: validating the whole file would reject an edit whenever an unrelated pre-existing field is malformed, locking the user out of the very tool that could fix it. + * + * @param params A single top-level setting subtree to validate. + * + * @returns Outcome of validating one top-level setting subtree. + */ + validate: async (params: UserSettingsValidateRequest): Promise => + connection.sendRequest("user.settings.validate", params), + }, + }, + /** @experimental */ + repo: { + /** @experimental */ + settings: { + /** + * Atomically edits one allowed top-level repository setting. Reads the raw file, preserves unrelated keys, applies one scalar or list edit, validates the result and writes under one file lock, so concurrent sibling or list edits are not lost. A malformed or unsafe existing file returns `invalid` without a write; rejected keys, invalid values and I/O errors reject the call. + * + * @param params One atomic edit of an allowed top-level repository setting. + * + * @returns Outcome of an atomic user or repository settings edit. + */ + edit: async (params: RepoSettingsEditRequest): Promise => + connection.sendRequest("repo.settings.edit", params), + /** + * Reads one repository settings file without settings normalization or layering. The existing JSONC parser accepts comments and trailing commas and applies its prototype-safety rules. Missing or blank files return an empty valid config. Invalid files return an empty config with invalid=true; other read failures reject. + * + * @param params Which repository settings file to read. + * + * @returns Parsed repository settings without normalization or layering. + */ + readRaw: async (params: RepoSettingsReadRawRequest): Promise => + connection.sendRequest("repo.settings.readRaw", params), + /** + * Writes or removes one allowed top-level repository setting through the existing validator and file lock. Preserves unrelated stored keys. Invalid keys, values, existing documents, and I/O errors reject without replacing the file. Deletion requires delete=true; otherwise value must be present. + * + * @param params One key to write or remove in a repository settings file. + */ + writeKey: async (params: RepoSettingsWriteKeyRequest): Promise => + connection.sendRequest("repo.settings.writeKey", params), + /** + * Replaces the repository-overridable settings in one locked write. Allowed keys present in settings are validated and written; allowed keys absent from settings are removed. Other input keys are ignored, and unknown keys already stored in the file remain unchanged. Invalid values or an invalid existing file reject without a partial write. + * + * @param params The complete set of repository-overridable settings to store. + */ + writeAll: async (params: RepoSettingsWriteAllRequest): Promise => + connection.sendRequest("repo.settings.writeAll", params), + }, + }, + /** @experimental */ + featureFlags: { /** - * Backfills missing summary and context fields on the supplied session metadata records. + * Resolves named gates against this installation's cached online-experiment assignment, for the account the runtime is already authenticated as. Unlike `featureFlags.resolve`, which layers static availability with the populations supplied, this reads the experiment assignment the runtime cached for its own current authentication, so a launch can honor a rollout before any session exists. The account is never taken from the request: naming one would read another account's cached assignments. The cached assignment answers immediately and any network refresh happens behind it, so this call does not wait on the network. Not available to an extension, which cannot carry the user's consent to read their assignment. * - * @param params Session metadata records to enrich with summary and context information. + * @param params Caller population and startup inputs to resolve named online-experiment gates for. Carries no account: the runtime resolves the assignment for the authentication it already holds. * - * @returns The enriched metadata records, with summary and context fields backfilled where available. Sessions confirmed empty and unnamed are omitted. + * @returns The resolved gates, keyed by flag name. */ - enrichMetadata: async (params: SessionsEnrichMetadataRequest): Promise => - connection.sendRequest("sessions.enrichMetadata", params), + resolveStartupGates: async (params: FeatureFlagsResolveStartupGatesRequest): Promise => + connection.sendRequest("featureFlags.resolveStartupGates", params), /** - * Reloads user, plugin, and (optionally) repo hooks on the active session. - * - * @param params Active session ID and an optional flag for deferring repo-level hooks until folder trust. + * Lists every feature flag this runtime declares, with the population each one is declared for, its experimental description, and the online-experiment flag it maps to. This is the static catalog: it describes how each flag is defined, not whether it is on for anyone. Use `featureFlags.resolve` for static values with caller overrides, not active runtime values or experiment assignments. * - * @returns Reload all hooks (user, plugin, optionally repo) and apply them to the active session. Call after installing or removing plugins so their hooks take effect immediately. No-op when no active session matches the given sessionId. + * @returns Every feature flag this runtime declares, with the shape each one was declared with. */ - reloadPluginHooks: async (params: SessionsReloadPluginHooksRequest): Promise => - connection.sendRequest("sessions.reloadPluginHooks", params), + listMetadata: async (): Promise => + connection.sendRequest("featureFlags.listMetadata", {}), /** - * Loads previously-deferred repo-level hooks on the active session, returning queued startup prompts. + * Computes static feature flags from the supplied population and overrides without changing runtime state or verifying audience membership. Starts from declared availability, then applies direct feature-flag environment values, user settings, and explicit `flagOverrides`. It does not apply `COPILOT_EXP_*` experiment assignments, authenticated startup gates, or active runtime state. Settings include `enabledFeatureFlags`, the legacy `feature_flags.enabled` list, and supported convenience settings. Supply `baseFlags` to use an existing flag set instead of declared availability. Omit `isStaffGitHub` or `isStaffMicrosoft` when membership was never recorded: a legacy staff account then counts as both populations. * - * @param params Active session ID whose deferred repo-level hooks should be loaded. + * @param params Caller population and overrides for static feature-flag resolution, independent of experiment assignments and active runtime state. * - * @returns Queued repo-level startup prompts and the total hook command count after loading. + * @returns The resolved feature flags, keyed by flag name. */ - loadDeferredRepoHooks: async (params: SessionsLoadDeferredRepoHooksRequest): Promise => - connection.sendRequest("sessions.loadDeferredRepoHooks", params), + resolve: async (params: FeatureFlagsResolveRequest): Promise => + connection.sendRequest("featureFlags.resolve", params), + }, + /** @experimental */ + permissions: { + /** @experimental */ + locations: { + /** + * Drops stored per-location permission grants whose directory no longer exists, and reports which location keys were removed. Runs against the permission store under the runtime's own Copilot home, the same store `session.permissions.locations.resolve` reads. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. It can become public once an SDK consumer needs to prune its own permission store. + * + * @returns Which stored location permissions were dropped because their directory is gone. + */ + cleanupOrphaned: async (): Promise => + connection.sendRequest("permissions.locations.cleanupOrphaned", {}), + }, + /** @experimental */ + folderTrust: { + /** + * Reports whether a folder is trusted, reading the persisted trusted-folders list directly rather than through a session. Use this from a host that has no session yet, such as a one-shot command deciding whether to honor a checkout's own settings. It differs from the session-scoped check in two ways that matter: it takes the configuration directory to read the list from, instead of inheriting the session's, and it answers only from the persisted list, so trust a user granted for the lifetime of one session is not visible here. A host that has a session should prefer the session-scoped check, which also covers session-only trust. + * + * @param params A folder to check against a persisted trusted-folders list, and the configuration directory holding that list. + * + * @returns Folder trust check result. + */ + checkTrust: async (params: FolderTrustIsTrustedParams): Promise => + connection.sendRequest("permissions.folderTrust.checkTrust", params), + }, /** - * Replaces the manager-wide additional plugins registered with the session manager. + * Interprets a verbatim managed `permissions` slice into the three policy questions a host asks before granting elevated permissions: whether bypass-permissions mode is forbidden, whether a policy exists that this build could not determine, and whether the layer supplies permission rules the session must enforce. An absent or empty slice means no managed policy applies. The runtime and its permission service share one policy type, so a new managed permission setting is interpreted in exactly one place; a host that reimplements the reading would silently diverge the first time that set grows. Hosts must fail closed on an undetermined policy rather than treating it as permission granted. * - * @param params Manager-wide additional plugins to register; replaces any previously-configured set. + * @param params The verbatim managed `permissions` slice to interpret. * - * @returns Replace the manager-wide additional plugins. New session creations and subsequent hook reloads see the new set; already-running sessions keep their existing hook installation until the next reload. + * @returns The policy questions a host asks before granting elevated permissions. */ - setAdditionalPlugins: async (params: SessionsSetAdditionalPluginsRequest): Promise => - connection.sendRequest("sessions.setAdditionalPlugins", params), + evaluateManagedPolicy: async (params: PermissionsEvaluateManagedPolicyParams): Promise => + connection.sendRequest("permissions.evaluateManagedPolicy", params), + }, + /** @experimental */ + managedSettings: { /** - * Attaches the runtime-managed remote-control singleton to a session, awaiting initial setup. If remote control is already attached to a different session, the singleton is transferred (preserving the underlying Mission Control connection). Returns the final status. - * - * @param params Parameters for attaching the remote-control singleton to a session. + * Discovers device-managed settings the way the runtime's own device layer does, and reports the sandbox floor and the load outcome alongside the validated document. This differs from `managedSettings.read` in three ways a policy-enforcing host depends on: a document that validates to an empty object is reported as absent rather than as an empty policy, a discovery error does not suppress a document that still validates, and a failure is reported as a flag rather than only as error text. Hosts that compose the device layer into an effective policy use this, because `managedSettings.read` cannot distinguish "no device policy" from "device policy could not be read" and would silently hand the user's own layer the win. * - * @returns Wrapper for the singleton's current status. + * @returns The device-managed settings layer, with the sandbox floor and the load outcome a host needs to compose it into an effective policy. */ - startRemoteControl: async (params: SessionsStartRemoteControlRequest): Promise => - connection.sendRequest("sessions.startRemoteControl", params), + readDevice: async (): Promise => + connection.sendRequest("managedSettings.readDevice", {}), /** - * Atomically rebinds the remote-control singleton to a different session, preserving the underlying Mission Control connection. When `expectedFromSessionId` is provided and does not match the singleton's current `attachedSessionId`, the transfer is rejected with `transferred: false` and the current status is returned unchanged. - * - * @param params Parameters for atomically rebinding the remote-control singleton. + * Retains the supplied managed layers as this runtime process's startup policy and re-applies the result to every live session. Hosts that own their own short-lived process policy use this, so a guarded mutation is checked against the policy the host actually fetched. Retaining is a whole-process replacement rather than a merge, so a host that already resolved a good policy must not retain a partial one over it. The failure flags are honest inputs rather than assumptions: reporting a fetch or load that failed keeps the layers already retained, and the interim fail-closed state, instead of clearing them. * - * @returns Outcome of a transferRemoteControl call. + * @param params The managed layers to retain as this process's startup policy, with the outcome of fetching each one. */ - transferRemoteControl: async (params: SessionsTransferRemoteControlRequest): Promise => - connection.sendRequest("sessions.transferRemoteControl", params), + retainPolicy: async (params: ManagedSettingsRetainPolicyParams): Promise => + connection.sendRequest("managedSettings.retainPolicy", params), /** - * Patches the steering state of the active remote-control singleton. When remote control is off, this is a no-op and the off status is returned. Today only `enabled: true` is actionable on the underlying exporter; passing `false` is reserved for future use. + * Stamps an effective managed policy's individually-controlled entries onto a user settings document, returning the settings a host should actually act on. The managed layer wins on every plugin spec and marketplace name it names, and leaves everything it does not name as the user wrote it. Hosts use this rather than merging the two documents themselves, because the merge is per entry rather than per document and a whole-document overlay would either discard the user's unmanaged entries or let a user entry outrank a managed one. Omitting the managed layer returns the settings unchanged, which is what an unmanaged host wants. Rejects when either document is present but is not a JSON object rather than treating it as absent, since silently dropping a malformed policy hands the user's layer the win on exactly the entries the policy exists to control. * - * @param params Patch for the singleton's steering state. + * @param params A user settings document and the effective managed policy whose controlled entries should be stamped onto it. * - * @returns Wrapper for the singleton's current status. + * @returns The user settings with the managed layer's controlled entries stamped on. */ - setRemoteControlSteering: async (params: SessionsSetRemoteControlSteeringRequest): Promise => - connection.sendRequest("sessions.setRemoteControlSteering", params), + applyControls: async (params: ManagedSettingsApplyControlsParams): Promise => + connection.sendRequest("managedSettings.applyControls", params), /** - * Stops the remote-control singleton. When `expectedSessionId` is provided and does not match the singleton's current `attachedSessionId`, the stop is rejected with `stopped: false` and the current status is returned unchanged (unless `force` is set, in which case the singleton is unconditionally torn down). + * Validates the managed settings a client is supplying for a session it is about to open, and returns them reduced to the keys a client is allowed to set. A client-supplied policy is not the same thing as an administrator's: it may only narrow permissions, so this accepts `permissions` and rejects every other key outright rather than ignoring it. Rejecting is the point — a host that silently dropped an unsupported key would report a policy as applied while running without it. Hosts call this before opening the session rather than letting the open fail, so a malformed policy is reported against the request that carried it. The runtime applies the same rule again when the session starts, so this cannot be used to smuggle a wider document past it. An accepted document that sets nothing comes back as an empty object, which is distinct from supplying nothing at all. * - * @param params Parameters for stopping the remote-control singleton. + * @param params The client-supplied managed settings to validate and normalize. Omitting them is valid and yields no policy. * - * @returns Outcome of a stopRemoteControl call. + * @returns The accepted managed settings, reduced to the keys a client is allowed to set. */ - stopRemoteControl: async (params: SessionsStopRemoteControlRequest): Promise => - connection.sendRequest("sessions.stopRemoteControl", params), + parseClientValue: async (params: ManagedSettingsParseClientValueParams): Promise => + connection.sendRequest("managedSettings.parseClientValue", params), /** - * Returns the current state of the remote-control singleton, including the attached session id and frontend URL when active. + * Composes the supplied server, device/MDM, device sandbox floor and policy-helper layers into the single effective managed policy a host should enforce, resolving each key across the layers by the runtime's own precedence rules. Hosts that assemble managed layers themselves use this so their precedence matches the runtime's exactly instead of reimplementing it. The composition is not a pure function of its inputs: an advisory sandbox force-on that arrived over the server channel is declined when this host cannot run a sandbox, so the result reflects the runtime host's capabilities, and the returned settings carry `sandboxAdvisoryFloorDeclined: true` when that happened. Enforced channels (device/MDM and policy helper) are never declined, and a server force-on carrying `failIfUnavailable` is preserved so the session fails loudly instead of quietly running unsandboxed. Rejects when a supplied layer is present but is not a JSON object, rather than treating it as unmanaged, because silently dropping a malformed policy would hand the user's own layer the win on exactly the keys the policy exists to control. * - * @returns Wrapper for the singleton's current status. + * @param params The managed-settings layers to compose into an effective policy. Every layer is optional; omitting all of them yields no effective policy. + * + * @returns The effective managed policy composed from the supplied layers. */ - getRemoteControlStatus: async (): Promise => - connection.sendRequest("sessions.getRemoteControlStatus", {}), - }, - /** @experimental */ - agentRegistry: { + resolveEffectiveValue: async (params: ManagedSettingsResolveEffectiveValueParams): Promise => + connection.sendRequest("managedSettings.resolveEffectiveValue", params), /** - * Spawns a managed-server child with the supplied configuration and returns a discriminated-union result. The caller (typically the CLI controller) is responsible for attaching to the spawned child and sending any follow-up prompt. When the controller-local spawn gate is closed the server returns JSON-RPC MethodNotFound. + * Decides what a host must do to its bypass-permissions state after a managed-policy resolution lands, given the state already in force and the account now signed in. A host holds two pieces of state — which layer disabled bypass mode, and for a server-delivered disable, the account it was pinned to — and cannot decide the next step from the new policy alone. Three rules make that so, and each one is a control rather than a preference. A device/MDM disable outranks the account, so a later server answer never lifts it. An unknown policy, which is what a failed fetch or a refusal this build cannot enforce yields, preserves whatever is in force instead of reverting to permissive. And a server disable is lifted only when the account it was pinned to is no longer the signed-in one, which is what makes signing in to an unrestricted account recover without a restart while a reconnect on the same restricted account does not. Hosts call this rather than reimplementing it because getting the pinning backwards either strands a disable on an account that never carried one or drops one that still applies. `setDisabledState` is omitted when the host must leave its stored flag untouched, which is distinct from being told to set it to false. * - * @param params Inputs to spawn a managed-server child via the controller's spawn delegate. + * @param params The bypass-permissions state a host holds today, the account now signed in, and what the managed-policy resolution said. * - * @returns Outcome of an agentRegistry.spawn call. + * @returns The bypass-permissions state a host should hold after the resolution, and what it must do to get there. */ - spawn: async (params: AgentRegistrySpawnRequest): Promise => - connection.sendRequest("agentRegistry.spawn", params), - }, - /** @experimental */ - connectors: { + resolveBypassDisableTransition: async (params: ManagedSettingsResolveBypassDisableTransitionParams): Promise => + connection.sendRequest("managedSettings.resolveBypassDisableTransition", params), /** - * Returns feature availability. + * Resolves managed (enterprise policy) settings for a host from every layer at once: the account's server-delivered policy, the device/MDM layer, and a platform policy helper. Hosts use this instead of fetching and composing the layers themselves, because the per-layer precedence and the fail-closed rules that apply when a layer cannot be confirmed are the runtime's own and must match the policy a session will later enforce. It does not retain or apply anything to process-global policy state, so a host may call it before any session exists — which is the point, since plugin activation and one-shot commands resolve policy before a session is available to carry it. The returned per-layer outcome flags are load-bearing rather than diagnostic: a host must distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. Reports its diagnostics in `logMessages` rather than logging them, so a host that runs before a log sink exists still sees them. * - * @returns Feature availability. + * @param params Inputs describing the host and account an ingestion should resolve managed policy for. + * + * @returns The managed policy layers an ingestion resolved, together with the per-layer outcome flags a host needs to decide how much to trust the result. The flags are reported rather than folded into the settings because a host must be able to distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. */ - getCapabilities: async (): Promise => - connection.sendRequest("connectors.getCapabilities", {}), + ingest: async (params: ManagedSettingsIngestParams): Promise => + connection.sendRequest("managedSettings.ingest", params), /** - * Returns eligible accounts. + * Resolves the managed (enterprise policy) settings a host must enforce from startup, and judges the account against the enterprise sign-in pin in the same pass. This composes the layers the way `managedSettings.ingest` does and then answers the two questions a host cannot answer for itself: which fail-closed floors apply when a layer could not be confirmed, and whether this credential is allowed to sign in at all. The sign-in verdict is the reason a host must not assemble this itself from `managedSettings.ingest` — a pinned organization is an access control, and a host that composed the layers but skipped the pin would let a developer sign in with a personal or another enterprise's account and escape every control that keys off the signed-in identity. The verdict is computed on every resolution, including one that is not retained, so declining to apply policy never widens access. Set `retainAndApply` to keep the resolved policy as this runtime process's startup policy; leave it false to resolve without side effects. * - * @returns Eligible accounts. + * @param params Inputs describing the host and account a startup policy resolution should run for. Mirrors `managedSettings.ingest`, and adds the decision of whether the resolved policy is retained for this runtime process. + * + * @returns The startup policy a resolution composed, the per-layer outcome flags a host needs to decide how much to trust it, and the enterprise sign-in verdict for the credential it ran against. The flags are reported rather than folded into the settings because a host must distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. */ - getAccounts: async (): Promise => - connection.sendRequest("connectors.getAccounts", {}), + resolveStartupPolicy: async (params: ManagedSettingsResolveStartupPolicyParams): Promise => + connection.sendRequest("managedSettings.resolveStartupPolicy", params), /** - * Lists entries for the selected account. + * Resolves the managed `remoteControl` policy for an account on its own, for a host deciding whether a remote-control session may start. Composes the same layers as `managedSettings.ingest` and returns only that one key, so a host does not have to know which layer won. An absent policy means the account is unmanaged for this capability and the host may proceed; that default is safe only while absence really does mean "no policy", so a service refusal that says an account policy exists which this client is too old to enforce resolves to an explicit disabled policy instead of to absence. A resolution that cannot be completed is rejected rather than answered as absence, for the same reason. * - * @param params Selected account. + * @param params Inputs describing the host and account whose managed remote-control policy should be resolved. Mirrors `managedSettings.ingest`, and deliberately carries no retention decision: reading this gate never becomes this runtime process's startup policy. * - * @returns Entries for the selected account. + * @returns The managed remote-control policy in force for an account, if any. An absent policy means the account is unmanaged for this capability, which a host reads as allowed — so absence here is a positive statement that no policy applies, never a stand-in for a resolution that failed. A resolution that cannot be completed is rejected instead. */ - list: async (params: ConnectorDiscoveryAccountRequest): Promise => - connection.sendRequest("connectors.list", params), + loadRemoteControl: async (params: ManagedSettingsLoadRemoteControlParams): Promise => + connection.sendRequest("managedSettings.loadRemoteControl", params), /** - * Refreshes entries for the selected account. + * Evaluates the device-channel enterprise sign-in pin (MDM plist, registry, or managed-settings file) against a credential, without resolving any server-delivered policy. This is the gate an entry point runs before it branches, and the only one that can refuse a developer's first sign-in: it is local, needs no credential, and a server-delivered pin only ever reaches accounts already inside the organization. It fails closed by construction — a discovery that cannot determine whether a pin exists refuses rather than allows, because a control that fails open under a triggerable condition is not a control. Hosts that also want the server channel should call `managedSettings.resolveStartupPolicy`, which folds both channels into one verdict. * - * @param params Selected account. + * @param params The credential and environment to evaluate the device-channel sign-in pin against. * - * @returns Entries for the selected account. + * @returns The verdict of the `forceLoginOrgs` enterprise sign-in pin for one credential. A managed device may pin Copilot to an approved set of GitHub organizations so a developer cannot sign in with a personal — or another enterprise's — account and escape every control that keys off the signed-in identity. A host must refuse to proceed when `allowed` is false; the remaining fields explain the refusal rather than qualifying it. */ - refresh: async (params: ConnectorDiscoveryAccountRequest): Promise => - connection.sendRequest("connectors.refresh", params), + resolveDeviceForceLoginOrgsGate: async (params: ManagedSettingsResolveDeviceForceLoginOrgsGateParams): Promise => + connection.sendRequest("managedSettings.resolveDeviceForceLoginOrgsGate", params), }, - }; -} - -/** - * Create typed server-scoped RPC methods that are part of the SDK's internal - * surface (e.g. handshake helpers). Not exported on the public client API. - * @internal - */ -export function createInternalServerRpc(connection: MessageConnection) { - return { /** @experimental */ host: { /** @@ -34541,144 +36960,6 @@ export function createInternalServerRpc(connection: MessageConnection) { connection.sendRequest("globalState.writeKey", params), }, /** @experimental */ - user: { - /** @experimental */ - settings: { - /** - * Resolves the on-disk locations of the settings files this runtime reads, so a consumer can show or open them. The user path is the same file `user.settings.get`, `user.settings.load`, and `user.settings.set` operate on. Supply `repoRoot` to also resolve that repository's checked-in and local settings paths. A path is reported whether or not the file exists. - * - * @param params Selects which settings file paths to resolve. - * - * @returns On-disk locations of the settings files this runtime reads. A path is reported whether or not the file exists. - */ - getPaths: async (params: UserSettingsGetPathsRequest): Promise => - connection.sendRequest("user.settings.getPaths", params), - /** - * Lists the top-level user-setting keys by who is allowed to govern them: `repo` keys a repository may override through `.github/copilot/settings.json`, `claudeRepo` keys a repository may override through a Claude-compatible config, and `managed` keys an enterprise policy may fix. The lists are static for a given runtime build and fail closed: a key absent from a list cannot be governed that way. - * - * @returns Top-level user-setting keys grouped by who may govern them. - */ - listGovernanceKeys: async (): Promise => - connection.sendRequest("user.settings.listGovernanceKeys", {}), - /** - * Atomically edits one canonical user setting inside its settings-file lock. Reads, canonicalizes touched aliases, applies the edit, validates the resulting top-level setting and writes before releasing the lock. An explicit autoUpdatesChannel set completes the staff migration in the same transaction. Only a malformed existing file returns `invalid`; refused keys, invalid values and I/O errors reject the call. - * - * @param params One atomic edit of a canonical setting in settings.json. - * - * @returns Outcome of an atomic user or repository settings edit. - */ - edit: async (params: UserSettingsEditRequest): Promise => - connection.sendRequest("user.settings.edit", params), - /** - * Rewrites legacy and snake_case setting names in a settings object to their canonical spelling. A caller editing settings.json must normalize before writing: a legacy key left in place survives the write, is re-normalized on the next load, and silently shadows the canonical value the write just stored. - * - * @param params Settings object whose key names should be canonicalized. - * - * @returns Settings object with canonical key names. - */ - normalize: async (params: UserSettingsNormalizeRequest): Promise => - connection.sendRequest("user.settings.normalize", params), - /** - * Diagnoses a set of already-loaded settings layers, reporting each key that will not take effect and why. Settings load tolerantly so that one bad key does not stop a session from starting; this method surfaces what was dropped so a caller can report it instead of silently ignoring the user's intent. Takes the layers as given rather than reading them, so a caller can diagnose exactly the content it is showing, including unsaved edits. Never echoes a setting's value, because a value may be a token or another secret. Marked internal because it exists to carry a CLI call site off the native addon, not to serve a consumer-facing need; it becomes public once an SDK consumer needs to inspect settings health itself. - * - * @param params The settings layers to diagnose. - * - * @returns The settings that will not take effect across the given layers. - */ - diagnoseProblems: async (params: UserSettingsProblemsRequest): Promise => - connection.sendRequest("user.settings.diagnoseProblems", params), - /** - * Validates one top-level setting subtree and writes just that key to settings.json as a single step. Doing both here closes the race a caller cannot close itself: between a separate preflight read and the write, the file may change. Rewriting only the touched key keeps legacy siblings out of settings.json. Answers a status rather than failing, so a validation problem and a write problem stay distinguishable. - * - * @param params A single top-level setting subtree to validate and write. - * - * @returns Outcome of validating and writing one top-level setting subtree. - */ - applyTopKey: async (params: UserSettingsApplyTopKeyRequest): Promise => - connection.sendRequest("user.settings.applyTopKey", params), - /** - * Replaces the user settings file's entire content in one write. A key absent from `settings` is removed, which is what distinguishes this from `user.settings.set`: that one merges, so it can never clear a key the caller has dropped. For a caller saving the result of a raw edit, a merge would silently resurrect every key the user deleted. Records the same one-time mutation marks a per-key write records, so a setting the user has now chosen explicitly stops being migrated for them. - * - * @param params The whole content to store in the user settings file. - */ - writeAll: async (params: UserSettingsWriteAllRequest): Promise => - connection.sendRequest("user.settings.writeAll", params), - /** - * Merges a partial object into one top-level user setting, re-reading the stored value inside this runtime process's settings.json write lock so that concurrent writers in this process to different sub-fields of the same key do not clobber each other. Unlike `user.settings.set`, which replaces a key's whole value with what the caller last read, this keeps sub-fields the caller did not name when both the stored value and supplied value are objects; otherwise the supplied value replaces the stored value. Use it whenever two independent surfaces own different sub-fields of one setting. Returns the key's stored value after the write, in `value`. - * - * @param params Names the user setting to merge into, and the partial object to merge. - * - * @returns The stored value of the user setting after the merge. - */ - update: async (params: UserSettingsUpdateRequest): Promise => - connection.sendRequest("user.settings.update", params), - /** - * Reads settings.json as stored for a caller that is about to edit it. Unlike `user.settings.get`, this returns file values rather than per-key metadata and defaults. Reports `missing` for an absent file and `invalid` when the existing file will not parse. Retired config.json and extensionless files are not read. - * - * @returns Contents of settings.json as stored, for a caller about to rewrite it. - */ - loadForEdit: async (): Promise => - connection.sendRequest("user.settings.loadForEdit", {}), - /** - * Validates one top-level setting subtree without writing it, reporting each problem with the path it applies to. Scoped to a single top-level key on purpose: validating the whole file would reject an edit whenever an unrelated pre-existing field is malformed, locking the user out of the very tool that could fix it. - * - * @param params A single top-level setting subtree to validate. - * - * @returns Outcome of validating one top-level setting subtree. - */ - validate: async (params: UserSettingsValidateRequest): Promise => - connection.sendRequest("user.settings.validate", params), - }, - }, - /** @experimental */ - featureFlags: { - /** - * Lists every feature flag this runtime declares, with the population each one is declared for, its experimental description, and the online-experiment flag it maps to. This is the static catalog: it describes how each flag is defined, not whether it is on for anyone. Use `featureFlags.resolve` for static values with caller overrides, not active runtime values or experiment assignments. - * - * @returns Every feature flag this runtime declares, with the shape each one was declared with. - */ - listMetadata: async (): Promise => - connection.sendRequest("featureFlags.listMetadata", {}), - /** - * Computes static feature flags from the supplied population and overrides without changing runtime state or verifying audience membership. Starts from declared availability, then applies direct feature-flag environment values, user settings, and explicit `flagOverrides`. It does not apply `COPILOT_EXP_*` experiment assignments, authenticated startup gates, or active runtime state. Settings include `enabledFeatureFlags`, the legacy `feature_flags.enabled` list, and supported convenience settings. Supply `baseFlags` to use an existing flag set instead of declared availability. Omit `isStaffGitHub` or `isStaffMicrosoft` when membership was never recorded: a legacy staff account then counts as both populations. - * - * @param params Caller population and overrides for static feature-flag resolution, independent of experiment assignments and active runtime state. - * - * @returns The resolved feature flags, keyed by flag name. - */ - resolve: async (params: FeatureFlagsResolveRequest): Promise => - connection.sendRequest("featureFlags.resolve", params), - }, - /** @experimental */ - repo: { - /** @experimental */ - settings: { - /** - * Reads one repository settings file without settings normalization or layering. The existing JSONC parser accepts comments and trailing commas and applies its prototype-safety rules. Missing or blank files return an empty valid config. Invalid files return an empty config with invalid=true; other read failures reject. - * - * @param params Which repository settings file to read. - * - * @returns Parsed repository settings without normalization or layering. - */ - readRaw: async (params: RepoSettingsReadRawRequest): Promise => - connection.sendRequest("repo.settings.readRaw", params), - /** - * Writes or removes one allowed top-level repository setting through the existing validator and file lock. Preserves unrelated stored keys. Invalid keys, values, existing documents, and I/O errors reject without replacing the file. Deletion requires delete=true; otherwise value must be present. - * - * @param params One key to write or remove in a repository settings file. - */ - writeKey: async (params: RepoSettingsWriteKeyRequest): Promise => - connection.sendRequest("repo.settings.writeKey", params), - /** - * Replaces the repository-overridable settings in one locked write. Allowed keys present in settings are validated and written; allowed keys absent from settings are removed. Other input keys are ignored, and unknown keys already stored in the file remain unchanged. Invalid values or an invalid existing file reject without a partial write. - * - * @param params The complete set of repository-overridable settings to store. - */ - writeAll: async (params: RepoSettingsWriteAllRequest): Promise => - connection.sendRequest("repo.settings.writeAll", params), - }, - }, - /** @experimental */ gitHubRepository: { /** * Resolves the GitHub repository that owns a working-tree path by reading the selected git remote configured for it, preferring `origin`. Returns a null `repository` when the path is inside a git working tree but that selected remote does not resolve to a GitHub host. Fails when the path is not inside a git working tree at all, so a caller can tell 'not a repository' apart from 'a repository with no GitHub remote'. diff --git a/nodejs/test/csharp-codegen.test.ts b/nodejs/test/csharp-codegen.test.ts index 5120fabc95..4d215e1b11 100644 --- a/nodejs/test/csharp-codegen.test.ts +++ b/nodejs/test/csharp-codegen.test.ts @@ -6,6 +6,60 @@ import type { ApiSchema, RpcMethod } from "../../scripts/codegen/utils.ts"; import { postProcessSchema } from "../../scripts/codegen/utils.ts"; import { legacyRequestSchema } from "./legacy-parameters-fixture.ts"; +describe("C# RPC dictionaries", () => { + it.each([undefined, true, { type: "string" } as const])( + "retains open object entries with additionalProperties=%j", + (additionalProperties) => { + const dictionary: JSONSchema7 = { + type: "object", + properties: {}, + ...(additionalProperties === undefined ? {} : { additionalProperties }), + }; + const schema: ApiSchema = { + server: { + sample: { + read: { + rpcMethod: "sample.read", + params: { + title: "SampleRequest", + type: "object", + properties: { environment: dictionary }, + required: ["environment"], + }, + result: { + title: "SampleResult", + type: "object", + properties: { + settings: dictionary, + referenced: { $ref: "#/definitions/Dictionary" }, + entries: { type: "array", items: dictionary }, + closed: { + type: "object", + properties: {}, + additionalProperties: false, + }, + }, + }, + }, + }, + }, + definitions: { Dictionary: dictionary }, + }; + const before = structuredClone(schema); + const code = generateRpcCode(schema); + const valueType = typeof additionalProperties === "object" ? "string" : "JsonElement"; + expect(code).toContain(`IDictionary Environment`); + expect(code).toContain(`IDictionary? Settings`); + expect(code).toContain(`IDictionary? Referenced`); + expect(code).toContain(`IList>? Entries`); + expect(code).toContain("class SampleResultClosed"); + expect(code).not.toContain("class SampleRequestEnvironment"); + expect(code).not.toContain("class SampleResultSettings"); + expect(schema).toEqual(before); + } + ); +}); + function legacySignatureFixture(scope: "server" | "session", legacy: unknown) { const params: JSONSchema7 & { "x-legacy-parameters"?: unknown } = { title: "SampleRequest", diff --git a/nodejs/test/e2e/rpc_surface_coverage.e2e.test.ts b/nodejs/test/e2e/rpc_surface_coverage.e2e.test.ts index daa26e42a3..30f4793d31 100644 --- a/nodejs/test/e2e/rpc_surface_coverage.e2e.test.ts +++ b/nodejs/test/e2e/rpc_surface_coverage.e2e.test.ts @@ -327,7 +327,7 @@ describe("Generated RPC surface coverage", () => { ...collectRuntimeFunctions(session.rpc, "session"), ]); - expect(inventory).toHaveLength(408); + expect(inventory).toHaveLength(410); expect( inventory.filter( (method) => method.wireMethod === "session.model.getReasoningSummaries" diff --git a/nodejs/test/e2e/startup_policy.e2e.test.ts b/nodejs/test/e2e/startup_policy.e2e.test.ts new file mode 100644 index 0000000000..330cf3c44b --- /dev/null +++ b/nodejs/test/e2e/startup_policy.e2e.test.ts @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import { describe, expect, it } from "vitest"; +import { createSdkTestContext } from "./harness/sdkTestContext.js"; + +describe("Sandbox proxy CA policy", async () => { + const { copilotClient: client } = await createSdkTestContext(); + + it("reports relevance without installation or caller config changes", async () => { + await client.start(); + const configured = { sandboxConfig: { enabled: true, auth: { gh: true } } }; + const before = structuredClone(configured); + expect(await client.rpc.sandbox.proxyCa.checkRelevance(configured)).toBe(true); + expect(configured).toEqual(before); + expect( + await client.rpc.sandbox.proxyCa.checkRelevance({ + sandboxConfig: { enabled: false, auth: { gh: true } }, + }) + ).toBe(false); + expect(await client.rpc.sandbox.proxyCa.checkRelevance({})).toBe(false); + }); + + it("reports installation support without an elevation prompt", async () => { + await client.start(); + const supported = await client.rpc.sandbox.proxyCa.checkInstallationSupport(); + expect(typeof supported).toBe("boolean"); + if (process.platform !== "win32") { + expect(supported).toBe(true); + } + }); +}); diff --git a/nodejs/test/java-codegen.test.ts b/nodejs/test/java-codegen.test.ts index 62c3027584..28db7fe54a 100644 --- a/nodejs/test/java-codegen.test.ts +++ b/nodejs/test/java-codegen.test.ts @@ -15,6 +15,43 @@ function rpcSource(files: Map, name: string): string { return source!; } +describe("java RPC primitive results", () => { + it.each([ + ["boolean", "Boolean"], + ["integer", "Long"], + ["number", "Double"], + ["string", "String"], + ] as const)("preserves inline and referenced %s results", async (type, javaType) => { + const schema = { + server: { + sample: { + inline: { + rpcMethod: "sample.inline", + params: null, + result: { type }, + }, + referenced: { + rpcMethod: "sample.referenced", + visibility: "internal", + params: null, + result: { $ref: "#/definitions/ScalarResult" }, + }, + empty: { rpcMethod: "sample.empty", params: null, result: null }, + }, + }, + definitions: { ScalarResult: { type } }, + } satisfies Parameters[0]; + const code = rpcSource(await renderRpcWrappers(schema), "ServerSampleApi"); + + expect(code).toContain(`CompletableFuture<${javaType}> inline()`); + expect(code).toContain(`"sample.inline", java.util.Map.of(), ${javaType}.class`); + expect(code).toContain(`CompletableFuture<${javaType}> referenced()`); + expect(code).toContain(`"sample.referenced", java.util.Map.of(), ${javaType}.class`); + expect(code).toContain("CompletableFuture empty()"); + expect(code).toContain('"sample.empty", java.util.Map.of(), Void.class'); + }); +}); + it("preserves boolean-map RPC results without widening them to JsonNode", async () => { const files = await renderRpcWrappers({ server: { diff --git a/python/copilot/generated/rpc.py b/python/copilot/generated/rpc.py index 973b275803..e08198249b 100644 --- a/python/copilot/generated/rpc.py +++ b/python/copilot/generated/rpc.py @@ -4351,6 +4351,90 @@ def to_dict(self) -> dict: result["isStaffMicrosoft"] = from_union([from_bool, from_none], self.is_staff_microsoft) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _FeatureFlagsResolveStartupGatesRequest: + """Caller population and startup inputs to resolve named online-experiment gates for. + Carries no account: the runtime resolves the assignment for the authentication it already + holds. + """ + flags: list[str] + """The feature flags to resolve. A name this runtime does not declare is reported as an + error rather than as a disabled flag. + """ + is_experimental: bool + """Whether the caller is in an experimental population.""" + + is_staff: bool + """Whether the caller is GitHub or Microsoft staff.""" + + is_team: bool + """Whether the caller belongs to a team plan.""" + + refresh_without_session: bool + """Whether the runtime may refresh the cached assignment over the network without an active + session. The refresh never blocks this call: the answer comes from the cache either way, + so a refresh only affects a later launch. + """ + streamer_mode: bool + """Whether streamer mode is on, which withholds the populations an experiment would + otherwise segment on. + """ + config: Any = None + """User settings document whose `featureFlags` block is layered on top of the resolved set.""" + + environment: dict[str, str] | None = None + """Environment to read flag overrides from. Defaults to this runtime process's own + environment. + """ + first_launch_at_millis: float | None = None + """When this installation first launched, in milliseconds since the Unix epoch. Experiments + that segment on installation age read it. Omit when the first launch was never recorded. + """ + is_staff_github: bool | None = None + """GitHub-staff membership. Omit when it was never recorded: a legacy staff account then + counts as both staff populations and keeps every staff feature. + """ + is_staff_microsoft: bool | None = None + """Microsoft-staff membership. Omitted the same way as `isStaffGitHub`.""" + + @staticmethod + def from_dict(obj: Any) -> '_FeatureFlagsResolveStartupGatesRequest': + assert isinstance(obj, dict) + flags = from_list(from_str, obj.get("flags")) + is_experimental = from_bool(obj.get("isExperimental")) + is_staff = from_bool(obj.get("isStaff")) + is_team = from_bool(obj.get("isTeam")) + refresh_without_session = from_bool(obj.get("refreshWithoutSession")) + streamer_mode = from_bool(obj.get("streamerMode")) + config = obj.get("config") + environment = from_union([lambda x: from_dict(from_str, x), from_none], obj.get("environment")) + first_launch_at_millis = from_union([from_float, from_none], obj.get("firstLaunchAtMillis")) + is_staff_github = from_union([from_bool, from_none], obj.get("isStaffGithub")) + is_staff_microsoft = from_union([from_bool, from_none], obj.get("isStaffMicrosoft")) + return _FeatureFlagsResolveStartupGatesRequest(flags, is_experimental, is_staff, is_team, refresh_without_session, streamer_mode, config, environment, first_launch_at_millis, is_staff_github, is_staff_microsoft) + + def to_dict(self) -> dict: + result: dict = {} + result["flags"] = from_list(from_str, self.flags) + result["isExperimental"] = from_bool(self.is_experimental) + result["isStaff"] = from_bool(self.is_staff) + result["isTeam"] = from_bool(self.is_team) + result["refreshWithoutSession"] = from_bool(self.refresh_without_session) + result["streamerMode"] = from_bool(self.streamer_mode) + if self.config is not None: + result["config"] = self.config + if self.environment is not None: + result["environment"] = from_union([lambda x: from_dict(from_str, x), from_none], self.environment) + if self.first_launch_at_millis is not None: + result["firstLaunchAtMillis"] = from_union([to_float, from_none], self.first_launch_at_millis) + if self.is_staff_github is not None: + result["isStaffGithub"] = from_union([from_bool, from_none], self.is_staff_github) + if self.is_staff_microsoft is not None: + result["isStaffMicrosoft"] = from_union([from_bool, from_none], self.is_staff_microsoft) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class FleetStartRequest: @@ -4471,6 +4555,110 @@ def to_dict(self) -> dict: result["trusted"] = from_bool(self.trusted) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _FolderTrustIsTrustedParams: + """A folder to check against a persisted trusted-folders list, and the configuration + directory holding that list. + """ + path: str + """Folder to check. A folder counts as trusted when it is itself listed, when an ancestor is + listed, or when its git root is listed. + """ + config_dir: str | None = None + """Configuration directory to read the trusted-folders list from. Omit it to read the + default location; supply it when the host has redirected its configuration, or the check + answers from a list the host is not using. + """ + + @staticmethod + def from_dict(obj: Any) -> '_FolderTrustIsTrustedParams': + assert isinstance(obj, dict) + path = from_str(obj.get("path")) + config_dir = from_union([from_str, from_none], obj.get("configDir")) + return _FolderTrustIsTrustedParams(path, config_dir) + + def to_dict(self) -> dict: + result: dict = {} + result["path"] = from_str(self.path) + if self.config_dir is not None: + result["configDir"] = from_union([from_str, from_none], self.config_dir) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _ForceLoginOrgsDecision: + """The verdict of the `forceLoginOrgs` enterprise sign-in pin for one credential. A managed + device may pin Copilot to an approved set of GitHub organizations so a developer cannot + sign in with a personal — or another enterprise's — account and escape every control that + keys off the signed-in identity. A host must refuse to proceed when `allowed` is false; + the remaining fields explain the refusal rather than qualifying it. + + The enterprise sign-in verdict for the credential this resolution ran against, evaluated + over the effective policy so a server-delivered pin is honored alongside a device one. + Computed on every resolution, including one that was not retained, so a host that + declines to apply policy still cannot proceed past a pin. + """ + allowed: bool + """Whether the client may proceed. True whenever no pin is in force, so an unmanaged host is + never blocked. + """ + enforced: bool + """Whether a pin applies at all. Distinguishes "allowed because unmanaged" from "allowed + because the account is approved", which a diagnostics surface needs and which also + decides whether a bring-your-own-key provider may serve inference. + """ + policy_diagnostics: list[str] + """Error-level detail from managed-policy discovery — which file failed to load, which field + failed validation. Carried on the decision rather than left to the log because a refusal + can exit the process before a log sink exists, which would discard the only actionable + diagnostic a misconfigured managed device produces. + """ + required_orgs: list[str] + """The approved organization logins, as configured. Enterprise configuration rather than + user data, so it is safe to name in a message or a log line. + """ + denial: str | None = None + """A stable kebab-case reason code when refused: `org-not-approved`, + `unverifiable-credential`, `policy-undetermined`, `policy-invalid`, `not-signed-in`, or + `membership-unknown`. Omitted when allowed. Treat an unrecognized code as a refusal + rather than mapping it to an allow: a code this host has not been taught about still + denied the credential. + """ + matched_org: str | None = None + """The approved organization the account matched, when allowed under a pin.""" + + message: str | None = None + """A developer-facing explanation of the refusal. Omitted when allowed.""" + + @staticmethod + def from_dict(obj: Any) -> '_ForceLoginOrgsDecision': + assert isinstance(obj, dict) + allowed = from_bool(obj.get("allowed")) + enforced = from_bool(obj.get("enforced")) + policy_diagnostics = from_list(from_str, obj.get("policyDiagnostics")) + required_orgs = from_list(from_str, obj.get("requiredOrgs")) + denial = from_union([from_str, from_none], obj.get("denial")) + matched_org = from_union([from_str, from_none], obj.get("matchedOrg")) + message = from_union([from_str, from_none], obj.get("message")) + return _ForceLoginOrgsDecision(allowed, enforced, policy_diagnostics, required_orgs, denial, matched_org, message) + + def to_dict(self) -> dict: + result: dict = {} + result["allowed"] = from_bool(self.allowed) + result["enforced"] = from_bool(self.enforced) + result["policyDiagnostics"] = from_list(from_str, self.policy_diagnostics) + result["requiredOrgs"] = from_list(from_str, self.required_orgs) + if self.denial is not None: + result["denial"] = from_union([from_str, from_none], self.denial) + if self.matched_org is not None: + result["matchedOrg"] = from_union([from_str, from_none], self.matched_org) + if self.message is not None: + result["message"] = from_union([from_str, from_none], self.message) + return result + class GhCLIAuthInfoType(Enum): GH_CLI = "gh-cli" @@ -6690,6 +6878,26 @@ class HostType(Enum): ADO = "ado" GITHUB = "github" +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _LocationPermissionsCleanupResult: + """Which stored location permissions were dropped because their directory is gone.""" + + removed_location_keys: list[str] + """Location keys whose grants were removed. Empty when every stored location still exists.""" + + @staticmethod + def from_dict(obj: Any) -> '_LocationPermissionsCleanupResult': + assert isinstance(obj, dict) + removed_location_keys = from_list(from_str, obj.get("removedLocationKeys")) + return _LocationPermissionsCleanupResult(removed_location_keys) + + def to_dict(self) -> dict: + result: dict = {} + result["removedLocationKeys"] = from_list(from_str, self.removed_location_keys) + return result + # Experimental: this type is part of an experimental API and may change or be removed. class SessionLogLevel(Enum): """Log severity level. Determines how the message is displayed in the timeline. Defaults to @@ -6867,6 +7075,86 @@ def to_dict(self) -> dict: result["requested"] = from_union([from_str, from_none], self.requested) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _ManagedSettingsApplyControlsParams: + """A user settings document and the effective managed policy whose controlled entries should + be stamped onto it. + """ + settings: Any + """The user settings document to stamp. Entries the managed layer does not name are returned + exactly as supplied. + """ + managed: Any = None + """The effective managed policy, as composed by `managedSettings.resolveEffectiveValue`. + Omit it on an unmanaged host: the settings then come back unchanged. + """ + + @staticmethod + def from_dict(obj: Any) -> '_ManagedSettingsApplyControlsParams': + assert isinstance(obj, dict) + settings = obj.get("settings") + managed = obj.get("managed") + return _ManagedSettingsApplyControlsParams(settings, managed) + + def to_dict(self) -> dict: + result: dict = {} + result["settings"] = self.settings + if self.managed is not None: + result["managed"] = self.managed + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _ManagedSettingsApplyControlsResult: + """The user settings with the managed layer's controlled entries stamped on.""" + + settings_json: Any + """The resulting settings document.""" + + @staticmethod + def from_dict(obj: Any) -> '_ManagedSettingsApplyControlsResult': + assert isinstance(obj, dict) + settings_json = obj.get("settingsJson") + return _ManagedSettingsApplyControlsResult(settings_json) + + def to_dict(self) -> dict: + result: dict = {} + result["settingsJson"] = self.settings_json + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +class _ManagedSettingsBypassDisableSource(Enum): + """Which layer disabled bypass-permissions mode. The layer matters because only a + server-delivered disable is pinned to an account and can later be lifted by signing in + elsewhere. + + Which layer currently disables bypass mode. Omit it when nothing does. + + Which layer disables bypass mode after this resolution. Omitted when none does, which is + what a lifted disable looks like. + """ + MANAGED = "managed" + MDM = "mdm" + USER = "user" + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +class _ManagedSettingsBypassPolicyResolution(Enum): + """What the managed-policy resolution said about bypass-permissions mode. `unknown` is a + third answer rather than a missing one, and the caller must send it explicitly when it + has no verdict. + + What the resolution said about bypass mode. Send `unknown` rather than omitting the field + when there is no verdict. + """ + ALLOWED = "allowed" + DISABLED = "disabled" + UNKNOWN = "unknown" + # Experimental: this type is part of an experimental API and may change or be removed. class ManagedSettingsChannel(Enum): """A channel accepted by managedSettings.compose. @@ -7072,6 +7360,186 @@ def to_dict(self) -> dict: result["model"] = from_union([from_str, from_none], self.model) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +class _ManagedSettingsPolicyHelperReason(Enum): + """The policy-helper invocation reason. Defaults to sessionStart. + + The operation that requires a policy-helper response. + """ + PLUGIN_ACTIVATION = "pluginActivation" + SESSION_START = "sessionStart" + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +class _ManagedSettingsServerPolicyCacheMode(Enum): + """How this ingestion may use the on-disk server-policy cache. Defaults to the runtime's own + policy when omitted. + + How an ingestion may use the on-disk server-policy cache. + + How this resolution may use the on-disk server-policy cache. Defaults to the runtime's + own policy when omitted. Rejected when combined with `bypassCacheRead`, because the two + express the same decision and accepting both would leave the caller unsure which one the + runtime honored. + """ + CACHE_ONLY = "cacheOnly" + DISABLED = "disabled" + FALLBACK_ONLY = "fallbackOnly" + PREFER_FRESH = "preferFresh" + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +class _ManagedSettingsLogLevel(Enum): + """Severity of this diagnostic. + + Severity of a diagnostic emitted while ingesting managed settings. + """ + DEBUG = "debug" + ERROR = "error" + INFO = "info" + WARNING = "warning" + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +class _ManagedSettingsPolicyHelperAuthority(Enum): + """Which channel registered the policy helper that produced the helper layer. + + Which channel registered the policy helper that produced a helper layer. + """ + DEVICE = "device" + SERVER = "server" + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +class _ManagedSettingsServerPolicyResolution(Enum): + """How the server layer was resolved. + + How the server layer of an ingestion was resolved. + + How the current runtime resolved the server layer. + """ + CACHE_MISS = "cacheMiss" + FAIL_CLOSED = "failClosed" + FAIL_OPEN = "failOpen" + FALLBACK_CACHE = "fallbackCache" + FRESH_CACHE = "freshCache" + LIVE = "live" + SKIPPED_NO_TOKEN = "skippedNoToken" + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _ManagedSettingsLoadRemoteControlResult: + """The managed remote-control policy in force for an account, if any. An absent policy means + the account is unmanaged for this capability, which a host reads as allowed — so absence + here is a positive statement that no policy applies, never a stand-in for a resolution + that failed. A resolution that cannot be completed is rejected instead. + """ + remote_control: Any = None + """The account's `remoteControl` policy document. Absent when no managed policy governs + remote control for this account. Reported as an explicit disabled policy, rather than as + absence, when the service refused to deliver a policy this client is too old to enforce. + """ + + @staticmethod + def from_dict(obj: Any) -> '_ManagedSettingsLoadRemoteControlResult': + assert isinstance(obj, dict) + remote_control = obj.get("remoteControl") + return _ManagedSettingsLoadRemoteControlResult(remote_control) + + def to_dict(self) -> dict: + result: dict = {} + if self.remote_control is not None: + result["remoteControl"] = self.remote_control + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _ManagedSettingsParseClientValueParams: + """The client-supplied managed settings to validate and normalize. Omitting them is valid + and yields no policy. + """ + settings: Any = None + """The managed settings a client is supplying for a session it is about to open. Omit them + when the client is imposing no policy of its own. + """ + + @staticmethod + def from_dict(obj: Any) -> '_ManagedSettingsParseClientValueParams': + assert isinstance(obj, dict) + settings = obj.get("settings") + return _ManagedSettingsParseClientValueParams(settings) + + def to_dict(self) -> dict: + result: dict = {} + if self.settings is not None: + result["settings"] = self.settings + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _ManagedSettingsParseClientValueResult: + """The accepted managed settings, reduced to the keys a client is allowed to set.""" + + settings_json: Any = None + """The normalized settings. Omitted when the client supplied none. An accepted document that + sets nothing comes back as an empty object, which is distinct from omission. + """ + + @staticmethod + def from_dict(obj: Any) -> '_ManagedSettingsParseClientValueResult': + assert isinstance(obj, dict) + settings_json = obj.get("settingsJson") + return _ManagedSettingsParseClientValueResult(settings_json) + + def to_dict(self) -> dict: + result: dict = {} + if self.settings_json is not None: + result["settingsJson"] = self.settings_json + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _ManagedSettingsReadDeviceResult: + """The device-managed settings layer, with the sandbox floor and the load outcome a host + needs to compose it into an effective policy. + """ + load_failed: bool + """Whether discovery or validation failed. A host must treat this as "policy unknown" rather + than "no policy": absent settings with this set false mean the device genuinely has none. + """ + sandbox_floor: Any = None + """Sandbox floor read from the discovered document before validation, so a document that is + otherwise rejected can still raise the floor it declared. + """ + settings: Any = None + """Validated, canonical device-managed settings. Omitted when no device policy was + discovered, when the discovered document failed validation, or when it validated to an + empty object — an empty document carries no policy, and reporting it as present would + outrank layers that do. + """ + + @staticmethod + def from_dict(obj: Any) -> '_ManagedSettingsReadDeviceResult': + assert isinstance(obj, dict) + load_failed = from_bool(obj.get("loadFailed")) + sandbox_floor = obj.get("sandboxFloor") + settings = obj.get("settings") + return _ManagedSettingsReadDeviceResult(load_failed, sandbox_floor, settings) + + def to_dict(self) -> dict: + result: dict = {} + result["loadFailed"] = from_bool(self.load_failed) + if self.sandbox_floor is not None: + result["sandboxFloor"] = self.sandbox_floor + if self.settings is not None: + result["settings"] = self.settings + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class ManagedSettingsReadResult: @@ -7100,6 +7568,105 @@ def to_dict(self) -> dict: result["settingsJson"] = self.settings_json return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _ManagedSettingsResolveDeviceForceLoginOrgsGateParams: + """The credential and environment to evaluate the device-channel sign-in pin against.""" + + environment: Any + """The host's environment variables. Read for the variables that would make an identity's + membership snapshot forgeable, so a credential whose provenance cannot be trusted is + refused rather than accepted. + """ + auth_info: Any = None + """The authenticated identity to judge. Omitted when signed out, which is the case the + device channel exists to serve: it can refuse a first sign-in before any credential + exists. + """ + + @staticmethod + def from_dict(obj: Any) -> '_ManagedSettingsResolveDeviceForceLoginOrgsGateParams': + assert isinstance(obj, dict) + environment = obj.get("environment") + auth_info = obj.get("authInfo") + return _ManagedSettingsResolveDeviceForceLoginOrgsGateParams(environment, auth_info) + + def to_dict(self) -> dict: + result: dict = {} + result["environment"] = self.environment + if self.auth_info is not None: + result["authInfo"] = self.auth_info + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _ManagedSettingsResolveEffectiveValueParams: + """The managed-settings layers to compose into an effective policy. Every layer is optional; + omitting all of them yields no effective policy. + """ + device_sandbox_floor: Any = None + """The device sandbox floor, folded into the device layer under `sandbox` before composition.""" + + mdm: Any = None + """The device layer: native MDM and managed-file settings describing the machine rather than + the account. + """ + policy_helper: Any = None + """The policy-helper layer, an enforced channel sourced from a platform policy helper + process. + """ + server: Any = None + """The account's server-delivered org policy, as returned by a managed-settings fetch. + Omitted before sign-in or when the fetch has not landed. + """ + + @staticmethod + def from_dict(obj: Any) -> '_ManagedSettingsResolveEffectiveValueParams': + assert isinstance(obj, dict) + device_sandbox_floor = obj.get("deviceSandboxFloor") + mdm = obj.get("mdm") + policy_helper = obj.get("policyHelper") + server = obj.get("server") + return _ManagedSettingsResolveEffectiveValueParams(device_sandbox_floor, mdm, policy_helper, server) + + def to_dict(self) -> dict: + result: dict = {} + if self.device_sandbox_floor is not None: + result["deviceSandboxFloor"] = self.device_sandbox_floor + if self.mdm is not None: + result["mdm"] = self.mdm + if self.policy_helper is not None: + result["policyHelper"] = self.policy_helper + if self.server is not None: + result["server"] = self.server + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _ManagedSettingsResolveEffectiveValueResult: + """The effective managed policy composed from the supplied layers.""" + + settings_json: Any = None + """The composed effective managed settings. Omitted when no layer sets anything, so an + unmanaged host locks nothing. Carries `sandboxAdvisoryFloorDeclined: true` when an + advisory server force-on was dropped because this host cannot run the sandbox. + """ + + @staticmethod + def from_dict(obj: Any) -> '_ManagedSettingsResolveEffectiveValueResult': + assert isinstance(obj, dict) + settings_json = obj.get("settingsJson") + return _ManagedSettingsResolveEffectiveValueResult(settings_json) + + def to_dict(self) -> dict: + result: dict = {} + if self.settings_json is not None: + result["settingsJson"] = self.settings_json + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class ManagedSettingsResolveRequest: @@ -7141,6 +7708,119 @@ def to_dict(self) -> dict: result["workingDirectory"] = from_union([from_str, from_none], self.working_directory) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _ManagedSettingsRetainPolicyParams: + """The managed layers to retain as this process's startup policy, with the outcome of + fetching each one. + """ + device_load_failed: bool + """Whether the device load failed. Report it honestly, for the same reason as + `serverFetchFailed`. + """ + device_sandbox_undetermined: bool + """Whether the device sandbox intent is unreadable independently of its other settings.""" + + device_source_found: bool + """Whether a device policy source demonstrably exists. This, not a read error, is the + evidence a device is managed, so a fail-closed policy gates on it. + """ + managed_policy_present: bool + """Whether any managed policy source exists, independently of fetch failures.""" + + permission_policy_undetermined: bool + """Whether permission policy is undetermined. Sandbox-only uncertainty does not imply this + flag. + """ + preserve_server_state: bool + """Preserve the retained server layer during a device-only resolution.""" + + sandbox_enabled_by_undetermined_policy: bool + """Whether uncertainty alone enabled the shared sandbox floor.""" + + sandbox_floor_undetermined: bool + """Whether the shared sandbox policy is undetermined. Diagnostic errors alone do not imply + this flag. + """ + server_fetch_failed: bool + """Whether the server fetch failed. Report it honestly: true keeps the already-retained + server layer rather than replacing it with an absent one. + """ + server_forced_refresh_failure: bool + """Whether a required fresh server-policy confirmation failed.""" + + server_source_found: bool + """Whether the server policy source exists, even when its response is unavailable.""" + + device_response: Any = None + """The device/MDM policy layer.""" + + device_sandbox_floor: Any = None + """Sandbox floor declared by the device layer, carried separately so a document that failed + validation can still raise the floor. + """ + policy_helper_response: Any = None + """The policy helper's response: the third managed layer that a process owning its startup + policy resolves. It is retained with the other two so that every ambient read in this + process, including the mutation guards and the governed marketplace allowlist that the + `plugins.*` handlers derive, sees the whole policy the process fetched. A session-owning + process omits it, because it resolves a helper per session against that session's working + directory. + """ + server_response: Any = None + """The resolved server policy. A known source can lack a response after a forced-refresh + failure. + """ + shared_sandbox_floor: Any = None + """Shared server/device sandbox floor, excluding session-local helper policy.""" + + @staticmethod + def from_dict(obj: Any) -> '_ManagedSettingsRetainPolicyParams': + assert isinstance(obj, dict) + device_load_failed = from_bool(obj.get("deviceLoadFailed")) + device_sandbox_undetermined = from_bool(obj.get("deviceSandboxUndetermined")) + device_source_found = from_bool(obj.get("deviceSourceFound")) + managed_policy_present = from_bool(obj.get("managedPolicyPresent")) + permission_policy_undetermined = from_bool(obj.get("permissionPolicyUndetermined")) + preserve_server_state = from_bool(obj.get("preserveServerState")) + sandbox_enabled_by_undetermined_policy = from_bool(obj.get("sandboxEnabledByUndeterminedPolicy")) + sandbox_floor_undetermined = from_bool(obj.get("sandboxFloorUndetermined")) + server_fetch_failed = from_bool(obj.get("serverFetchFailed")) + server_forced_refresh_failure = from_bool(obj.get("serverForcedRefreshFailure")) + server_source_found = from_bool(obj.get("serverSourceFound")) + device_response = obj.get("deviceResponse") + device_sandbox_floor = obj.get("deviceSandboxFloor") + policy_helper_response = obj.get("policyHelperResponse") + server_response = obj.get("serverResponse") + shared_sandbox_floor = obj.get("sharedSandboxFloor") + return _ManagedSettingsRetainPolicyParams(device_load_failed, device_sandbox_undetermined, device_source_found, managed_policy_present, permission_policy_undetermined, preserve_server_state, sandbox_enabled_by_undetermined_policy, sandbox_floor_undetermined, server_fetch_failed, server_forced_refresh_failure, server_source_found, device_response, device_sandbox_floor, policy_helper_response, server_response, shared_sandbox_floor) + + def to_dict(self) -> dict: + result: dict = {} + result["deviceLoadFailed"] = from_bool(self.device_load_failed) + result["deviceSandboxUndetermined"] = from_bool(self.device_sandbox_undetermined) + result["deviceSourceFound"] = from_bool(self.device_source_found) + result["managedPolicyPresent"] = from_bool(self.managed_policy_present) + result["permissionPolicyUndetermined"] = from_bool(self.permission_policy_undetermined) + result["preserveServerState"] = from_bool(self.preserve_server_state) + result["sandboxEnabledByUndeterminedPolicy"] = from_bool(self.sandbox_enabled_by_undetermined_policy) + result["sandboxFloorUndetermined"] = from_bool(self.sandbox_floor_undetermined) + result["serverFetchFailed"] = from_bool(self.server_fetch_failed) + result["serverForcedRefreshFailure"] = from_bool(self.server_forced_refresh_failure) + result["serverSourceFound"] = from_bool(self.server_source_found) + if self.device_response is not None: + result["deviceResponse"] = self.device_response + if self.device_sandbox_floor is not None: + result["deviceSandboxFloor"] = self.device_sandbox_floor + if self.policy_helper_response is not None: + result["policyHelperResponse"] = self.policy_helper_response + if self.server_response is not None: + result["serverResponse"] = self.server_response + if self.shared_sandbox_floor is not None: + result["sharedSandboxFloor"] = self.shared_sandbox_floor + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class ManagedSettingsValidateRequest: @@ -10998,6 +11678,62 @@ def to_dict(self) -> dict: result["success"] = from_bool(self.success) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _PermissionsEvaluateManagedPolicyParams: + """The verbatim managed `permissions` slice to interpret.""" + + permissions: Any = None + """The `permissions` object from a managed settings layer, for example + `{"disableBypassPermissionsMode":"disable"}`. Omitted or null means no managed policy + applies. + """ + + @staticmethod + def from_dict(obj: Any) -> '_PermissionsEvaluateManagedPolicyParams': + assert isinstance(obj, dict) + permissions = obj.get("permissions") + return _PermissionsEvaluateManagedPolicyParams(permissions) + + def to_dict(self) -> dict: + result: dict = {} + if self.permissions is not None: + result["permissions"] = self.permissions + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class PermissionsEvaluateManagedPolicyResult: + """The policy questions a host asks before granting elevated permissions.""" + + bypass_permissions_disabled: bool + """True when managed policy forbids bypass-permissions mode, so allow-all style flags must + not take effect. + """ + permission_rules_active: bool + """True when the managed layer supplies permission rules that the session must enforce.""" + + policy_undetermined: bool + """True when a managed policy exists but this build could not determine its meaning. Hosts + fail closed on it rather than assuming permission was granted. + """ + + @staticmethod + def from_dict(obj: Any) -> 'PermissionsEvaluateManagedPolicyResult': + assert isinstance(obj, dict) + bypass_permissions_disabled = from_bool(obj.get("bypassPermissionsDisabled")) + permission_rules_active = from_bool(obj.get("permissionRulesActive")) + policy_undetermined = from_bool(obj.get("policyUndetermined")) + return PermissionsEvaluateManagedPolicyResult(bypass_permissions_disabled, permission_rules_active, policy_undetermined) + + def to_dict(self) -> dict: + result: dict = {} + result["bypassPermissionsDisabled"] = from_bool(self.bypass_permissions_disabled) + result["permissionRulesActive"] = from_bool(self.permission_rules_active) + result["policyUndetermined"] = from_bool(self.policy_undetermined) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class PermissionsFolderTrustAddTrustedResult: @@ -11326,6 +12062,66 @@ def to_dict(self) -> dict: result["success"] = from_bool(self.success) return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class PersistenceWriteRawJSONLockedRequest: + """A complete JSON snapshot to write under the runtime's per-path file lock.""" + + data_json: str + """The serialized JSON document to write. It replaces the file's contents entirely; nothing + is merged. + """ + path: str + """Absolute path of the file to replace. Parent directories are created when missing.""" + + file_header: str | None = None + """Comment lines to emit above the document, for a format that tolerates them. Omit for + strict JSON. + """ + + @staticmethod + def from_dict(obj: Any) -> 'PersistenceWriteRawJSONLockedRequest': + assert isinstance(obj, dict) + data_json = from_str(obj.get("dataJson")) + path = from_str(obj.get("path")) + file_header = from_union([from_none, from_str], obj.get("fileHeader")) + return PersistenceWriteRawJSONLockedRequest(data_json, path, file_header) + + def to_dict(self) -> dict: + result: dict = {} + result["dataJson"] = from_str(self.data_json) + result["path"] = from_str(self.path) + if self.file_header is not None: + result["fileHeader"] = from_union([from_none, from_str], self.file_header) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class PersistenceWriteRawJSONLockedResult: + """The outcome of a locked snapshot write.""" + + success: bool + """Whether the file now holds the requested contents.""" + + error: str | None = None + """Why the write failed. Absent when `success` is true. A lock the runtime could not acquire + in time reports here rather than raising. + """ + + @staticmethod + def from_dict(obj: Any) -> 'PersistenceWriteRawJSONLockedResult': + assert isinstance(obj, dict) + success = from_bool(obj.get("success")) + error = from_union([from_none, from_str], obj.get("error")) + return PersistenceWriteRawJSONLockedResult(success, error) + + def to_dict(self) -> dict: + result: dict = {} + result["success"] = from_bool(self.success) + if self.error is not None: + result["error"] = from_union([from_none, from_str], self.error) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class PingRequest: @@ -13038,6 +13834,29 @@ def to_dict(self) -> dict: result["branch"] = from_union([from_str, from_none], self.branch) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +class _SettingsEditOperation(Enum): + """Set a scalar, add or remove a string list item, or remove the setting. The handler + rejects a missing or incompatible value. + + One atomic settings mutation. + """ + ADD_ITEM = "add-item" + REMOVE = "remove" + REMOVE_ITEM = "remove-item" + SET = "set" + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +class _RepoSettingsEditScope(Enum): + """Shared or local repository settings file. + + Which repository settings file to edit. + """ + LOCAL = "local" + REPO = "repo" + # Experimental: this type is part of an experimental API and may change or be removed. # Internal: this type is an internal SDK API and is not part of the public surface. @dataclass @@ -13170,6 +13989,27 @@ def to_dict(self) -> dict: class ResponseFormatType(Enum): JSON_SCHEMA = "json_schema" +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SandboxApplyDefaultsRequest: + """The stored sandbox settings to resolve against the defaults.""" + + stored: Any + """The sandbox settings as stored in the settings file. An empty object resolves to the + defaults alone. + """ + + @staticmethod + def from_dict(obj: Any) -> 'SandboxApplyDefaultsRequest': + assert isinstance(obj, dict) + stored = obj.get("stored") + return SandboxApplyDefaultsRequest(stored) + + def to_dict(self) -> dict: + result: dict = {} + result["stored"] = self.stored + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class SandboxConfigAuth: @@ -13431,6 +14271,102 @@ def to_dict(self) -> dict: result["success"] = from_bool(self.success) return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SandboxDocsURLResult: + """The documentation URL a host cites when it declines or downgrades a sandbox setting.""" + + url: str + """Documentation URL describing the sandbox and the settings that control it.""" + + @staticmethod + def from_dict(obj: Any) -> 'SandboxDocsURLResult': + assert isinstance(obj, dict) + url = from_str(obj.get("url")) + return SandboxDocsURLResult(url) + + def to_dict(self) -> dict: + result: dict = {} + result["url"] = from_str(self.url) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _SandboxEffectiveForOptionalParams: + """A sandbox config and the per-feature routing flag to resolve it for.""" + + routing_flag: str + """The routing flag naming the feature being launched, such as `sandboxMcpServers` or + `sandboxLspServers`. + """ + sandbox: Any = None + """The session's resolved `sandbox` slice. Omitted when the host has none, which yields a + disabled sandbox rather than an error. + """ + + @staticmethod + def from_dict(obj: Any) -> '_SandboxEffectiveForOptionalParams': + assert isinstance(obj, dict) + routing_flag = from_str(obj.get("routingFlag")) + sandbox = obj.get("sandbox") + return _SandboxEffectiveForOptionalParams(routing_flag, sandbox) + + def to_dict(self) -> dict: + result: dict = {} + result["routingFlag"] = from_str(self.routing_flag) + if self.sandbox is not None: + result["sandbox"] = self.sandbox + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _SandboxEffectiveForOptionalResult: + """The sandbox a named feature actually launches under.""" + + sandbox_json: Any + """The effective sandbox config for the requested feature, or a disabled sandbox when the + feature is routed out of it. + """ + + @staticmethod + def from_dict(obj: Any) -> '_SandboxEffectiveForOptionalResult': + assert isinstance(obj, dict) + sandbox_json = obj.get("sandboxJson") + return _SandboxEffectiveForOptionalResult(sandbox_json) + + def to_dict(self) -> dict: + result: dict = {} + result["sandboxJson"] = self.sandbox_json + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _SandboxEnforcementCommandAllowedParams: + """One slash command, as typed, to test against the enforcement-block allowlist.""" + + args: list[str] + """The command's arguments, in order. Pass an empty array for a bare command: several + entries in the allowlist admit the bare form and refuse every argument. + """ + command_name: str + """The command name as the user typed it, with or without its leading slash.""" + + @staticmethod + def from_dict(obj: Any) -> '_SandboxEnforcementCommandAllowedParams': + assert isinstance(obj, dict) + args = from_list(from_str, obj.get("args")) + command_name = from_str(obj.get("commandName")) + return _SandboxEnforcementCommandAllowedParams(args, command_name) + + def to_dict(self) -> dict: + result: dict = {} + result["args"] = from_list(from_str, self.args) + result["commandName"] = from_str(self.command_name) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class SandboxEnforcementStatus: @@ -13461,6 +14397,54 @@ def to_dict(self) -> dict: result["reason"] = from_union([from_str, from_none], self.reason) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _SandboxPickerCandidate: + """One file-picker suggestion offered up for the sandbox filesystem check.""" + + is_directory: bool + """Whether the suggestion is a directory. A directory the policy does not itself allow may + still be needed as a waypoint to an allowed subtree. + """ + path: str + """Absolute path the suggestion would attach.""" + + @staticmethod + def from_dict(obj: Any) -> '_SandboxPickerCandidate': + assert isinstance(obj, dict) + is_directory = from_bool(obj.get("isDirectory")) + path = from_str(obj.get("path")) + return _SandboxPickerCandidate(is_directory, path) + + def to_dict(self) -> dict: + result: dict = {} + result["isDirectory"] = from_bool(self.is_directory) + result["path"] = from_str(self.path) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _SandboxFilterPickerCandidatesResult: + """Per-candidate allow decisions, positionally aligned with the request.""" + + allowed: list[bool] + """One decision per candidate, in the same order. Always the same length as the request's + `candidates`. + """ + + @staticmethod + def from_dict(obj: Any) -> '_SandboxFilterPickerCandidatesResult': + assert isinstance(obj, dict) + allowed = from_list(from_bool, obj.get("allowed")) + return _SandboxFilterPickerCandidatesResult(allowed) + + def to_dict(self) -> dict: + result: dict = {} + result["allowed"] = from_list(from_bool, self.allowed) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class SandboxGrantPathForRequestResult: @@ -13530,6 +14514,58 @@ def to_dict(self) -> dict: result["reason"] = from_union([from_str, from_none], self.reason) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _SandboxPreparePickerPolicyParams: + """The working directory and sandbox settings to build a file-picker policy from.""" + + cwd: str + """The session's working directory. Git discovery and grant canonicalization are resolved + against it. + """ + sandbox: Any = None + """The session's resolved `sandbox` slice. Omitted, or disabled, yields no policy and every + candidate is kept. + """ + + @staticmethod + def from_dict(obj: Any) -> '_SandboxPreparePickerPolicyParams': + assert isinstance(obj, dict) + cwd = from_str(obj.get("cwd")) + sandbox = obj.get("sandbox") + return _SandboxPreparePickerPolicyParams(cwd, sandbox) + + def to_dict(self) -> dict: + result: dict = {} + result["cwd"] = from_str(self.cwd) + if self.sandbox is not None: + result["sandbox"] = self.sandbox + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _SandboxPreparePickerPolicyResult: + """The prepared file-picker policy, or none when the sandbox is disabled.""" + + sandbox_json: Any = None + """The prepared policy to pass back to `sandbox.filterPickerCandidates`. Absent when the + sandbox is disabled or absent, in which case filtering keeps every candidate. + """ + + @staticmethod + def from_dict(obj: Any) -> '_SandboxPreparePickerPolicyResult': + assert isinstance(obj, dict) + sandbox_json = obj.get("sandboxJson") + return _SandboxPreparePickerPolicyResult(sandbox_json) + + def to_dict(self) -> dict: + result: dict = {} + if self.sandbox_json is not None: + result["sandboxJson"] = self.sandbox_json + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class SandboxProxyCACreateResult: @@ -13560,6 +14596,148 @@ class SandboxProxyCAState(Enum): NOT_INSTALLED = "notInstalled" UNSUPPORTED = "unsupported" +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SandboxProxySecretGetResult: + """The stored sandbox proxy password, if one is present.""" + + value: str | None = None + """The stored password. Absent when no entry exists in either the keychain or the on-disk + fallback store. + """ + + @staticmethod + def from_dict(obj: Any) -> 'SandboxProxySecretGetResult': + assert isinstance(obj, dict) + value = from_union([from_str, from_none], obj.get("value")) + return SandboxProxySecretGetResult(value) + + def to_dict(self) -> dict: + result: dict = {} + if self.value is not None: + result["value"] = from_union([from_str, from_none], self.value) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SandboxProxySecretLocation: + """Where this runtime keeps the sandbox proxy password.""" + + config_dir: str + """Absolute path of the credential store holding the sandbox proxy password. The proxy + password belongs to no MCP server, so it is kept in its own directory rather than in the + MCP secret store. + """ + secret_id: str + """Identifier of the proxy password entry within that store. Derived from the configuration + directory, so two Copilot homes on one machine never share an entry. Use it to recognize + a `${secret:…}` reference in stored settings as this runtime's own proxy password. + """ + + @staticmethod + def from_dict(obj: Any) -> 'SandboxProxySecretLocation': + assert isinstance(obj, dict) + config_dir = from_str(obj.get("configDir")) + secret_id = from_str(obj.get("secretId")) + return SandboxProxySecretLocation(config_dir, secret_id) + + def to_dict(self) -> dict: + result: dict = {} + result["configDir"] = from_str(self.config_dir) + result["secretId"] = from_str(self.secret_id) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SandboxProxySecretSaveRequest: + """The sandbox proxy password to store.""" + + value: str + """The password to store for the sandbox proxy.""" + + @staticmethod + def from_dict(obj: Any) -> 'SandboxProxySecretSaveRequest': + assert isinstance(obj, dict) + value = from_str(obj.get("value")) + return SandboxProxySecretSaveRequest(value) + + def to_dict(self) -> dict: + result: dict = {} + result["value"] = from_str(self.value) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SandboxProxySecretSaveResult: + """Where the sandbox proxy password was stored.""" + + stored_in_keychain: bool + """Whether the OS keychain accepted the value. False means it was written to the on-disk + fallback store instead, which is still readable by `sandbox.proxySecret.get`. + """ + + @staticmethod + def from_dict(obj: Any) -> 'SandboxProxySecretSaveResult': + assert isinstance(obj, dict) + stored_in_keychain = from_bool(obj.get("storedInKeychain")) + return SandboxProxySecretSaveResult(stored_in_keychain) + + def to_dict(self) -> dict: + result: dict = {} + result["storedInKeychain"] = from_bool(self.stored_in_keychain) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _SandboxResolveFlooredConfigParams: + """The user's sandbox settings and the managed sandbox floor to raise them to.""" + + managed_sandbox: Any = None + """The effective managed `sandbox` slice acting as a floor. Omitted when no administrator + policy applies, in which case the user's own settings stand unchanged. + """ + user_sandbox: Any = None + """The user's own `sandbox` settings slice. Omitted when the user has configured none, which + still yields the managed floor rather than a disabled sandbox. + """ + + @staticmethod + def from_dict(obj: Any) -> '_SandboxResolveFlooredConfigParams': + assert isinstance(obj, dict) + managed_sandbox = obj.get("managedSandbox") + user_sandbox = obj.get("userSandbox") + return _SandboxResolveFlooredConfigParams(managed_sandbox, user_sandbox) + + def to_dict(self) -> dict: + result: dict = {} + if self.managed_sandbox is not None: + result["managedSandbox"] = self.managed_sandbox + if self.user_sandbox is not None: + result["userSandbox"] = self.user_sandbox + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class SandboxResolveFlooredConfigResult: + """The user's sandbox settings raised to the managed floor.""" + + sandbox_json: Any + """The floored sandbox config, normalized through the declared sandbox shape so only + declared fields in a fixed order are present. + """ + + @staticmethod + def from_dict(obj: Any) -> 'SandboxResolveFlooredConfigResult': + assert isinstance(obj, dict) + sandbox_json = obj.get("sandboxJson") + return SandboxResolveFlooredConfigResult(sandbox_json) + + def to_dict(self) -> dict: + result: dict = {} + result["sandboxJson"] = self.sandbox_json + return result + # Experimental: this type is part of an experimental API and may change or be removed. class SandboxSessionChange(Enum): """A session-scoped sandbox transition applied while handling a slash command @@ -13571,6 +14749,63 @@ class SandboxSessionChange(Enum): DISABLED = "disabled" RESTORED = "restored" +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _SandboxUnsupportedStartupNoticeParams: + """The managed sandbox policy in force, which selects which remedy the notice offers.""" + + enabled_by_undetermined_policy: bool | None = None + """True when the sandbox stayed on only because the managed policy could not be determined. + Distinguishes a policy that positively enforces the sandbox from one that merely failed + to resolve, which is the difference between telling the user to contact an administrator + and telling them to wait. Defaults to false. + """ + managed_sandbox: Any = None + """The managed `sandbox` slice, when a policy supplies one. The notice treats the sandbox as + enforced only when this both enables it and sets `failIfUnavailable`, because a managed + sandbox that tolerates being unavailable still leaves the user able to turn it off. + """ + + @staticmethod + def from_dict(obj: Any) -> '_SandboxUnsupportedStartupNoticeParams': + assert isinstance(obj, dict) + enabled_by_undetermined_policy = from_union([from_bool, from_none], obj.get("enabledByUndeterminedPolicy")) + managed_sandbox = obj.get("managedSandbox") + return _SandboxUnsupportedStartupNoticeParams(enabled_by_undetermined_policy, managed_sandbox) + + def to_dict(self) -> dict: + result: dict = {} + if self.enabled_by_undetermined_policy is not None: + result["enabledByUndeterminedPolicy"] = from_union([from_bool, from_none], self.enabled_by_undetermined_policy) + if self.managed_sandbox is not None: + result["managedSandbox"] = self.managed_sandbox + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _SandboxUnsupportedStartupNoticeResult: + """The startup warning, absent when the machine can run a sandbox.""" + + notice: str | None = None + """The user-facing warning, carrying the platform remedy and the recovery the policy in + force actually allows. Absent when this machine supports a sandbox, so a host can call + unconditionally and print only what it gets. + """ + + @staticmethod + def from_dict(obj: Any) -> '_SandboxUnsupportedStartupNoticeResult': + assert isinstance(obj, dict) + notice = from_union([from_str, from_none], obj.get("notice")) + return _SandboxUnsupportedStartupNoticeResult(notice) + + def to_dict(self) -> dict: + result: dict = {} + if self.notice is not None: + result["notice"] = from_union([from_str, from_none], self.notice) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class ScheduleAddAtRequest: @@ -16915,19 +18150,6 @@ def to_dict(self) -> dict: class SettableTokenAuthInfoType(Enum): TOKEN = "token" -# Experimental: this type is part of an experimental API and may change or be removed. -# Internal: this type is an internal SDK API and is not part of the public surface. -class _SettingsEditOperation(Enum): - """One atomic settings mutation. - - Set a scalar, add or remove a string list item, or remove the setting. The handler - rejects a missing or incompatible value. - """ - ADD_ITEM = "add-item" - REMOVE = "remove" - REMOVE_ITEM = "remove-item" - SET = "set" - # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class ShellCancelUserRequestedRequest: @@ -17530,6 +18752,28 @@ class SlashCommandSetPlanModelResultKind(Enum): class SlashCommandShowDialogResultKind(Enum): SHOW_DIALOG = "show-dialog" +# Experimental: this type is part of an experimental API and may change or be removed. +class StaffLogLevelMigrationStatus(Enum): + """What the one-time staff log-level migration did. + + What the migration did. Only `refreshed` can have changed the persisted settings. + """ + CURRENT = "current" + INELIGIBLE = "ineligible" + REFRESHED = "refreshed" + +# Experimental: this type is part of an experimental API and may change or be removed. +class StaffUpdateChannelMigrationStatus(Enum): + """What the one-time staff update-channel migration did. + + What the migration did. Only `migrated` means the persisted settings changed. + """ + COMPLETED = "completed" + CURRENT = "current" + EXCLUDED_EXPERIMENTAL = "excluded-experimental" + INELIGIBLE = "ineligible" + MIGRATED = "migrated" + # Experimental: this type is part of an experimental API and may change or be removed. class SubagentSettingsEntryContextTier(Enum): """Context tier override for matching subagents""" @@ -18777,6 +20021,51 @@ def to_dict(self) -> dict: result["path"] = from_list(lambda x: x, self.path) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _UserSettingsBuildRuntimeRequest: + """The overrides and host context to resolve effective runtime settings from.""" + + environment: dict[str, str] + """The environment to read settings-bearing variables from. Passed explicitly rather than + read from the server process so a host can resolve settings for an environment it is + about to create rather than the one it runs in. + """ + platform: str + """The platform to apply platform-specific defaults for, in the same spelling the host's own + runtime reports. + """ + working_directory: str + """The directory the settings are being resolved for. This selects the repository-scoped + document, so a host resolving settings for a directory other than its own process working + directory must pass that directory here. + """ + overrides: dict[str, Any] | None = None + """Settings that take precedence over every document and environment layer, such as the + values a host derived from its own command line. Keyed by setting name, with each value + carried verbatim, so a host may pass keys this runtime does not recognize. Absent when + the host contributes no overrides of its own. + """ + + @staticmethod + def from_dict(obj: Any) -> '_UserSettingsBuildRuntimeRequest': + assert isinstance(obj, dict) + environment = from_dict(from_str, obj.get("environment")) + platform = from_str(obj.get("platform")) + working_directory = from_str(obj.get("workingDirectory")) + overrides = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("overrides")) + return _UserSettingsBuildRuntimeRequest(environment, platform, working_directory, overrides) + + def to_dict(self) -> dict: + result: dict = {} + result["environment"] = from_dict(from_str, self.environment) + result["platform"] = from_str(self.platform) + result["workingDirectory"] = from_str(self.working_directory) + if self.overrides is not None: + result["overrides"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.overrides) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class UserSettingsGetPathsRequest: @@ -18864,6 +20153,142 @@ def to_dict(self) -> dict: result["repo"] = from_list(from_str, self.repo) return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsHostContext: + """The filesystem and environment facts a user-settings file is resolved from. Passed + explicitly rather than read from the runtime's own process, so a host whose configuration + directory differs from its process environment resolves the file it means. + + The configuration directory, home directory and environment to resolve the settings and + global-state documents from. A host that scopes a session to its own Copilot home must + pass that directory here, or the migration is evaluated against the server's own home + instead. + + The configuration directory, home directory and environment to resolve the settings and + global-state documents from. A host that scopes a session to its own Copilot home must + pass that directory here, or the reset is evaluated against the server's own home + instead. + + The configuration directory, home directory and environment to resolve the settings + document from. A host that scopes a session to its own Copilot home must pass that + directory here, or the server's own home is inspected instead. + """ + environment: dict[str, Any] + """The host's environment variables. `COPILOT_HOME` is read from here, as are the variables + a settings hook may expand. + """ + home_directory: str + """The user's home directory, used when neither a configuration directory nor `COPILOT_HOME` + is set. + """ + config_dir: str | None = None + """The Copilot configuration directory, when the host set one. Takes precedence over + `COPILOT_HOME` and the home directory. + """ + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsHostContext': + assert isinstance(obj, dict) + environment = from_dict(lambda x: x, obj.get("environment")) + home_directory = from_str(obj.get("homeDirectory")) + config_dir = from_union([from_str, from_none], obj.get("configDir")) + return UserSettingsHostContext(environment, home_directory, config_dir) + + def to_dict(self) -> dict: + result: dict = {} + result["environment"] = from_dict(lambda x: x, self.environment) + result["homeDirectory"] = from_str(self.home_directory) + if self.config_dir is not None: + result["configDir"] = from_union([from_str, from_none], self.config_dir) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _UserSettingsLoadAndMergeRepoRequest: + """A repository to read settings from, and the user layer they are merged over.""" + + repo_root: str + """Absolute path of the repository root whose settings to read. When this is the user's home + directory, the Claude-compatible configuration is skipped, so a home-directory session + does not inherit a personal config as if it were repository policy. + """ + user_settings: dict[str, Any] + """The user's own settings, keyed by setting name. The repository layer is merged over this; + a repository may only add to the collection settings it is allowed to influence, so a + user setting it does not name survives unchanged. + """ + + @staticmethod + def from_dict(obj: Any) -> '_UserSettingsLoadAndMergeRepoRequest': + assert isinstance(obj, dict) + repo_root = from_str(obj.get("repoRoot")) + user_settings = from_dict(lambda x: x, obj.get("userSettings")) + return _UserSettingsLoadAndMergeRepoRequest(repo_root, user_settings) + + def to_dict(self) -> dict: + result: dict = {} + result["repoRoot"] = from_str(self.repo_root) + result["userSettings"] = from_dict(lambda x: x, self.user_settings) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _UserSettingsLoadAndMergeRepoResult: + """The settings a consumer should act on inside a repository, together with any diagnostic + raised while reading the repository layer. + """ + settings: dict[str, Any] + """The merged settings document, keyed by setting name. Equals the supplied user layer when + the repository declares no settings. + """ + warning: str | None = None + """Why part of the repository document was ignored, as a single human-readable string + joining every diagnostic with `; `. Null when it loaded cleanly. The settings that did + load are still merged, so a consumer should surface this and continue rather than treat + it as a failure. + """ + + @staticmethod + def from_dict(obj: Any) -> '_UserSettingsLoadAndMergeRepoResult': + assert isinstance(obj, dict) + settings = from_dict(lambda x: x, obj.get("settings")) + warning = from_union([from_none, from_str], obj.get("warning")) + return _UserSettingsLoadAndMergeRepoResult(settings, warning) + + def to_dict(self) -> dict: + result: dict = {} + result["settings"] = from_dict(lambda x: x, self.settings) + if self.warning is not None: + result["warning"] = from_union([from_none, from_str], self.warning) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _UserSettingsLoadForConfigDirRequest: + """Selects the configuration directory whose user settings to read.""" + + config_dir: str | None = None + """Copilot configuration directory to read the settings document from, taking precedence + over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, + to read the directory the server resolved for itself. + """ + + @staticmethod + def from_dict(obj: Any) -> '_UserSettingsLoadForConfigDirRequest': + assert isinstance(obj, dict) + config_dir = from_union([from_str, from_none], obj.get("configDir")) + return _UserSettingsLoadForConfigDirRequest(config_dir) + + def to_dict(self) -> dict: + result: dict = {} + if self.config_dir is not None: + result["configDir"] = from_union([from_str, from_none], self.config_dir) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class UserSettingsLoadForEditResult: @@ -18890,6 +20315,230 @@ def to_dict(self) -> dict: result["settings"] = self.settings return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsLoadRepoRequest: + """Selects the repository whose checked-in settings to read.""" + + repo_root: str + """Absolute path of the repository root whose settings to read. When this is the user's home + directory, the Claude-compatible configuration is skipped, so a home-directory session + does not inherit a personal config as if it were repository policy. + """ + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsLoadRepoRequest': + assert isinstance(obj, dict) + repo_root = from_str(obj.get("repoRoot")) + return UserSettingsLoadRepoRequest(repo_root) + + def to_dict(self) -> dict: + result: dict = {} + result["repoRoot"] = from_str(self.repo_root) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsLoadRepoResult: + """A repository's settings as stored, together with any diagnostic raised while reading them.""" + + settings: dict[str, Any] | None = None + """The repository's settings document, keyed by setting name, with each value carried + verbatim. Null when the repository declares no settings. + """ + warning: str | None = None + """Why part of the document was ignored, as a single human-readable string joining every + diagnostic with `; `. Null when the document loaded cleanly. The settings that did load + are still reported, so a consumer should surface this and continue rather than treat it + as a failure. + """ + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsLoadRepoResult': + assert isinstance(obj, dict) + settings = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("settings")) + warning = from_union([from_none, from_str], obj.get("warning")) + return UserSettingsLoadRepoResult(settings, warning) + + def to_dict(self) -> dict: + result: dict = {} + if self.settings is not None: + result["settings"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.settings) + if self.warning is not None: + result["warning"] = from_union([from_none, from_str], self.warning) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsLoadWithWarningResult: + """The user's stored settings, together with any diagnostic raised while reading them.""" + + settings: dict[str, Any] + """The stored user settings document, keyed by setting name, with each value carried + verbatim. Empty when the file could not be read at all. + """ + warning: str | None = None + """Why part of the document was ignored, phrased for display to the user. Null when the + document loaded cleanly. The settings that did load are still reported, so a consumer may + surface this and continue rather than treat it as a failure. + """ + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsLoadWithWarningResult': + assert isinstance(obj, dict) + settings = from_dict(lambda x: x, obj.get("settings")) + warning = from_union([from_none, from_str], obj.get("warning")) + return UserSettingsLoadWithWarningResult(settings, warning) + + def to_dict(self) -> dict: + result: dict = {} + result["settings"] = from_dict(lambda x: x, self.settings) + if self.warning is not None: + result["warning"] = from_union([from_none, from_str], self.warning) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _UserSettingsMergeManagedAndUserParams: + """The managed (enterprise policy) layer and the user layer to fold together. The field + names carry the layer identity: nothing about a settings object identifies which layer + produced it, so a generic base/override pair would let a caller transpose them and + silently resolve the governance keys in the user's favour. + """ + managed: Any = None + """The managed layer. Its governance keys win, and the per-entry `enabledPlugins` and + `extraKnownMarketplaces` control maps are stamped back from it after the union. Omitted + when the host is unmanaged. + """ + user: Any = None + """The user's own settings layer. Wins on every key the managed layer does not govern. + Omitted when the user has no settings yet. + """ + + @staticmethod + def from_dict(obj: Any) -> '_UserSettingsMergeManagedAndUserParams': + assert isinstance(obj, dict) + managed = obj.get("managed") + user = obj.get("user") + return _UserSettingsMergeManagedAndUserParams(managed, user) + + def to_dict(self) -> dict: + result: dict = {} + if self.managed is not None: + result["managed"] = self.managed + if self.user is not None: + result["user"] = self.user + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsMergeManagedAndUserResult: + """The user layer folded over the managed layer.""" + + settings_json: Any + """The merged settings. An empty object when neither layer was supplied, so an unmanaged + host with no user settings governs nothing. + """ + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsMergeManagedAndUserResult': + assert isinstance(obj, dict) + settings_json = obj.get("settingsJson") + return UserSettingsMergeManagedAndUserResult(settings_json) + + def to_dict(self) -> dict: + result: dict = {} + result["settingsJson"] = self.settings_json + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _UserSettingsMergeRepoValueParams: + """The user layer and the repository layer to fold together.""" + + repo_settings: Any + """The repository's checked-in settings layer.""" + + user_settings: Any + """The user's settings, already resolved against any managed layer.""" + + @staticmethod + def from_dict(obj: Any) -> '_UserSettingsMergeRepoValueParams': + assert isinstance(obj, dict) + repo_settings = obj.get("repoSettings") + user_settings = obj.get("userSettings") + return _UserSettingsMergeRepoValueParams(repo_settings, user_settings) + + def to_dict(self) -> dict: + result: dict = {} + result["repoSettings"] = self.repo_settings + result["userSettings"] = self.user_settings + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsMergeRepoValueResult: + """The repository layer folded into the user layer.""" + + settings_json: Any + """The merged settings, with the per-entry managed control maps re-stamped from the + runtime's ambient managed policy. + """ + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsMergeRepoValueResult': + assert isinstance(obj, dict) + settings_json = obj.get("settingsJson") + return UserSettingsMergeRepoValueResult(settings_json) + + def to_dict(self) -> dict: + result: dict = {} + result["settingsJson"] = self.settings_json + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _UserSettingsMigrateObsoleteOnDiskRequest: + """Selects the configuration directory whose settings document to clean.""" + + config_dir: str | None = None + """The configuration directory holding the settings document to clean. A host that scopes a + session to its own Copilot home passes that directory here; omit it to clean the document + under the home the server resolved for itself. The home directory and environment are + deliberately not caller-supplied: they decide only the settings path root and the two + hook-parsing flags, and those describe the process doing the reading rather than the + caller. + """ + + @staticmethod + def from_dict(obj: Any) -> '_UserSettingsMigrateObsoleteOnDiskRequest': + assert isinstance(obj, dict) + config_dir = from_union([from_str, from_none], obj.get("configDir")) + return _UserSettingsMigrateObsoleteOnDiskRequest(config_dir) + + def to_dict(self) -> dict: + result: dict = {} + if self.config_dir is not None: + result["configDir"] = from_union([from_str, from_none], self.config_dir) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +class _UserSettingsMigrateObsoleteOnDiskStatus(Enum): + """What the cleanup did. Only `changed` rewrote the document. The cleaned settings are not + returned here: the document is written before this replies, so `user.settings.load` reads + it authoritatively. + + What the one-time obsolete-settings cleanup did to the document. + """ + CHANGED = "changed" + INVALID = "invalid" + MISSING = "missing" + UNCHANGED = "unchanged" + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class UserSettingsNormalizeRequest: @@ -18928,6 +20577,28 @@ def to_dict(self) -> dict: result["settings"] = self.settings return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class UserSettingsPathResult: + """The on-disk location of the user's settings document.""" + + path: str + """Absolute path to the settings file this runtime reads and writes. Normally + `settings.json` under the Copilot configuration directory; an extensionless legacy + `settings` file is reported instead when it exists and `settings.json` does not. + """ + + @staticmethod + def from_dict(obj: Any) -> 'UserSettingsPathResult': + assert isinstance(obj, dict) + path = from_str(obj.get("path")) + return UserSettingsPathResult(path) + + def to_dict(self) -> dict: + result: dict = {} + result["path"] = from_str(self.path) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class UserSettingsProblemLocation: @@ -19002,6 +20673,105 @@ def to_dict(self) -> dict: result["invalid"] = from_union([from_bool, from_none], self.invalid) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _UserSettingsResetStaffModelSelectionOnceResult: + """The outcome of the one-time staff model-selection reset.""" + + cutoff: str + """The cutoff this reset is gated on, as an ISO-8601 timestamp. A recorded timestamp at or + after it means the reset is already done. + """ + did_reset: bool + """Whether the persisted model selection was cleared. Only `true` means the settings + document changed and the host should adopt the returned settings. + """ + reset_at: str | None = None + """The timestamp the host should now record, as an ISO-8601 timestamp. Carries the caller's + own value back unchanged when nothing was reset. + """ + settings: dict[str, Any] | None = None + """The settings document as it stands after the reset, keyed by setting name. Present only + when `didReset` is true. + """ + + @staticmethod + def from_dict(obj: Any) -> '_UserSettingsResetStaffModelSelectionOnceResult': + assert isinstance(obj, dict) + cutoff = from_str(obj.get("cutoff")) + did_reset = from_bool(obj.get("didReset")) + reset_at = from_union([from_str, from_none], obj.get("resetAt")) + settings = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("settings")) + return _UserSettingsResetStaffModelSelectionOnceResult(cutoff, did_reset, reset_at, settings) + + def to_dict(self) -> dict: + result: dict = {} + result["cutoff"] = from_str(self.cutoff) + result["didReset"] = from_bool(self.did_reset) + if self.reset_at is not None: + result["resetAt"] = from_union([from_str, from_none], self.reset_at) + if self.settings is not None: + result["settings"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.settings) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _UserSettingsSetHookDisabledRequest: + """One hook to disable or re-enable.""" + + disabled: bool + """True adds the key to `disabledHooks`, false removes it.""" + + disable_key: str + """Durable content-hash key of the hook, as `hooks.loadResources` reports it.""" + + settings_path: str + """Path of the settings.json to rewrite.""" + + @staticmethod + def from_dict(obj: Any) -> '_UserSettingsSetHookDisabledRequest': + assert isinstance(obj, dict) + disabled = from_bool(obj.get("disabled")) + disable_key = from_str(obj.get("disableKey")) + settings_path = from_str(obj.get("settingsPath")) + return _UserSettingsSetHookDisabledRequest(disabled, disable_key, settings_path) + + def to_dict(self) -> dict: + result: dict = {} + result["disabled"] = from_bool(self.disabled) + result["disableKey"] = from_str(self.disable_key) + result["settingsPath"] = from_str(self.settings_path) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _UserSettingsSetHookDisabledResult: + """Outcome of rewriting the `disabledHooks` setting.""" + + status: str + """`ok` when the setting was written, `invalid` when settings.json could not be parsed and + was left alone, `error` when the write itself failed. + """ + error_message: str | None = None + """Why the write failed. Absent when the status is `ok`.""" + + @staticmethod + def from_dict(obj: Any) -> '_UserSettingsSetHookDisabledResult': + assert isinstance(obj, dict) + status = from_str(obj.get("status")) + error_message = from_union([from_str, from_none], obj.get("errorMessage")) + return _UserSettingsSetHookDisabledResult(status, error_message) + + def to_dict(self) -> dict: + result: dict = {} + result["status"] = from_str(self.status) + if self.error_message is not None: + result["errorMessage"] = from_union([from_str, from_none], self.error_message) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class UserSettingsSetRequest: @@ -19022,6 +20792,32 @@ def to_dict(self) -> dict: result["settings"] = self.settings return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _UserSettingsUnknownKeysWarningResult: + """The unrecognized top-level keys found in the user settings document, already phrased for + display. + """ + warning: str | None = None + """The warning to show the user, naming the unrecognized keys and the file they were found + in. Absent when every top-level key is recognized, and also when the document is missing + or could not be read, because an unknown-key list taken from a document the runtime could + not load would name keys that may not be there. + """ + + @staticmethod + def from_dict(obj: Any) -> '_UserSettingsUnknownKeysWarningResult': + assert isinstance(obj, dict) + warning = from_union([from_str, from_none], obj.get("warning")) + return _UserSettingsUnknownKeysWarningResult(warning) + + def to_dict(self) -> dict: + result: dict = {} + if self.warning is not None: + result["warning"] = from_union([from_str, from_none], self.warning) + return result + # Experimental: this type is part of an experimental API and may change or be removed. # Internal: this type is an internal SDK API and is not part of the public surface. @dataclass @@ -26200,6 +27996,91 @@ def to_dict(self) -> dict: result["url"] = from_union([from_str, from_none], self.url) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _ManagedSettingsResolveBypassDisableTransitionResult: + """The bypass-permissions state a host should hold after the resolution, and what it must do + to get there. + """ + suppress_runtime_allow_all: bool + """Whether a bypass-permissions session already running must be turned off. True only when + this resolution newly disables bypass mode, so a host that is already compliant is not + interrupted. + """ + managed_identity: str | None = None + """The account the returned `managed` source is pinned to. Store it alongside `source`; the + next call needs it to decide whether an account switch lifts the disable. + """ + set_disabled_state: bool | None = None + """The value to store in the host's own bypass-disabled flag. Omitted means leave it exactly + as it is, which is not the same as being told to store `false`. + """ + source: _ManagedSettingsBypassDisableSource | None = None + """Which layer disables bypass mode after this resolution. Omitted when none does, which is + what a lifted disable looks like. + """ + + @staticmethod + def from_dict(obj: Any) -> '_ManagedSettingsResolveBypassDisableTransitionResult': + assert isinstance(obj, dict) + suppress_runtime_allow_all = from_bool(obj.get("suppressRuntimeAllowAll")) + managed_identity = from_union([from_str, from_none], obj.get("managedIdentity")) + set_disabled_state = from_union([from_bool, from_none], obj.get("setDisabledState")) + source = from_union([_ManagedSettingsBypassDisableSource, from_none], obj.get("source")) + return _ManagedSettingsResolveBypassDisableTransitionResult(suppress_runtime_allow_all, managed_identity, set_disabled_state, source) + + def to_dict(self) -> dict: + result: dict = {} + result["suppressRuntimeAllowAll"] = from_bool(self.suppress_runtime_allow_all) + if self.managed_identity is not None: + result["managedIdentity"] = from_union([from_str, from_none], self.managed_identity) + if self.set_disabled_state is not None: + result["setDisabledState"] = from_union([from_bool, from_none], self.set_disabled_state) + if self.source is not None: + result["source"] = from_union([lambda x: to_enum(_ManagedSettingsBypassDisableSource, x), from_none], self.source) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _ManagedSettingsResolveBypassDisableTransitionParams: + """The bypass-permissions state a host holds today, the account now signed in, and what the + managed-policy resolution said. + """ + active_identity: str + """The account signed in now. A `managed` disable pinned to a different account is lifted.""" + + policy: _ManagedSettingsBypassPolicyResolution + """What the resolution said about bypass mode. Send `unknown` rather than omitting the field + when there is no verdict. + """ + current_managed_identity: str | None = None + """The account a `managed` disable is pinned to. Omit it when the current source is not + `managed`; it is ignored for the other sources. + """ + current_source: _ManagedSettingsBypassDisableSource | None = None + """Which layer currently disables bypass mode. Omit it when nothing does.""" + + @staticmethod + def from_dict(obj: Any) -> '_ManagedSettingsResolveBypassDisableTransitionParams': + assert isinstance(obj, dict) + active_identity = from_str(obj.get("activeIdentity")) + policy = _ManagedSettingsBypassPolicyResolution(obj.get("policy")) + current_managed_identity = from_union([from_str, from_none], obj.get("currentManagedIdentity")) + current_source = from_union([_ManagedSettingsBypassDisableSource, from_none], obj.get("currentSource")) + return _ManagedSettingsResolveBypassDisableTransitionParams(active_identity, policy, current_managed_identity, current_source) + + def to_dict(self) -> dict: + result: dict = {} + result["activeIdentity"] = from_str(self.active_identity) + result["policy"] = to_enum(_ManagedSettingsBypassPolicyResolution, self.policy) + if self.current_managed_identity is not None: + result["currentManagedIdentity"] = from_union([from_str, from_none], self.current_managed_identity) + if self.current_source is not None: + result["currentSource"] = from_union([lambda x: to_enum(_ManagedSettingsBypassDisableSource, x), from_none], self.current_source) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class ManagedSettingsComposeLayer: @@ -26301,6 +28182,500 @@ def to_dict(self) -> dict: result["model"] = from_union([lambda x: to_class(ManagedSettingMeta, x), from_none], self.model) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _ManagedSettingsLoadRemoteControlParams: + """Inputs describing the host and account whose managed remote-control policy should be + resolved. Mirrors `managedSettings.ingest`, and deliberately carries no retention + decision: reading this gate never becomes this runtime process's startup policy. + """ + environment: Any + """The host's environment variables, read for cache location and policy overrides.""" + + home_directory: str + """The host's home directory, used to resolve cache and managed-file locations.""" + + platform: str + """The host's platform, in Node's `process.platform` spelling, used to locate + platform-specific cache and policy paths. + """ + user_agent: str + """User agent to send with the policy fetch.""" + + auth_info: Any = None + """The authenticated identity to resolve policy for. Omitted before sign-in, in which case + no server layer is fetched. + """ + client_name: str | None = None + """Name of the embedding client, reported to the managed-settings service as `client_id` so + it can refuse to deliver a policy this client is too old to enforce. That refusal is + exactly what turns into an explicit `disabled` below, so a host that omits this field + forfeits the protection. + """ + device_response: Any = None + """A device layer supplied by the host instead of discovered from the machine. Pair it with + `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + """ + has_device_response: bool | None = None + """Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts + the device layer is empty; false discovers it from the machine. + """ + policy_helper_enabled: bool | None = None + """Whether a configured platform policy helper may be run to produce an enforced helper + layer. + """ + policy_helper_reason: _ManagedSettingsPolicyHelperReason | None = None + """The policy-helper invocation reason. Defaults to sessionStart.""" + + self_fetch: bool | None = None + """Whether to run ingestion. Omit or set false to return an empty result without discovering + or fetching policy. + """ + + @staticmethod + def from_dict(obj: Any) -> '_ManagedSettingsLoadRemoteControlParams': + assert isinstance(obj, dict) + environment = obj.get("environment") + home_directory = from_str(obj.get("homeDirectory")) + platform = from_str(obj.get("platform")) + user_agent = from_str(obj.get("userAgent")) + auth_info = obj.get("authInfo") + client_name = from_union([from_str, from_none], obj.get("clientName")) + device_response = obj.get("deviceResponse") + has_device_response = from_union([from_bool, from_none], obj.get("hasDeviceResponse")) + policy_helper_enabled = from_union([from_bool, from_none], obj.get("policyHelperEnabled")) + policy_helper_reason = from_union([_ManagedSettingsPolicyHelperReason, from_none], obj.get("policyHelperReason")) + self_fetch = from_union([from_bool, from_none], obj.get("selfFetch")) + return _ManagedSettingsLoadRemoteControlParams(environment, home_directory, platform, user_agent, auth_info, client_name, device_response, has_device_response, policy_helper_enabled, policy_helper_reason, self_fetch) + + def to_dict(self) -> dict: + result: dict = {} + result["environment"] = self.environment + result["homeDirectory"] = from_str(self.home_directory) + result["platform"] = from_str(self.platform) + result["userAgent"] = from_str(self.user_agent) + if self.auth_info is not None: + result["authInfo"] = self.auth_info + if self.client_name is not None: + result["clientName"] = from_union([from_str, from_none], self.client_name) + if self.device_response is not None: + result["deviceResponse"] = self.device_response + if self.has_device_response is not None: + result["hasDeviceResponse"] = from_union([from_bool, from_none], self.has_device_response) + if self.policy_helper_enabled is not None: + result["policyHelperEnabled"] = from_union([from_bool, from_none], self.policy_helper_enabled) + if self.policy_helper_reason is not None: + result["policyHelperReason"] = from_union([lambda x: to_enum(_ManagedSettingsPolicyHelperReason, x), from_none], self.policy_helper_reason) + if self.self_fetch is not None: + result["selfFetch"] = from_union([from_bool, from_none], self.self_fetch) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _ManagedSettingsIngestParams: + """Inputs describing the host and account an ingestion should resolve managed policy for.""" + + environment: Any + """The host's environment variables, read for cache location and policy overrides. Supplied + by the host rather than read from the runtime process so a command that selected its own + configuration home is honored. + """ + home_directory: str + """The host's home directory, used to resolve cache and managed-file locations.""" + + platform: str + """The host's platform, in Node's `process.platform` spelling, used to locate + platform-specific cache and policy paths. + """ + user_agent: str + """User agent to send with the policy fetch.""" + + auth_info: Any = None + """The authenticated identity to resolve policy for. Omitted before sign-in, in which case + no server layer is fetched. + """ + bypass_cache_read: bool | None = None + """Whether to ignore a cached server policy when reading, forcing the resolution to come + from a live fetch. + """ + client_name: str | None = None + """Name of the embedding client, reported to the managed-settings service as `client_id` so + it can refuse to deliver a policy this client is too old to enforce. Omit it and the + runtime reports a generic identity; the runtime version sent alongside is the gate that + actually matters. + """ + device_response: Any = None + """A device layer supplied by the host instead of discovered from the machine. Pair it with + `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + """ + has_device_response: bool | None = None + """Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts + the device layer is empty; false discovers it from the machine. + """ + policy_helper_enabled: bool | None = None + """Whether a configured platform policy helper may be run to produce an enforced helper + layer. + """ + policy_helper_reason: _ManagedSettingsPolicyHelperReason | None = None + """The policy-helper invocation reason. Defaults to sessionStart.""" + + policy_helper_working_directory: str | None = None + """Directory the policy helper runs in when this ingestion is not owned by a registered + session. A host resolving policy before its session exists must pass this, or a + directory-sensitive helper judges the wrong repository. + """ + self_fetch: bool | None = None + """Whether to run ingestion. Omit or set false to return an empty result without discovering + or fetching policy. + """ + server_policy_cache_mode: _ManagedSettingsServerPolicyCacheMode | None = None + """How this ingestion may use the on-disk server-policy cache. Defaults to the runtime's own + policy when omitted. + """ + session_id: str | None = None + """The session whose credential store and working directory the policy helper should use. + Omit it when no session exists yet and the process-wide store applies. + """ + + @staticmethod + def from_dict(obj: Any) -> '_ManagedSettingsIngestParams': + assert isinstance(obj, dict) + environment = obj.get("environment") + home_directory = from_str(obj.get("homeDirectory")) + platform = from_str(obj.get("platform")) + user_agent = from_str(obj.get("userAgent")) + auth_info = obj.get("authInfo") + bypass_cache_read = from_union([from_bool, from_none], obj.get("bypassCacheRead")) + client_name = from_union([from_str, from_none], obj.get("clientName")) + device_response = obj.get("deviceResponse") + has_device_response = from_union([from_bool, from_none], obj.get("hasDeviceResponse")) + policy_helper_enabled = from_union([from_bool, from_none], obj.get("policyHelperEnabled")) + policy_helper_reason = from_union([_ManagedSettingsPolicyHelperReason, from_none], obj.get("policyHelperReason")) + policy_helper_working_directory = from_union([from_str, from_none], obj.get("policyHelperWorkingDirectory")) + self_fetch = from_union([from_bool, from_none], obj.get("selfFetch")) + server_policy_cache_mode = from_union([_ManagedSettingsServerPolicyCacheMode, from_none], obj.get("serverPolicyCacheMode")) + session_id = from_union([from_str, from_none], obj.get("sessionId")) + return _ManagedSettingsIngestParams(environment, home_directory, platform, user_agent, auth_info, bypass_cache_read, client_name, device_response, has_device_response, policy_helper_enabled, policy_helper_reason, policy_helper_working_directory, self_fetch, server_policy_cache_mode, session_id) + + def to_dict(self) -> dict: + result: dict = {} + result["environment"] = self.environment + result["homeDirectory"] = from_str(self.home_directory) + result["platform"] = from_str(self.platform) + result["userAgent"] = from_str(self.user_agent) + if self.auth_info is not None: + result["authInfo"] = self.auth_info + if self.bypass_cache_read is not None: + result["bypassCacheRead"] = from_union([from_bool, from_none], self.bypass_cache_read) + if self.client_name is not None: + result["clientName"] = from_union([from_str, from_none], self.client_name) + if self.device_response is not None: + result["deviceResponse"] = self.device_response + if self.has_device_response is not None: + result["hasDeviceResponse"] = from_union([from_bool, from_none], self.has_device_response) + if self.policy_helper_enabled is not None: + result["policyHelperEnabled"] = from_union([from_bool, from_none], self.policy_helper_enabled) + if self.policy_helper_reason is not None: + result["policyHelperReason"] = from_union([lambda x: to_enum(_ManagedSettingsPolicyHelperReason, x), from_none], self.policy_helper_reason) + if self.policy_helper_working_directory is not None: + result["policyHelperWorkingDirectory"] = from_union([from_str, from_none], self.policy_helper_working_directory) + if self.self_fetch is not None: + result["selfFetch"] = from_union([from_bool, from_none], self.self_fetch) + if self.server_policy_cache_mode is not None: + result["serverPolicyCacheMode"] = from_union([lambda x: to_enum(_ManagedSettingsServerPolicyCacheMode, x), from_none], self.server_policy_cache_mode) + if self.session_id is not None: + result["sessionId"] = from_union([from_str, from_none], self.session_id) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _ManagedSettingsResolveStartupPolicyParams: + """Inputs describing the host and account a startup policy resolution should run for. + Mirrors `managedSettings.ingest`, and adds the decision of whether the resolved policy is + retained for this runtime process. + """ + environment: Any + """The host's environment variables, read for cache location, policy overrides, and the + variables that would make a membership snapshot forgeable. + """ + home_directory: str + """The host's home directory, used to resolve cache and managed-file locations.""" + + platform: str + """The host's platform, in Node's `process.platform` spelling, used to locate + platform-specific cache and policy paths. + """ + retain_and_apply: bool + """Whether to retain the resolved policy as this runtime process's startup policy, so later + work in the process enforces it. Set false to resolve without side effects, which is what + a protocol host wants before session creation: its sessions apply the complete policy + through the normal lifecycle, and retaining here would let a readiness credential affect + unrelated sessions. The returned verdict is identical either way — this decides only + whether the process keeps it. + """ + user_agent: str + """User agent to send with the policy fetch.""" + + auth_info: Any = None + """The authenticated identity to resolve policy for. Omitted before sign-in, in which case + no server layer is fetched and the sign-in pin is evaluated against no credential. + """ + bypass_cache_read: bool | None = None + """Whether to ignore a cached server policy when reading, forcing the resolution to come + from a live fetch. + """ + client_name: str | None = None + """Name of the embedding client, reported to the managed-settings service as `client_id` so + it can refuse to deliver a policy this client is too old to enforce. + """ + device_response: Any = None + """A device layer supplied by the host instead of discovered from the machine. Pair it with + `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + """ + has_device_response: bool | None = None + """Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts + the device layer is empty; false discovers it from the machine. + """ + policy_helper_enabled: bool | None = None + """Whether a configured platform policy helper may be run to produce an enforced helper + layer. + """ + policy_helper_reason: _ManagedSettingsPolicyHelperReason | None = None + """The policy-helper invocation reason. Defaults to sessionStart.""" + + policy_helper_working_directory: str | None = None + """Directory the policy helper runs in when this resolution is not owned by a registered + session. A host resolving policy before its session exists must pass this, or a + directory-sensitive helper judges the wrong repository. + """ + self_fetch: bool | None = None + """Whether to run ingestion. Omit or set false to return an empty result without discovering + or fetching policy. + """ + server_policy_cache_mode: _ManagedSettingsServerPolicyCacheMode | None = None + """How this resolution may use the on-disk server-policy cache. Defaults to the runtime's + own policy when omitted. Rejected when combined with `bypassCacheRead`, because the two + express the same decision and accepting both would leave the caller unsure which one the + runtime honored. + """ + session_id: str | None = None + """The session whose credential store, working directory and client kind the resolution + should use. Omit it when no session exists yet and the process-wide store applies. A + resolution whose session names a credential other than `authInfo` is returned but not + retained, so a stale sign-in cannot apply policy for an account that has already been + switched away from. + """ + + @staticmethod + def from_dict(obj: Any) -> '_ManagedSettingsResolveStartupPolicyParams': + assert isinstance(obj, dict) + environment = obj.get("environment") + home_directory = from_str(obj.get("homeDirectory")) + platform = from_str(obj.get("platform")) + retain_and_apply = from_bool(obj.get("retainAndApply")) + user_agent = from_str(obj.get("userAgent")) + auth_info = obj.get("authInfo") + bypass_cache_read = from_union([from_bool, from_none], obj.get("bypassCacheRead")) + client_name = from_union([from_str, from_none], obj.get("clientName")) + device_response = obj.get("deviceResponse") + has_device_response = from_union([from_bool, from_none], obj.get("hasDeviceResponse")) + policy_helper_enabled = from_union([from_bool, from_none], obj.get("policyHelperEnabled")) + policy_helper_reason = from_union([_ManagedSettingsPolicyHelperReason, from_none], obj.get("policyHelperReason")) + policy_helper_working_directory = from_union([from_str, from_none], obj.get("policyHelperWorkingDirectory")) + self_fetch = from_union([from_bool, from_none], obj.get("selfFetch")) + server_policy_cache_mode = from_union([_ManagedSettingsServerPolicyCacheMode, from_none], obj.get("serverPolicyCacheMode")) + session_id = from_union([from_str, from_none], obj.get("sessionId")) + return _ManagedSettingsResolveStartupPolicyParams(environment, home_directory, platform, retain_and_apply, user_agent, auth_info, bypass_cache_read, client_name, device_response, has_device_response, policy_helper_enabled, policy_helper_reason, policy_helper_working_directory, self_fetch, server_policy_cache_mode, session_id) + + def to_dict(self) -> dict: + result: dict = {} + result["environment"] = self.environment + result["homeDirectory"] = from_str(self.home_directory) + result["platform"] = from_str(self.platform) + result["retainAndApply"] = from_bool(self.retain_and_apply) + result["userAgent"] = from_str(self.user_agent) + if self.auth_info is not None: + result["authInfo"] = self.auth_info + if self.bypass_cache_read is not None: + result["bypassCacheRead"] = from_union([from_bool, from_none], self.bypass_cache_read) + if self.client_name is not None: + result["clientName"] = from_union([from_str, from_none], self.client_name) + if self.device_response is not None: + result["deviceResponse"] = self.device_response + if self.has_device_response is not None: + result["hasDeviceResponse"] = from_union([from_bool, from_none], self.has_device_response) + if self.policy_helper_enabled is not None: + result["policyHelperEnabled"] = from_union([from_bool, from_none], self.policy_helper_enabled) + if self.policy_helper_reason is not None: + result["policyHelperReason"] = from_union([lambda x: to_enum(_ManagedSettingsPolicyHelperReason, x), from_none], self.policy_helper_reason) + if self.policy_helper_working_directory is not None: + result["policyHelperWorkingDirectory"] = from_union([from_str, from_none], self.policy_helper_working_directory) + if self.self_fetch is not None: + result["selfFetch"] = from_union([from_bool, from_none], self.self_fetch) + if self.server_policy_cache_mode is not None: + result["serverPolicyCacheMode"] = from_union([lambda x: to_enum(_ManagedSettingsServerPolicyCacheMode, x), from_none], self.server_policy_cache_mode) + if self.session_id is not None: + result["sessionId"] = from_union([from_str, from_none], self.session_id) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _ManagedSettingsLogMessage: + """One diagnostic emitted while ingesting managed settings. Returned rather than logged by + the runtime so the host decides where ingestion diagnostics go, which matters because an + ingestion runs before a session exists to carry a log sink. + """ + level: _ManagedSettingsLogLevel + """Severity of this diagnostic.""" + + message: str + """Human-readable diagnostic text.""" + + @staticmethod + def from_dict(obj: Any) -> '_ManagedSettingsLogMessage': + assert isinstance(obj, dict) + level = _ManagedSettingsLogLevel(obj.get("level")) + message = from_str(obj.get("message")) + return _ManagedSettingsLogMessage(level, message) + + def to_dict(self) -> dict: + result: dict = {} + result["level"] = to_enum(_ManagedSettingsLogLevel, self.level) + result["message"] = from_str(self.message) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _ManagedSettingsResolveStartupPolicyResult: + """The startup policy a resolution composed, the per-layer outcome flags a host needs to + decide how much to trust it, and the enterprise sign-in verdict for the credential it ran + against. The flags are reported rather than folded into the settings because a host must + distinguish an unmanaged device from a managed device whose policy could not be + confirmed, and apply its fail-closed gates in the second case. + """ + device_load_failed: bool + """The device layer could not be read, so it is unconfirmed rather than known-absent.""" + + force_login_orgs: _ForceLoginOrgsDecision + """The enterprise sign-in verdict for the credential this resolution ran against, evaluated + over the effective policy so a server-delivered pin is honored alongside a device one. + Computed on every resolution, including one that was not retained, so a host that + declines to apply policy still cannot proceed past a pin. + """ + managed_policy_present: bool + """A managed policy is known to apply to this host, from a discovered source or a resolved + document. + """ + permission_policy_undetermined: bool + """The permissions layer specifically could not be confirmed, so permission gates apply + their fail-closed posture. + """ + policy_helper_load_failed: bool + """The policy helper was configured but could not be run, or its output could not be read.""" + + policy_undetermined: bool + """Some layer of the policy could not be confirmed, so its absence must not be read as + permission. Folds in a failed server fetch as well as an unreadable device layer. + """ + sandbox_enabled_by_undetermined_policy: bool + """The sandbox was enabled because policy could not be confirmed rather than because an + administrator asked for it. Lets a host explain a sandbox the user did not configure. + """ + server_fetch_failed: bool + """The server fetch failed and no cached entry stood in for it, so the server layer is + unconfirmed and fail-closed gates apply. + """ + server_resolution: _ManagedSettingsServerPolicyResolution + """How the current runtime resolved the server layer.""" + + telemetry: Any + """Telemetry describing which layers answered and how, for the host to report alongside its + own startup events. + """ + warnings: list[str] + """Warnings raised while resolving, in the order they occurred.""" + + client_update_requested: str | None = None + """Advisory minimum client version from a successful server response.""" + + client_update_required: str | None = None + """The server refused to deliver a policy because this client is too old to enforce it, + carrying the user-facing sentence describing the refusal. No retry will help; the remedy + is a client update. + """ + device_response: Any = None + """The device layer discovered from the machine, when one exists.""" + + device_sandbox_floor: Any = None + """The sandbox floor contributed by the device layer.""" + + policy_helper_response: Any = None + """The layer produced by the platform policy helper, when one ran.""" + + sandbox_floor: Any = None + """The effective sandbox floor composed across every layer, which a host must apply rather + than its own default. + """ + server_response: Any = None + """The account's server-delivered policy, when one was resolved.""" + + @staticmethod + def from_dict(obj: Any) -> '_ManagedSettingsResolveStartupPolicyResult': + assert isinstance(obj, dict) + device_load_failed = from_bool(obj.get("deviceLoadFailed")) + force_login_orgs = _ForceLoginOrgsDecision.from_dict(obj.get("forceLoginOrgs")) + managed_policy_present = from_bool(obj.get("managedPolicyPresent")) + permission_policy_undetermined = from_bool(obj.get("permissionPolicyUndetermined")) + policy_helper_load_failed = from_bool(obj.get("policyHelperLoadFailed")) + policy_undetermined = from_bool(obj.get("policyUndetermined")) + sandbox_enabled_by_undetermined_policy = from_bool(obj.get("sandboxEnabledByUndeterminedPolicy")) + server_fetch_failed = from_bool(obj.get("serverFetchFailed")) + server_resolution = _ManagedSettingsServerPolicyResolution(obj.get("serverResolution")) + telemetry = obj.get("telemetry") + warnings = from_list(from_str, obj.get("warnings")) + client_update_requested = from_union([from_str, from_none], obj.get("clientUpdateRequested")) + client_update_required = from_union([from_str, from_none], obj.get("clientUpdateRequired")) + device_response = obj.get("deviceResponse") + device_sandbox_floor = obj.get("deviceSandboxFloor") + policy_helper_response = obj.get("policyHelperResponse") + sandbox_floor = obj.get("sandboxFloor") + server_response = obj.get("serverResponse") + return _ManagedSettingsResolveStartupPolicyResult(device_load_failed, force_login_orgs, managed_policy_present, permission_policy_undetermined, policy_helper_load_failed, policy_undetermined, sandbox_enabled_by_undetermined_policy, server_fetch_failed, server_resolution, telemetry, warnings, client_update_requested, client_update_required, device_response, device_sandbox_floor, policy_helper_response, sandbox_floor, server_response) + + def to_dict(self) -> dict: + result: dict = {} + result["deviceLoadFailed"] = from_bool(self.device_load_failed) + result["forceLoginOrgs"] = to_class(_ForceLoginOrgsDecision, self.force_login_orgs) + result["managedPolicyPresent"] = from_bool(self.managed_policy_present) + result["permissionPolicyUndetermined"] = from_bool(self.permission_policy_undetermined) + result["policyHelperLoadFailed"] = from_bool(self.policy_helper_load_failed) + result["policyUndetermined"] = from_bool(self.policy_undetermined) + result["sandboxEnabledByUndeterminedPolicy"] = from_bool(self.sandbox_enabled_by_undetermined_policy) + result["serverFetchFailed"] = from_bool(self.server_fetch_failed) + result["serverResolution"] = to_enum(_ManagedSettingsServerPolicyResolution, self.server_resolution) + result["telemetry"] = self.telemetry + result["warnings"] = from_list(from_str, self.warnings) + if self.client_update_requested is not None: + result["clientUpdateRequested"] = from_union([from_str, from_none], self.client_update_requested) + if self.client_update_required is not None: + result["clientUpdateRequired"] = from_union([from_str, from_none], self.client_update_required) + if self.device_response is not None: + result["deviceResponse"] = self.device_response + if self.device_sandbox_floor is not None: + result["deviceSandboxFloor"] = self.device_sandbox_floor + if self.policy_helper_response is not None: + result["policyHelperResponse"] = self.policy_helper_response + if self.sandbox_floor is not None: + result["sandboxFloor"] = self.sandbox_floor + if self.server_response is not None: + result["serverResponse"] = self.server_response + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class MarketplaceListResult: @@ -31113,6 +33488,91 @@ def to_dict(self) -> dict: result["mode"] = from_union([lambda x: to_enum(RemoteSessionMode, x), from_none], self.mode) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _UserSettingsEditRequest: + """One atomic edit of a canonical setting in settings.json.""" + + canonical_path: list[str] + """Nonempty canonical path segments of the setting to edit, starting with its top-level key.""" + + operation: _SettingsEditOperation + """Set a scalar, add or remove a string list item, or remove the setting. The handler + rejects a missing or incompatible value. + """ + config_dir: str | None = None + """Configuration directory to edit. Omitted or empty resolves the server's own home, as in + `user.settings.loadForConfigDir`. + """ + value: Any = UNSET_SENTINEL + """Required boolean, string or number for set, required string for add-item and remove-item, + and forbidden for remove. The runtime rejects all other JSON values. + """ + + @staticmethod + def from_dict(obj: Any) -> '_UserSettingsEditRequest': + assert isinstance(obj, dict) + canonical_path = from_list(from_str, obj.get("canonicalPath")) + operation = _SettingsEditOperation(obj.get("operation")) + config_dir = from_union([from_str, from_none], obj.get("configDir")) + value = obj["value"] if "value" in obj else UNSET_SENTINEL + return _UserSettingsEditRequest(canonical_path, operation, config_dir, value) + + def to_dict(self) -> dict: + result: dict = {} + result["canonicalPath"] = from_list(from_str, self.canonical_path) + result["operation"] = to_enum(_SettingsEditOperation, self.operation) + if self.config_dir is not None: + result["configDir"] = from_union([from_str, from_none], self.config_dir) + if self.value is not UNSET_SENTINEL: + result["value"] = self.value + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _RepoSettingsEditRequest: + """One atomic edit of an allowed top-level repository setting.""" + + key: str + """One canonical top-level repository setting that the allowlist permits.""" + + operation: _SettingsEditOperation + """Set a scalar, add or remove a string list item, or remove the setting. The handler + rejects a missing or incompatible value. + """ + repo_root: str + """Absolute path of the repository root.""" + + scope: _RepoSettingsEditScope + """Shared or local repository settings file.""" + + value: Any = None + """Required boolean, string or number for set, required string for add-item and remove-item, + and forbidden for remove. The runtime rejects all other JSON values. + """ + + @staticmethod + def from_dict(obj: Any) -> '_RepoSettingsEditRequest': + assert isinstance(obj, dict) + key = from_str(obj.get("key")) + operation = _SettingsEditOperation(obj.get("operation")) + repo_root = from_str(obj.get("repoRoot")) + scope = _RepoSettingsEditScope(obj.get("scope")) + value = obj.get("value") + return _RepoSettingsEditRequest(key, operation, repo_root, scope, value) + + def to_dict(self) -> dict: + result: dict = {} + result["key"] = from_str(self.key) + result["operation"] = to_enum(_SettingsEditOperation, self.operation) + result["repoRoot"] = from_str(self.repo_root) + result["scope"] = to_enum(_RepoSettingsEditScope, self.scope) + if self.value is not None: + result["value"] = self.value + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class ResponseFormat: @@ -31277,6 +33737,37 @@ def to_dict(self) -> dict: result["suggestions"] = from_list(lambda x: to_class(SandboxCredentialSuggestion, x), self.suggestions) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _SandboxFilterPickerCandidatesParams: + """A batch of file-picker candidates to check against a prepared policy.""" + + candidates: list[_SandboxPickerCandidate] + """The candidates to check, in the order the answers are returned.""" + + cwd: str + """The session's working directory, matching the one the policy was prepared from.""" + + sandbox: Any = None + """The policy returned by `sandbox.preparePickerPolicy`. Omitted keeps every candidate.""" + + @staticmethod + def from_dict(obj: Any) -> '_SandboxFilterPickerCandidatesParams': + assert isinstance(obj, dict) + candidates = from_list(_SandboxPickerCandidate.from_dict, obj.get("candidates")) + cwd = from_str(obj.get("cwd")) + sandbox = obj.get("sandbox") + return _SandboxFilterPickerCandidatesParams(candidates, cwd, sandbox) + + def to_dict(self) -> dict: + result: dict = {} + result["candidates"] = from_list(lambda x: to_class(_SandboxPickerCandidate, x), self.candidates) + result["cwd"] = from_str(self.cwd) + if self.sandbox is not None: + result["sandbox"] = self.sandbox + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class SandboxHostSupport: @@ -32451,47 +34942,6 @@ def to_dict(self) -> dict: result["sessionId"] = from_str(self.session_id) return result -# Experimental: this type is part of an experimental API and may change or be removed. -# Internal: this type is an internal SDK API and is not part of the public surface. -@dataclass -class _UserSettingsEditRequest: - """One atomic edit of a canonical setting in settings.json.""" - - canonical_path: list[str] - """Nonempty canonical path segments of the setting to edit, starting with its top-level key.""" - - operation: _SettingsEditOperation - """Set a scalar, add or remove a string list item, or remove the setting. The handler - rejects a missing or incompatible value. - """ - config_dir: str | None = None - """Configuration directory to edit. Omitted or empty resolves the server's own home, as in - `user.settings.loadForConfigDir`. - """ - value: Any = UNSET_SENTINEL - """Required boolean, string or number for set, required string for add-item and remove-item, - and forbidden for remove. The runtime rejects all other JSON values. - """ - - @staticmethod - def from_dict(obj: Any) -> '_UserSettingsEditRequest': - assert isinstance(obj, dict) - canonical_path = from_list(from_str, obj.get("canonicalPath")) - operation = _SettingsEditOperation(obj.get("operation")) - config_dir = from_union([from_str, from_none], obj.get("configDir")) - value = obj["value"] if "value" in obj else UNSET_SENTINEL - return _UserSettingsEditRequest(canonical_path, operation, config_dir, value) - - def to_dict(self) -> dict: - result: dict = {} - result["canonicalPath"] = from_list(from_str, self.canonical_path) - result["operation"] = to_enum(_SettingsEditOperation, self.operation) - if self.config_dir is not None: - result["configDir"] = from_union([from_str, from_none], self.config_dir) - if self.value is not UNSET_SENTINEL: - result["value"] = self.value - return result - # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class ShellKillRequest: @@ -33217,6 +35667,69 @@ def to_dict(self) -> dict: result["runtimeSettingsChanged"] = from_union([from_bool, from_none], self.runtime_settings_changed) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _UserSettingsMigrateStaffLogLevelOnceResult: + """The outcome of the one-time staff log-level migration.""" + + status: StaffLogLevelMigrationStatus + """What the migration did. Only `refreshed` can have changed the persisted settings.""" + + completed_at: str | None = None + """When the migration was recorded as done, as an ISO-8601 timestamp. Absent only for + `ineligible`, which records nothing. + """ + settings: dict[str, Any] | None = None + """The settings document as it stands after the migration, keyed by setting name. Present + only for `refreshed`, and only when the document could be re-read cleanly. + """ + + @staticmethod + def from_dict(obj: Any) -> '_UserSettingsMigrateStaffLogLevelOnceResult': + assert isinstance(obj, dict) + status = StaffLogLevelMigrationStatus(obj.get("status")) + completed_at = from_union([from_str, from_none], obj.get("completedAt")) + settings = from_union([lambda x: from_dict(lambda x: x, x), from_none], obj.get("settings")) + return _UserSettingsMigrateStaffLogLevelOnceResult(status, completed_at, settings) + + def to_dict(self) -> dict: + result: dict = {} + result["status"] = to_enum(StaffLogLevelMigrationStatus, self.status) + if self.completed_at is not None: + result["completedAt"] = from_union([from_str, from_none], self.completed_at) + if self.settings is not None: + result["settings"] = from_union([lambda x: from_dict(lambda x: x, x), from_none], self.settings) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _UserSettingsMigrateStaffUpdateChannelOnceResult: + """The outcome of the one-time staff update-channel migration.""" + + status: StaffUpdateChannelMigrationStatus + """What the migration did. Only `migrated` means the persisted settings changed.""" + + completed_at: str | None = None + """When the migration was recorded as done, as an ISO-8601 timestamp. Absent only for + `ineligible`, which records nothing. + """ + + @staticmethod + def from_dict(obj: Any) -> '_UserSettingsMigrateStaffUpdateChannelOnceResult': + assert isinstance(obj, dict) + status = StaffUpdateChannelMigrationStatus(obj.get("status")) + completed_at = from_union([from_str, from_none], obj.get("completedAt")) + return _UserSettingsMigrateStaffUpdateChannelOnceResult(status, completed_at) + + def to_dict(self) -> dict: + result: dict = {} + result["status"] = to_enum(StaffUpdateChannelMigrationStatus, self.status) + if self.completed_at is not None: + result["completedAt"] = from_union([from_str, from_none], self.completed_at) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class TaskAgentProgress: @@ -34199,6 +36712,124 @@ def to_dict(self) -> dict: result["issues"] = from_union([lambda x: from_list(lambda x: to_class(UserSettingsValidationIssue, x), x), from_none], self.issues) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _UserSettingsMigrateStaffLogLevelOnceRequest: + """Selects the configuration directory to run the one-time staff log-level migration + against, and supplies the caller's record of whether it has already run. + """ + context: UserSettingsHostContext + """The configuration directory, home directory and environment to resolve the settings and + global-state documents from. A host that scopes a session to its own Copilot home must + pass that directory here, or the migration is evaluated against the server's own home + instead. + """ + cached_completed_at: str | None = None + """When the caller last recorded this migration, as an ISO-8601 timestamp. Supplying it lets + the runtime answer `current` without re-running the evaluation. + """ + + @staticmethod + def from_dict(obj: Any) -> '_UserSettingsMigrateStaffLogLevelOnceRequest': + assert isinstance(obj, dict) + context = UserSettingsHostContext.from_dict(obj.get("context")) + cached_completed_at = from_union([from_str, from_none], obj.get("cachedCompletedAt")) + return _UserSettingsMigrateStaffLogLevelOnceRequest(context, cached_completed_at) + + def to_dict(self) -> dict: + result: dict = {} + result["context"] = to_class(UserSettingsHostContext, self.context) + if self.cached_completed_at is not None: + result["cachedCompletedAt"] = from_union([from_str, from_none], self.cached_completed_at) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _UserSettingsResetStaffModelSelectionOnceRequest: + """Selects the configuration directory to run the one-time staff model-selection reset + against, and supplies the caller's record of whether it has already run. + """ + context: UserSettingsHostContext + """The configuration directory, home directory and environment to resolve the settings and + global-state documents from. A host that scopes a session to its own Copilot home must + pass that directory here, or the reset is evaluated against the server's own home instead. + """ + staff: bool | None = None + """Whether the signed-in account is a staff account. The reset applies only to staff, so + anything other than `true` returns `didReset: false` without touching the settings + document. + """ + staff_model_reset_at: str | None = None + """When the caller last recorded this reset, as an ISO-8601 timestamp. A timestamp at or + after the cutoff means the reset already ran and is returned unchanged. + """ + + @staticmethod + def from_dict(obj: Any) -> '_UserSettingsResetStaffModelSelectionOnceRequest': + assert isinstance(obj, dict) + context = UserSettingsHostContext.from_dict(obj.get("context")) + staff = from_union([from_bool, from_none], obj.get("staff")) + staff_model_reset_at = from_union([from_str, from_none], obj.get("staffModelResetAt")) + return _UserSettingsResetStaffModelSelectionOnceRequest(context, staff, staff_model_reset_at) + + def to_dict(self) -> dict: + result: dict = {} + result["context"] = to_class(UserSettingsHostContext, self.context) + if self.staff is not None: + result["staff"] = from_union([from_bool, from_none], self.staff) + if self.staff_model_reset_at is not None: + result["staffModelResetAt"] = from_union([from_str, from_none], self.staff_model_reset_at) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _UserSettingsUnknownKeysWarningRequest: + """Selects the configuration directory whose user settings document should be inspected for + unrecognized top-level keys. + """ + context: UserSettingsHostContext + """The configuration directory, home directory and environment to resolve the settings + document from. A host that scopes a session to its own Copilot home must pass that + directory here, or the server's own home is inspected instead. + """ + + @staticmethod + def from_dict(obj: Any) -> '_UserSettingsUnknownKeysWarningRequest': + assert isinstance(obj, dict) + context = UserSettingsHostContext.from_dict(obj.get("context")) + return _UserSettingsUnknownKeysWarningRequest(context) + + def to_dict(self) -> dict: + result: dict = {} + result["context"] = to_class(UserSettingsHostContext, self.context) + return result + +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _UserSettingsMigrateObsoleteOnDiskResult: + """The outcome of the one-time obsolete-settings cleanup.""" + + status: _UserSettingsMigrateObsoleteOnDiskStatus + """What the cleanup did. Only `changed` rewrote the document. The cleaned settings are not + returned here: the document is written before this replies, so `user.settings.load` reads + it authoritatively. + """ + + @staticmethod + def from_dict(obj: Any) -> '_UserSettingsMigrateObsoleteOnDiskResult': + assert isinstance(obj, dict) + status = _UserSettingsMigrateObsoleteOnDiskStatus(obj.get("status")) + return _UserSettingsMigrateObsoleteOnDiskResult(status) + + def to_dict(self) -> dict: + result: dict = {} + result["status"] = to_enum(_UserSettingsMigrateObsoleteOnDiskStatus, self.status) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class UserSettingsProblem: @@ -38057,6 +40688,185 @@ def to_dict(self) -> dict: result["values"] = from_union([lambda x: to_class(ManagedSettingsValues, x), from_none], self.values) return result +# Experimental: this type is part of an experimental API and may change or be removed. +# Internal: this type is an internal SDK API and is not part of the public surface. +@dataclass +class _ManagedSettingsIngestResult: + """The managed policy layers an ingestion resolved, together with the per-layer outcome + flags a host needs to decide how much to trust the result. The flags are reported rather + than folded into the settings because a host must be able to distinguish an unmanaged + device from a managed device whose policy could not be confirmed, and apply its + fail-closed gates in the second case. + """ + device_load_failed: bool + """The device layer could not be read, so it is unconfirmed rather than known-absent.""" + + device_sandbox_undetermined: bool + """Whether the device layer's sandbox intent could not be determined, so a consumer must not + read its absence as permission to run unsandboxed. + """ + device_source_found: bool + """A device-managed policy is known to exist.""" + + log_messages: list[_ManagedSettingsLogMessage] + """Diagnostics emitted while resolving the layers, in the order they occurred.""" + + policy_helper_configured: bool + """A policy helper is configured for this host.""" + + policy_helper_fail_closed: bool + """The policy helper's failure must be treated as fail-closed rather than ignored.""" + + policy_helper_load_failed: bool + """The policy helper was configured but could not be run or its output could not be read.""" + + server_cache_fallback: bool + """A live fetch failed but a recent cached entry was served in its place, so + `serverFetchFailed` stays false. Lets a consumer distinguish a clean fetch from a + cache-backed fallback. + """ + server_fetch_failed: bool + """The server fetch failed and no cached entry stood in for it, so the server layer is + unconfirmed and fail-closed gates apply. + """ + server_forced_refresh_failure: bool + """The server fetch failed while a policy demanded a fresh confirmation, which is the strict + posture an enterprise opted into rather than an ordinary transient failure. + """ + server_resolution: _ManagedSettingsServerPolicyResolution + """How the server layer was resolved.""" + + server_retryable_failure: bool + """The server fetch failed in a way a later retry could succeed at, as opposed to a refusal + that no retry will change. + """ + server_source_found: bool + """A server-managed policy is known to exist even though `serverResponse` is intentionally + unset. Consumers should OR this with the presence of `serverResponse` when deciding + whether the device is managed, so a fresh start during an outage still applies the + fail-closed gates instead of treating the device as unmanaged. + """ + server_token_unavailable: bool + """No usable token was available, so no server fetch was attempted.""" + + device_response: Any = None + """The device layer discovered from the machine, when one exists.""" + + device_sandbox_floor: Any = None + """The sandbox floor contributed by the device layer.""" + + permissions: Any = None + """The effective managed permissions layer, when the resolved policy carries one.""" + + policy_helper_authority: _ManagedSettingsPolicyHelperAuthority | None = None + """Which channel registered the policy helper that produced the helper layer.""" + + policy_helper_response: Any = None + """The layer produced by the platform policy helper, when one ran.""" + + server_client_update_requested: str | None = None + """Minimum client version requested by a successful response. Advisory only; the delivered + policy remains active. + """ + server_client_update_required: str | None = None + """The server refused to deliver a policy because this client is too old to enforce it, + carrying the user-facing sentence describing the refusal. No retry will help; the remedy + is a client update. Gates that exist only because of managed policy should deny on this + rather than falling back to their unmanaged default. + """ + server_fetch_error: str | None = None + """The error that made the server fetch fail, when one did.""" + + server_permissions_floor: Any = None + """The synthesized fail-closed permissions layer applied in place of a policy a refused + client may not enforce. + """ + server_response: Any = None + """The account's server-delivered policy, when one was resolved.""" + + server_sandbox_floor: Any = None + """The sandbox object from a cached server policy that a forced refresh declined to serve in + full. Folded back into the effective sandbox layer so an outage during a forced refresh + still synthesizes the fail-closed sandbox floor from the administrator's known intent. + """ + settings: Any = None + """The effective managed settings composed from every resolved layer. Omitted when no layer + set anything, so an unmanaged host locks nothing. + """ + + @staticmethod + def from_dict(obj: Any) -> '_ManagedSettingsIngestResult': + assert isinstance(obj, dict) + device_load_failed = from_bool(obj.get("deviceLoadFailed")) + device_sandbox_undetermined = from_bool(obj.get("deviceSandboxUndetermined")) + device_source_found = from_bool(obj.get("deviceSourceFound")) + log_messages = from_list(_ManagedSettingsLogMessage.from_dict, obj.get("logMessages")) + policy_helper_configured = from_bool(obj.get("policyHelperConfigured")) + policy_helper_fail_closed = from_bool(obj.get("policyHelperFailClosed")) + policy_helper_load_failed = from_bool(obj.get("policyHelperLoadFailed")) + server_cache_fallback = from_bool(obj.get("serverCacheFallback")) + server_fetch_failed = from_bool(obj.get("serverFetchFailed")) + server_forced_refresh_failure = from_bool(obj.get("serverForcedRefreshFailure")) + server_resolution = _ManagedSettingsServerPolicyResolution(obj.get("serverResolution")) + server_retryable_failure = from_bool(obj.get("serverRetryableFailure")) + server_source_found = from_bool(obj.get("serverSourceFound")) + server_token_unavailable = from_bool(obj.get("serverTokenUnavailable")) + device_response = obj.get("deviceResponse") + device_sandbox_floor = obj.get("deviceSandboxFloor") + permissions = obj.get("permissions") + policy_helper_authority = from_union([_ManagedSettingsPolicyHelperAuthority, from_none], obj.get("policyHelperAuthority")) + policy_helper_response = obj.get("policyHelperResponse") + server_client_update_requested = from_union([from_str, from_none], obj.get("serverClientUpdateRequested")) + server_client_update_required = from_union([from_str, from_none], obj.get("serverClientUpdateRequired")) + server_fetch_error = from_union([from_str, from_none], obj.get("serverFetchError")) + server_permissions_floor = obj.get("serverPermissionsFloor") + server_response = obj.get("serverResponse") + server_sandbox_floor = obj.get("serverSandboxFloor") + settings = obj.get("settings") + return _ManagedSettingsIngestResult(device_load_failed, device_sandbox_undetermined, device_source_found, log_messages, policy_helper_configured, policy_helper_fail_closed, policy_helper_load_failed, server_cache_fallback, server_fetch_failed, server_forced_refresh_failure, server_resolution, server_retryable_failure, server_source_found, server_token_unavailable, device_response, device_sandbox_floor, permissions, policy_helper_authority, policy_helper_response, server_client_update_requested, server_client_update_required, server_fetch_error, server_permissions_floor, server_response, server_sandbox_floor, settings) + + def to_dict(self) -> dict: + result: dict = {} + result["deviceLoadFailed"] = from_bool(self.device_load_failed) + result["deviceSandboxUndetermined"] = from_bool(self.device_sandbox_undetermined) + result["deviceSourceFound"] = from_bool(self.device_source_found) + result["logMessages"] = from_list(lambda x: to_class(_ManagedSettingsLogMessage, x), self.log_messages) + result["policyHelperConfigured"] = from_bool(self.policy_helper_configured) + result["policyHelperFailClosed"] = from_bool(self.policy_helper_fail_closed) + result["policyHelperLoadFailed"] = from_bool(self.policy_helper_load_failed) + result["serverCacheFallback"] = from_bool(self.server_cache_fallback) + result["serverFetchFailed"] = from_bool(self.server_fetch_failed) + result["serverForcedRefreshFailure"] = from_bool(self.server_forced_refresh_failure) + result["serverResolution"] = to_enum(_ManagedSettingsServerPolicyResolution, self.server_resolution) + result["serverRetryableFailure"] = from_bool(self.server_retryable_failure) + result["serverSourceFound"] = from_bool(self.server_source_found) + result["serverTokenUnavailable"] = from_bool(self.server_token_unavailable) + if self.device_response is not None: + result["deviceResponse"] = self.device_response + if self.device_sandbox_floor is not None: + result["deviceSandboxFloor"] = self.device_sandbox_floor + if self.permissions is not None: + result["permissions"] = self.permissions + if self.policy_helper_authority is not None: + result["policyHelperAuthority"] = from_union([lambda x: to_enum(_ManagedSettingsPolicyHelperAuthority, x), from_none], self.policy_helper_authority) + if self.policy_helper_response is not None: + result["policyHelperResponse"] = self.policy_helper_response + if self.server_client_update_requested is not None: + result["serverClientUpdateRequested"] = from_union([from_str, from_none], self.server_client_update_requested) + if self.server_client_update_required is not None: + result["serverClientUpdateRequired"] = from_union([from_str, from_none], self.server_client_update_required) + if self.server_fetch_error is not None: + result["serverFetchError"] = from_union([from_str, from_none], self.server_fetch_error) + if self.server_permissions_floor is not None: + result["serverPermissionsFloor"] = self.server_permissions_floor + if self.server_response is not None: + result["serverResponse"] = self.server_response + if self.server_sandbox_floor is not None: + result["serverSandboxFloor"] = self.server_sandbox_floor + if self.settings is not None: + result["settings"] = self.settings + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class MCPAppsHostContext: @@ -51999,12 +54809,16 @@ class RPC: feature_flags_metadata_result: _FeatureFlagsMetadataResult feature_flags_resolve_request: _FeatureFlagsResolveRequest feature_flags_resolve_result: dict[str, bool] + feature_flags_resolve_startup_gates_request: _FeatureFlagsResolveStartupGatesRequest + feature_flags_resolve_startup_gates_result: dict[str, bool] filter_mapping: dict[str, ContentFilterMode] | ContentFilterMode fleet_start_request: FleetStartRequest fleet_start_result: FleetStartResult folder_trust_add_params: FolderTrustAddParams folder_trust_check_params: FolderTrustCheckParams folder_trust_check_result: FolderTrustCheckResult + folder_trust_is_trusted_params: _FolderTrustIsTrustedParams + force_login_orgs_decision: _ForceLoginOrgsDecision gh_cli_auth_info: GhCLIAuthInfo git_current_branch_remote_result: _GitCurrentBranchRemoteResult git_cwd_request: _GitCwdRequest @@ -52124,6 +54938,7 @@ class RPC: llm_inference_http_response_start_result: LlmInferenceHTTPResponseStartResult llm_inference_set_provider_result: LlmInferenceSetProviderResult local_session_metadata_value: LocalSessionMetadataValue + location_permissions_cleanup_result: _LocationPermissionsCleanupResult logged_in_user: _LoggedInUser login_provider_kind: LoginProviderKind log_request: LogRequest @@ -52139,19 +54954,44 @@ class RPC: managed_plugin_retry_entry: ManagedPluginRetryEntry managed_plugin_retry_status: ManagedPluginRetryStatus managed_setting_meta: ManagedSettingMeta + managed_settings_apply_controls_params: _ManagedSettingsApplyControlsParams + managed_settings_apply_controls_result: _ManagedSettingsApplyControlsResult + managed_settings_bypass_disable_source: _ManagedSettingsBypassDisableSource + managed_settings_bypass_policy_resolution: _ManagedSettingsBypassPolicyResolution managed_settings_channel: ManagedSettingsChannel managed_settings_compose_layer: ManagedSettingsComposeLayer managed_settings_compose_request: ManagedSettingsComposeRequest managed_settings_compose_result: ManagedSettingsComposeResult managed_settings_diagnostic: ManagedSettingsDiagnostic managed_settings_diagnostic_severity: ManagedSettingsDiagnosticSeverity + managed_settings_ingest_params: _ManagedSettingsIngestParams + managed_settings_ingest_result: _ManagedSettingsIngestResult managed_settings_layer: ManagedSettingsLayer + managed_settings_load_remote_control_params: _ManagedSettingsLoadRemoteControlParams + managed_settings_load_remote_control_result: _ManagedSettingsLoadRemoteControlResult + managed_settings_log_level: _ManagedSettingsLogLevel + managed_settings_log_message: _ManagedSettingsLogMessage managed_settings_meta: ManagedSettingsMeta + managed_settings_parse_client_value_params: _ManagedSettingsParseClientValueParams + managed_settings_parse_client_value_result: _ManagedSettingsParseClientValueResult + managed_settings_policy_helper_authority: _ManagedSettingsPolicyHelperAuthority + managed_settings_policy_helper_reason: _ManagedSettingsPolicyHelperReason + managed_settings_read_device_result: _ManagedSettingsReadDeviceResult managed_settings_read_result: ManagedSettingsReadResult + managed_settings_resolve_bypass_disable_transition_params: _ManagedSettingsResolveBypassDisableTransitionParams + managed_settings_resolve_bypass_disable_transition_result: _ManagedSettingsResolveBypassDisableTransitionResult managed_settings_resolved_data: ManagedSettingsResolvedData + managed_settings_resolve_device_force_login_orgs_gate_params: _ManagedSettingsResolveDeviceForceLoginOrgsGateParams + managed_settings_resolve_effective_value_params: _ManagedSettingsResolveEffectiveValueParams + managed_settings_resolve_effective_value_result: _ManagedSettingsResolveEffectiveValueResult managed_settings_resolve_request: ManagedSettingsResolveRequest managed_settings_resolve_result: ManagedSettingsResolveResult + managed_settings_resolve_startup_policy_params: _ManagedSettingsResolveStartupPolicyParams + managed_settings_resolve_startup_policy_result: _ManagedSettingsResolveStartupPolicyResult + managed_settings_retain_policy_params: _ManagedSettingsRetainPolicyParams managed_settings_schema_result: ManagedSettingsSchemaResult + managed_settings_server_policy_cache_mode: _ManagedSettingsServerPolicyCacheMode + managed_settings_server_policy_resolution: _ManagedSettingsServerPolicyResolution managed_settings_validate_request: ManagedSettingsValidateRequest managed_settings_validate_result: ManagedSettingsValidateResult managed_settings_values: ManagedSettingsValues @@ -52541,6 +55381,8 @@ class RPC: permissions_configure_additional_content_exclusion_policy_scope: AdditionalContentExclusionPolicyScope permissions_configure_params: PermissionsConfigureParams permissions_configure_result: PermissionsConfigureResult + permissions_evaluate_managed_policy_params: _PermissionsEvaluateManagedPolicyParams + permissions_evaluate_managed_policy_result: PermissionsEvaluateManagedPolicyResult permissions_folder_trust_add_trusted_result: PermissionsFolderTrustAddTrustedResult permissions_get_mode_request: PermissionsGetModeRequest permissions_get_mode_result: PermissionsGetModeResult @@ -52577,6 +55419,8 @@ class RPC: permissions_urls_set_unrestricted_mode_result: PermissionsUrlsSetUnrestrictedModeResult permission_urls_config: PermissionUrlsConfig permission_urls_set_unrestricted_mode_params: PermissionUrlsSetUnrestrictedModeParams + persistence_write_raw_json_locked_request: PersistenceWriteRawJSONLockedRequest + persistence_write_raw_json_locked_result: PersistenceWriteRawJSONLockedResult ping_request: PingRequest ping_result: PingResult plan_read_result: PlanReadResult @@ -52721,11 +55565,17 @@ class RPC: remote_session_metadata_value: RemoteSessionMetadataValue remote_session_mode: RemoteSessionMode remote_session_repository: RemoteSessionRepository + repo_settings_edit_request: _RepoSettingsEditRequest + repo_settings_edit_scope: _RepoSettingsEditScope repo_settings_read_raw_request: _RepoSettingsReadRawRequest repo_settings_read_raw_result: _RepoSettingsReadRawResult repo_settings_write_all_request: _RepoSettingsWriteAllRequest repo_settings_write_key_request: _RepoSettingsWriteKeyRequest response_format: ResponseFormat + sandbox_apply_defaults_request: SandboxApplyDefaultsRequest + sandbox_check_enforcement_command_result: bool + sandbox_check_platform_support_result: bool + sandbox_check_windows_host_loopback_support_result: bool sandbox_config: SandboxConfig sandbox_config_auth: SandboxConfigAuth sandbox_config_source: SandboxConfigSource @@ -52741,18 +55591,40 @@ class RPC: sandbox_credential_suggestions_result: SandboxCredentialSuggestionsResult sandbox_disable_for_session_request: SandboxDisableForSessionRequest sandbox_disable_for_session_result: SandboxDisableForSessionResult + sandbox_docs_url_result: SandboxDocsURLResult + sandbox_effective_for_optional_params: _SandboxEffectiveForOptionalParams + sandbox_effective_for_optional_result: _SandboxEffectiveForOptionalResult + sandbox_enforcement_command_allowed_params: _SandboxEnforcementCommandAllowedParams sandbox_enforcement_status: SandboxEnforcementStatus + sandbox_filter_picker_candidates_params: _SandboxFilterPickerCandidatesParams + sandbox_filter_picker_candidates_result: _SandboxFilterPickerCandidatesResult + sandbox_get_unsupported_message_result: str + sandbox_get_unsupported_setting_disabled_notice_result: str sandbox_grant_path_for_request_request: SandboxGrantPathForRequestRequest sandbox_grant_path_for_request_result: SandboxGrantPathForRequestResult sandbox_host_capability: SandboxHostCapability sandbox_host_capability_name: str sandbox_host_support: SandboxHostSupport sandbox_masked_env_var: SandboxMaskedEnvVar + sandbox_picker_candidate: _SandboxPickerCandidate + sandbox_prepare_picker_policy_params: _SandboxPreparePickerPolicyParams + sandbox_prepare_picker_policy_result: _SandboxPreparePickerPolicyResult + sandbox_proxy_ca_check_installation_support_result: bool + sandbox_proxy_ca_check_relevance_result: bool sandbox_proxy_ca_create_result: SandboxProxyCACreateResult sandbox_proxy_ca_request: SandboxProxyCARequest sandbox_proxy_ca_state: SandboxProxyCAState sandbox_proxy_ca_status: SandboxProxyCAStatus + sandbox_proxy_secret_get_result: SandboxProxySecretGetResult + sandbox_proxy_secret_location: SandboxProxySecretLocation + sandbox_proxy_secret_save_request: SandboxProxySecretSaveRequest + sandbox_proxy_secret_save_result: SandboxProxySecretSaveResult + sandbox_resolve_floored_config_params: _SandboxResolveFlooredConfigParams + sandbox_resolve_floored_config_result: SandboxResolveFlooredConfigResult sandbox_session_change: SandboxSessionChange + sandbox_settings_apply_defaults_result: dict[str, Any] + sandbox_unsupported_startup_notice_params: _SandboxUnsupportedStartupNoticeParams + sandbox_unsupported_startup_notice_result: _SandboxUnsupportedStartupNoticeResult schedule_add_at_request: ScheduleAddAtRequest schedule_add_cron_request: ScheduleAddCronRequest schedule_add_request: ScheduleAddRequest @@ -53056,6 +55928,8 @@ class RPC: slash_command_show_dialog_result: SlashCommandShowDialogResult slash_command_text_result: SlashCommandTextResult slash_command_timeline_entry: SlashCommandTimelineEntry + staff_log_level_migration_status: StaffLogLevelMigrationStatus + staff_update_channel_migration_status: StaffUpdateChannelMigrationStatus subagent_settings_entry: SubagentSettingsEntry subagent_settings_entry_context_tier: SubagentSettingsEntryContextTier system_message_block: SystemMessageBlock @@ -53172,20 +56046,47 @@ class RPC: user_setting_metadata: UserSettingMetadata user_settings_apply_top_key_request: UserSettingsApplyTopKeyRequest user_settings_apply_top_key_result: UserSettingsApplyTopKeyResult + user_settings_build_runtime_request: _UserSettingsBuildRuntimeRequest + user_settings_build_runtime_result: dict[str, Any] user_settings_edit_request: _UserSettingsEditRequest user_settings_get_paths_request: UserSettingsGetPathsRequest user_settings_get_paths_result: UserSettingsGetPathsResult user_settings_get_result: UserSettingsGetResult user_settings_governance_keys_result: UserSettingsGovernanceKeysResult + user_settings_host_context: UserSettingsHostContext + user_settings_load_and_merge_repo_request: _UserSettingsLoadAndMergeRepoRequest + user_settings_load_and_merge_repo_result: _UserSettingsLoadAndMergeRepoResult + user_settings_load_for_config_dir_request: _UserSettingsLoadForConfigDirRequest + user_settings_load_for_config_dir_result: dict[str, Any] user_settings_load_for_edit_result: UserSettingsLoadForEditResult + user_settings_load_repo_request: UserSettingsLoadRepoRequest + user_settings_load_repo_result: UserSettingsLoadRepoResult + user_settings_load_with_warning_result: UserSettingsLoadWithWarningResult + user_settings_merge_managed_and_user_params: _UserSettingsMergeManagedAndUserParams + user_settings_merge_managed_and_user_result: UserSettingsMergeManagedAndUserResult + user_settings_merge_repo_value_params: _UserSettingsMergeRepoValueParams + user_settings_merge_repo_value_result: UserSettingsMergeRepoValueResult + user_settings_migrate_obsolete_on_disk_request: _UserSettingsMigrateObsoleteOnDiskRequest + user_settings_migrate_obsolete_on_disk_result: _UserSettingsMigrateObsoleteOnDiskResult + user_settings_migrate_obsolete_on_disk_status: _UserSettingsMigrateObsoleteOnDiskStatus + user_settings_migrate_staff_log_level_once_request: _UserSettingsMigrateStaffLogLevelOnceRequest + user_settings_migrate_staff_log_level_once_result: _UserSettingsMigrateStaffLogLevelOnceResult + user_settings_migrate_staff_update_channel_once_result: _UserSettingsMigrateStaffUpdateChannelOnceResult user_settings_normalize_request: UserSettingsNormalizeRequest user_settings_normalize_result: UserSettingsNormalizeResult + user_settings_path_result: UserSettingsPathResult user_settings_problem: UserSettingsProblem user_settings_problem_location: UserSettingsProblemLocation user_settings_problem_source: UserSettingsProblemSource user_settings_problems_request: UserSettingsProblemsRequest user_settings_problems_result: UserSettingsProblemsResult + user_settings_reset_staff_model_selection_once_request: _UserSettingsResetStaffModelSelectionOnceRequest + user_settings_reset_staff_model_selection_once_result: _UserSettingsResetStaffModelSelectionOnceResult + user_settings_set_hook_disabled_request: _UserSettingsSetHookDisabledRequest + user_settings_set_hook_disabled_result: _UserSettingsSetHookDisabledResult user_settings_set_request: UserSettingsSetRequest + user_settings_unknown_keys_warning_request: _UserSettingsUnknownKeysWarningRequest + user_settings_unknown_keys_warning_result: _UserSettingsUnknownKeysWarningResult user_settings_update_request: _UserSettingsUpdateRequest user_settings_update_result: _UserSettingsUpdateResult user_settings_validate_request: UserSettingsValidateRequest @@ -53658,12 +56559,16 @@ def from_dict(obj: Any) -> 'RPC': feature_flags_metadata_result = _FeatureFlagsMetadataResult.from_dict(obj.get("FeatureFlagsMetadataResult")) feature_flags_resolve_request = _FeatureFlagsResolveRequest.from_dict(obj.get("FeatureFlagsResolveRequest")) feature_flags_resolve_result = from_dict(from_bool, obj.get("FeatureFlagsResolveResult")) + feature_flags_resolve_startup_gates_request = _FeatureFlagsResolveStartupGatesRequest.from_dict(obj.get("FeatureFlagsResolveStartupGatesRequest")) + feature_flags_resolve_startup_gates_result = from_dict(from_bool, obj.get("FeatureFlagsResolveStartupGatesResult")) filter_mapping = from_union([lambda x: from_dict(ContentFilterMode, x), ContentFilterMode], obj.get("FilterMapping")) fleet_start_request = FleetStartRequest.from_dict(obj.get("FleetStartRequest")) fleet_start_result = FleetStartResult.from_dict(obj.get("FleetStartResult")) folder_trust_add_params = FolderTrustAddParams.from_dict(obj.get("FolderTrustAddParams")) folder_trust_check_params = FolderTrustCheckParams.from_dict(obj.get("FolderTrustCheckParams")) folder_trust_check_result = FolderTrustCheckResult.from_dict(obj.get("FolderTrustCheckResult")) + folder_trust_is_trusted_params = _FolderTrustIsTrustedParams.from_dict(obj.get("FolderTrustIsTrustedParams")) + force_login_orgs_decision = _ForceLoginOrgsDecision.from_dict(obj.get("ForceLoginOrgsDecision")) gh_cli_auth_info = GhCLIAuthInfo.from_dict(obj.get("GhCliAuthInfo")) git_current_branch_remote_result = _GitCurrentBranchRemoteResult.from_dict(obj.get("GitCurrentBranchRemoteResult")) git_cwd_request = _GitCwdRequest.from_dict(obj.get("GitCwdRequest")) @@ -53783,6 +56688,7 @@ def from_dict(obj: Any) -> 'RPC': llm_inference_http_response_start_result = LlmInferenceHTTPResponseStartResult.from_dict(obj.get("LlmInferenceHttpResponseStartResult")) llm_inference_set_provider_result = LlmInferenceSetProviderResult.from_dict(obj.get("LlmInferenceSetProviderResult")) local_session_metadata_value = LocalSessionMetadataValue.from_dict(obj.get("LocalSessionMetadataValue")) + location_permissions_cleanup_result = _LocationPermissionsCleanupResult.from_dict(obj.get("LocationPermissionsCleanupResult")) logged_in_user = _LoggedInUser.from_dict(obj.get("LoggedInUser")) login_provider_kind = LoginProviderKind(obj.get("LoginProviderKind")) log_request = LogRequest.from_dict(obj.get("LogRequest")) @@ -53798,19 +56704,44 @@ def from_dict(obj: Any) -> 'RPC': managed_plugin_retry_entry = ManagedPluginRetryEntry.from_dict(obj.get("ManagedPluginRetryEntry")) managed_plugin_retry_status = ManagedPluginRetryStatus(obj.get("ManagedPluginRetryStatus")) managed_setting_meta = ManagedSettingMeta.from_dict(obj.get("ManagedSettingMeta")) + managed_settings_apply_controls_params = _ManagedSettingsApplyControlsParams.from_dict(obj.get("ManagedSettingsApplyControlsParams")) + managed_settings_apply_controls_result = _ManagedSettingsApplyControlsResult.from_dict(obj.get("ManagedSettingsApplyControlsResult")) + managed_settings_bypass_disable_source = _ManagedSettingsBypassDisableSource(obj.get("ManagedSettingsBypassDisableSource")) + managed_settings_bypass_policy_resolution = _ManagedSettingsBypassPolicyResolution(obj.get("ManagedSettingsBypassPolicyResolution")) managed_settings_channel = ManagedSettingsChannel(obj.get("ManagedSettingsChannel")) managed_settings_compose_layer = ManagedSettingsComposeLayer.from_dict(obj.get("ManagedSettingsComposeLayer")) managed_settings_compose_request = ManagedSettingsComposeRequest.from_dict(obj.get("ManagedSettingsComposeRequest")) managed_settings_compose_result = ManagedSettingsComposeResult.from_dict(obj.get("ManagedSettingsComposeResult")) managed_settings_diagnostic = ManagedSettingsDiagnostic.from_dict(obj.get("ManagedSettingsDiagnostic")) managed_settings_diagnostic_severity = ManagedSettingsDiagnosticSeverity(obj.get("ManagedSettingsDiagnosticSeverity")) + managed_settings_ingest_params = _ManagedSettingsIngestParams.from_dict(obj.get("ManagedSettingsIngestParams")) + managed_settings_ingest_result = _ManagedSettingsIngestResult.from_dict(obj.get("ManagedSettingsIngestResult")) managed_settings_layer = ManagedSettingsLayer.from_dict(obj.get("ManagedSettingsLayer")) + managed_settings_load_remote_control_params = _ManagedSettingsLoadRemoteControlParams.from_dict(obj.get("ManagedSettingsLoadRemoteControlParams")) + managed_settings_load_remote_control_result = _ManagedSettingsLoadRemoteControlResult.from_dict(obj.get("ManagedSettingsLoadRemoteControlResult")) + managed_settings_log_level = _ManagedSettingsLogLevel(obj.get("ManagedSettingsLogLevel")) + managed_settings_log_message = _ManagedSettingsLogMessage.from_dict(obj.get("ManagedSettingsLogMessage")) managed_settings_meta = ManagedSettingsMeta.from_dict(obj.get("ManagedSettingsMeta")) + managed_settings_parse_client_value_params = _ManagedSettingsParseClientValueParams.from_dict(obj.get("ManagedSettingsParseClientValueParams")) + managed_settings_parse_client_value_result = _ManagedSettingsParseClientValueResult.from_dict(obj.get("ManagedSettingsParseClientValueResult")) + managed_settings_policy_helper_authority = _ManagedSettingsPolicyHelperAuthority(obj.get("ManagedSettingsPolicyHelperAuthority")) + managed_settings_policy_helper_reason = _ManagedSettingsPolicyHelperReason(obj.get("ManagedSettingsPolicyHelperReason")) + managed_settings_read_device_result = _ManagedSettingsReadDeviceResult.from_dict(obj.get("ManagedSettingsReadDeviceResult")) managed_settings_read_result = ManagedSettingsReadResult.from_dict(obj.get("ManagedSettingsReadResult")) + managed_settings_resolve_bypass_disable_transition_params = _ManagedSettingsResolveBypassDisableTransitionParams.from_dict(obj.get("ManagedSettingsResolveBypassDisableTransitionParams")) + managed_settings_resolve_bypass_disable_transition_result = _ManagedSettingsResolveBypassDisableTransitionResult.from_dict(obj.get("ManagedSettingsResolveBypassDisableTransitionResult")) managed_settings_resolved_data = ManagedSettingsResolvedData.from_dict(obj.get("ManagedSettingsResolvedData")) + managed_settings_resolve_device_force_login_orgs_gate_params = _ManagedSettingsResolveDeviceForceLoginOrgsGateParams.from_dict(obj.get("ManagedSettingsResolveDeviceForceLoginOrgsGateParams")) + managed_settings_resolve_effective_value_params = _ManagedSettingsResolveEffectiveValueParams.from_dict(obj.get("ManagedSettingsResolveEffectiveValueParams")) + managed_settings_resolve_effective_value_result = _ManagedSettingsResolveEffectiveValueResult.from_dict(obj.get("ManagedSettingsResolveEffectiveValueResult")) managed_settings_resolve_request = ManagedSettingsResolveRequest.from_dict(obj.get("ManagedSettingsResolveRequest")) managed_settings_resolve_result = ManagedSettingsResolveResult.from_dict(obj.get("ManagedSettingsResolveResult")) + managed_settings_resolve_startup_policy_params = _ManagedSettingsResolveStartupPolicyParams.from_dict(obj.get("ManagedSettingsResolveStartupPolicyParams")) + managed_settings_resolve_startup_policy_result = _ManagedSettingsResolveStartupPolicyResult.from_dict(obj.get("ManagedSettingsResolveStartupPolicyResult")) + managed_settings_retain_policy_params = _ManagedSettingsRetainPolicyParams.from_dict(obj.get("ManagedSettingsRetainPolicyParams")) managed_settings_schema_result = ManagedSettingsSchemaResult.from_dict(obj.get("ManagedSettingsSchemaResult")) + managed_settings_server_policy_cache_mode = _ManagedSettingsServerPolicyCacheMode(obj.get("ManagedSettingsServerPolicyCacheMode")) + managed_settings_server_policy_resolution = _ManagedSettingsServerPolicyResolution(obj.get("ManagedSettingsServerPolicyResolution")) managed_settings_validate_request = ManagedSettingsValidateRequest.from_dict(obj.get("ManagedSettingsValidateRequest")) managed_settings_validate_result = ManagedSettingsValidateResult.from_dict(obj.get("ManagedSettingsValidateResult")) managed_settings_values = ManagedSettingsValues.from_dict(obj.get("ManagedSettingsValues")) @@ -54200,6 +57131,8 @@ def from_dict(obj: Any) -> 'RPC': permissions_configure_additional_content_exclusion_policy_scope = AdditionalContentExclusionPolicyScope(obj.get("PermissionsConfigureAdditionalContentExclusionPolicyScope")) permissions_configure_params = PermissionsConfigureParams.from_dict(obj.get("PermissionsConfigureParams")) permissions_configure_result = PermissionsConfigureResult.from_dict(obj.get("PermissionsConfigureResult")) + permissions_evaluate_managed_policy_params = _PermissionsEvaluateManagedPolicyParams.from_dict(obj.get("PermissionsEvaluateManagedPolicyParams")) + permissions_evaluate_managed_policy_result = PermissionsEvaluateManagedPolicyResult.from_dict(obj.get("PermissionsEvaluateManagedPolicyResult")) permissions_folder_trust_add_trusted_result = PermissionsFolderTrustAddTrustedResult.from_dict(obj.get("PermissionsFolderTrustAddTrustedResult")) permissions_get_mode_request = PermissionsGetModeRequest.from_dict(obj.get("PermissionsGetModeRequest")) permissions_get_mode_result = PermissionsGetModeResult.from_dict(obj.get("PermissionsGetModeResult")) @@ -54236,6 +57169,8 @@ def from_dict(obj: Any) -> 'RPC': permissions_urls_set_unrestricted_mode_result = PermissionsUrlsSetUnrestrictedModeResult.from_dict(obj.get("PermissionsUrlsSetUnrestrictedModeResult")) permission_urls_config = PermissionUrlsConfig.from_dict(obj.get("PermissionUrlsConfig")) permission_urls_set_unrestricted_mode_params = PermissionUrlsSetUnrestrictedModeParams.from_dict(obj.get("PermissionUrlsSetUnrestrictedModeParams")) + persistence_write_raw_json_locked_request = PersistenceWriteRawJSONLockedRequest.from_dict(obj.get("PersistenceWriteRawJsonLockedRequest")) + persistence_write_raw_json_locked_result = PersistenceWriteRawJSONLockedResult.from_dict(obj.get("PersistenceWriteRawJsonLockedResult")) ping_request = PingRequest.from_dict(obj.get("PingRequest")) ping_result = PingResult.from_dict(obj.get("PingResult")) plan_read_result = PlanReadResult.from_dict(obj.get("PlanReadResult")) @@ -54380,11 +57315,17 @@ def from_dict(obj: Any) -> 'RPC': remote_session_metadata_value = RemoteSessionMetadataValue.from_dict(obj.get("RemoteSessionMetadataValue")) remote_session_mode = RemoteSessionMode(obj.get("RemoteSessionMode")) remote_session_repository = RemoteSessionRepository.from_dict(obj.get("RemoteSessionRepository")) + repo_settings_edit_request = _RepoSettingsEditRequest.from_dict(obj.get("RepoSettingsEditRequest")) + repo_settings_edit_scope = _RepoSettingsEditScope(obj.get("RepoSettingsEditScope")) repo_settings_read_raw_request = _RepoSettingsReadRawRequest.from_dict(obj.get("RepoSettingsReadRawRequest")) repo_settings_read_raw_result = _RepoSettingsReadRawResult.from_dict(obj.get("RepoSettingsReadRawResult")) repo_settings_write_all_request = _RepoSettingsWriteAllRequest.from_dict(obj.get("RepoSettingsWriteAllRequest")) repo_settings_write_key_request = _RepoSettingsWriteKeyRequest.from_dict(obj.get("RepoSettingsWriteKeyRequest")) response_format = ResponseFormat.from_dict(obj.get("ResponseFormat")) + sandbox_apply_defaults_request = SandboxApplyDefaultsRequest.from_dict(obj.get("SandboxApplyDefaultsRequest")) + sandbox_check_enforcement_command_result = from_bool(obj.get("SandboxCheckEnforcementCommandResult")) + sandbox_check_platform_support_result = from_bool(obj.get("SandboxCheckPlatformSupportResult")) + sandbox_check_windows_host_loopback_support_result = from_bool(obj.get("SandboxCheckWindowsHostLoopbackSupportResult")) sandbox_config = SandboxConfig.from_dict(obj.get("SandboxConfig")) sandbox_config_auth = SandboxConfigAuth.from_dict(obj.get("SandboxConfigAuth")) sandbox_config_source = SandboxConfigSource(obj.get("SandboxConfigSource")) @@ -54400,18 +57341,40 @@ def from_dict(obj: Any) -> 'RPC': sandbox_credential_suggestions_result = SandboxCredentialSuggestionsResult.from_dict(obj.get("SandboxCredentialSuggestionsResult")) sandbox_disable_for_session_request = SandboxDisableForSessionRequest.from_dict(obj.get("SandboxDisableForSessionRequest")) sandbox_disable_for_session_result = SandboxDisableForSessionResult.from_dict(obj.get("SandboxDisableForSessionResult")) + sandbox_docs_url_result = SandboxDocsURLResult.from_dict(obj.get("SandboxDocsUrlResult")) + sandbox_effective_for_optional_params = _SandboxEffectiveForOptionalParams.from_dict(obj.get("SandboxEffectiveForOptionalParams")) + sandbox_effective_for_optional_result = _SandboxEffectiveForOptionalResult.from_dict(obj.get("SandboxEffectiveForOptionalResult")) + sandbox_enforcement_command_allowed_params = _SandboxEnforcementCommandAllowedParams.from_dict(obj.get("SandboxEnforcementCommandAllowedParams")) sandbox_enforcement_status = SandboxEnforcementStatus.from_dict(obj.get("SandboxEnforcementStatus")) + sandbox_filter_picker_candidates_params = _SandboxFilterPickerCandidatesParams.from_dict(obj.get("SandboxFilterPickerCandidatesParams")) + sandbox_filter_picker_candidates_result = _SandboxFilterPickerCandidatesResult.from_dict(obj.get("SandboxFilterPickerCandidatesResult")) + sandbox_get_unsupported_message_result = from_str(obj.get("SandboxGetUnsupportedMessageResult")) + sandbox_get_unsupported_setting_disabled_notice_result = from_str(obj.get("SandboxGetUnsupportedSettingDisabledNoticeResult")) sandbox_grant_path_for_request_request = SandboxGrantPathForRequestRequest.from_dict(obj.get("SandboxGrantPathForRequestRequest")) sandbox_grant_path_for_request_result = SandboxGrantPathForRequestResult.from_dict(obj.get("SandboxGrantPathForRequestResult")) sandbox_host_capability = SandboxHostCapability.from_dict(obj.get("SandboxHostCapability")) sandbox_host_capability_name = from_str(obj.get("SandboxHostCapabilityName")) sandbox_host_support = SandboxHostSupport.from_dict(obj.get("SandboxHostSupport")) sandbox_masked_env_var = SandboxMaskedEnvVar.from_dict(obj.get("SandboxMaskedEnvVar")) + sandbox_picker_candidate = _SandboxPickerCandidate.from_dict(obj.get("SandboxPickerCandidate")) + sandbox_prepare_picker_policy_params = _SandboxPreparePickerPolicyParams.from_dict(obj.get("SandboxPreparePickerPolicyParams")) + sandbox_prepare_picker_policy_result = _SandboxPreparePickerPolicyResult.from_dict(obj.get("SandboxPreparePickerPolicyResult")) + sandbox_proxy_ca_check_installation_support_result = from_bool(obj.get("SandboxProxyCaCheckInstallationSupportResult")) + sandbox_proxy_ca_check_relevance_result = from_bool(obj.get("SandboxProxyCaCheckRelevanceResult")) sandbox_proxy_ca_create_result = SandboxProxyCACreateResult.from_dict(obj.get("SandboxProxyCaCreateResult")) sandbox_proxy_ca_request = SandboxProxyCARequest.from_dict(obj.get("SandboxProxyCaRequest")) sandbox_proxy_ca_state = SandboxProxyCAState(obj.get("SandboxProxyCaState")) sandbox_proxy_ca_status = SandboxProxyCAStatus.from_dict(obj.get("SandboxProxyCaStatus")) + sandbox_proxy_secret_get_result = SandboxProxySecretGetResult.from_dict(obj.get("SandboxProxySecretGetResult")) + sandbox_proxy_secret_location = SandboxProxySecretLocation.from_dict(obj.get("SandboxProxySecretLocation")) + sandbox_proxy_secret_save_request = SandboxProxySecretSaveRequest.from_dict(obj.get("SandboxProxySecretSaveRequest")) + sandbox_proxy_secret_save_result = SandboxProxySecretSaveResult.from_dict(obj.get("SandboxProxySecretSaveResult")) + sandbox_resolve_floored_config_params = _SandboxResolveFlooredConfigParams.from_dict(obj.get("SandboxResolveFlooredConfigParams")) + sandbox_resolve_floored_config_result = SandboxResolveFlooredConfigResult.from_dict(obj.get("SandboxResolveFlooredConfigResult")) sandbox_session_change = SandboxSessionChange(obj.get("SandboxSessionChange")) + sandbox_settings_apply_defaults_result = from_dict(lambda x: x, obj.get("SandboxSettingsApplyDefaultsResult")) + sandbox_unsupported_startup_notice_params = _SandboxUnsupportedStartupNoticeParams.from_dict(obj.get("SandboxUnsupportedStartupNoticeParams")) + sandbox_unsupported_startup_notice_result = _SandboxUnsupportedStartupNoticeResult.from_dict(obj.get("SandboxUnsupportedStartupNoticeResult")) schedule_add_at_request = ScheduleAddAtRequest.from_dict(obj.get("ScheduleAddAtRequest")) schedule_add_cron_request = ScheduleAddCronRequest.from_dict(obj.get("ScheduleAddCronRequest")) schedule_add_request = ScheduleAddRequest.from_dict(obj.get("ScheduleAddRequest")) @@ -54715,6 +57678,8 @@ def from_dict(obj: Any) -> 'RPC': slash_command_show_dialog_result = SlashCommandShowDialogResult.from_dict(obj.get("SlashCommandShowDialogResult")) slash_command_text_result = SlashCommandTextResult.from_dict(obj.get("SlashCommandTextResult")) slash_command_timeline_entry = SlashCommandTimelineEntry.from_dict(obj.get("SlashCommandTimelineEntry")) + staff_log_level_migration_status = StaffLogLevelMigrationStatus(obj.get("StaffLogLevelMigrationStatus")) + staff_update_channel_migration_status = StaffUpdateChannelMigrationStatus(obj.get("StaffUpdateChannelMigrationStatus")) subagent_settings_entry = SubagentSettingsEntry.from_dict(obj.get("SubagentSettingsEntry")) subagent_settings_entry_context_tier = SubagentSettingsEntryContextTier(obj.get("SubagentSettingsEntryContextTier")) system_message_block = SystemMessageBlock.from_dict(obj.get("SystemMessageBlock")) @@ -54831,20 +57796,47 @@ def from_dict(obj: Any) -> 'RPC': user_setting_metadata = UserSettingMetadata.from_dict(obj.get("UserSettingMetadata")) user_settings_apply_top_key_request = UserSettingsApplyTopKeyRequest.from_dict(obj.get("UserSettingsApplyTopKeyRequest")) user_settings_apply_top_key_result = UserSettingsApplyTopKeyResult.from_dict(obj.get("UserSettingsApplyTopKeyResult")) + user_settings_build_runtime_request = _UserSettingsBuildRuntimeRequest.from_dict(obj.get("UserSettingsBuildRuntimeRequest")) + user_settings_build_runtime_result = from_dict(lambda x: x, obj.get("UserSettingsBuildRuntimeResult")) user_settings_edit_request = _UserSettingsEditRequest.from_dict(obj.get("UserSettingsEditRequest")) user_settings_get_paths_request = UserSettingsGetPathsRequest.from_dict(obj.get("UserSettingsGetPathsRequest")) user_settings_get_paths_result = UserSettingsGetPathsResult.from_dict(obj.get("UserSettingsGetPathsResult")) user_settings_get_result = UserSettingsGetResult.from_dict(obj.get("UserSettingsGetResult")) user_settings_governance_keys_result = UserSettingsGovernanceKeysResult.from_dict(obj.get("UserSettingsGovernanceKeysResult")) + user_settings_host_context = UserSettingsHostContext.from_dict(obj.get("UserSettingsHostContext")) + user_settings_load_and_merge_repo_request = _UserSettingsLoadAndMergeRepoRequest.from_dict(obj.get("UserSettingsLoadAndMergeRepoRequest")) + user_settings_load_and_merge_repo_result = _UserSettingsLoadAndMergeRepoResult.from_dict(obj.get("UserSettingsLoadAndMergeRepoResult")) + user_settings_load_for_config_dir_request = _UserSettingsLoadForConfigDirRequest.from_dict(obj.get("UserSettingsLoadForConfigDirRequest")) + user_settings_load_for_config_dir_result = from_dict(lambda x: x, obj.get("UserSettingsLoadForConfigDirResult")) user_settings_load_for_edit_result = UserSettingsLoadForEditResult.from_dict(obj.get("UserSettingsLoadForEditResult")) + user_settings_load_repo_request = UserSettingsLoadRepoRequest.from_dict(obj.get("UserSettingsLoadRepoRequest")) + user_settings_load_repo_result = UserSettingsLoadRepoResult.from_dict(obj.get("UserSettingsLoadRepoResult")) + user_settings_load_with_warning_result = UserSettingsLoadWithWarningResult.from_dict(obj.get("UserSettingsLoadWithWarningResult")) + user_settings_merge_managed_and_user_params = _UserSettingsMergeManagedAndUserParams.from_dict(obj.get("UserSettingsMergeManagedAndUserParams")) + user_settings_merge_managed_and_user_result = UserSettingsMergeManagedAndUserResult.from_dict(obj.get("UserSettingsMergeManagedAndUserResult")) + user_settings_merge_repo_value_params = _UserSettingsMergeRepoValueParams.from_dict(obj.get("UserSettingsMergeRepoValueParams")) + user_settings_merge_repo_value_result = UserSettingsMergeRepoValueResult.from_dict(obj.get("UserSettingsMergeRepoValueResult")) + user_settings_migrate_obsolete_on_disk_request = _UserSettingsMigrateObsoleteOnDiskRequest.from_dict(obj.get("UserSettingsMigrateObsoleteOnDiskRequest")) + user_settings_migrate_obsolete_on_disk_result = _UserSettingsMigrateObsoleteOnDiskResult.from_dict(obj.get("UserSettingsMigrateObsoleteOnDiskResult")) + user_settings_migrate_obsolete_on_disk_status = _UserSettingsMigrateObsoleteOnDiskStatus(obj.get("UserSettingsMigrateObsoleteOnDiskStatus")) + user_settings_migrate_staff_log_level_once_request = _UserSettingsMigrateStaffLogLevelOnceRequest.from_dict(obj.get("UserSettingsMigrateStaffLogLevelOnceRequest")) + user_settings_migrate_staff_log_level_once_result = _UserSettingsMigrateStaffLogLevelOnceResult.from_dict(obj.get("UserSettingsMigrateStaffLogLevelOnceResult")) + user_settings_migrate_staff_update_channel_once_result = _UserSettingsMigrateStaffUpdateChannelOnceResult.from_dict(obj.get("UserSettingsMigrateStaffUpdateChannelOnceResult")) user_settings_normalize_request = UserSettingsNormalizeRequest.from_dict(obj.get("UserSettingsNormalizeRequest")) user_settings_normalize_result = UserSettingsNormalizeResult.from_dict(obj.get("UserSettingsNormalizeResult")) + user_settings_path_result = UserSettingsPathResult.from_dict(obj.get("UserSettingsPathResult")) user_settings_problem = UserSettingsProblem.from_dict(obj.get("UserSettingsProblem")) user_settings_problem_location = UserSettingsProblemLocation.from_dict(obj.get("UserSettingsProblemLocation")) user_settings_problem_source = UserSettingsProblemSource.from_dict(obj.get("UserSettingsProblemSource")) user_settings_problems_request = UserSettingsProblemsRequest.from_dict(obj.get("UserSettingsProblemsRequest")) user_settings_problems_result = UserSettingsProblemsResult.from_dict(obj.get("UserSettingsProblemsResult")) + user_settings_reset_staff_model_selection_once_request = _UserSettingsResetStaffModelSelectionOnceRequest.from_dict(obj.get("UserSettingsResetStaffModelSelectionOnceRequest")) + user_settings_reset_staff_model_selection_once_result = _UserSettingsResetStaffModelSelectionOnceResult.from_dict(obj.get("UserSettingsResetStaffModelSelectionOnceResult")) + user_settings_set_hook_disabled_request = _UserSettingsSetHookDisabledRequest.from_dict(obj.get("UserSettingsSetHookDisabledRequest")) + user_settings_set_hook_disabled_result = _UserSettingsSetHookDisabledResult.from_dict(obj.get("UserSettingsSetHookDisabledResult")) user_settings_set_request = UserSettingsSetRequest.from_dict(obj.get("UserSettingsSetRequest")) + user_settings_unknown_keys_warning_request = _UserSettingsUnknownKeysWarningRequest.from_dict(obj.get("UserSettingsUnknownKeysWarningRequest")) + user_settings_unknown_keys_warning_result = _UserSettingsUnknownKeysWarningResult.from_dict(obj.get("UserSettingsUnknownKeysWarningResult")) user_settings_update_request = _UserSettingsUpdateRequest.from_dict(obj.get("UserSettingsUpdateRequest")) user_settings_update_result = _UserSettingsUpdateResult.from_dict(obj.get("UserSettingsUpdateResult")) user_settings_validate_request = UserSettingsValidateRequest.from_dict(obj.get("UserSettingsValidateRequest")) @@ -54942,7 +57934,7 @@ def from_dict(obj: Any) -> 'RPC': subagent_settings = from_union([SubagentSettings.from_dict, from_none], obj.get("SubagentSettings")) task_progress = from_union([TaskProgress.from_dict, from_none], obj.get("TaskProgress")) workspace_summary = from_union([WorkspaceSummary.from_dict, from_none], obj.get("WorkspaceSummary")) - return RPC(abort_request, abort_result, accepted_enqueue_command_result, account_all_users, account_auth_info, account_describe_auth_info_request, account_describe_auth_info_result, account_get_all_users_result, account_get_current_auth_result, account_get_gist_support_request, account_get_gist_support_result, account_get_quota_request, account_get_quota_result, account_get_token_env_var_result, account_get_web_url_request, account_get_web_url_result, account_kind, account_login_request, account_login_result, account_logout_request, account_logout_result, account_quota_snapshot, accounts_enumerate_request, accounts_get_request, accounts_set_request, account_status, adaptive_thinking_support, agent_discovery_path, agent_discovery_path_list, agent_discovery_path_scope, agent_get_current_result, agent_info, agent_info_source, agent_list, agent_list_request, agent_registry_live_target_entry, agent_registry_live_target_entry_attention_kind, agent_registry_live_target_entry_kind, agent_registry_live_target_entry_last_terminal_event, agent_registry_live_target_entry_status, agent_registry_log_capture, agent_registry_log_capture_open_error_reason, agent_registry_spawn_error, agent_registry_spawn_permission_mode, agent_registry_spawn_registry_timeout, agent_registry_spawn_request, agent_registry_spawn_result, agent_registry_spawn_spawned, agent_registry_spawn_validation_error, agent_registry_spawn_validation_error_field, agent_registry_spawn_validation_error_reason, agent_reload_result, agents_custom_agent_initial_model_decision_params, agents_custom_agent_initial_model_decision_result, agents_discover_request, agent_select_request, agent_select_result, agent_set_prompt_request, agents_get_available_builtins_request, agents_get_available_builtins_result, agents_get_builtin_definition_request, agents_get_builtin_definition_result, agents_get_builtin_listing_definition_request, agents_get_builtin_listing_definition_result, agents_get_builtins_result, agents_get_discovery_paths_request, api_key_auth_info, auth_enumerate_query, auth_enumerate_value, auth_identity, auth_identity_metadata, auth_info, auth_info_type, auth_login_account, auth_login_advance_request, auth_login_begin_request, auth_login_begun, auth_login_cancel_request, auth_login_result_dto, auth_login_result_status, auth_login_step, auth_read_query, auth_read_value, auth_status_dto, auth_validation_error, auth_validation_errors, auth_write, auth_write_result, autopilot_objective_credit_limit, autopilot_objective_get_state_result, autopilot_objective_state, autopilot_objective_status, auto_tier_descriptor, auto_tier_metadata, auto_tier_status, builtin_agent_summary, built_in_model_catalog, built_in_model_catalog_entry, builtin_tool_descriptor, builtin_tool_format, builtin_tool_format_type, builtin_tool_input_schema, builtin_tool_input_schema_type, builtin_tool_safe_for_telemetry, builtin_tool_safe_telemetry_fields, cancel_user_requested_shell_command_result, canvas_action, canvas_action_invoke_request, canvas_action_invoke_result, canvas_close_request, canvas_host_context, canvas_host_context_capabilities, canvas_json_schema, canvas_list, canvas_list_open_result, canvas_open_request, canvas_provider_close_request, canvas_provider_invoke_action_request, canvas_provider_open_request, canvas_provider_open_result, canvas_provider_register_request, canvas_provider_unregister_request, canvas_session_context, capi_session_options, card_digest, card_digest_algorithm, card_digest_value, catalog_agent_plugin_candidate, catalog_agent_plugin_candidate_kind, catalog_agent_plugin_candidate_provenance, catalog_agent_plugin_compatibility_tag, catalog_agent_plugin_media_type, catalog_ai_skill_candidate, catalog_ai_skill_candidate_kind, catalog_ai_skill_candidate_provenance, catalog_ai_skill_installability, catalog_ai_skill_media_type, catalog_authentication_required_error, catalog_authentication_required_reason, catalog_candidate, catalog_candidate_kind, catalog_candidate_source, catalog_candidate_source_embedded, catalog_candidate_source_url, catalog_capability, catalog_capability_id, catalog_client_contract, catalog_contract_violation_error, catalog_contract_violation_reason, catalog_handle_rejected_error, catalog_handle_rejection_reason, catalog_handle_type, catalog_invalid_request_error, catalog_invalid_request_field, catalog_malformed_card_error, catalog_malformed_card_reason, catalog_mcp_server_candidate, catalog_mcp_server_candidate_kind, catalog_mcp_server_candidate_provenance, catalog_mcp_server_installability, catalog_media_type, catalog_negotiated_contract, catalog_negotiation_refused_error, catalog_negotiation_refused_reason, catalog_network_failure_error, catalog_network_failure_reason, catalog_not_installable_error, catalog_not_installable_reason, catalog_plugin_repository_source, catalog_policy_rejected_error, catalog_resource_identity, catalog_resource_version, catalog_search_page, catalog_search_pagination, catalog_search_request, catalog_search_result, catalog_search_succeeded, catalog_search_total_count_relation, catalog_selection_cancelled, catalog_selection_decision, catalog_selection_declined, catalog_selection_foreign, catalog_selection_invalid, catalog_selection_replayed, catalog_selection_request, catalog_selection_result, catalog_selection_selected, catalog_selection_stale, catalog_selection_timed_out, catalog_selection_wrong_kind, catalog_trust_eligibility, catalog_trust_provenance, catalog_trust_snapshot, catalog_trust_snapshot_absent, catalog_trust_snapshot_absent_status, catalog_trust_snapshot_current, catalog_trust_snapshot_current_status, catalog_trust_snapshot_downgraded, catalog_trust_snapshot_downgraded_status, catalog_trust_snapshot_malformed, catalog_trust_snapshot_malformed_status, catalog_trust_snapshot_revoked, catalog_trust_snapshot_revoked_status, catalog_trust_snapshot_schema_version, catalog_trust_snapshot_stale, catalog_trust_snapshot_stale_status, catalog_trust_snapshot_unsupported, catalog_trust_snapshot_unsupported_status, catalog_trust_source, catalog_trust_tier, catalog_unavailable_error, catalog_unavailable_reason, catalog_unavailable_transport_error, catalog_unavailable_transport_reason, catalog_unsafe_retrieval_error, catalog_unsafe_retrieval_reason, catalog_unsupported_kind_error, client_metadata, client_task_cancel_reason, client_task_cancel_request, client_task_cancel_result, command_list, commands_finalize_invocation_effect_request, commands_finalize_invocation_effect_result, commands_handle_pending_command_request, commands_handle_pending_command_result, commands_invocation_effect_outcome, commands_invocation_origin, commands_invoke_request, commands_list_request, commands_respond_to_queued_command_request, commands_respond_to_queued_command_result, completions_get_trigger_characters_result, completions_request_request, completions_request_result, configure_session_extensions_params, connect_client_info, connected_remote_session_metadata, connected_remote_session_metadata_kind, connected_remote_session_metadata_repository, connector_account_request, connector_authorization_requirement, connector_authorization_scope, connector_availability, connector_capabilities, connector_catalog_entry, connector_catalog_result, connector_catalog_status, connector_connect_request, connector_connect_result, connector_continue_request, connector_disconnect_result, connector_discovery_account, connector_discovery_account_list, connector_discovery_account_request, connector_discovery_auth_info, connector_discovery_availability, connector_discovery_capabilities, connector_discovery_catalog_entry, connector_discovery_catalog_result, connector_mcp_status, connector_reconcile_request, connector_runtime_status, connector_session_account, connector_status, connect_remote_session_params, connect_request, connect_result, content_exclusion_check_paths_request, content_exclusion_check_paths_result, content_exclusion_path_check, content_filter_mode, context_heaviest_message, copilot_api_token_auth_info, copilot_user_response, copilot_user_response_endpoints, copilot_user_response_quota_snapshots, copilot_user_response_quota_snapshots_chat, copilot_user_response_quota_snapshots_completions, copilot_user_response_quota_snapshots_premium_interactions, current_model, current_tool_metadata, customization_reload_outcome, customization_reload_status, customization_reload_subsystem, customizations_reload_result, debug_collect_logs_collected_entry, debug_collect_logs_destination, debug_collect_logs_entry, debug_collect_logs_entry_kind, debug_collect_logs_include, debug_collect_logs_redaction, debug_collect_logs_request, debug_collect_logs_result, debug_collect_logs_result_kind, debug_collect_logs_skipped_entry, debug_collect_logs_source, diagnostic_cursor_status, diagnostic_entry, diagnostic_log_level, diagnostics_configuration, diagnostics_configure_request, diagnostic_severity, diagnostic_source, diagnostic_sources_configuration, diagnostics_read_request, diagnostics_read_result, discovered_canvas, discovered_extension, discovered_extension_mode, discovered_extension_plugin, discovered_extensions, discovered_extensions_disable_request, discovered_extensions_enable_request, discovered_extension_source, discovered_hook, discovered_mcp_server, discovered_mcp_server_type, discovered_model, discovered_model_list, enqueue_command_params, enqueue_command_result, env_auth_info, environment_capabilities, environment_kind, environments_delete_request, environments_delete_result, environments_get_request, environments_get_result, environments_list_request, environments_list_result, event_log_read_request, event_log_release_interest_result, event_log_tail_result, event_log_types, events_agent_scope, events_cursor_status, events_read_direction, events_read_result, execute_command_params, execute_command_result, extension, extension_context_push_input, extension_launch_profile, extension_launch_provider_resolve_request, extension_launch_provider_resolve_result, extension_list, extensions_disable_request, extensions_enable_request, extension_source, extension_status, external_tool_result, external_tool_text_result_for_llm, external_tool_text_result_for_llm_binary_results_for_llm, external_tool_text_result_for_llm_binary_results_for_llm_type, external_tool_text_result_for_llm_content, external_tool_text_result_for_llm_content_audio, external_tool_text_result_for_llm_content_image, external_tool_text_result_for_llm_content_resource, external_tool_text_result_for_llm_content_resource_details, external_tool_text_result_for_llm_content_resource_link, external_tool_text_result_for_llm_content_resource_link_icon, external_tool_text_result_for_llm_content_resource_link_icon_theme, external_tool_text_result_for_llm_content_shell_exit, external_tool_text_result_for_llm_content_terminal, external_tool_text_result_for_llm_content_text, feature_flag_availability, feature_flag_metadata, feature_flags_metadata_result, feature_flags_resolve_request, feature_flags_resolve_result, filter_mapping, fleet_start_request, fleet_start_result, folder_trust_add_params, folder_trust_check_params, folder_trust_check_result, gh_cli_auth_info, git_current_branch_remote_result, git_cwd_request, git_hub_environment, git_hub_owner_option, git_hub_owners_cancel_request, git_hub_owners_cancel_result, git_hub_owners_list_request, git_hub_owners_list_result, git_hub_owners_request_id_result, git_hub_repository_at_path_request, git_hub_repository_at_path_result, git_hub_repository_identity, git_hub_telemetry_client_info, git_hub_telemetry_event, git_hub_telemetry_notification, git_hub_token_acquire_reason, git_hub_token_acquire_request, git_hub_token_acquire_result, git_remote_repository, git_repos_from_remotes_request, git_repos_from_remotes_result, global_state_load_for_config_dir_request, global_state_load_result, global_state_write_key_request, handle_pending_tool_call_request, handle_pending_tool_call_result, history_abort_manual_compaction_result, history_cancel_background_compaction_result, history_clear_context_request, history_clear_context_result, history_compact_context_window, history_compact_request, history_compact_result, history_file_restore_skip_reason, history_list_rewind_points_result, history_preview_rewind_request, history_preview_rewind_result, history_rewind_change_type, history_rewind_file_preview, history_rewind_mode, history_rewind_outcome, history_rewind_point, history_rewind_request, history_rewind_result, history_rewind_unavailable_reason, history_skipped_file_restore, history_summarize_for_handoff_result, history_truncate_request, history_truncate_result, hmac_auth_info, hook_invoke_request, hook_invoke_response, hook_origin, hooks_discover_request, hooks_discover_result, hook_type, host_configuration, host_dispose_request, host_empty_result, host_environment_credentials, host_exited_notification, host_exit_reason, host_git_hub_environment_options, host_list_sessions_request, host_list_sessions_result, host_local_server_configuration, host_local_server_options, host_publish_session_request, host_publish_session_result, host_ready_request, host_register_session_request, host_session_create_callback, host_session_create_request, host_session_create_result, host_session_released_notification, host_session_release_request, host_session_summary, host_start_request, host_start_result, installation_catalogue_identity, installation_confirmation_request, installation_confirmation_response, installation_decision, installation_review, installed_plugin, installed_plugin_info, installed_plugin_source, installed_plugin_source_git_hub, installed_plugin_source_local, installed_plugin_source_url, instruction_discovery_path, instruction_discovery_path_kind, instruction_discovery_path_list, instruction_discovery_path_location, instructions_discover_repo_sources_request, instructions_discover_request, instructions_get_discovery_paths_request, instructions_get_sources_result, instructions_init_prompt_result, instruction_source, instruction_source_location, instruction_source_type, interrupt_main_turn_request, interrupt_main_turn_result, json_schema_response_format, llm_inference_headers, llm_inference_http_request_chunk_request, llm_inference_http_request_chunk_result, llm_inference_http_request_start_request, llm_inference_http_request_start_result, llm_inference_http_request_start_transport, llm_inference_http_response_chunk_error, llm_inference_http_response_chunk_request, llm_inference_http_response_chunk_result, llm_inference_http_response_start_request, llm_inference_http_response_start_result, llm_inference_set_provider_result, local_session_metadata_value, logged_in_user, login_provider_kind, log_request, log_result, lsp_initialize_request, managed_mcp_server_config, managed_permission_evaluation, managed_permission_operation, managed_permission_operation_kind, managed_permissions_evaluate_request, managed_permissions_evaluate_result, managed_permission_verdict, managed_plugin_retry_entry, managed_plugin_retry_status, managed_setting_meta, managed_settings_channel, managed_settings_compose_layer, managed_settings_compose_request, managed_settings_compose_result, managed_settings_diagnostic, managed_settings_diagnostic_severity, managed_settings_layer, managed_settings_meta, managed_settings_read_result, managed_settings_resolved_data, managed_settings_resolve_request, managed_settings_resolve_result, managed_settings_schema_result, managed_settings_validate_request, managed_settings_validate_result, managed_settings_values, marketplace_add_result, marketplace_browse_result, marketplace_info, marketplace_list_result, marketplace_plugin_info, marketplace_refresh_entry, marketplace_refresh_result, marketplace_remove_result, mcp_allowed_server, mcp_apply_install_request, mcp_apply_uninstall_request, mcp_apps_call_tool_request, mcp_apps_diagnose_capability, mcp_apps_diagnose_request, mcp_apps_diagnose_result, mcp_apps_diagnose_server, mcp_apps_host_context, mcp_apps_host_context_details, mcp_apps_host_context_details_available_display_mode, mcp_apps_host_context_details_display_mode, mcp_apps_host_context_details_platform, mcp_apps_host_context_details_theme, mcp_apps_list_tools_request, mcp_apps_list_tools_result, mcp_apps_read_resource_request, mcp_apps_read_resource_result, mcp_apps_resource_content, mcp_apps_set_host_context_details, mcp_apps_set_host_context_details_available_display_mode, mcp_apps_set_host_context_details_display_mode, mcp_apps_set_host_context_details_platform, mcp_apps_set_host_context_details_theme, mcp_apps_set_host_context_request, mcp_cancel_sampling_execution_params, mcp_cancel_sampling_execution_result, mcp_config_add_request, mcp_config_disable_request, mcp_config_enable_request, mcp_config_list, mcp_config_remove_request, mcp_config_update_request, mcp_configured_server, mcp_configured_server_list, mcp_configured_server_state, mcp_configure_git_hub_request, mcp_configure_git_hub_result, mcp_diagnostic_details, mcp_diagnostic_direction, mcp_diagnostic_kind, mcp_diagnostic_source_configuration, mcp_disable_request, mcp_discover_request, mcp_discover_result, mcp_elicitation_form_mode, mcp_enable_request, mcp_execute_sampling_params, mcp_execute_sampling_request, mcp_execute_sampling_result, mcp_failed_server, mcp_filtered_server, mcp_headers_handle_pending_headers_refresh_request, mcp_headers_handle_pending_headers_refresh_request_request, mcp_headers_handle_pending_headers_refresh_request_result, mcp_host_state, mcp_installation_failure_reason, mcp_installation_input, mcp_installation_management_outcome, mcp_installation_management_result, mcp_installation_operation_request, mcp_installation_operation_status, mcp_installation_outcome, mcp_installation_remote_configuration, mcp_installation_result, mcp_installation_review, mcp_installation_secret, mcp_installation_secret_storage, mcp_installations_request, mcp_installation_state, mcp_installation_summary, mcp_install_plan, mcp_is_server_running_request, mcp_is_server_running_result, mcp_list_builtin_server_names_result, mcp_list_tools_request, mcp_list_tools_result, mcp_oauth_authentication_state_changed_request, mcp_oauth_cancel_login_request, mcp_oauth_cancel_login_result, mcp_oauth_complete_request, mcp_oauth_handle_pending_request, mcp_oauth_handle_pending_result, mcp_oauth_login_grant_type, mcp_oauth_login_request, mcp_oauth_login_result, mcp_oauth_pending_request_response, mcp_oauth_prepare_login_request, mcp_oauth_prepare_login_result, mcp_oauth_probe_needs_auth_reason, mcp_oauth_probe_request, mcp_oauth_probe_result, mcp_oauth_respond_request, mcp_oauth_respond_result, mcp_owned_oauth_login_status, mcp_plan_configuration_change, mcp_plan_configuration_operation, mcp_plan_enum_value_type, mcp_plan_install_planned, mcp_plan_install_request, mcp_plan_install_result, mcp_plan_install_source, mcp_plan_install_source_candidate, mcp_plan_install_source_candidate_kind, mcp_plan_install_source_card, mcp_plan_install_source_card_kind, mcp_plan_package_install_method, mcp_plan_package_transport, mcp_plan_policy_decision, mcp_plan_policy_result, mcp_plan_policy_source, mcp_plan_provenance, mcp_plan_remote_install_method, mcp_plan_remote_transport, mcp_plan_required_value, mcp_plan_required_value_enum, mcp_plan_required_value_enum_kind, mcp_plan_required_value_scalar, mcp_plan_required_value_scalar_kind, mcp_plan_resource_identity, mcp_plan_scalar_value_type, mcp_plan_scope, mcp_plan_secret_placeholder, mcp_plan_secret_reference, mcp_plan_target, mcp_plan_transport_choice, mcp_plan_transport_choice_package, mcp_plan_transport_choice_remote, mcp_plan_uninstall_request, mcp_plan_value_category, mcp_prepared_install, mcp_prepare_install_request, mcp_prompt, mcp_prompt_argument, mcp_prompt_icon, mcp_prompt_message, mcp_prompt_role, mcp_prompts_get_request, mcp_prompts_get_result, mcp_prompts_list_request, mcp_prompts_list_result, mcp_register_external_client_request, mcp_registry_cancel_request, mcp_registry_cancel_result, mcp_registry_request_id_result, mcp_registry_search_request, mcp_registry_search_result, mcp_reload_config, mcp_reload_with_config_request, mcp_remove_git_hub_result, mcp_resource, mcp_resource_annotations, mcp_resource_content, mcp_resource_icon, mcp_resources_list_request, mcp_resources_list_result, mcp_resources_list_templates_request, mcp_resources_list_templates_result, mcp_resources_read_request, mcp_resources_read_result, mcp_resource_template, mcp_restart_server_request, mcp_safe_for_telemetry, mcp_safe_for_telemetry_fields, mcp_sampling_execution_action, mcp_sampling_execution_result, mcp_serializable_server_config, mcp_server, mcp_server_auth_config, mcp_server_auth_config_redirect_port, mcp_server_card_embedded, mcp_server_card_embedded_kind, mcp_server_card_media_type, mcp_server_card_reference, mcp_server_card_url, mcp_server_card_url_kind, mcp_server_config, mcp_server_config_defer_tools, mcp_server_config_http, mcp_server_config_http_oauth_grant_type, mcp_server_config_http_type, mcp_server_config_memory, mcp_server_config_memory_type, mcp_server_config_stdio, mcp_server_config_stdio_type, mcp_server_failure_info, mcp_server_list, mcp_server_needs_auth_info, mcp_server_ownership, mcp_set_env_value_mode_details, mcp_set_env_value_mode_params, mcp_set_env_value_mode_result, mcp_should_exclude_git_hub_tools_request, mcp_should_exclude_git_hub_tools_result, mcp_source_file, mcp_source_plugin, mcp_source_ref, mcp_start_server_request, mcp_start_servers_result, mcp_stop_server_request, mcp_task_metadata, mcp_tools, mcp_tool_ui, mcp_tool_ui_visibility, mcp_uninstall_plan, mcp_unregister_external_client_request, memory_configuration, metadata_context_attribution_result, metadata_context_heaviest_messages_request, metadata_context_heaviest_messages_result, metadata_context_info_request, metadata_context_info_result, metadata_is_processing_result, metadata_recompute_context_tokens_request, metadata_recompute_context_tokens_result, metadata_record_context_change_request, metadata_record_context_change_result, metadata_set_working_directory_request, metadata_set_working_directory_result, metadata_snapshot_current_mode, metadata_snapshot_remote_metadata, metadata_snapshot_remote_metadata_repository, metadata_snapshot_remote_metadata_task_type, metadata_update_client_metadata_request, model, model_apply_startup_overlay_request, model_artifact_details, model_billing, model_billing_promo, model_billing_token_prices, model_billing_token_prices_long_context, model_capabilities, model_capabilities_limits, model_capabilities_limits_vision, model_capabilities_override, model_capabilities_override_limits, model_capabilities_override_limits_vision, model_capabilities_override_supports, model_capabilities_supports, model_clear_startup_seed_request, model_clear_startup_seed_result, model_get_reasoning_summaries_request, model_get_reasoning_summaries_result, model_list, model_list_request, model_message, model_picker_category, model_picker_persistence_request, model_picker_price_category, model_picker_settings_context, model_policy, model_policy_state, model_provider_adapter_catalog, model_provider_adapter_descriptor, model_provider_adapter_operation_descriptor, model_provider_attribution, model_provider_automatic_discovery_mode, model_provider_automatic_discovery_policy, model_provider_configuration_disposition, model_provider_configuration_plan, model_provider_descriptor, model_provider_discover_request, model_provider_discover_result, model_provider_discovery_network_scope, model_provider_get_status_request, model_provider_instance, model_provider_instance_reference, model_provider_models_list_request, model_provider_operation_outcome, model_provider_operation_outcome_code, model_provider_prepare_configuration_request, model_provider_provenance, model_provider_provenance_source, model_provider_status, model_provider_warning, model_set_allowed_models_request, model_set_allowed_models_result, model_set_reasoning_effort_request, model_set_reasoning_effort_result, models_list_request, model_switch_auto_tier_request, model_switch_auto_tier_result, model_switch_auto_tier_status, model_switch_confirmation, model_switch_to_request, model_switch_to_result, model_warning_text, mode_set_request, mode_set_result, move_mcp_loading_to_background_result, named_provider_config, name_get_result, name_set_auto_request, name_set_auto_result, name_set_request, open_canvas_instance, options_update_additional_content_exclusion_policy, options_update_additional_content_exclusion_policy_rule, options_update_additional_content_exclusion_policy_rule_source, options_update_additional_content_exclusion_policy_scope, options_update_context_tier, options_update_env_value_mode, options_update_reasoning_summary, options_update_tool_filter_precedence, pending_external_tool_request, pending_external_tool_request_list, pending_permission_request, pending_permission_request_list, permission_decision, permission_decision_approved, permission_decision_approved_for_location, permission_decision_approved_for_session, permission_decision_approve_for_location, permission_decision_approve_for_location_approval, permission_decision_approve_for_location_approval_commands, permission_decision_approve_for_location_approval_custom_tool, permission_decision_approve_for_location_approval_extension_env_access, permission_decision_approve_for_location_approval_extension_management, permission_decision_approve_for_location_approval_extension_permission_access, permission_decision_approve_for_location_approval_mcp, permission_decision_approve_for_location_approval_mcp_sampling, permission_decision_approve_for_location_approval_memory, permission_decision_approve_for_location_approval_read, permission_decision_approve_for_location_approval_workflow, permission_decision_approve_for_location_approval_write, permission_decision_approve_for_session, permission_decision_approve_for_session_approval, permission_decision_approve_for_session_approval_commands, permission_decision_approve_for_session_approval_custom_tool, permission_decision_approve_for_session_approval_extension_env_access, permission_decision_approve_for_session_approval_extension_management, permission_decision_approve_for_session_approval_extension_permission_access, permission_decision_approve_for_session_approval_mcp, permission_decision_approve_for_session_approval_mcp_sampling, permission_decision_approve_for_session_approval_memory, permission_decision_approve_for_session_approval_read, permission_decision_approve_for_session_approval_workflow, permission_decision_approve_for_session_approval_write, permission_decision_approve_once, permission_decision_approve_permanently, permission_decision_approve_read_only_for_session, permission_decision_cancelled, permission_decision_context, permission_decision_denied_by_content_exclusion_policy, permission_decision_denied_by_permission_request_hook, permission_decision_denied_by_rules, permission_decision_denied_interactively_by_user, permission_decision_denied_no_approval_rule_and_could_not_request_from_user, permission_decision_outcome, permission_decision_reject, permission_decision_request, permission_decision_surface, permission_decision_user_not_available, permission_location_add_tool_approval_params, permission_location_apply_params, permission_location_apply_result, permission_location_resolve_params, permission_location_resolve_result, permission_location_type, permission_mode_source, permission_paths_add_params, permission_paths_allowed_check_params, permission_paths_allowed_check_result, permission_paths_config, permission_paths_list, permission_paths_update_primary_params, permission_paths_workspace_check_params, permission_paths_workspace_check_result, permission_prompt_shown_notification, permission_request_result, permission_response_capability, permission_rules_set, permissions_configure_additional_content_exclusion_policy, permissions_configure_additional_content_exclusion_policy_rule, permissions_configure_additional_content_exclusion_policy_rule_source, permissions_configure_additional_content_exclusion_policy_scope, permissions_configure_params, permissions_configure_result, permissions_folder_trust_add_trusted_result, permissions_get_mode_request, permissions_get_mode_result, permissions_locations_add_tool_approval_details, permissions_locations_add_tool_approval_details_commands, permissions_locations_add_tool_approval_details_custom_tool, permissions_locations_add_tool_approval_details_extension_env_access, permissions_locations_add_tool_approval_details_extension_management, permissions_locations_add_tool_approval_details_extension_permission_access, permissions_locations_add_tool_approval_details_mcp, permissions_locations_add_tool_approval_details_mcp_sampling, permissions_locations_add_tool_approval_details_memory, permissions_locations_add_tool_approval_details_read, permissions_locations_add_tool_approval_details_workflow, permissions_locations_add_tool_approval_details_write, permissions_locations_add_tool_approval_result, permissions_modify_rules_params, permissions_modify_rules_result, permissions_modify_rules_scope, permissions_notify_prompt_shown_result, permissions_paths_add_result, permissions_paths_list_request, permissions_paths_update_primary_result, permissions_pending_requests_request, permissions_reset_session_approvals_request, permissions_reset_session_approvals_result, permissions_set_approve_all_request, permissions_set_approve_all_result, permissions_set_approve_all_source, permissions_set_mode_request, permissions_set_mode_result, permissions_set_required_request, permissions_set_required_result, permissions_urls_set_unrestricted_mode_result, permission_urls_config, permission_urls_set_unrestricted_mode_params, ping_request, ping_result, plan_read_result, plan_read_sql_todos_result, plan_read_sql_todos_with_dependencies_result, plan_sql_todo_dependency, plan_sql_todos_row, plan_update_request, plugin, plugin_install_result, plugin_install_staging_mode, plugin_list, plugin_list_result, plugins_builtin_set_request, plugins_disable_request, plugins_enable_request, plugins_install_request, plugins_marketplaces_add_request, plugins_marketplaces_browse_request, plugins_marketplaces_refresh_request, plugins_marketplaces_remove_request, plugins_reload_request, plugins_uninstall_request, plugins_update_request, plugin_update_all_entry, plugin_update_all_result, plugin_update_result, protocol_append_mode, protocol_customize_mode, protocol_external_tool_defer, protocol_external_tool_definition, protocol_marker_section_override, protocol_replace_mode, protocol_section_override, protocol_static_section_action, protocol_static_section_override, protocol_system_message_append_config, protocol_system_message_config, protocol_system_message_customize_config, protocol_system_message_replace_config, provider_add_request, provider_add_result, provider_config, provider_config_azure, provider_config_model_provider, provider_config_transport, provider_config_type, provider_config_wire_api, provider_descriptor, provider_endpoint, provider_endpoint_transport, provider_endpoint_type, provider_endpoint_wire_api, provider_get_endpoint_request, provider_model_config, provider_session_token, provider_sync_request, provider_sync_result, provider_token_acquire_request, provider_token_acquire_result, provider_withdraw_request, provider_withdraw_result, push_attachment, push_attachment_blob, push_attachment_directory, push_attachment_file, push_attachment_file_line_range, push_attachment_git_hub_actions_job, push_attachment_git_hub_commit, push_attachment_git_hub_file, push_attachment_git_hub_file_diff, push_attachment_git_hub_file_diff_side, push_attachment_git_hub_reference, push_attachment_git_hub_reference_type, push_attachment_git_hub_release, push_attachment_git_hub_repository, push_attachment_git_hub_snippet, push_attachment_git_hub_tree_comparison, push_attachment_git_hub_tree_comparison_side, push_attachment_git_hub_url, push_attachment_selection, push_attachment_selection_details, push_attachment_selection_details_end, push_attachment_selection_details_start, push_git_hub_repo_ref, queue_append_steering_request, queue_begin_deferred_idle_drain_request, queue_begin_deferred_idle_drain_result, queue_consume_system_notifications_request, queued_command_handled, queued_command_not_handled, queued_command_result, queue_defer_session_idle_request, queue_duplicate_at_request, queue_duplicate_at_result, queue_enqueue_resume_pending_result, queue_finish_deferred_idle_drain_request, queue_finish_deferred_idle_drain_result, queue_has_pending_result, queue_insert_at_request, queue_insert_at_result, queue_insert_message, queue_move_item_request, queue_move_item_result, queue_pending_items, queue_pending_items_kind, queue_pending_items_result, queue_remove_at_request, queue_remove_at_result, queue_remove_most_recent_result, queue_send_now_request, queue_send_now_result, queue_set_drain_paused_request, queue_snapshot_result, queue_update_text_request, queue_update_text_result, queue_withdraw_message_request, queue_withdraw_message_result, quota_take_warnings_result, quota_warning_projection, register_event_interest_params, register_event_interest_result, release_event_interest_params, remote_control_config, remote_control_config_existing_mc_session, remote_control_status, remote_control_status_active, remote_control_status_connecting, remote_control_status_error, remote_control_status_off, remote_control_status_result, remote_control_stop_result, remote_control_transfer_result, remote_enable_request, remote_enable_result, remote_notify_steerable_changed_request, remote_notify_steerable_changed_result, remote_session_connection_result, remote_session_host_status, remote_session_metadata_repository, remote_session_metadata_task_type, remote_session_metadata_value, remote_session_mode, remote_session_repository, repo_settings_read_raw_request, repo_settings_read_raw_result, repo_settings_write_all_request, repo_settings_write_key_request, response_format, sandbox_config, sandbox_config_auth, sandbox_config_source, sandbox_config_user_policy, sandbox_config_user_policy_experimental, sandbox_config_user_policy_experimental_seatbelt, sandbox_config_user_policy_filesystem, sandbox_config_user_policy_network, sandbox_config_user_policy_network_proxy, sandbox_config_user_policy_seatbelt, sandbox_credentials_config, sandbox_credential_suggestion, sandbox_credential_suggestions_result, sandbox_disable_for_session_request, sandbox_disable_for_session_result, sandbox_enforcement_status, sandbox_grant_path_for_request_request, sandbox_grant_path_for_request_result, sandbox_host_capability, sandbox_host_capability_name, sandbox_host_support, sandbox_masked_env_var, sandbox_proxy_ca_create_result, sandbox_proxy_ca_request, sandbox_proxy_ca_state, sandbox_proxy_ca_status, sandbox_session_change, schedule_add_at_request, schedule_add_cron_request, schedule_add_request, schedule_add_result, schedule_add_self_paced_request, schedule_entry, schedule_has_self_paced_result, schedule_list, schedule_rearm_self_paced_request, schedule_stop_request, schedule_stop_result, secrets_add_filter_values_request, secrets_add_filter_values_result, send_agent_mode, send_attachments_to_message_params, send_message_item, send_messages_request, send_messages_result, send_mode, send_request, send_result, send_system_notification_request, server_agent_list, server_instruction_source_list, server_skill, server_skill_list, session_activity, session_agent_list_request, session_auth_login_request, session_auth_logout_user_request, session_auth_status, session_auth_switch_request, session_bulk_delete_result, session_cancel_all_background_agents_result, session_capability, session_commands_list_request, session_completion_item, session_connected_ide_info, session_context, session_context_host_type, session_enrich_metadata_result, session_fs_append_file_request, session_fs_error, session_fs_error_code, session_fs_exists_request, session_fs_exists_result, session_fs_mkdir_request, session_fs_readdir_request, session_fs_readdir_result, session_fs_readdir_with_types_entry, session_fs_readdir_with_types_entry_type, session_fs_readdir_with_types_request, session_fs_readdir_with_types_result, session_fs_read_file_bytes_request, session_fs_read_file_bytes_result, session_fs_read_file_request, session_fs_read_file_result, session_fs_rename_request, session_fs_rm_request, session_fs_set_provider_capabilities, session_fs_set_provider_conventions, session_fs_set_provider_request, session_fs_set_provider_result, session_fs_sqlite_exists_request, session_fs_sqlite_exists_result, session_fs_sqlite_query_request, session_fs_sqlite_query_result, session_fs_sqlite_query_type, session_fs_sqlite_transaction_error, session_fs_sqlite_transaction_error_class, session_fs_sqlite_transaction_request, session_fs_sqlite_transaction_result, session_fs_sqlite_transaction_statement, session_fs_stat_request, session_fs_stat_result, session_fs_write_file_bytes_request, session_fs_write_file_request, session_git_hub_auth_get_all_auth_available_result, session_git_hub_auth_logout_result, session_git_hub_auth_logout_user_result, session_history_compact_request, session_installed_plugin, session_installed_plugin_source, session_installed_plugin_source_git_hub, session_installed_plugin_source_local, session_installed_plugin_source_url, session_limit_prediction_baseline_data, session_limit_prediction_client_type, session_limit_prediction_details, session_limit_prediction_predict_request, session_limit_prediction_request, session_limit_prediction_result, session_limit_prediction_source, session_limit_prediction_tier, session_limit_prediction_tier_option, session_limit_prediction_unavailable_reason, session_list, session_list_entry, session_list_filter, session_load_deferred_repo_hooks_result, session_log_level, session_managed_permissions, session_managed_settings, session_mcp_apps_call_tool_result, session_mcp_oauth_cancel_login_request, session_mcp_oauth_cancel_login_result, session_mcp_oauth_prepare_login_request, session_mcp_oauth_prepare_login_result, session_mcp_set_connected_ide_info_params, session_metadata_snapshot, session_mode, session_model_clear_startup_seed_request, session_model_clear_startup_seed_result, session_model_list, session_model_list_request, session_model_price_category, session_open_options, session_open_options_additional_content_exclusion_policy, session_open_options_additional_content_exclusion_policy_rule, session_open_options_additional_content_exclusion_policy_rule_source, session_open_options_additional_content_exclusion_policy_scope, session_open_options_env_value_mode, session_open_options_reasoning_summary, session_open_params, session_open_result, session_plugins_disable_request, session_plugins_enable_request, session_plugins_install_request, session_plugins_marketplaces_refresh_request, session_plugins_reload_request, session_plugins_retry_managed_request, session_plugins_retry_managed_result, session_provider_get_endpoint_request, session_prune_result, session_quota_delegate_warning, session_quota_get_result, session_quota_plan_tier, session_quota_projection, session_quota_refresh_result, session_quota_snapshot, session_quota_take_warnings_result, sessions_bulk_delete_request, sessions_check_in_use_request, sessions_check_in_use_result, sessions_client_metadata_entry, sessions_close_request, sessions_close_result, sessions_create_workspace_request, sessions_create_workspace_result, sessions_delete_request, sessions_enrich_metadata_request, session_set_credentials_params, session_set_credentials_result, session_settings_built_in_tool_availability_snapshot, session_settings_evaluate_predicate_request, session_settings_evaluate_predicate_result, session_settings_job_snapshot, session_settings_model_snapshot, session_settings_online_evaluation_snapshot, session_settings_predicate_name, session_settings_repo_snapshot, session_settings_snapshot, session_settings_validation_snapshot, sessions_find_by_prefix_request, sessions_find_by_prefix_result, sessions_find_by_task_id_request, sessions_find_by_task_id_result, sessions_fork_request, sessions_fork_result, sessions_get_board_entry_count_request, sessions_get_board_entry_count_result, sessions_get_client_metadata_request, sessions_get_client_metadata_result, sessions_get_event_file_path_request, sessions_get_event_file_path_result, sessions_get_last_for_context_request, sessions_get_last_for_context_result, sessions_get_metadata_request, sessions_get_metadata_result, sessions_get_persisted_remote_steerable_request, sessions_get_persisted_remote_steerable_result, session_sizes, sessions_list_non_empty_session_ids_request, sessions_list_non_empty_session_ids_result, sessions_list_request, sessions_load_deferred_repo_hooks_request, sessions_load_workspace_request, sessions_load_workspace_result, sessions_open_attach, sessions_open_cloud, sessions_open_create, sessions_open_handoff, sessions_open_handoff_task_type, sessions_open_progress, sessions_open_progress_status, sessions_open_progress_step, sessions_open_remote, sessions_open_resume, sessions_open_resume_last, sessions_open_status, session_source, sessions_prune_old_request, sessions_read_persisted_events_request, sessions_release_lock_request, sessions_release_lock_result, sessions_reload_plugin_hooks_request, sessions_reload_plugin_hooks_result, sessions_save_request, sessions_save_result, sessions_set_additional_plugins_request, sessions_set_additional_plugins_result, sessions_set_remote_control_steering_request, sessions_start_remote_control_request, sessions_stop_remote_control_request, sessions_transfer_remote_control_request, sessions_update_workspace_fields_request, sessions_update_workspace_fields_result, session_telemetry_engagement, session_update_options_params, session_update_options_result, session_usage_set_code_changes_request, session_visibility_status, session_workflow_pause_at_checkpoint_result, session_working_directory_context, session_working_directory_context_host_type, session_working_directory_context_with_client, settable_auth_info, settable_token_auth_info, settings_edit_operation, settings_edit_result, settings_edit_status, shell_cancel_user_requested_request, shell_credentials, shell_exec_request, shell_exec_result, shell_execute_user_requested_request, shell_init_profile, shell_init_script, shell_init_script_shell, shell_kill_request, shell_kill_result, shell_kill_signal, shell_options, shutdown_request, skill, skill_apply_install_request, skill_apply_uninstall_request, skill_discovery_path, skill_discovery_path_list, skill_discovery_scope, skill_installation_failure_reason, skill_installation_file_review, skill_installation_location, skill_installation_management_outcome, skill_installation_management_result, skill_installation_operation_request, skill_installation_operation_status, skill_installation_outcome, skill_installation_ownership_state, skill_installation_result, skill_installation_review, skill_installation_scope, skill_installation_session_state, skill_installation_source, skill_installations_request, skill_installation_summary, skill_install_plan, skill_list, skill_plan_install_request, skill_plan_uninstall_request, skill_provider_descriptor, skill_provider_list_request, skill_provider_list_result, skill_provider_read_request, skill_provider_read_result, skills_config_set_disabled_skills_request, skills_config_set_skill_disabled_request, skills_disable_request, skills_discover_request, skills_enable_request, skill_set_enabled_request, skills_get_discovery_paths_request, skills_get_invoked_result, skills_invoked_skill, skills_load_diagnostics, skill_uninstall_plan, slash_command_add_timeline_entry_result, slash_command_agent_prompt_result, slash_command_completed_result, slash_command_info, slash_command_input, slash_command_input_choice, slash_command_input_completion, slash_command_invocation_result, slash_command_kind, slash_command_model_picker_dialog, slash_command_select_subcommand_option, slash_command_select_subcommand_result, slash_command_set_model_result, slash_command_set_plan_model_result, slash_command_show_dialog_result, slash_command_text_result, slash_command_timeline_entry, subagent_settings_entry, subagent_settings_entry_context_tier, system_message_block, task_agent_info, task_agent_progress, task_client_active_status, task_client_execution_mode, task_client_info, task_client_owner, task_client_owner_kind, task_client_owner_presence, task_client_progress, task_client_status, task_client_type, task_client_update, task_complete_data, task_completion_decision, task_execution_mode, task_info, task_kind, task_list, task_progress_line, tasks_cancel_request, tasks_cancel_result, tasks_get_current_promotable_result, tasks_get_progress_request, tasks_get_progress_result, task_shell_info, task_shell_info_attachment_mode, task_shell_progress, tasks_promote_current_to_background_result, tasks_promote_to_background_request, tasks_promote_to_background_result, tasks_refresh_result, tasks_register_request, tasks_register_result, tasks_remove_request, tasks_remove_result, tasks_send_message_request, tasks_send_message_result, tasks_start_agent_request, tasks_start_agent_result, task_status, tasks_update_request, tasks_update_result, tasks_wait_for_pending_result, telemetry_set_feature_overrides_request, token_auth_info, token_provider_auth_info, tool, tool_list, tool_result, tool_result_expanded, tool_result_new_message, tool_result_type, tools_execute_request, tools_get_builtin_descriptors_request, tools_get_builtin_descriptors_result, tools_get_current_metadata_result, tools_initialize_and_validate_result, tools_list_pending_requests_request, tools_list_request, tools_set_request, tools_set_result, tools_shell_descriptor_config, tools_task_complete_event_data_request, tools_update_subagent_settings_result, ui_auto_mode_switch_response, ui_elicitation_array_any_of_field, ui_elicitation_array_any_of_field_items, ui_elicitation_array_any_of_field_items_any_of, ui_elicitation_array_enum_field, ui_elicitation_array_enum_field_items, ui_elicitation_field_value, ui_elicitation_request, ui_elicitation_response, ui_elicitation_response_action, ui_elicitation_response_content, ui_elicitation_result, ui_elicitation_schema, ui_elicitation_schema_property, ui_elicitation_schema_property_boolean, ui_elicitation_schema_property_number, ui_elicitation_schema_property_number_type, ui_elicitation_schema_property_string, ui_elicitation_schema_property_string_format, ui_elicitation_string_enum_field, ui_elicitation_string_one_of_field, ui_elicitation_string_one_of_field_one_of, ui_ephemeral_query_request, ui_ephemeral_query_result, ui_exit_plan_mode_action, ui_exit_plan_mode_response, ui_handle_pending_auto_mode_switch_request, ui_handle_pending_elicitation_request, ui_handle_pending_exit_plan_mode_request, ui_handle_pending_result, ui_handle_pending_sampling_request, ui_handle_pending_sampling_response, ui_handle_pending_session_limits_exhausted_request, ui_handle_pending_user_input_request, ui_register_direct_auto_mode_switch_handler_result, ui_session_limits_exhausted_response, ui_session_limits_exhausted_response_action, ui_unregister_direct_auto_mode_switch_handler_request, ui_unregister_direct_auto_mode_switch_handler_result, ui_user_input_response, unsupported_enqueue_command_result, update_subagent_settings_request, usage_get_metrics_result, usage_set_code_changes_request, user_auth_info, user_requested_shell_command_result, user_setting_metadata, user_settings_apply_top_key_request, user_settings_apply_top_key_result, user_settings_edit_request, user_settings_get_paths_request, user_settings_get_paths_result, user_settings_get_result, user_settings_governance_keys_result, user_settings_load_for_edit_result, user_settings_normalize_request, user_settings_normalize_result, user_settings_problem, user_settings_problem_location, user_settings_problem_source, user_settings_problems_request, user_settings_problems_result, user_settings_set_request, user_settings_update_request, user_settings_update_result, user_settings_validate_request, user_settings_validate_result, user_settings_validation_issue, user_settings_write_all_request, visibility_get_result, visibility_set_request, visibility_set_result, workflow_abort_request, workflow_ack_result, workflow_agent_options, workflow_agent_request, workflow_agent_result, workflow_agent_summary, workflow_cancel_request, workflow_current_phase, workflow_declared_limits, workflow_durable_operation, workflow_execute_request, workflow_execute_result, workflow_get_run_progress_request, workflow_get_run_request, workflow_journal_get_request, workflow_journal_get_result, workflow_journal_put_request, workflow_list_runs_request, workflow_list_runs_result, workflow_log_line, workflow_log_line_kind, workflow_log_request, workflow_pause_checkpoint_action, workflow_pause_checkpoint_request, workflow_pause_checkpoint_result, workflow_pause_info, workflow_pause_request, workflow_phase_observation, workflow_phase_status, workflow_progress_line, workflow_progress_page, workflow_resume_request, workflow_resume_result, workflow_run_consumed, workflow_run_detail, workflow_run_failure, workflow_run_failure_kind, workflow_run_limits, workflow_run_options, workflow_run_request, workflow_run_result, workflow_run_status, workflow_run_summary, workflow_run_terminal, workflow_tool_resume_request, workflow_tool_run_options, workflow_tool_run_request, workspace_diff_contents, workspace_diff_file_change, workspace_diff_file_change_type, workspace_diff_mode, workspace_diff_result, workspaces_add_summary_request, workspaces_add_summary_result, workspaces_autopilot_objective_exists_result, workspaces_checkpoints, workspaces_create_directory_request, workspaces_create_file_request, workspaces_delete_autopilot_objective_result, workspaces_diff_request, workspaces_ensure_request, workspaces_get_workspace_result, workspaces_list_checkpoints_result, workspaces_list_files_result, workspaces_read_autopilot_objective_result, workspaces_read_checkpoint_request, workspaces_read_checkpoint_result, workspaces_read_file_request, workspaces_read_file_result, workspaces_remove_path_request, workspaces_rename_path_request, workspaces_save_large_paste_request, workspaces_save_large_paste_result, workspaces_stat_file_request, workspaces_stat_file_result, workspaces_truncate_summaries_request, workspace_summary_host_type, workspaces_update_metadata_request, workspaces_workspace_details_host_type, workspaces_write_autopilot_objective_request, workspaces_write_autopilot_objective_result, connector_session_account_result, session_auth_info_result, session_context_attribution, session_context_info, subagent_settings, task_progress, workspace_summary) + return RPC(abort_request, abort_result, accepted_enqueue_command_result, account_all_users, account_auth_info, account_describe_auth_info_request, account_describe_auth_info_result, account_get_all_users_result, account_get_current_auth_result, account_get_gist_support_request, account_get_gist_support_result, account_get_quota_request, account_get_quota_result, account_get_token_env_var_result, account_get_web_url_request, account_get_web_url_result, account_kind, account_login_request, account_login_result, account_logout_request, account_logout_result, account_quota_snapshot, accounts_enumerate_request, accounts_get_request, accounts_set_request, account_status, adaptive_thinking_support, agent_discovery_path, agent_discovery_path_list, agent_discovery_path_scope, agent_get_current_result, agent_info, agent_info_source, agent_list, agent_list_request, agent_registry_live_target_entry, agent_registry_live_target_entry_attention_kind, agent_registry_live_target_entry_kind, agent_registry_live_target_entry_last_terminal_event, agent_registry_live_target_entry_status, agent_registry_log_capture, agent_registry_log_capture_open_error_reason, agent_registry_spawn_error, agent_registry_spawn_permission_mode, agent_registry_spawn_registry_timeout, agent_registry_spawn_request, agent_registry_spawn_result, agent_registry_spawn_spawned, agent_registry_spawn_validation_error, agent_registry_spawn_validation_error_field, agent_registry_spawn_validation_error_reason, agent_reload_result, agents_custom_agent_initial_model_decision_params, agents_custom_agent_initial_model_decision_result, agents_discover_request, agent_select_request, agent_select_result, agent_set_prompt_request, agents_get_available_builtins_request, agents_get_available_builtins_result, agents_get_builtin_definition_request, agents_get_builtin_definition_result, agents_get_builtin_listing_definition_request, agents_get_builtin_listing_definition_result, agents_get_builtins_result, agents_get_discovery_paths_request, api_key_auth_info, auth_enumerate_query, auth_enumerate_value, auth_identity, auth_identity_metadata, auth_info, auth_info_type, auth_login_account, auth_login_advance_request, auth_login_begin_request, auth_login_begun, auth_login_cancel_request, auth_login_result_dto, auth_login_result_status, auth_login_step, auth_read_query, auth_read_value, auth_status_dto, auth_validation_error, auth_validation_errors, auth_write, auth_write_result, autopilot_objective_credit_limit, autopilot_objective_get_state_result, autopilot_objective_state, autopilot_objective_status, auto_tier_descriptor, auto_tier_metadata, auto_tier_status, builtin_agent_summary, built_in_model_catalog, built_in_model_catalog_entry, builtin_tool_descriptor, builtin_tool_format, builtin_tool_format_type, builtin_tool_input_schema, builtin_tool_input_schema_type, builtin_tool_safe_for_telemetry, builtin_tool_safe_telemetry_fields, cancel_user_requested_shell_command_result, canvas_action, canvas_action_invoke_request, canvas_action_invoke_result, canvas_close_request, canvas_host_context, canvas_host_context_capabilities, canvas_json_schema, canvas_list, canvas_list_open_result, canvas_open_request, canvas_provider_close_request, canvas_provider_invoke_action_request, canvas_provider_open_request, canvas_provider_open_result, canvas_provider_register_request, canvas_provider_unregister_request, canvas_session_context, capi_session_options, card_digest, card_digest_algorithm, card_digest_value, catalog_agent_plugin_candidate, catalog_agent_plugin_candidate_kind, catalog_agent_plugin_candidate_provenance, catalog_agent_plugin_compatibility_tag, catalog_agent_plugin_media_type, catalog_ai_skill_candidate, catalog_ai_skill_candidate_kind, catalog_ai_skill_candidate_provenance, catalog_ai_skill_installability, catalog_ai_skill_media_type, catalog_authentication_required_error, catalog_authentication_required_reason, catalog_candidate, catalog_candidate_kind, catalog_candidate_source, catalog_candidate_source_embedded, catalog_candidate_source_url, catalog_capability, catalog_capability_id, catalog_client_contract, catalog_contract_violation_error, catalog_contract_violation_reason, catalog_handle_rejected_error, catalog_handle_rejection_reason, catalog_handle_type, catalog_invalid_request_error, catalog_invalid_request_field, catalog_malformed_card_error, catalog_malformed_card_reason, catalog_mcp_server_candidate, catalog_mcp_server_candidate_kind, catalog_mcp_server_candidate_provenance, catalog_mcp_server_installability, catalog_media_type, catalog_negotiated_contract, catalog_negotiation_refused_error, catalog_negotiation_refused_reason, catalog_network_failure_error, catalog_network_failure_reason, catalog_not_installable_error, catalog_not_installable_reason, catalog_plugin_repository_source, catalog_policy_rejected_error, catalog_resource_identity, catalog_resource_version, catalog_search_page, catalog_search_pagination, catalog_search_request, catalog_search_result, catalog_search_succeeded, catalog_search_total_count_relation, catalog_selection_cancelled, catalog_selection_decision, catalog_selection_declined, catalog_selection_foreign, catalog_selection_invalid, catalog_selection_replayed, catalog_selection_request, catalog_selection_result, catalog_selection_selected, catalog_selection_stale, catalog_selection_timed_out, catalog_selection_wrong_kind, catalog_trust_eligibility, catalog_trust_provenance, catalog_trust_snapshot, catalog_trust_snapshot_absent, catalog_trust_snapshot_absent_status, catalog_trust_snapshot_current, catalog_trust_snapshot_current_status, catalog_trust_snapshot_downgraded, catalog_trust_snapshot_downgraded_status, catalog_trust_snapshot_malformed, catalog_trust_snapshot_malformed_status, catalog_trust_snapshot_revoked, catalog_trust_snapshot_revoked_status, catalog_trust_snapshot_schema_version, catalog_trust_snapshot_stale, catalog_trust_snapshot_stale_status, catalog_trust_snapshot_unsupported, catalog_trust_snapshot_unsupported_status, catalog_trust_source, catalog_trust_tier, catalog_unavailable_error, catalog_unavailable_reason, catalog_unavailable_transport_error, catalog_unavailable_transport_reason, catalog_unsafe_retrieval_error, catalog_unsafe_retrieval_reason, catalog_unsupported_kind_error, client_metadata, client_task_cancel_reason, client_task_cancel_request, client_task_cancel_result, command_list, commands_finalize_invocation_effect_request, commands_finalize_invocation_effect_result, commands_handle_pending_command_request, commands_handle_pending_command_result, commands_invocation_effect_outcome, commands_invocation_origin, commands_invoke_request, commands_list_request, commands_respond_to_queued_command_request, commands_respond_to_queued_command_result, completions_get_trigger_characters_result, completions_request_request, completions_request_result, configure_session_extensions_params, connect_client_info, connected_remote_session_metadata, connected_remote_session_metadata_kind, connected_remote_session_metadata_repository, connector_account_request, connector_authorization_requirement, connector_authorization_scope, connector_availability, connector_capabilities, connector_catalog_entry, connector_catalog_result, connector_catalog_status, connector_connect_request, connector_connect_result, connector_continue_request, connector_disconnect_result, connector_discovery_account, connector_discovery_account_list, connector_discovery_account_request, connector_discovery_auth_info, connector_discovery_availability, connector_discovery_capabilities, connector_discovery_catalog_entry, connector_discovery_catalog_result, connector_mcp_status, connector_reconcile_request, connector_runtime_status, connector_session_account, connector_status, connect_remote_session_params, connect_request, connect_result, content_exclusion_check_paths_request, content_exclusion_check_paths_result, content_exclusion_path_check, content_filter_mode, context_heaviest_message, copilot_api_token_auth_info, copilot_user_response, copilot_user_response_endpoints, copilot_user_response_quota_snapshots, copilot_user_response_quota_snapshots_chat, copilot_user_response_quota_snapshots_completions, copilot_user_response_quota_snapshots_premium_interactions, current_model, current_tool_metadata, customization_reload_outcome, customization_reload_status, customization_reload_subsystem, customizations_reload_result, debug_collect_logs_collected_entry, debug_collect_logs_destination, debug_collect_logs_entry, debug_collect_logs_entry_kind, debug_collect_logs_include, debug_collect_logs_redaction, debug_collect_logs_request, debug_collect_logs_result, debug_collect_logs_result_kind, debug_collect_logs_skipped_entry, debug_collect_logs_source, diagnostic_cursor_status, diagnostic_entry, diagnostic_log_level, diagnostics_configuration, diagnostics_configure_request, diagnostic_severity, diagnostic_source, diagnostic_sources_configuration, diagnostics_read_request, diagnostics_read_result, discovered_canvas, discovered_extension, discovered_extension_mode, discovered_extension_plugin, discovered_extensions, discovered_extensions_disable_request, discovered_extensions_enable_request, discovered_extension_source, discovered_hook, discovered_mcp_server, discovered_mcp_server_type, discovered_model, discovered_model_list, enqueue_command_params, enqueue_command_result, env_auth_info, environment_capabilities, environment_kind, environments_delete_request, environments_delete_result, environments_get_request, environments_get_result, environments_list_request, environments_list_result, event_log_read_request, event_log_release_interest_result, event_log_tail_result, event_log_types, events_agent_scope, events_cursor_status, events_read_direction, events_read_result, execute_command_params, execute_command_result, extension, extension_context_push_input, extension_launch_profile, extension_launch_provider_resolve_request, extension_launch_provider_resolve_result, extension_list, extensions_disable_request, extensions_enable_request, extension_source, extension_status, external_tool_result, external_tool_text_result_for_llm, external_tool_text_result_for_llm_binary_results_for_llm, external_tool_text_result_for_llm_binary_results_for_llm_type, external_tool_text_result_for_llm_content, external_tool_text_result_for_llm_content_audio, external_tool_text_result_for_llm_content_image, external_tool_text_result_for_llm_content_resource, external_tool_text_result_for_llm_content_resource_details, external_tool_text_result_for_llm_content_resource_link, external_tool_text_result_for_llm_content_resource_link_icon, external_tool_text_result_for_llm_content_resource_link_icon_theme, external_tool_text_result_for_llm_content_shell_exit, external_tool_text_result_for_llm_content_terminal, external_tool_text_result_for_llm_content_text, feature_flag_availability, feature_flag_metadata, feature_flags_metadata_result, feature_flags_resolve_request, feature_flags_resolve_result, feature_flags_resolve_startup_gates_request, feature_flags_resolve_startup_gates_result, filter_mapping, fleet_start_request, fleet_start_result, folder_trust_add_params, folder_trust_check_params, folder_trust_check_result, folder_trust_is_trusted_params, force_login_orgs_decision, gh_cli_auth_info, git_current_branch_remote_result, git_cwd_request, git_hub_environment, git_hub_owner_option, git_hub_owners_cancel_request, git_hub_owners_cancel_result, git_hub_owners_list_request, git_hub_owners_list_result, git_hub_owners_request_id_result, git_hub_repository_at_path_request, git_hub_repository_at_path_result, git_hub_repository_identity, git_hub_telemetry_client_info, git_hub_telemetry_event, git_hub_telemetry_notification, git_hub_token_acquire_reason, git_hub_token_acquire_request, git_hub_token_acquire_result, git_remote_repository, git_repos_from_remotes_request, git_repos_from_remotes_result, global_state_load_for_config_dir_request, global_state_load_result, global_state_write_key_request, handle_pending_tool_call_request, handle_pending_tool_call_result, history_abort_manual_compaction_result, history_cancel_background_compaction_result, history_clear_context_request, history_clear_context_result, history_compact_context_window, history_compact_request, history_compact_result, history_file_restore_skip_reason, history_list_rewind_points_result, history_preview_rewind_request, history_preview_rewind_result, history_rewind_change_type, history_rewind_file_preview, history_rewind_mode, history_rewind_outcome, history_rewind_point, history_rewind_request, history_rewind_result, history_rewind_unavailable_reason, history_skipped_file_restore, history_summarize_for_handoff_result, history_truncate_request, history_truncate_result, hmac_auth_info, hook_invoke_request, hook_invoke_response, hook_origin, hooks_discover_request, hooks_discover_result, hook_type, host_configuration, host_dispose_request, host_empty_result, host_environment_credentials, host_exited_notification, host_exit_reason, host_git_hub_environment_options, host_list_sessions_request, host_list_sessions_result, host_local_server_configuration, host_local_server_options, host_publish_session_request, host_publish_session_result, host_ready_request, host_register_session_request, host_session_create_callback, host_session_create_request, host_session_create_result, host_session_released_notification, host_session_release_request, host_session_summary, host_start_request, host_start_result, installation_catalogue_identity, installation_confirmation_request, installation_confirmation_response, installation_decision, installation_review, installed_plugin, installed_plugin_info, installed_plugin_source, installed_plugin_source_git_hub, installed_plugin_source_local, installed_plugin_source_url, instruction_discovery_path, instruction_discovery_path_kind, instruction_discovery_path_list, instruction_discovery_path_location, instructions_discover_repo_sources_request, instructions_discover_request, instructions_get_discovery_paths_request, instructions_get_sources_result, instructions_init_prompt_result, instruction_source, instruction_source_location, instruction_source_type, interrupt_main_turn_request, interrupt_main_turn_result, json_schema_response_format, llm_inference_headers, llm_inference_http_request_chunk_request, llm_inference_http_request_chunk_result, llm_inference_http_request_start_request, llm_inference_http_request_start_result, llm_inference_http_request_start_transport, llm_inference_http_response_chunk_error, llm_inference_http_response_chunk_request, llm_inference_http_response_chunk_result, llm_inference_http_response_start_request, llm_inference_http_response_start_result, llm_inference_set_provider_result, local_session_metadata_value, location_permissions_cleanup_result, logged_in_user, login_provider_kind, log_request, log_result, lsp_initialize_request, managed_mcp_server_config, managed_permission_evaluation, managed_permission_operation, managed_permission_operation_kind, managed_permissions_evaluate_request, managed_permissions_evaluate_result, managed_permission_verdict, managed_plugin_retry_entry, managed_plugin_retry_status, managed_setting_meta, managed_settings_apply_controls_params, managed_settings_apply_controls_result, managed_settings_bypass_disable_source, managed_settings_bypass_policy_resolution, managed_settings_channel, managed_settings_compose_layer, managed_settings_compose_request, managed_settings_compose_result, managed_settings_diagnostic, managed_settings_diagnostic_severity, managed_settings_ingest_params, managed_settings_ingest_result, managed_settings_layer, managed_settings_load_remote_control_params, managed_settings_load_remote_control_result, managed_settings_log_level, managed_settings_log_message, managed_settings_meta, managed_settings_parse_client_value_params, managed_settings_parse_client_value_result, managed_settings_policy_helper_authority, managed_settings_policy_helper_reason, managed_settings_read_device_result, managed_settings_read_result, managed_settings_resolve_bypass_disable_transition_params, managed_settings_resolve_bypass_disable_transition_result, managed_settings_resolved_data, managed_settings_resolve_device_force_login_orgs_gate_params, managed_settings_resolve_effective_value_params, managed_settings_resolve_effective_value_result, managed_settings_resolve_request, managed_settings_resolve_result, managed_settings_resolve_startup_policy_params, managed_settings_resolve_startup_policy_result, managed_settings_retain_policy_params, managed_settings_schema_result, managed_settings_server_policy_cache_mode, managed_settings_server_policy_resolution, managed_settings_validate_request, managed_settings_validate_result, managed_settings_values, marketplace_add_result, marketplace_browse_result, marketplace_info, marketplace_list_result, marketplace_plugin_info, marketplace_refresh_entry, marketplace_refresh_result, marketplace_remove_result, mcp_allowed_server, mcp_apply_install_request, mcp_apply_uninstall_request, mcp_apps_call_tool_request, mcp_apps_diagnose_capability, mcp_apps_diagnose_request, mcp_apps_diagnose_result, mcp_apps_diagnose_server, mcp_apps_host_context, mcp_apps_host_context_details, mcp_apps_host_context_details_available_display_mode, mcp_apps_host_context_details_display_mode, mcp_apps_host_context_details_platform, mcp_apps_host_context_details_theme, mcp_apps_list_tools_request, mcp_apps_list_tools_result, mcp_apps_read_resource_request, mcp_apps_read_resource_result, mcp_apps_resource_content, mcp_apps_set_host_context_details, mcp_apps_set_host_context_details_available_display_mode, mcp_apps_set_host_context_details_display_mode, mcp_apps_set_host_context_details_platform, mcp_apps_set_host_context_details_theme, mcp_apps_set_host_context_request, mcp_cancel_sampling_execution_params, mcp_cancel_sampling_execution_result, mcp_config_add_request, mcp_config_disable_request, mcp_config_enable_request, mcp_config_list, mcp_config_remove_request, mcp_config_update_request, mcp_configured_server, mcp_configured_server_list, mcp_configured_server_state, mcp_configure_git_hub_request, mcp_configure_git_hub_result, mcp_diagnostic_details, mcp_diagnostic_direction, mcp_diagnostic_kind, mcp_diagnostic_source_configuration, mcp_disable_request, mcp_discover_request, mcp_discover_result, mcp_elicitation_form_mode, mcp_enable_request, mcp_execute_sampling_params, mcp_execute_sampling_request, mcp_execute_sampling_result, mcp_failed_server, mcp_filtered_server, mcp_headers_handle_pending_headers_refresh_request, mcp_headers_handle_pending_headers_refresh_request_request, mcp_headers_handle_pending_headers_refresh_request_result, mcp_host_state, mcp_installation_failure_reason, mcp_installation_input, mcp_installation_management_outcome, mcp_installation_management_result, mcp_installation_operation_request, mcp_installation_operation_status, mcp_installation_outcome, mcp_installation_remote_configuration, mcp_installation_result, mcp_installation_review, mcp_installation_secret, mcp_installation_secret_storage, mcp_installations_request, mcp_installation_state, mcp_installation_summary, mcp_install_plan, mcp_is_server_running_request, mcp_is_server_running_result, mcp_list_builtin_server_names_result, mcp_list_tools_request, mcp_list_tools_result, mcp_oauth_authentication_state_changed_request, mcp_oauth_cancel_login_request, mcp_oauth_cancel_login_result, mcp_oauth_complete_request, mcp_oauth_handle_pending_request, mcp_oauth_handle_pending_result, mcp_oauth_login_grant_type, mcp_oauth_login_request, mcp_oauth_login_result, mcp_oauth_pending_request_response, mcp_oauth_prepare_login_request, mcp_oauth_prepare_login_result, mcp_oauth_probe_needs_auth_reason, mcp_oauth_probe_request, mcp_oauth_probe_result, mcp_oauth_respond_request, mcp_oauth_respond_result, mcp_owned_oauth_login_status, mcp_plan_configuration_change, mcp_plan_configuration_operation, mcp_plan_enum_value_type, mcp_plan_install_planned, mcp_plan_install_request, mcp_plan_install_result, mcp_plan_install_source, mcp_plan_install_source_candidate, mcp_plan_install_source_candidate_kind, mcp_plan_install_source_card, mcp_plan_install_source_card_kind, mcp_plan_package_install_method, mcp_plan_package_transport, mcp_plan_policy_decision, mcp_plan_policy_result, mcp_plan_policy_source, mcp_plan_provenance, mcp_plan_remote_install_method, mcp_plan_remote_transport, mcp_plan_required_value, mcp_plan_required_value_enum, mcp_plan_required_value_enum_kind, mcp_plan_required_value_scalar, mcp_plan_required_value_scalar_kind, mcp_plan_resource_identity, mcp_plan_scalar_value_type, mcp_plan_scope, mcp_plan_secret_placeholder, mcp_plan_secret_reference, mcp_plan_target, mcp_plan_transport_choice, mcp_plan_transport_choice_package, mcp_plan_transport_choice_remote, mcp_plan_uninstall_request, mcp_plan_value_category, mcp_prepared_install, mcp_prepare_install_request, mcp_prompt, mcp_prompt_argument, mcp_prompt_icon, mcp_prompt_message, mcp_prompt_role, mcp_prompts_get_request, mcp_prompts_get_result, mcp_prompts_list_request, mcp_prompts_list_result, mcp_register_external_client_request, mcp_registry_cancel_request, mcp_registry_cancel_result, mcp_registry_request_id_result, mcp_registry_search_request, mcp_registry_search_result, mcp_reload_config, mcp_reload_with_config_request, mcp_remove_git_hub_result, mcp_resource, mcp_resource_annotations, mcp_resource_content, mcp_resource_icon, mcp_resources_list_request, mcp_resources_list_result, mcp_resources_list_templates_request, mcp_resources_list_templates_result, mcp_resources_read_request, mcp_resources_read_result, mcp_resource_template, mcp_restart_server_request, mcp_safe_for_telemetry, mcp_safe_for_telemetry_fields, mcp_sampling_execution_action, mcp_sampling_execution_result, mcp_serializable_server_config, mcp_server, mcp_server_auth_config, mcp_server_auth_config_redirect_port, mcp_server_card_embedded, mcp_server_card_embedded_kind, mcp_server_card_media_type, mcp_server_card_reference, mcp_server_card_url, mcp_server_card_url_kind, mcp_server_config, mcp_server_config_defer_tools, mcp_server_config_http, mcp_server_config_http_oauth_grant_type, mcp_server_config_http_type, mcp_server_config_memory, mcp_server_config_memory_type, mcp_server_config_stdio, mcp_server_config_stdio_type, mcp_server_failure_info, mcp_server_list, mcp_server_needs_auth_info, mcp_server_ownership, mcp_set_env_value_mode_details, mcp_set_env_value_mode_params, mcp_set_env_value_mode_result, mcp_should_exclude_git_hub_tools_request, mcp_should_exclude_git_hub_tools_result, mcp_source_file, mcp_source_plugin, mcp_source_ref, mcp_start_server_request, mcp_start_servers_result, mcp_stop_server_request, mcp_task_metadata, mcp_tools, mcp_tool_ui, mcp_tool_ui_visibility, mcp_uninstall_plan, mcp_unregister_external_client_request, memory_configuration, metadata_context_attribution_result, metadata_context_heaviest_messages_request, metadata_context_heaviest_messages_result, metadata_context_info_request, metadata_context_info_result, metadata_is_processing_result, metadata_recompute_context_tokens_request, metadata_recompute_context_tokens_result, metadata_record_context_change_request, metadata_record_context_change_result, metadata_set_working_directory_request, metadata_set_working_directory_result, metadata_snapshot_current_mode, metadata_snapshot_remote_metadata, metadata_snapshot_remote_metadata_repository, metadata_snapshot_remote_metadata_task_type, metadata_update_client_metadata_request, model, model_apply_startup_overlay_request, model_artifact_details, model_billing, model_billing_promo, model_billing_token_prices, model_billing_token_prices_long_context, model_capabilities, model_capabilities_limits, model_capabilities_limits_vision, model_capabilities_override, model_capabilities_override_limits, model_capabilities_override_limits_vision, model_capabilities_override_supports, model_capabilities_supports, model_clear_startup_seed_request, model_clear_startup_seed_result, model_get_reasoning_summaries_request, model_get_reasoning_summaries_result, model_list, model_list_request, model_message, model_picker_category, model_picker_persistence_request, model_picker_price_category, model_picker_settings_context, model_policy, model_policy_state, model_provider_adapter_catalog, model_provider_adapter_descriptor, model_provider_adapter_operation_descriptor, model_provider_attribution, model_provider_automatic_discovery_mode, model_provider_automatic_discovery_policy, model_provider_configuration_disposition, model_provider_configuration_plan, model_provider_descriptor, model_provider_discover_request, model_provider_discover_result, model_provider_discovery_network_scope, model_provider_get_status_request, model_provider_instance, model_provider_instance_reference, model_provider_models_list_request, model_provider_operation_outcome, model_provider_operation_outcome_code, model_provider_prepare_configuration_request, model_provider_provenance, model_provider_provenance_source, model_provider_status, model_provider_warning, model_set_allowed_models_request, model_set_allowed_models_result, model_set_reasoning_effort_request, model_set_reasoning_effort_result, models_list_request, model_switch_auto_tier_request, model_switch_auto_tier_result, model_switch_auto_tier_status, model_switch_confirmation, model_switch_to_request, model_switch_to_result, model_warning_text, mode_set_request, mode_set_result, move_mcp_loading_to_background_result, named_provider_config, name_get_result, name_set_auto_request, name_set_auto_result, name_set_request, open_canvas_instance, options_update_additional_content_exclusion_policy, options_update_additional_content_exclusion_policy_rule, options_update_additional_content_exclusion_policy_rule_source, options_update_additional_content_exclusion_policy_scope, options_update_context_tier, options_update_env_value_mode, options_update_reasoning_summary, options_update_tool_filter_precedence, pending_external_tool_request, pending_external_tool_request_list, pending_permission_request, pending_permission_request_list, permission_decision, permission_decision_approved, permission_decision_approved_for_location, permission_decision_approved_for_session, permission_decision_approve_for_location, permission_decision_approve_for_location_approval, permission_decision_approve_for_location_approval_commands, permission_decision_approve_for_location_approval_custom_tool, permission_decision_approve_for_location_approval_extension_env_access, permission_decision_approve_for_location_approval_extension_management, permission_decision_approve_for_location_approval_extension_permission_access, permission_decision_approve_for_location_approval_mcp, permission_decision_approve_for_location_approval_mcp_sampling, permission_decision_approve_for_location_approval_memory, permission_decision_approve_for_location_approval_read, permission_decision_approve_for_location_approval_workflow, permission_decision_approve_for_location_approval_write, permission_decision_approve_for_session, permission_decision_approve_for_session_approval, permission_decision_approve_for_session_approval_commands, permission_decision_approve_for_session_approval_custom_tool, permission_decision_approve_for_session_approval_extension_env_access, permission_decision_approve_for_session_approval_extension_management, permission_decision_approve_for_session_approval_extension_permission_access, permission_decision_approve_for_session_approval_mcp, permission_decision_approve_for_session_approval_mcp_sampling, permission_decision_approve_for_session_approval_memory, permission_decision_approve_for_session_approval_read, permission_decision_approve_for_session_approval_workflow, permission_decision_approve_for_session_approval_write, permission_decision_approve_once, permission_decision_approve_permanently, permission_decision_approve_read_only_for_session, permission_decision_cancelled, permission_decision_context, permission_decision_denied_by_content_exclusion_policy, permission_decision_denied_by_permission_request_hook, permission_decision_denied_by_rules, permission_decision_denied_interactively_by_user, permission_decision_denied_no_approval_rule_and_could_not_request_from_user, permission_decision_outcome, permission_decision_reject, permission_decision_request, permission_decision_surface, permission_decision_user_not_available, permission_location_add_tool_approval_params, permission_location_apply_params, permission_location_apply_result, permission_location_resolve_params, permission_location_resolve_result, permission_location_type, permission_mode_source, permission_paths_add_params, permission_paths_allowed_check_params, permission_paths_allowed_check_result, permission_paths_config, permission_paths_list, permission_paths_update_primary_params, permission_paths_workspace_check_params, permission_paths_workspace_check_result, permission_prompt_shown_notification, permission_request_result, permission_response_capability, permission_rules_set, permissions_configure_additional_content_exclusion_policy, permissions_configure_additional_content_exclusion_policy_rule, permissions_configure_additional_content_exclusion_policy_rule_source, permissions_configure_additional_content_exclusion_policy_scope, permissions_configure_params, permissions_configure_result, permissions_evaluate_managed_policy_params, permissions_evaluate_managed_policy_result, permissions_folder_trust_add_trusted_result, permissions_get_mode_request, permissions_get_mode_result, permissions_locations_add_tool_approval_details, permissions_locations_add_tool_approval_details_commands, permissions_locations_add_tool_approval_details_custom_tool, permissions_locations_add_tool_approval_details_extension_env_access, permissions_locations_add_tool_approval_details_extension_management, permissions_locations_add_tool_approval_details_extension_permission_access, permissions_locations_add_tool_approval_details_mcp, permissions_locations_add_tool_approval_details_mcp_sampling, permissions_locations_add_tool_approval_details_memory, permissions_locations_add_tool_approval_details_read, permissions_locations_add_tool_approval_details_workflow, permissions_locations_add_tool_approval_details_write, permissions_locations_add_tool_approval_result, permissions_modify_rules_params, permissions_modify_rules_result, permissions_modify_rules_scope, permissions_notify_prompt_shown_result, permissions_paths_add_result, permissions_paths_list_request, permissions_paths_update_primary_result, permissions_pending_requests_request, permissions_reset_session_approvals_request, permissions_reset_session_approvals_result, permissions_set_approve_all_request, permissions_set_approve_all_result, permissions_set_approve_all_source, permissions_set_mode_request, permissions_set_mode_result, permissions_set_required_request, permissions_set_required_result, permissions_urls_set_unrestricted_mode_result, permission_urls_config, permission_urls_set_unrestricted_mode_params, persistence_write_raw_json_locked_request, persistence_write_raw_json_locked_result, ping_request, ping_result, plan_read_result, plan_read_sql_todos_result, plan_read_sql_todos_with_dependencies_result, plan_sql_todo_dependency, plan_sql_todos_row, plan_update_request, plugin, plugin_install_result, plugin_install_staging_mode, plugin_list, plugin_list_result, plugins_builtin_set_request, plugins_disable_request, plugins_enable_request, plugins_install_request, plugins_marketplaces_add_request, plugins_marketplaces_browse_request, plugins_marketplaces_refresh_request, plugins_marketplaces_remove_request, plugins_reload_request, plugins_uninstall_request, plugins_update_request, plugin_update_all_entry, plugin_update_all_result, plugin_update_result, protocol_append_mode, protocol_customize_mode, protocol_external_tool_defer, protocol_external_tool_definition, protocol_marker_section_override, protocol_replace_mode, protocol_section_override, protocol_static_section_action, protocol_static_section_override, protocol_system_message_append_config, protocol_system_message_config, protocol_system_message_customize_config, protocol_system_message_replace_config, provider_add_request, provider_add_result, provider_config, provider_config_azure, provider_config_model_provider, provider_config_transport, provider_config_type, provider_config_wire_api, provider_descriptor, provider_endpoint, provider_endpoint_transport, provider_endpoint_type, provider_endpoint_wire_api, provider_get_endpoint_request, provider_model_config, provider_session_token, provider_sync_request, provider_sync_result, provider_token_acquire_request, provider_token_acquire_result, provider_withdraw_request, provider_withdraw_result, push_attachment, push_attachment_blob, push_attachment_directory, push_attachment_file, push_attachment_file_line_range, push_attachment_git_hub_actions_job, push_attachment_git_hub_commit, push_attachment_git_hub_file, push_attachment_git_hub_file_diff, push_attachment_git_hub_file_diff_side, push_attachment_git_hub_reference, push_attachment_git_hub_reference_type, push_attachment_git_hub_release, push_attachment_git_hub_repository, push_attachment_git_hub_snippet, push_attachment_git_hub_tree_comparison, push_attachment_git_hub_tree_comparison_side, push_attachment_git_hub_url, push_attachment_selection, push_attachment_selection_details, push_attachment_selection_details_end, push_attachment_selection_details_start, push_git_hub_repo_ref, queue_append_steering_request, queue_begin_deferred_idle_drain_request, queue_begin_deferred_idle_drain_result, queue_consume_system_notifications_request, queued_command_handled, queued_command_not_handled, queued_command_result, queue_defer_session_idle_request, queue_duplicate_at_request, queue_duplicate_at_result, queue_enqueue_resume_pending_result, queue_finish_deferred_idle_drain_request, queue_finish_deferred_idle_drain_result, queue_has_pending_result, queue_insert_at_request, queue_insert_at_result, queue_insert_message, queue_move_item_request, queue_move_item_result, queue_pending_items, queue_pending_items_kind, queue_pending_items_result, queue_remove_at_request, queue_remove_at_result, queue_remove_most_recent_result, queue_send_now_request, queue_send_now_result, queue_set_drain_paused_request, queue_snapshot_result, queue_update_text_request, queue_update_text_result, queue_withdraw_message_request, queue_withdraw_message_result, quota_take_warnings_result, quota_warning_projection, register_event_interest_params, register_event_interest_result, release_event_interest_params, remote_control_config, remote_control_config_existing_mc_session, remote_control_status, remote_control_status_active, remote_control_status_connecting, remote_control_status_error, remote_control_status_off, remote_control_status_result, remote_control_stop_result, remote_control_transfer_result, remote_enable_request, remote_enable_result, remote_notify_steerable_changed_request, remote_notify_steerable_changed_result, remote_session_connection_result, remote_session_host_status, remote_session_metadata_repository, remote_session_metadata_task_type, remote_session_metadata_value, remote_session_mode, remote_session_repository, repo_settings_edit_request, repo_settings_edit_scope, repo_settings_read_raw_request, repo_settings_read_raw_result, repo_settings_write_all_request, repo_settings_write_key_request, response_format, sandbox_apply_defaults_request, sandbox_check_enforcement_command_result, sandbox_check_platform_support_result, sandbox_check_windows_host_loopback_support_result, sandbox_config, sandbox_config_auth, sandbox_config_source, sandbox_config_user_policy, sandbox_config_user_policy_experimental, sandbox_config_user_policy_experimental_seatbelt, sandbox_config_user_policy_filesystem, sandbox_config_user_policy_network, sandbox_config_user_policy_network_proxy, sandbox_config_user_policy_seatbelt, sandbox_credentials_config, sandbox_credential_suggestion, sandbox_credential_suggestions_result, sandbox_disable_for_session_request, sandbox_disable_for_session_result, sandbox_docs_url_result, sandbox_effective_for_optional_params, sandbox_effective_for_optional_result, sandbox_enforcement_command_allowed_params, sandbox_enforcement_status, sandbox_filter_picker_candidates_params, sandbox_filter_picker_candidates_result, sandbox_get_unsupported_message_result, sandbox_get_unsupported_setting_disabled_notice_result, sandbox_grant_path_for_request_request, sandbox_grant_path_for_request_result, sandbox_host_capability, sandbox_host_capability_name, sandbox_host_support, sandbox_masked_env_var, sandbox_picker_candidate, sandbox_prepare_picker_policy_params, sandbox_prepare_picker_policy_result, sandbox_proxy_ca_check_installation_support_result, sandbox_proxy_ca_check_relevance_result, sandbox_proxy_ca_create_result, sandbox_proxy_ca_request, sandbox_proxy_ca_state, sandbox_proxy_ca_status, sandbox_proxy_secret_get_result, sandbox_proxy_secret_location, sandbox_proxy_secret_save_request, sandbox_proxy_secret_save_result, sandbox_resolve_floored_config_params, sandbox_resolve_floored_config_result, sandbox_session_change, sandbox_settings_apply_defaults_result, sandbox_unsupported_startup_notice_params, sandbox_unsupported_startup_notice_result, schedule_add_at_request, schedule_add_cron_request, schedule_add_request, schedule_add_result, schedule_add_self_paced_request, schedule_entry, schedule_has_self_paced_result, schedule_list, schedule_rearm_self_paced_request, schedule_stop_request, schedule_stop_result, secrets_add_filter_values_request, secrets_add_filter_values_result, send_agent_mode, send_attachments_to_message_params, send_message_item, send_messages_request, send_messages_result, send_mode, send_request, send_result, send_system_notification_request, server_agent_list, server_instruction_source_list, server_skill, server_skill_list, session_activity, session_agent_list_request, session_auth_login_request, session_auth_logout_user_request, session_auth_status, session_auth_switch_request, session_bulk_delete_result, session_cancel_all_background_agents_result, session_capability, session_commands_list_request, session_completion_item, session_connected_ide_info, session_context, session_context_host_type, session_enrich_metadata_result, session_fs_append_file_request, session_fs_error, session_fs_error_code, session_fs_exists_request, session_fs_exists_result, session_fs_mkdir_request, session_fs_readdir_request, session_fs_readdir_result, session_fs_readdir_with_types_entry, session_fs_readdir_with_types_entry_type, session_fs_readdir_with_types_request, session_fs_readdir_with_types_result, session_fs_read_file_bytes_request, session_fs_read_file_bytes_result, session_fs_read_file_request, session_fs_read_file_result, session_fs_rename_request, session_fs_rm_request, session_fs_set_provider_capabilities, session_fs_set_provider_conventions, session_fs_set_provider_request, session_fs_set_provider_result, session_fs_sqlite_exists_request, session_fs_sqlite_exists_result, session_fs_sqlite_query_request, session_fs_sqlite_query_result, session_fs_sqlite_query_type, session_fs_sqlite_transaction_error, session_fs_sqlite_transaction_error_class, session_fs_sqlite_transaction_request, session_fs_sqlite_transaction_result, session_fs_sqlite_transaction_statement, session_fs_stat_request, session_fs_stat_result, session_fs_write_file_bytes_request, session_fs_write_file_request, session_git_hub_auth_get_all_auth_available_result, session_git_hub_auth_logout_result, session_git_hub_auth_logout_user_result, session_history_compact_request, session_installed_plugin, session_installed_plugin_source, session_installed_plugin_source_git_hub, session_installed_plugin_source_local, session_installed_plugin_source_url, session_limit_prediction_baseline_data, session_limit_prediction_client_type, session_limit_prediction_details, session_limit_prediction_predict_request, session_limit_prediction_request, session_limit_prediction_result, session_limit_prediction_source, session_limit_prediction_tier, session_limit_prediction_tier_option, session_limit_prediction_unavailable_reason, session_list, session_list_entry, session_list_filter, session_load_deferred_repo_hooks_result, session_log_level, session_managed_permissions, session_managed_settings, session_mcp_apps_call_tool_result, session_mcp_oauth_cancel_login_request, session_mcp_oauth_cancel_login_result, session_mcp_oauth_prepare_login_request, session_mcp_oauth_prepare_login_result, session_mcp_set_connected_ide_info_params, session_metadata_snapshot, session_mode, session_model_clear_startup_seed_request, session_model_clear_startup_seed_result, session_model_list, session_model_list_request, session_model_price_category, session_open_options, session_open_options_additional_content_exclusion_policy, session_open_options_additional_content_exclusion_policy_rule, session_open_options_additional_content_exclusion_policy_rule_source, session_open_options_additional_content_exclusion_policy_scope, session_open_options_env_value_mode, session_open_options_reasoning_summary, session_open_params, session_open_result, session_plugins_disable_request, session_plugins_enable_request, session_plugins_install_request, session_plugins_marketplaces_refresh_request, session_plugins_reload_request, session_plugins_retry_managed_request, session_plugins_retry_managed_result, session_provider_get_endpoint_request, session_prune_result, session_quota_delegate_warning, session_quota_get_result, session_quota_plan_tier, session_quota_projection, session_quota_refresh_result, session_quota_snapshot, session_quota_take_warnings_result, sessions_bulk_delete_request, sessions_check_in_use_request, sessions_check_in_use_result, sessions_client_metadata_entry, sessions_close_request, sessions_close_result, sessions_create_workspace_request, sessions_create_workspace_result, sessions_delete_request, sessions_enrich_metadata_request, session_set_credentials_params, session_set_credentials_result, session_settings_built_in_tool_availability_snapshot, session_settings_evaluate_predicate_request, session_settings_evaluate_predicate_result, session_settings_job_snapshot, session_settings_model_snapshot, session_settings_online_evaluation_snapshot, session_settings_predicate_name, session_settings_repo_snapshot, session_settings_snapshot, session_settings_validation_snapshot, sessions_find_by_prefix_request, sessions_find_by_prefix_result, sessions_find_by_task_id_request, sessions_find_by_task_id_result, sessions_fork_request, sessions_fork_result, sessions_get_board_entry_count_request, sessions_get_board_entry_count_result, sessions_get_client_metadata_request, sessions_get_client_metadata_result, sessions_get_event_file_path_request, sessions_get_event_file_path_result, sessions_get_last_for_context_request, sessions_get_last_for_context_result, sessions_get_metadata_request, sessions_get_metadata_result, sessions_get_persisted_remote_steerable_request, sessions_get_persisted_remote_steerable_result, session_sizes, sessions_list_non_empty_session_ids_request, sessions_list_non_empty_session_ids_result, sessions_list_request, sessions_load_deferred_repo_hooks_request, sessions_load_workspace_request, sessions_load_workspace_result, sessions_open_attach, sessions_open_cloud, sessions_open_create, sessions_open_handoff, sessions_open_handoff_task_type, sessions_open_progress, sessions_open_progress_status, sessions_open_progress_step, sessions_open_remote, sessions_open_resume, sessions_open_resume_last, sessions_open_status, session_source, sessions_prune_old_request, sessions_read_persisted_events_request, sessions_release_lock_request, sessions_release_lock_result, sessions_reload_plugin_hooks_request, sessions_reload_plugin_hooks_result, sessions_save_request, sessions_save_result, sessions_set_additional_plugins_request, sessions_set_additional_plugins_result, sessions_set_remote_control_steering_request, sessions_start_remote_control_request, sessions_stop_remote_control_request, sessions_transfer_remote_control_request, sessions_update_workspace_fields_request, sessions_update_workspace_fields_result, session_telemetry_engagement, session_update_options_params, session_update_options_result, session_usage_set_code_changes_request, session_visibility_status, session_workflow_pause_at_checkpoint_result, session_working_directory_context, session_working_directory_context_host_type, session_working_directory_context_with_client, settable_auth_info, settable_token_auth_info, settings_edit_operation, settings_edit_result, settings_edit_status, shell_cancel_user_requested_request, shell_credentials, shell_exec_request, shell_exec_result, shell_execute_user_requested_request, shell_init_profile, shell_init_script, shell_init_script_shell, shell_kill_request, shell_kill_result, shell_kill_signal, shell_options, shutdown_request, skill, skill_apply_install_request, skill_apply_uninstall_request, skill_discovery_path, skill_discovery_path_list, skill_discovery_scope, skill_installation_failure_reason, skill_installation_file_review, skill_installation_location, skill_installation_management_outcome, skill_installation_management_result, skill_installation_operation_request, skill_installation_operation_status, skill_installation_outcome, skill_installation_ownership_state, skill_installation_result, skill_installation_review, skill_installation_scope, skill_installation_session_state, skill_installation_source, skill_installations_request, skill_installation_summary, skill_install_plan, skill_list, skill_plan_install_request, skill_plan_uninstall_request, skill_provider_descriptor, skill_provider_list_request, skill_provider_list_result, skill_provider_read_request, skill_provider_read_result, skills_config_set_disabled_skills_request, skills_config_set_skill_disabled_request, skills_disable_request, skills_discover_request, skills_enable_request, skill_set_enabled_request, skills_get_discovery_paths_request, skills_get_invoked_result, skills_invoked_skill, skills_load_diagnostics, skill_uninstall_plan, slash_command_add_timeline_entry_result, slash_command_agent_prompt_result, slash_command_completed_result, slash_command_info, slash_command_input, slash_command_input_choice, slash_command_input_completion, slash_command_invocation_result, slash_command_kind, slash_command_model_picker_dialog, slash_command_select_subcommand_option, slash_command_select_subcommand_result, slash_command_set_model_result, slash_command_set_plan_model_result, slash_command_show_dialog_result, slash_command_text_result, slash_command_timeline_entry, staff_log_level_migration_status, staff_update_channel_migration_status, subagent_settings_entry, subagent_settings_entry_context_tier, system_message_block, task_agent_info, task_agent_progress, task_client_active_status, task_client_execution_mode, task_client_info, task_client_owner, task_client_owner_kind, task_client_owner_presence, task_client_progress, task_client_status, task_client_type, task_client_update, task_complete_data, task_completion_decision, task_execution_mode, task_info, task_kind, task_list, task_progress_line, tasks_cancel_request, tasks_cancel_result, tasks_get_current_promotable_result, tasks_get_progress_request, tasks_get_progress_result, task_shell_info, task_shell_info_attachment_mode, task_shell_progress, tasks_promote_current_to_background_result, tasks_promote_to_background_request, tasks_promote_to_background_result, tasks_refresh_result, tasks_register_request, tasks_register_result, tasks_remove_request, tasks_remove_result, tasks_send_message_request, tasks_send_message_result, tasks_start_agent_request, tasks_start_agent_result, task_status, tasks_update_request, tasks_update_result, tasks_wait_for_pending_result, telemetry_set_feature_overrides_request, token_auth_info, token_provider_auth_info, tool, tool_list, tool_result, tool_result_expanded, tool_result_new_message, tool_result_type, tools_execute_request, tools_get_builtin_descriptors_request, tools_get_builtin_descriptors_result, tools_get_current_metadata_result, tools_initialize_and_validate_result, tools_list_pending_requests_request, tools_list_request, tools_set_request, tools_set_result, tools_shell_descriptor_config, tools_task_complete_event_data_request, tools_update_subagent_settings_result, ui_auto_mode_switch_response, ui_elicitation_array_any_of_field, ui_elicitation_array_any_of_field_items, ui_elicitation_array_any_of_field_items_any_of, ui_elicitation_array_enum_field, ui_elicitation_array_enum_field_items, ui_elicitation_field_value, ui_elicitation_request, ui_elicitation_response, ui_elicitation_response_action, ui_elicitation_response_content, ui_elicitation_result, ui_elicitation_schema, ui_elicitation_schema_property, ui_elicitation_schema_property_boolean, ui_elicitation_schema_property_number, ui_elicitation_schema_property_number_type, ui_elicitation_schema_property_string, ui_elicitation_schema_property_string_format, ui_elicitation_string_enum_field, ui_elicitation_string_one_of_field, ui_elicitation_string_one_of_field_one_of, ui_ephemeral_query_request, ui_ephemeral_query_result, ui_exit_plan_mode_action, ui_exit_plan_mode_response, ui_handle_pending_auto_mode_switch_request, ui_handle_pending_elicitation_request, ui_handle_pending_exit_plan_mode_request, ui_handle_pending_result, ui_handle_pending_sampling_request, ui_handle_pending_sampling_response, ui_handle_pending_session_limits_exhausted_request, ui_handle_pending_user_input_request, ui_register_direct_auto_mode_switch_handler_result, ui_session_limits_exhausted_response, ui_session_limits_exhausted_response_action, ui_unregister_direct_auto_mode_switch_handler_request, ui_unregister_direct_auto_mode_switch_handler_result, ui_user_input_response, unsupported_enqueue_command_result, update_subagent_settings_request, usage_get_metrics_result, usage_set_code_changes_request, user_auth_info, user_requested_shell_command_result, user_setting_metadata, user_settings_apply_top_key_request, user_settings_apply_top_key_result, user_settings_build_runtime_request, user_settings_build_runtime_result, user_settings_edit_request, user_settings_get_paths_request, user_settings_get_paths_result, user_settings_get_result, user_settings_governance_keys_result, user_settings_host_context, user_settings_load_and_merge_repo_request, user_settings_load_and_merge_repo_result, user_settings_load_for_config_dir_request, user_settings_load_for_config_dir_result, user_settings_load_for_edit_result, user_settings_load_repo_request, user_settings_load_repo_result, user_settings_load_with_warning_result, user_settings_merge_managed_and_user_params, user_settings_merge_managed_and_user_result, user_settings_merge_repo_value_params, user_settings_merge_repo_value_result, user_settings_migrate_obsolete_on_disk_request, user_settings_migrate_obsolete_on_disk_result, user_settings_migrate_obsolete_on_disk_status, user_settings_migrate_staff_log_level_once_request, user_settings_migrate_staff_log_level_once_result, user_settings_migrate_staff_update_channel_once_result, user_settings_normalize_request, user_settings_normalize_result, user_settings_path_result, user_settings_problem, user_settings_problem_location, user_settings_problem_source, user_settings_problems_request, user_settings_problems_result, user_settings_reset_staff_model_selection_once_request, user_settings_reset_staff_model_selection_once_result, user_settings_set_hook_disabled_request, user_settings_set_hook_disabled_result, user_settings_set_request, user_settings_unknown_keys_warning_request, user_settings_unknown_keys_warning_result, user_settings_update_request, user_settings_update_result, user_settings_validate_request, user_settings_validate_result, user_settings_validation_issue, user_settings_write_all_request, visibility_get_result, visibility_set_request, visibility_set_result, workflow_abort_request, workflow_ack_result, workflow_agent_options, workflow_agent_request, workflow_agent_result, workflow_agent_summary, workflow_cancel_request, workflow_current_phase, workflow_declared_limits, workflow_durable_operation, workflow_execute_request, workflow_execute_result, workflow_get_run_progress_request, workflow_get_run_request, workflow_journal_get_request, workflow_journal_get_result, workflow_journal_put_request, workflow_list_runs_request, workflow_list_runs_result, workflow_log_line, workflow_log_line_kind, workflow_log_request, workflow_pause_checkpoint_action, workflow_pause_checkpoint_request, workflow_pause_checkpoint_result, workflow_pause_info, workflow_pause_request, workflow_phase_observation, workflow_phase_status, workflow_progress_line, workflow_progress_page, workflow_resume_request, workflow_resume_result, workflow_run_consumed, workflow_run_detail, workflow_run_failure, workflow_run_failure_kind, workflow_run_limits, workflow_run_options, workflow_run_request, workflow_run_result, workflow_run_status, workflow_run_summary, workflow_run_terminal, workflow_tool_resume_request, workflow_tool_run_options, workflow_tool_run_request, workspace_diff_contents, workspace_diff_file_change, workspace_diff_file_change_type, workspace_diff_mode, workspace_diff_result, workspaces_add_summary_request, workspaces_add_summary_result, workspaces_autopilot_objective_exists_result, workspaces_checkpoints, workspaces_create_directory_request, workspaces_create_file_request, workspaces_delete_autopilot_objective_result, workspaces_diff_request, workspaces_ensure_request, workspaces_get_workspace_result, workspaces_list_checkpoints_result, workspaces_list_files_result, workspaces_read_autopilot_objective_result, workspaces_read_checkpoint_request, workspaces_read_checkpoint_result, workspaces_read_file_request, workspaces_read_file_result, workspaces_remove_path_request, workspaces_rename_path_request, workspaces_save_large_paste_request, workspaces_save_large_paste_result, workspaces_stat_file_request, workspaces_stat_file_result, workspaces_truncate_summaries_request, workspace_summary_host_type, workspaces_update_metadata_request, workspaces_workspace_details_host_type, workspaces_write_autopilot_objective_request, workspaces_write_autopilot_objective_result, connector_session_account_result, session_auth_info_result, session_context_attribution, session_context_info, subagent_settings, task_progress, workspace_summary) def to_dict(self) -> dict: result: dict = {} @@ -55317,12 +58309,16 @@ def to_dict(self) -> dict: result["FeatureFlagsMetadataResult"] = to_class(_FeatureFlagsMetadataResult, self.feature_flags_metadata_result) result["FeatureFlagsResolveRequest"] = to_class(_FeatureFlagsResolveRequest, self.feature_flags_resolve_request) result["FeatureFlagsResolveResult"] = from_dict(from_bool, self.feature_flags_resolve_result) + result["FeatureFlagsResolveStartupGatesRequest"] = to_class(_FeatureFlagsResolveStartupGatesRequest, self.feature_flags_resolve_startup_gates_request) + result["FeatureFlagsResolveStartupGatesResult"] = from_dict(from_bool, self.feature_flags_resolve_startup_gates_result) result["FilterMapping"] = from_union([lambda x: from_dict(lambda x: to_enum(ContentFilterMode, x), x), lambda x: to_enum(ContentFilterMode, x)], self.filter_mapping) result["FleetStartRequest"] = to_class(FleetStartRequest, self.fleet_start_request) result["FleetStartResult"] = to_class(FleetStartResult, self.fleet_start_result) result["FolderTrustAddParams"] = to_class(FolderTrustAddParams, self.folder_trust_add_params) result["FolderTrustCheckParams"] = to_class(FolderTrustCheckParams, self.folder_trust_check_params) result["FolderTrustCheckResult"] = to_class(FolderTrustCheckResult, self.folder_trust_check_result) + result["FolderTrustIsTrustedParams"] = to_class(_FolderTrustIsTrustedParams, self.folder_trust_is_trusted_params) + result["ForceLoginOrgsDecision"] = to_class(_ForceLoginOrgsDecision, self.force_login_orgs_decision) result["GhCliAuthInfo"] = to_class(GhCLIAuthInfo, self.gh_cli_auth_info) result["GitCurrentBranchRemoteResult"] = to_class(_GitCurrentBranchRemoteResult, self.git_current_branch_remote_result) result["GitCwdRequest"] = to_class(_GitCwdRequest, self.git_cwd_request) @@ -55442,6 +58438,7 @@ def to_dict(self) -> dict: result["LlmInferenceHttpResponseStartResult"] = to_class(LlmInferenceHTTPResponseStartResult, self.llm_inference_http_response_start_result) result["LlmInferenceSetProviderResult"] = to_class(LlmInferenceSetProviderResult, self.llm_inference_set_provider_result) result["LocalSessionMetadataValue"] = to_class(LocalSessionMetadataValue, self.local_session_metadata_value) + result["LocationPermissionsCleanupResult"] = to_class(_LocationPermissionsCleanupResult, self.location_permissions_cleanup_result) result["LoggedInUser"] = to_class(_LoggedInUser, self.logged_in_user) result["LoginProviderKind"] = to_enum(LoginProviderKind, self.login_provider_kind) result["LogRequest"] = to_class(LogRequest, self.log_request) @@ -55457,19 +58454,44 @@ def to_dict(self) -> dict: result["ManagedPluginRetryEntry"] = to_class(ManagedPluginRetryEntry, self.managed_plugin_retry_entry) result["ManagedPluginRetryStatus"] = to_enum(ManagedPluginRetryStatus, self.managed_plugin_retry_status) result["ManagedSettingMeta"] = to_class(ManagedSettingMeta, self.managed_setting_meta) + result["ManagedSettingsApplyControlsParams"] = to_class(_ManagedSettingsApplyControlsParams, self.managed_settings_apply_controls_params) + result["ManagedSettingsApplyControlsResult"] = to_class(_ManagedSettingsApplyControlsResult, self.managed_settings_apply_controls_result) + result["ManagedSettingsBypassDisableSource"] = to_enum(_ManagedSettingsBypassDisableSource, self.managed_settings_bypass_disable_source) + result["ManagedSettingsBypassPolicyResolution"] = to_enum(_ManagedSettingsBypassPolicyResolution, self.managed_settings_bypass_policy_resolution) result["ManagedSettingsChannel"] = to_enum(ManagedSettingsChannel, self.managed_settings_channel) result["ManagedSettingsComposeLayer"] = to_class(ManagedSettingsComposeLayer, self.managed_settings_compose_layer) result["ManagedSettingsComposeRequest"] = to_class(ManagedSettingsComposeRequest, self.managed_settings_compose_request) result["ManagedSettingsComposeResult"] = to_class(ManagedSettingsComposeResult, self.managed_settings_compose_result) result["ManagedSettingsDiagnostic"] = to_class(ManagedSettingsDiagnostic, self.managed_settings_diagnostic) result["ManagedSettingsDiagnosticSeverity"] = to_enum(ManagedSettingsDiagnosticSeverity, self.managed_settings_diagnostic_severity) + result["ManagedSettingsIngestParams"] = to_class(_ManagedSettingsIngestParams, self.managed_settings_ingest_params) + result["ManagedSettingsIngestResult"] = to_class(_ManagedSettingsIngestResult, self.managed_settings_ingest_result) result["ManagedSettingsLayer"] = to_class(ManagedSettingsLayer, self.managed_settings_layer) + result["ManagedSettingsLoadRemoteControlParams"] = to_class(_ManagedSettingsLoadRemoteControlParams, self.managed_settings_load_remote_control_params) + result["ManagedSettingsLoadRemoteControlResult"] = to_class(_ManagedSettingsLoadRemoteControlResult, self.managed_settings_load_remote_control_result) + result["ManagedSettingsLogLevel"] = to_enum(_ManagedSettingsLogLevel, self.managed_settings_log_level) + result["ManagedSettingsLogMessage"] = to_class(_ManagedSettingsLogMessage, self.managed_settings_log_message) result["ManagedSettingsMeta"] = to_class(ManagedSettingsMeta, self.managed_settings_meta) + result["ManagedSettingsParseClientValueParams"] = to_class(_ManagedSettingsParseClientValueParams, self.managed_settings_parse_client_value_params) + result["ManagedSettingsParseClientValueResult"] = to_class(_ManagedSettingsParseClientValueResult, self.managed_settings_parse_client_value_result) + result["ManagedSettingsPolicyHelperAuthority"] = to_enum(_ManagedSettingsPolicyHelperAuthority, self.managed_settings_policy_helper_authority) + result["ManagedSettingsPolicyHelperReason"] = to_enum(_ManagedSettingsPolicyHelperReason, self.managed_settings_policy_helper_reason) + result["ManagedSettingsReadDeviceResult"] = to_class(_ManagedSettingsReadDeviceResult, self.managed_settings_read_device_result) result["ManagedSettingsReadResult"] = to_class(ManagedSettingsReadResult, self.managed_settings_read_result) + result["ManagedSettingsResolveBypassDisableTransitionParams"] = to_class(_ManagedSettingsResolveBypassDisableTransitionParams, self.managed_settings_resolve_bypass_disable_transition_params) + result["ManagedSettingsResolveBypassDisableTransitionResult"] = to_class(_ManagedSettingsResolveBypassDisableTransitionResult, self.managed_settings_resolve_bypass_disable_transition_result) result["ManagedSettingsResolvedData"] = to_class(ManagedSettingsResolvedData, self.managed_settings_resolved_data) + result["ManagedSettingsResolveDeviceForceLoginOrgsGateParams"] = to_class(_ManagedSettingsResolveDeviceForceLoginOrgsGateParams, self.managed_settings_resolve_device_force_login_orgs_gate_params) + result["ManagedSettingsResolveEffectiveValueParams"] = to_class(_ManagedSettingsResolveEffectiveValueParams, self.managed_settings_resolve_effective_value_params) + result["ManagedSettingsResolveEffectiveValueResult"] = to_class(_ManagedSettingsResolveEffectiveValueResult, self.managed_settings_resolve_effective_value_result) result["ManagedSettingsResolveRequest"] = to_class(ManagedSettingsResolveRequest, self.managed_settings_resolve_request) result["ManagedSettingsResolveResult"] = to_class(ManagedSettingsResolveResult, self.managed_settings_resolve_result) + result["ManagedSettingsResolveStartupPolicyParams"] = to_class(_ManagedSettingsResolveStartupPolicyParams, self.managed_settings_resolve_startup_policy_params) + result["ManagedSettingsResolveStartupPolicyResult"] = to_class(_ManagedSettingsResolveStartupPolicyResult, self.managed_settings_resolve_startup_policy_result) + result["ManagedSettingsRetainPolicyParams"] = to_class(_ManagedSettingsRetainPolicyParams, self.managed_settings_retain_policy_params) result["ManagedSettingsSchemaResult"] = to_class(ManagedSettingsSchemaResult, self.managed_settings_schema_result) + result["ManagedSettingsServerPolicyCacheMode"] = to_enum(_ManagedSettingsServerPolicyCacheMode, self.managed_settings_server_policy_cache_mode) + result["ManagedSettingsServerPolicyResolution"] = to_enum(_ManagedSettingsServerPolicyResolution, self.managed_settings_server_policy_resolution) result["ManagedSettingsValidateRequest"] = to_class(ManagedSettingsValidateRequest, self.managed_settings_validate_request) result["ManagedSettingsValidateResult"] = to_class(ManagedSettingsValidateResult, self.managed_settings_validate_result) result["ManagedSettingsValues"] = to_class(ManagedSettingsValues, self.managed_settings_values) @@ -55859,6 +58881,8 @@ def to_dict(self) -> dict: result["PermissionsConfigureAdditionalContentExclusionPolicyScope"] = to_enum(AdditionalContentExclusionPolicyScope, self.permissions_configure_additional_content_exclusion_policy_scope) result["PermissionsConfigureParams"] = to_class(PermissionsConfigureParams, self.permissions_configure_params) result["PermissionsConfigureResult"] = to_class(PermissionsConfigureResult, self.permissions_configure_result) + result["PermissionsEvaluateManagedPolicyParams"] = to_class(_PermissionsEvaluateManagedPolicyParams, self.permissions_evaluate_managed_policy_params) + result["PermissionsEvaluateManagedPolicyResult"] = to_class(PermissionsEvaluateManagedPolicyResult, self.permissions_evaluate_managed_policy_result) result["PermissionsFolderTrustAddTrustedResult"] = to_class(PermissionsFolderTrustAddTrustedResult, self.permissions_folder_trust_add_trusted_result) result["PermissionsGetModeRequest"] = to_class(PermissionsGetModeRequest, self.permissions_get_mode_request) result["PermissionsGetModeResult"] = to_class(PermissionsGetModeResult, self.permissions_get_mode_result) @@ -55895,6 +58919,8 @@ def to_dict(self) -> dict: result["PermissionsUrlsSetUnrestrictedModeResult"] = to_class(PermissionsUrlsSetUnrestrictedModeResult, self.permissions_urls_set_unrestricted_mode_result) result["PermissionUrlsConfig"] = to_class(PermissionUrlsConfig, self.permission_urls_config) result["PermissionUrlsSetUnrestrictedModeParams"] = to_class(PermissionUrlsSetUnrestrictedModeParams, self.permission_urls_set_unrestricted_mode_params) + result["PersistenceWriteRawJsonLockedRequest"] = to_class(PersistenceWriteRawJSONLockedRequest, self.persistence_write_raw_json_locked_request) + result["PersistenceWriteRawJsonLockedResult"] = to_class(PersistenceWriteRawJSONLockedResult, self.persistence_write_raw_json_locked_result) result["PingRequest"] = to_class(PingRequest, self.ping_request) result["PingResult"] = to_class(PingResult, self.ping_result) result["PlanReadResult"] = to_class(PlanReadResult, self.plan_read_result) @@ -56039,11 +59065,17 @@ def to_dict(self) -> dict: result["RemoteSessionMetadataValue"] = to_class(RemoteSessionMetadataValue, self.remote_session_metadata_value) result["RemoteSessionMode"] = to_enum(RemoteSessionMode, self.remote_session_mode) result["RemoteSessionRepository"] = to_class(RemoteSessionRepository, self.remote_session_repository) + result["RepoSettingsEditRequest"] = to_class(_RepoSettingsEditRequest, self.repo_settings_edit_request) + result["RepoSettingsEditScope"] = to_enum(_RepoSettingsEditScope, self.repo_settings_edit_scope) result["RepoSettingsReadRawRequest"] = to_class(_RepoSettingsReadRawRequest, self.repo_settings_read_raw_request) result["RepoSettingsReadRawResult"] = to_class(_RepoSettingsReadRawResult, self.repo_settings_read_raw_result) result["RepoSettingsWriteAllRequest"] = to_class(_RepoSettingsWriteAllRequest, self.repo_settings_write_all_request) result["RepoSettingsWriteKeyRequest"] = to_class(_RepoSettingsWriteKeyRequest, self.repo_settings_write_key_request) result["ResponseFormat"] = to_class(ResponseFormat, self.response_format) + result["SandboxApplyDefaultsRequest"] = to_class(SandboxApplyDefaultsRequest, self.sandbox_apply_defaults_request) + result["SandboxCheckEnforcementCommandResult"] = from_bool(self.sandbox_check_enforcement_command_result) + result["SandboxCheckPlatformSupportResult"] = from_bool(self.sandbox_check_platform_support_result) + result["SandboxCheckWindowsHostLoopbackSupportResult"] = from_bool(self.sandbox_check_windows_host_loopback_support_result) result["SandboxConfig"] = to_class(SandboxConfig, self.sandbox_config) result["SandboxConfigAuth"] = to_class(SandboxConfigAuth, self.sandbox_config_auth) result["SandboxConfigSource"] = to_enum(SandboxConfigSource, self.sandbox_config_source) @@ -56059,18 +59091,40 @@ def to_dict(self) -> dict: result["SandboxCredentialSuggestionsResult"] = to_class(SandboxCredentialSuggestionsResult, self.sandbox_credential_suggestions_result) result["SandboxDisableForSessionRequest"] = to_class(SandboxDisableForSessionRequest, self.sandbox_disable_for_session_request) result["SandboxDisableForSessionResult"] = to_class(SandboxDisableForSessionResult, self.sandbox_disable_for_session_result) + result["SandboxDocsUrlResult"] = to_class(SandboxDocsURLResult, self.sandbox_docs_url_result) + result["SandboxEffectiveForOptionalParams"] = to_class(_SandboxEffectiveForOptionalParams, self.sandbox_effective_for_optional_params) + result["SandboxEffectiveForOptionalResult"] = to_class(_SandboxEffectiveForOptionalResult, self.sandbox_effective_for_optional_result) + result["SandboxEnforcementCommandAllowedParams"] = to_class(_SandboxEnforcementCommandAllowedParams, self.sandbox_enforcement_command_allowed_params) result["SandboxEnforcementStatus"] = to_class(SandboxEnforcementStatus, self.sandbox_enforcement_status) + result["SandboxFilterPickerCandidatesParams"] = to_class(_SandboxFilterPickerCandidatesParams, self.sandbox_filter_picker_candidates_params) + result["SandboxFilterPickerCandidatesResult"] = to_class(_SandboxFilterPickerCandidatesResult, self.sandbox_filter_picker_candidates_result) + result["SandboxGetUnsupportedMessageResult"] = from_str(self.sandbox_get_unsupported_message_result) + result["SandboxGetUnsupportedSettingDisabledNoticeResult"] = from_str(self.sandbox_get_unsupported_setting_disabled_notice_result) result["SandboxGrantPathForRequestRequest"] = to_class(SandboxGrantPathForRequestRequest, self.sandbox_grant_path_for_request_request) result["SandboxGrantPathForRequestResult"] = to_class(SandboxGrantPathForRequestResult, self.sandbox_grant_path_for_request_result) result["SandboxHostCapability"] = to_class(SandboxHostCapability, self.sandbox_host_capability) result["SandboxHostCapabilityName"] = from_str(self.sandbox_host_capability_name) result["SandboxHostSupport"] = to_class(SandboxHostSupport, self.sandbox_host_support) result["SandboxMaskedEnvVar"] = to_class(SandboxMaskedEnvVar, self.sandbox_masked_env_var) + result["SandboxPickerCandidate"] = to_class(_SandboxPickerCandidate, self.sandbox_picker_candidate) + result["SandboxPreparePickerPolicyParams"] = to_class(_SandboxPreparePickerPolicyParams, self.sandbox_prepare_picker_policy_params) + result["SandboxPreparePickerPolicyResult"] = to_class(_SandboxPreparePickerPolicyResult, self.sandbox_prepare_picker_policy_result) + result["SandboxProxyCaCheckInstallationSupportResult"] = from_bool(self.sandbox_proxy_ca_check_installation_support_result) + result["SandboxProxyCaCheckRelevanceResult"] = from_bool(self.sandbox_proxy_ca_check_relevance_result) result["SandboxProxyCaCreateResult"] = to_class(SandboxProxyCACreateResult, self.sandbox_proxy_ca_create_result) result["SandboxProxyCaRequest"] = to_class(SandboxProxyCARequest, self.sandbox_proxy_ca_request) result["SandboxProxyCaState"] = to_enum(SandboxProxyCAState, self.sandbox_proxy_ca_state) result["SandboxProxyCaStatus"] = to_class(SandboxProxyCAStatus, self.sandbox_proxy_ca_status) + result["SandboxProxySecretGetResult"] = to_class(SandboxProxySecretGetResult, self.sandbox_proxy_secret_get_result) + result["SandboxProxySecretLocation"] = to_class(SandboxProxySecretLocation, self.sandbox_proxy_secret_location) + result["SandboxProxySecretSaveRequest"] = to_class(SandboxProxySecretSaveRequest, self.sandbox_proxy_secret_save_request) + result["SandboxProxySecretSaveResult"] = to_class(SandboxProxySecretSaveResult, self.sandbox_proxy_secret_save_result) + result["SandboxResolveFlooredConfigParams"] = to_class(_SandboxResolveFlooredConfigParams, self.sandbox_resolve_floored_config_params) + result["SandboxResolveFlooredConfigResult"] = to_class(SandboxResolveFlooredConfigResult, self.sandbox_resolve_floored_config_result) result["SandboxSessionChange"] = to_enum(SandboxSessionChange, self.sandbox_session_change) + result["SandboxSettingsApplyDefaultsResult"] = from_dict(lambda x: x, self.sandbox_settings_apply_defaults_result) + result["SandboxUnsupportedStartupNoticeParams"] = to_class(_SandboxUnsupportedStartupNoticeParams, self.sandbox_unsupported_startup_notice_params) + result["SandboxUnsupportedStartupNoticeResult"] = to_class(_SandboxUnsupportedStartupNoticeResult, self.sandbox_unsupported_startup_notice_result) result["ScheduleAddAtRequest"] = to_class(ScheduleAddAtRequest, self.schedule_add_at_request) result["ScheduleAddCronRequest"] = to_class(ScheduleAddCronRequest, self.schedule_add_cron_request) result["ScheduleAddRequest"] = to_class(ScheduleAddRequest, self.schedule_add_request) @@ -56374,6 +59428,8 @@ def to_dict(self) -> dict: result["SlashCommandShowDialogResult"] = to_class(SlashCommandShowDialogResult, self.slash_command_show_dialog_result) result["SlashCommandTextResult"] = to_class(SlashCommandTextResult, self.slash_command_text_result) result["SlashCommandTimelineEntry"] = to_class(SlashCommandTimelineEntry, self.slash_command_timeline_entry) + result["StaffLogLevelMigrationStatus"] = to_enum(StaffLogLevelMigrationStatus, self.staff_log_level_migration_status) + result["StaffUpdateChannelMigrationStatus"] = to_enum(StaffUpdateChannelMigrationStatus, self.staff_update_channel_migration_status) result["SubagentSettingsEntry"] = to_class(SubagentSettingsEntry, self.subagent_settings_entry) result["SubagentSettingsEntryContextTier"] = to_enum(SubagentSettingsEntryContextTier, self.subagent_settings_entry_context_tier) result["SystemMessageBlock"] = to_class(SystemMessageBlock, self.system_message_block) @@ -56490,20 +59546,47 @@ def to_dict(self) -> dict: result["UserSettingMetadata"] = to_class(UserSettingMetadata, self.user_setting_metadata) result["UserSettingsApplyTopKeyRequest"] = to_class(UserSettingsApplyTopKeyRequest, self.user_settings_apply_top_key_request) result["UserSettingsApplyTopKeyResult"] = to_class(UserSettingsApplyTopKeyResult, self.user_settings_apply_top_key_result) + result["UserSettingsBuildRuntimeRequest"] = to_class(_UserSettingsBuildRuntimeRequest, self.user_settings_build_runtime_request) + result["UserSettingsBuildRuntimeResult"] = from_dict(lambda x: x, self.user_settings_build_runtime_result) result["UserSettingsEditRequest"] = to_class(_UserSettingsEditRequest, self.user_settings_edit_request) result["UserSettingsGetPathsRequest"] = to_class(UserSettingsGetPathsRequest, self.user_settings_get_paths_request) result["UserSettingsGetPathsResult"] = to_class(UserSettingsGetPathsResult, self.user_settings_get_paths_result) result["UserSettingsGetResult"] = to_class(UserSettingsGetResult, self.user_settings_get_result) result["UserSettingsGovernanceKeysResult"] = to_class(UserSettingsGovernanceKeysResult, self.user_settings_governance_keys_result) + result["UserSettingsHostContext"] = to_class(UserSettingsHostContext, self.user_settings_host_context) + result["UserSettingsLoadAndMergeRepoRequest"] = to_class(_UserSettingsLoadAndMergeRepoRequest, self.user_settings_load_and_merge_repo_request) + result["UserSettingsLoadAndMergeRepoResult"] = to_class(_UserSettingsLoadAndMergeRepoResult, self.user_settings_load_and_merge_repo_result) + result["UserSettingsLoadForConfigDirRequest"] = to_class(_UserSettingsLoadForConfigDirRequest, self.user_settings_load_for_config_dir_request) + result["UserSettingsLoadForConfigDirResult"] = from_dict(lambda x: x, self.user_settings_load_for_config_dir_result) result["UserSettingsLoadForEditResult"] = to_class(UserSettingsLoadForEditResult, self.user_settings_load_for_edit_result) + result["UserSettingsLoadRepoRequest"] = to_class(UserSettingsLoadRepoRequest, self.user_settings_load_repo_request) + result["UserSettingsLoadRepoResult"] = to_class(UserSettingsLoadRepoResult, self.user_settings_load_repo_result) + result["UserSettingsLoadWithWarningResult"] = to_class(UserSettingsLoadWithWarningResult, self.user_settings_load_with_warning_result) + result["UserSettingsMergeManagedAndUserParams"] = to_class(_UserSettingsMergeManagedAndUserParams, self.user_settings_merge_managed_and_user_params) + result["UserSettingsMergeManagedAndUserResult"] = to_class(UserSettingsMergeManagedAndUserResult, self.user_settings_merge_managed_and_user_result) + result["UserSettingsMergeRepoValueParams"] = to_class(_UserSettingsMergeRepoValueParams, self.user_settings_merge_repo_value_params) + result["UserSettingsMergeRepoValueResult"] = to_class(UserSettingsMergeRepoValueResult, self.user_settings_merge_repo_value_result) + result["UserSettingsMigrateObsoleteOnDiskRequest"] = to_class(_UserSettingsMigrateObsoleteOnDiskRequest, self.user_settings_migrate_obsolete_on_disk_request) + result["UserSettingsMigrateObsoleteOnDiskResult"] = to_class(_UserSettingsMigrateObsoleteOnDiskResult, self.user_settings_migrate_obsolete_on_disk_result) + result["UserSettingsMigrateObsoleteOnDiskStatus"] = to_enum(_UserSettingsMigrateObsoleteOnDiskStatus, self.user_settings_migrate_obsolete_on_disk_status) + result["UserSettingsMigrateStaffLogLevelOnceRequest"] = to_class(_UserSettingsMigrateStaffLogLevelOnceRequest, self.user_settings_migrate_staff_log_level_once_request) + result["UserSettingsMigrateStaffLogLevelOnceResult"] = to_class(_UserSettingsMigrateStaffLogLevelOnceResult, self.user_settings_migrate_staff_log_level_once_result) + result["UserSettingsMigrateStaffUpdateChannelOnceResult"] = to_class(_UserSettingsMigrateStaffUpdateChannelOnceResult, self.user_settings_migrate_staff_update_channel_once_result) result["UserSettingsNormalizeRequest"] = to_class(UserSettingsNormalizeRequest, self.user_settings_normalize_request) result["UserSettingsNormalizeResult"] = to_class(UserSettingsNormalizeResult, self.user_settings_normalize_result) + result["UserSettingsPathResult"] = to_class(UserSettingsPathResult, self.user_settings_path_result) result["UserSettingsProblem"] = to_class(UserSettingsProblem, self.user_settings_problem) result["UserSettingsProblemLocation"] = to_class(UserSettingsProblemLocation, self.user_settings_problem_location) result["UserSettingsProblemSource"] = to_class(UserSettingsProblemSource, self.user_settings_problem_source) result["UserSettingsProblemsRequest"] = to_class(UserSettingsProblemsRequest, self.user_settings_problems_request) result["UserSettingsProblemsResult"] = to_class(UserSettingsProblemsResult, self.user_settings_problems_result) + result["UserSettingsResetStaffModelSelectionOnceRequest"] = to_class(_UserSettingsResetStaffModelSelectionOnceRequest, self.user_settings_reset_staff_model_selection_once_request) + result["UserSettingsResetStaffModelSelectionOnceResult"] = to_class(_UserSettingsResetStaffModelSelectionOnceResult, self.user_settings_reset_staff_model_selection_once_result) + result["UserSettingsSetHookDisabledRequest"] = to_class(_UserSettingsSetHookDisabledRequest, self.user_settings_set_hook_disabled_request) + result["UserSettingsSetHookDisabledResult"] = to_class(_UserSettingsSetHookDisabledResult, self.user_settings_set_hook_disabled_result) result["UserSettingsSetRequest"] = to_class(UserSettingsSetRequest, self.user_settings_set_request) + result["UserSettingsUnknownKeysWarningRequest"] = to_class(_UserSettingsUnknownKeysWarningRequest, self.user_settings_unknown_keys_warning_request) + result["UserSettingsUnknownKeysWarningResult"] = to_class(_UserSettingsUnknownKeysWarningResult, self.user_settings_unknown_keys_warning_result) result["UserSettingsUpdateRequest"] = to_class(_UserSettingsUpdateRequest, self.user_settings_update_request) result["UserSettingsUpdateResult"] = to_class(_UserSettingsUpdateResult, self.user_settings_update_result) result["UserSettingsValidateRequest"] = to_class(UserSettingsValidateRequest, self.user_settings_validate_request) @@ -57025,6 +60108,7 @@ def _load_TaskInfo(obj: Any) -> "TaskInfo": ExternalToolResult = ExternalToolTextResultForLlm ExternalToolTextResultForLlmContentResourceLinkIconTheme = Theme FeatureFlagsResolveResult = dict +FeatureFlagsResolveStartupGatesResult = dict FilterMapping = dict HistoryCompactRequest = Any InstructionDiscoveryPathKind = DebugCollectLogsEntryKind @@ -57070,7 +60154,15 @@ def _load_TaskInfo(obj: Any) -> "TaskInfo": ProviderGetEndpointRequest = Any QuotaTakeWarningsResult = list RemoteSessionMetadataTaskType = TaskType +SandboxCheckEnforcementCommandResult = bool +SandboxCheckPlatformSupportResult = bool +SandboxCheckWindowsHostLoopbackSupportResult = bool +SandboxGetUnsupportedMessageResult = str +SandboxGetUnsupportedSettingDisabledNoticeResult = str SandboxHostCapabilityName = str +SandboxProxyCaCheckInstallationSupportResult = bool +SandboxProxyCaCheckRelevanceResult = bool +SandboxSettingsApplyDefaultsResult = dict SessionAuthInfoResult = AuthIdentity | None SessionCancelAllBackgroundAgentsResult = int SessionContextHostType = HostType @@ -57090,6 +60182,8 @@ def _load_TaskInfo(obj: Any) -> "TaskInfo": TaskInfoExecutionMode = TaskExecutionMode TaskInfoStatus = TaskStatus ToolResult = ToolResultExpanded +UserSettingsBuildRuntimeResult = dict +UserSettingsLoadForConfigDirResult = dict WorkspaceSummaryHostType = HostType WorkspacesWorkspaceDetailsHostType = HostType @@ -57121,6 +60215,123 @@ def _patch_model_capabilities(data: dict) -> dict: return data +# Experimental: this API group is experimental and may change or be removed. +class ServerSandboxProxyCaApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def check_installation_support(self, *, timeout: float | None = None) -> bool: + "Reports whether this runtime process can offer installing the sandbox credential-proxy certificate authority into OS trust.\n\nReturns:\n True when this process can offer installing the sandbox credential-proxy certificate authority into OS trust." + return bool(await self._client.request("sandbox.proxyCa.checkInstallationSupport", {}, **_timeout_kwargs(timeout))) + + async def check_relevance(self, params: SandboxProxyCARequest, *, timeout: float | None = None) -> bool: + "Reports whether this sandbox configuration uses the credential proxy and can need certificate-authority setup.\n\nArgs:\n params: Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings.\n\nReturns:\n True when the sandbox configuration uses the credential proxy and can need certificate-authority setup." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return bool(await self._client.request("sandbox.proxyCa.checkRelevance", params_dict, **_timeout_kwargs(timeout))) + + async def get_status(self, params: SandboxProxyCARequest, *, timeout: float | None = None) -> SandboxProxyCAStatus: + "Reports whether the persistent certificate authority of the sandbox credential proxy exists, whether OS trust includes it, and whether it must be rotated. Changes nothing.\n\nArgs:\n params: Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings.\n\nReturns:\n Status of the persistent certificate authority of the sandbox credential proxy." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return SandboxProxyCAStatus.from_dict(await self._client.request("sandbox.proxyCa.getStatus", params_dict, **_timeout_kwargs(timeout))) + + async def create(self, params: SandboxProxyCARequest, *, timeout: float | None = None) -> SandboxProxyCACreateResult: + "Creates the persistent certificate authority of the sandbox credential proxy if none is stored, without changing OS trust, and returns the path of its public certificate. Keeps an existing certificate authority, even one that must be rotated. Fails where OS trust is unsupported. Trust it with sandbox.proxyCa.trust: the CLI trusts only the hosts in the saved user settings, so it refuses a certificate authority that also covers hosts from sandboxConfig.\n\nArgs:\n params: Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings.\n\nReturns:\n Result of creating the persistent certificate authority of the sandbox credential proxy." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return SandboxProxyCACreateResult.from_dict(await self._client.request("sandbox.proxyCa.create", params_dict, **_timeout_kwargs(timeout))) + + async def rotate(self, params: SandboxProxyCARequest, *, timeout: float | None = None) -> SandboxProxyCAStatus: + "Replaces the persistent certificate authority of the sandbox credential proxy with a new one for the current credential hosts. If OS trust included the old one, removes it and trusts the new one, which can show an OS authentication prompt. Running sandboxed tools keep the old certificate authority until they restart.\n\nArgs:\n params: Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings.\n\nReturns:\n Status of the persistent certificate authority of the sandbox credential proxy." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return SandboxProxyCAStatus.from_dict(await self._client.request("sandbox.proxyCa.rotate", params_dict, **_timeout_kwargs(timeout))) + + async def trust(self, params: SandboxProxyCARequest, *, timeout: float | None = None) -> SandboxProxyCAStatus: + "Adds the persistent certificate authority of the sandbox credential proxy to OS trust, so sandboxed clients that read only OS trust accept the proxy. Call create first. Refuses a certificate authority that is not constrained to the current credential hosts. Can show an OS authentication prompt.\n\nArgs:\n params: Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings.\n\nReturns:\n Status of the persistent certificate authority of the sandbox credential proxy." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return SandboxProxyCAStatus.from_dict(await self._client.request("sandbox.proxyCa.trust", params_dict, **_timeout_kwargs(timeout))) + + async def remove(self, *, timeout: float | None = None) -> SandboxProxyCAStatus: + "Removes the persistent certificate authority of the sandbox credential proxy from OS trust. Keeps the stored certificate authority. Can show an OS authentication prompt. Sandboxed clients that read only OS trust then reject the proxy; clients that read the per-process certificate bundle continue to work.\n\nReturns:\n Status of the persistent certificate authority of the sandbox credential proxy." + return SandboxProxyCAStatus.from_dict(await self._client.request("sandbox.proxyCa.remove", {}, **_timeout_kwargs(timeout))) + + +# Experimental: this API group is experimental and may change or be removed. +class ServerSandboxApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + self.proxy_ca = ServerSandboxProxyCaApi(client) + + async def get_host_support(self, *, timeout: float | None = None) -> SandboxHostSupport: + "Reports whether the host running this runtime can run the command sandbox, without starting a session or spawning a sandboxed command.\n\nReturns:\n Whether the host running this runtime can run the command sandbox. The runtime checks `supported` once per process. A capability answer can change while the process runs, for example after the user installs a missing package." + return SandboxHostSupport.from_dict(await self._client.request("sandbox.getHostSupport", {}, **_timeout_kwargs(timeout))) + + +# Experimental: this API group is experimental and may change or be removed. +class ServerUserSettingsApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def get(self, *, timeout: float | None = None) -> UserSettingsGetResult: + "Lists every known user setting from settings.json, each with its effective value, its default, and whether it is at the default — so settings the user has never set still appear with their default value. Does not include repository- or enterprise-managed overrides that the runtime layers on top at session time.\n\nReturns:\n Per-key metadata for every known user setting in settings.json, including settings left at their default. Excludes repository- and enterprise-managed overrides." + return UserSettingsGetResult.from_dict(await self._client.request("user.settings.get", {}, **_timeout_kwargs(timeout))) + + async def set(self, params: UserSettingsSetRequest, *, timeout: float | None = None) -> None: + "Writes one or more user settings to settings.json, replacing each provided top-level key. A key whose value is null is removed.\n\nArgs:\n params: Partial user settings to write to settings.json. Each top-level key is written individually, replacing the existing value; a key whose value is null is removed." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + await self._client.request("user.settings.set", params_dict, **_timeout_kwargs(timeout)) + + +# Experimental: this API group is experimental and may change or be removed. +class ServerUserApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + self.settings = ServerUserSettingsApi(client) + + +# Experimental: this API group is experimental and may change or be removed. +class ServerManagedSettingsPermissionsApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def evaluate(self, params: ManagedPermissionsEvaluateRequest, *, timeout: float | None = None) -> ManagedPermissionsEvaluateResult: + "Pure, sessionless evaluation of operations against a supplied permissionsContext. Performs no policy discovery, I/O, prompting, navigation, permission grants, or sandbox changes. Obtain the context from managedSettings.resolve or session.managedSettings.get, or reuse an in-memory context. Results preserve input order and duplicates. Consumers must block deny, obtain approval for ask, and use their normal permission flow for unmanaged. Unknown policy returns failClosed with every operation denied. This is not a substitute for user permissions or other security controls.\n\nArgs:\n params: Managed policy context and ordered operations for pure, sessionless evaluation.\n\nReturns:\n Ordered managed permission verdicts and the supplied policy's fail-closed posture." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return ManagedPermissionsEvaluateResult.from_dict(await self._client.request("managedSettings.permissions.evaluate", params_dict, **_timeout_kwargs(timeout))) + + +# Experimental: this API group is experimental and may change or be removed. +class ServerManagedSettingsApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + self.permissions = ServerManagedSettingsPermissionsApi(client) + + async def read(self, *, timeout: float | None = None) -> ManagedSettingsReadResult: + "Discovers device-managed settings from production MDM and managed-file sources, validates them against the runtime-owned managed-settings schema, and returns the canonical JSON without requiring a session. `managedSettings.resolve` returns the same device settings together with the account's server policy.\n\nReturns:\n Validated device-managed settings discovered before a session exists." + return ManagedSettingsReadResult.from_dict(await self._client.request("managedSettings.read", {}, **_timeout_kwargs(timeout))) + + async def clear_cache(self, *, timeout: float | None = None) -> None: + "Force-refreshes enterprise managed settings for every account: wipes the persistent server-policy cache (the whole `/managed-settings` directory) and drops this runtime process's in-memory retained server policy. It does not itself fetch policy — the effect is that the next time a session resolves managed settings for an account, that resolution re-fetches the account's org policy from the network instead of serving a cached response. Note that `managedSettings.read` returns only device/MDM settings and never triggers the account server-policy fetch, so a host implementing \"sync account policy\" should call `managedSettings.resolve` or start a fresh session resolution rather than treat a subsequent `managedSettings.read` as the refreshed org policy. Mirrors the invalidation a sign-out performs, broadened from the one signing-out account to all of them; device/MDM layers describe the machine, not the account, and are left untouched. Rejects if the on-disk cache cannot be removed." + await self._client.request("managedSettings.clearCache", {}, **_timeout_kwargs(timeout)) + + async def resolve(self, params: ManagedSettingsResolveRequest, *, timeout: float | None = None) -> ManagedSettingsResolveResult: + "Resolves the effective enterprise managed settings without a session, from the device channel and, when an account is available, the account's server policy through the same per-account cache sessions use. A cached server policy less than an hour old is used without a fetch; otherwise the policy is fetched, and when the fetch fails a cached policy up to 24 hours old is used instead, unless `forceRemoteSettingsRefresh` requires a live fetch. With no account requested or signed in, it reports device policy only; signing out removes the account's cached policy. It can fetch server policy over the network when the cache is stale, so call it off latency-critical paths such as startup rather than before listing models. The policy helper is not run. `layers` lists each channel's document before merging, and `values` and `meta` carry typed effective values and their lock state for the keys typed so far.\n\nArgs:\n params: Optional opaque account selection or GitHub token whose managed settings are resolved.\n\nReturns:\n Effective enterprise managed settings for an account, resolved without a session." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return ManagedSettingsResolveResult.from_dict(await self._client.request("managedSettings.resolve", params_dict, **_timeout_kwargs(timeout))) + + async def schema(self, *, timeout: float | None = None) -> ManagedSettingsSchemaResult: + "Returns the managed-settings authoring JSON schema with descriptive `x-composition` annotations aligned with the shared settings-engine vocabulary. These annotations are not a complete runtime composition contract: model, effortLevel, and contextTier remain coupled. Use `managedSettings.compose` for the runtime's effective result. Performs no I/O.\n\nReturns:\n The authoring JSON schema for managed settings recognized by this runtime." + return ManagedSettingsSchemaResult.from_dict(await self._client.request("managedSettings.schema", {}, **_timeout_kwargs(timeout))) + + async def validate(self, params: ManagedSettingsValidateRequest, *, timeout: float | None = None) -> ManagedSettingsValidateResult: + "Validates a candidate managed-settings document the way the runtime validates delivered policy, without applying it. Reports errors that would reject the document, warnings for content the runtime ignores, and the canonical document it would apply. Document text nested more than 64 levels deep is rejected. Performs no I/O.\n\nArgs:\n params: A candidate managed-settings document to validate without applying it.\n\nReturns:\n Result of validating a managed-settings document." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return ManagedSettingsValidateResult.from_dict(await self._client.request("managedSettings.validate", params_dict, **_timeout_kwargs(timeout))) + + async def compose(self, params: ManagedSettingsComposeRequest, *, timeout: float | None = None) -> ManagedSettingsComposeResult: + "Merges candidate managed-settings documents for the device, server, and policy-helper channels into the effective settings the runtime would enforce on this host, using the same precedence and composition rules as live resolution, without applying them. Like live resolution, a server's advisory sandbox force-enable is declined on a host that cannot run the sandbox. Does not fetch policy or read policy files, but may perform blocking OS or subprocess probes for sandbox support. Preview documents are limited to 1 MiB and 64 levels of nesting.\n\nArgs:\n params: Candidate managed-settings documents to merge without applying them.\n\nReturns:\n The effective managed settings the runtime would enforce for the given documents, in the same shape `managedSettings.resolve` returns." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return ManagedSettingsComposeResult.from_dict(await self._client.request("managedSettings.compose", params_dict, **_timeout_kwargs(timeout))) + + # Experimental: this API group is experimental and may change or be removed. class ServerEnvironmentsApi: def __init__(self, client: "JsonRpcClient"): @@ -57194,47 +60405,6 @@ async def get_built_in_catalog(self, *, timeout: float | None = None) -> BuiltIn return BuiltInModelCatalog.from_dict(await self._client.request("models.getBuiltInCatalog", {}, **_timeout_kwargs(timeout))) -# Experimental: this API group is experimental and may change or be removed. -class ServerSandboxProxyCaApi: - def __init__(self, client: "JsonRpcClient"): - self._client = client - - async def get_status(self, params: SandboxProxyCARequest, *, timeout: float | None = None) -> SandboxProxyCAStatus: - "Reports whether the persistent certificate authority of the sandbox credential proxy exists, whether OS trust includes it, and whether it must be rotated. Changes nothing.\n\nArgs:\n params: Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings.\n\nReturns:\n Status of the persistent certificate authority of the sandbox credential proxy." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return SandboxProxyCAStatus.from_dict(await self._client.request("sandbox.proxyCa.getStatus", params_dict, **_timeout_kwargs(timeout))) - - async def create(self, params: SandboxProxyCARequest, *, timeout: float | None = None) -> SandboxProxyCACreateResult: - "Creates the persistent certificate authority of the sandbox credential proxy if none is stored, without changing OS trust, and returns the path of its public certificate. Keeps an existing certificate authority, even one that must be rotated. Fails where OS trust is unsupported. Trust it with sandbox.proxyCa.trust: the CLI trusts only the hosts in the saved user settings, so it refuses a certificate authority that also covers hosts from sandboxConfig.\n\nArgs:\n params: Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings.\n\nReturns:\n Result of creating the persistent certificate authority of the sandbox credential proxy." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return SandboxProxyCACreateResult.from_dict(await self._client.request("sandbox.proxyCa.create", params_dict, **_timeout_kwargs(timeout))) - - async def rotate(self, params: SandboxProxyCARequest, *, timeout: float | None = None) -> SandboxProxyCAStatus: - "Replaces the persistent certificate authority of the sandbox credential proxy with a new one for the current credential hosts. If OS trust included the old one, removes it and trusts the new one, which can show an OS authentication prompt. Running sandboxed tools keep the old certificate authority until they restart.\n\nArgs:\n params: Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings.\n\nReturns:\n Status of the persistent certificate authority of the sandbox credential proxy." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return SandboxProxyCAStatus.from_dict(await self._client.request("sandbox.proxyCa.rotate", params_dict, **_timeout_kwargs(timeout))) - - async def trust(self, params: SandboxProxyCARequest, *, timeout: float | None = None) -> SandboxProxyCAStatus: - "Adds the persistent certificate authority of the sandbox credential proxy to OS trust, so sandboxed clients that read only OS trust accept the proxy. Call create first. Refuses a certificate authority that is not constrained to the current credential hosts. Can show an OS authentication prompt.\n\nArgs:\n params: Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings.\n\nReturns:\n Status of the persistent certificate authority of the sandbox credential proxy." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return SandboxProxyCAStatus.from_dict(await self._client.request("sandbox.proxyCa.trust", params_dict, **_timeout_kwargs(timeout))) - - async def remove(self, *, timeout: float | None = None) -> SandboxProxyCAStatus: - "Removes the persistent certificate authority of the sandbox credential proxy from OS trust. Keeps the stored certificate authority. Can show an OS authentication prompt. Sandboxed clients that read only OS trust then reject the proxy; clients that read the per-process certificate bundle continue to work.\n\nReturns:\n Status of the persistent certificate authority of the sandbox credential proxy." - return SandboxProxyCAStatus.from_dict(await self._client.request("sandbox.proxyCa.remove", {}, **_timeout_kwargs(timeout))) - - -# Experimental: this API group is experimental and may change or be removed. -class ServerSandboxApi: - def __init__(self, client: "JsonRpcClient"): - self._client = client - self.proxy_ca = ServerSandboxProxyCaApi(client) - - async def get_host_support(self, *, timeout: float | None = None) -> SandboxHostSupport: - "Reports whether the host running this runtime can run the command sandbox, without starting a session or spawning a sandboxed command.\n\nReturns:\n Whether the host running this runtime can run the command sandbox. The runtime checks `supported` once per process. A capability answer can change while the process runs, for example after the user installs a missing package." - return SandboxHostSupport.from_dict(await self._client.request("sandbox.getHostSupport", {}, **_timeout_kwargs(timeout))) - - # Experimental: this API group is experimental and may change or be removed. class ServerToolsApi: def __init__(self, client: "JsonRpcClient"): @@ -57634,73 +60804,6 @@ async def list(self, *, timeout: float | None = None) -> CommandList: return CommandList.from_dict(await self._client.request("commands.list", {}, **_timeout_kwargs(timeout))) -# Experimental: this API group is experimental and may change or be removed. -class ServerUserSettingsApi: - def __init__(self, client: "JsonRpcClient"): - self._client = client - - async def get(self, *, timeout: float | None = None) -> UserSettingsGetResult: - "Lists every known user setting from settings.json, each with its effective value, its default, and whether it is at the default — so settings the user has never set still appear with their default value. Does not include repository- or enterprise-managed overrides that the runtime layers on top at session time.\n\nReturns:\n Per-key metadata for every known user setting in settings.json, including settings left at their default. Excludes repository- and enterprise-managed overrides." - return UserSettingsGetResult.from_dict(await self._client.request("user.settings.get", {}, **_timeout_kwargs(timeout))) - - async def set(self, params: UserSettingsSetRequest, *, timeout: float | None = None) -> None: - "Writes one or more user settings to settings.json, replacing each provided top-level key. A key whose value is null is removed.\n\nArgs:\n params: Partial user settings to write to settings.json. Each top-level key is written individually, replacing the existing value; a key whose value is null is removed." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - await self._client.request("user.settings.set", params_dict, **_timeout_kwargs(timeout)) - - -# Experimental: this API group is experimental and may change or be removed. -class ServerUserApi: - def __init__(self, client: "JsonRpcClient"): - self._client = client - self.settings = ServerUserSettingsApi(client) - - -# Experimental: this API group is experimental and may change or be removed. -class ServerManagedSettingsPermissionsApi: - def __init__(self, client: "JsonRpcClient"): - self._client = client - - async def evaluate(self, params: ManagedPermissionsEvaluateRequest, *, timeout: float | None = None) -> ManagedPermissionsEvaluateResult: - "Pure, sessionless evaluation of operations against a supplied permissionsContext. Performs no policy discovery, I/O, prompting, navigation, permission grants, or sandbox changes. Obtain the context from managedSettings.resolve or session.managedSettings.get, or reuse an in-memory context. Results preserve input order and duplicates. Consumers must block deny, obtain approval for ask, and use their normal permission flow for unmanaged. Unknown policy returns failClosed with every operation denied. This is not a substitute for user permissions or other security controls.\n\nArgs:\n params: Managed policy context and ordered operations for pure, sessionless evaluation.\n\nReturns:\n Ordered managed permission verdicts and the supplied policy's fail-closed posture." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return ManagedPermissionsEvaluateResult.from_dict(await self._client.request("managedSettings.permissions.evaluate", params_dict, **_timeout_kwargs(timeout))) - - -# Experimental: this API group is experimental and may change or be removed. -class ServerManagedSettingsApi: - def __init__(self, client: "JsonRpcClient"): - self._client = client - self.permissions = ServerManagedSettingsPermissionsApi(client) - - async def read(self, *, timeout: float | None = None) -> ManagedSettingsReadResult: - "Discovers device-managed settings from production MDM and managed-file sources, validates them against the runtime-owned managed-settings schema, and returns the canonical JSON without requiring a session. `managedSettings.resolve` returns the same device settings together with the account's server policy.\n\nReturns:\n Validated device-managed settings discovered before a session exists." - return ManagedSettingsReadResult.from_dict(await self._client.request("managedSettings.read", {}, **_timeout_kwargs(timeout))) - - async def clear_cache(self, *, timeout: float | None = None) -> None: - "Force-refreshes enterprise managed settings for every account: wipes the persistent server-policy cache (the whole `/managed-settings` directory) and drops this runtime process's in-memory retained server policy. It does not itself fetch policy — the effect is that the next time a session resolves managed settings for an account, that resolution re-fetches the account's org policy from the network instead of serving a cached response. Note that `managedSettings.read` returns only device/MDM settings and never triggers the account server-policy fetch, so a host implementing \"sync account policy\" should call `managedSettings.resolve` or start a fresh session resolution rather than treat a subsequent `managedSettings.read` as the refreshed org policy. Mirrors the invalidation a sign-out performs, broadened from the one signing-out account to all of them; device/MDM layers describe the machine, not the account, and are left untouched. Rejects if the on-disk cache cannot be removed." - await self._client.request("managedSettings.clearCache", {}, **_timeout_kwargs(timeout)) - - async def resolve(self, params: ManagedSettingsResolveRequest, *, timeout: float | None = None) -> ManagedSettingsResolveResult: - "Resolves the effective enterprise managed settings without a session, from the device channel and, when an account is available, the account's server policy through the same per-account cache sessions use. A cached server policy less than an hour old is used without a fetch; otherwise the policy is fetched, and when the fetch fails a cached policy up to 24 hours old is used instead, unless `forceRemoteSettingsRefresh` requires a live fetch. With no account requested or signed in, it reports device policy only; signing out removes the account's cached policy. It can fetch server policy over the network when the cache is stale, so call it off latency-critical paths such as startup rather than before listing models. The policy helper is not run. `layers` lists each channel's document before merging, and `values` and `meta` carry typed effective values and their lock state for the keys typed so far.\n\nArgs:\n params: Optional opaque account selection or GitHub token whose managed settings are resolved.\n\nReturns:\n Effective enterprise managed settings for an account, resolved without a session." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return ManagedSettingsResolveResult.from_dict(await self._client.request("managedSettings.resolve", params_dict, **_timeout_kwargs(timeout))) - - async def schema(self, *, timeout: float | None = None) -> ManagedSettingsSchemaResult: - "Returns the managed-settings authoring JSON schema with descriptive `x-composition` annotations aligned with the shared settings-engine vocabulary. These annotations are not a complete runtime composition contract: model, effortLevel, and contextTier remain coupled. Use `managedSettings.compose` for the runtime's effective result. Performs no I/O.\n\nReturns:\n The authoring JSON schema for managed settings recognized by this runtime." - return ManagedSettingsSchemaResult.from_dict(await self._client.request("managedSettings.schema", {}, **_timeout_kwargs(timeout))) - - async def validate(self, params: ManagedSettingsValidateRequest, *, timeout: float | None = None) -> ManagedSettingsValidateResult: - "Validates a candidate managed-settings document the way the runtime validates delivered policy, without applying it. Reports errors that would reject the document, warnings for content the runtime ignores, and the canonical document it would apply. Document text nested more than 64 levels deep is rejected. Performs no I/O.\n\nArgs:\n params: A candidate managed-settings document to validate without applying it.\n\nReturns:\n Result of validating a managed-settings document." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return ManagedSettingsValidateResult.from_dict(await self._client.request("managedSettings.validate", params_dict, **_timeout_kwargs(timeout))) - - async def compose(self, params: ManagedSettingsComposeRequest, *, timeout: float | None = None) -> ManagedSettingsComposeResult: - "Merges candidate managed-settings documents for the device, server, and policy-helper channels into the effective settings the runtime would enforce on this host, using the same precedence and composition rules as live resolution, without applying them. Like live resolution, a server's advisory sandbox force-enable is declined on a host that cannot run the sandbox. Does not fetch policy or read policy files, but may perform blocking OS or subprocess probes for sandbox support. Preview documents are limited to 1 MiB and 64 levels of nesting.\n\nArgs:\n params: Candidate managed-settings documents to merge without applying them.\n\nReturns:\n The effective managed settings the runtime would enforce for the given documents, in the same shape `managedSettings.resolve` returns." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return ManagedSettingsComposeResult.from_dict(await self._client.request("managedSettings.compose", params_dict, **_timeout_kwargs(timeout))) - - # Experimental: this API group is experimental and may change or be removed. class ServerRuntimeApi: def __init__(self, client: "JsonRpcClient"): @@ -57910,11 +61013,13 @@ class ServerRpc: """Typed server-scoped RPC methods.""" def __init__(self, client: "JsonRpcClient"): self._client = client + self.sandbox = ServerSandboxApi(client) + self.user = ServerUserApi(client) + self.managed_settings = ServerManagedSettingsApi(client) self.environments = ServerEnvironmentsApi(client) self.host = ServerHostApi(client) self.hooks = ServerHooksApi(client) self.models = ServerModelsApi(client) - self.sandbox = ServerSandboxApi(client) self.tools = ServerToolsApi(client) self.account = ServerAccountApi(client) self.secrets = ServerSecretsApi(client) @@ -57926,8 +61031,6 @@ def __init__(self, client: "JsonRpcClient"): self.plugins = ServerPluginsApi(client) self.agents = ServerAgentsApi(client) self.commands = ServerCommandsApi(client) - self.user = ServerUserApi(client) - self.managed_settings = ServerManagedSettingsApi(client) self.runtime = ServerRuntimeApi(client) self.session_fs = ServerSessionFsApi(client) self.llm_inference = ServerLlmInferenceApi(client) @@ -57945,6 +61048,380 @@ async def register_extension_launch_provider(self, *, timeout: float | None = No await self._client.request("registerExtensionLaunchProvider", {}, **_timeout_kwargs(timeout)) +# Experimental: this API group is experimental and may change or be removed. +class _InternalServerSandboxProxySecretApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def _get_location(self, *, timeout: float | None = None) -> SandboxProxySecretLocation: + "Reports where this runtime keeps the sandbox proxy password: the credential store directory and the entry identifier within it. Both are derived from the configuration directory this runtime was started with, so a host does not resolve them itself. Read this to recognize a `${secret:…}` value in stored sandbox settings as this runtime's own proxy password rather than a reference the user wrote by hand. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract.\n\nReturns:\n Where this runtime keeps the sandbox proxy password.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + return SandboxProxySecretLocation.from_dict(await self._client.request("sandbox.proxySecret.getLocation", {}, **_timeout_kwargs(timeout))) + + async def _get(self, *, timeout: float | None = None) -> SandboxProxySecretGetResult: + "Reads the stored sandbox proxy password from the credential store `sandbox.proxySecret.getLocation` names, preferring the OS keychain and falling back to the on-disk store. Reports an absent value rather than failing when no entry exists. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract.\n\nReturns:\n The stored sandbox proxy password, if one is present.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + return SandboxProxySecretGetResult.from_dict(await self._client.request("sandbox.proxySecret.get", {}, **_timeout_kwargs(timeout))) + + async def _save(self, params: SandboxProxySecretSaveRequest, *, timeout: float | None = None) -> SandboxProxySecretSaveResult: + "Stores the sandbox proxy password in the credential store `sandbox.proxySecret.getLocation` names, replacing any existing entry. Reports whether the OS keychain accepted it or it fell back to the on-disk store. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract.\n\nArgs:\n params: The sandbox proxy password to store.\n\nReturns:\n Where the sandbox proxy password was stored.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return SandboxProxySecretSaveResult.from_dict(await self._client.request("sandbox.proxySecret.save", params_dict, **_timeout_kwargs(timeout))) + + async def _delete(self, *, timeout: float | None = None) -> None: + "Removes the stored sandbox proxy password from the credential store `sandbox.proxySecret.getLocation` names. Succeeds when no entry exists, so it is safe to call while clearing a proxy password whose origin is unknown. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + await self._client.request("sandbox.proxySecret.delete", {}, **_timeout_kwargs(timeout)) + + +# Experimental: this API group is experimental and may change or be removed. +class _InternalServerSandboxSettingsApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def _apply_defaults(self, params: SandboxApplyDefaultsRequest, *, timeout: float | None = None) -> dict: + "Resolves a stored sandbox settings object into the effective one, filling every value the user left unset with its default. Read this to render or reason about the sandbox configuration a session would actually run under, rather than the sparse document the user wrote.\n\nArgs:\n params: The stored sandbox settings to resolve against the defaults.\n\nReturns:\n The effective sandbox settings, with every unset value resolved to its default.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return dict(await self._client.request("sandbox.settings.applyDefaults", params_dict, **_timeout_kwargs(timeout))) + + +# Experimental: this API group is experimental and may change or be removed. +class _InternalServerSandboxApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + self.proxy_secret = _InternalServerSandboxProxySecretApi(client) + self.settings = _InternalServerSandboxSettingsApi(client) + + async def _resolve_floored_config(self, params: _SandboxResolveFlooredConfigParams, *, timeout: float | None = None) -> SandboxResolveFlooredConfigResult: + "Raises a user's sandbox settings to an administrator's managed sandbox floor and returns the result a session should actually run under. The floor can only tighten: an enterprise force-on is reflected even when the user's own `enabled` is false, and a user cannot lower a setting the floor raised. The result is normalized through the declared sandbox shape, so a key reorder or an undeclared passthrough key is not mistaken for a policy change by callers that diff two results. A host must call this rather than merge the two layers itself, because reimplementing the direction of the fold is what turns an administrator's floor into a suggestion.\n\nArgs:\n params: The user's sandbox settings and the managed sandbox floor to raise them to.\n\nReturns:\n The user's sandbox settings raised to the managed floor.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return SandboxResolveFlooredConfigResult.from_dict(await self._client.request("sandbox.resolveFlooredConfig", params_dict, **_timeout_kwargs(timeout))) + + async def _prepare_picker_policy(self, params: _SandboxPreparePickerPolicyParams, *, timeout: float | None = None) -> _SandboxPreparePickerPolicyResult: + "Builds the effective filesystem policy one `@`-file picker checks its suggestions against, so Git discovery and grant canonicalization run once for the picker's lifetime instead of on every debounced keystroke. Returns no policy when the sandbox is absent or disabled, which the paired filter reads as \"keep every candidate\". A host must pair this with `sandbox.filterPickerCandidates` rather than resolve a grant list itself, because the picker's grants are narrower than a file tool's — the same path a built-in tool may read can be one the picker must not offer.\n\nArgs:\n params: The working directory and sandbox settings to build a file-picker policy from.\n\nReturns:\n The prepared file-picker policy, or none when the sandbox is disabled.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _SandboxPreparePickerPolicyResult.from_dict(await self._client.request("sandbox.preparePickerPolicy", params_dict, **_timeout_kwargs(timeout))) + + async def _filter_picker_candidates(self, params: _SandboxFilterPickerCandidatesParams, *, timeout: float | None = None) -> _SandboxFilterPickerCandidatesResult: + "Checks a batch of `@`-file picker suggestions against a policy prepared by `sandbox.preparePickerPolicy` and returns one allow decision per candidate, positionally aligned with the request. Batched deliberately: each check canonicalizes a path component-by-component through the real filesystem, so one call amortizes that over a single hop rather than dozens while the user types. A directory the policy does not itself allow can still be kept as a waypoint to an allowed subtree. An absent policy keeps every candidate.\n\nArgs:\n params: A batch of file-picker candidates to check against a prepared policy.\n\nReturns:\n Per-candidate allow decisions, positionally aligned with the request.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _SandboxFilterPickerCandidatesResult.from_dict(await self._client.request("sandbox.filterPickerCandidates", params_dict, **_timeout_kwargs(timeout))) + + async def _resolve_for_optional(self, params: _SandboxEffectiveForOptionalParams, *, timeout: float | None = None) -> _SandboxEffectiveForOptionalResult: + "The sandbox a single named feature actually launches under, which is not the same as the session's sandbox. A feature is routed out of the sandbox by its own flag — `sandboxMcpServers`, `sandboxLspServers` — so an enabled session can still start one server confined and another free. Returns a disabled sandbox rather than an error when the host has no sandbox slice at all, so an absent config and an opted-out feature read alike at the launch site. A host must ask per feature rather than reuse the session config, because reading only `enabled` confines a server the user opted out of, or reports as sandboxed one that is not.\n\nArgs:\n params: A sandbox config and the per-feature routing flag to resolve it for.\n\nReturns:\n The sandbox a named feature actually launches under.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _SandboxEffectiveForOptionalResult.from_dict(await self._client.request("sandbox.resolveForOptional", params_dict, **_timeout_kwargs(timeout))) + + async def _check_platform_support(self, *, timeout: float | None = None) -> bool: + "Reports whether this machine can run an OS-level command sandbox at all. A host must ask before it offers sandboxing, because the answer is a property of the machine rather than of any setting: on Linux it depends on bubblewrap being installed, and on Windows on the OS build supporting BaseContainer. Probing it requires spawning a process the first time, so the answer is cached for the life of the runtime. A host that assumes support and enables the sandbox anyway produces a session in which every shell command fails.\n\nReturns:\n True when an OS-level sandbox can run on this host.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + return bool(await self._client.request("sandbox.checkPlatformSupport", {}, **_timeout_kwargs(timeout))) + + async def _check_windows_host_loopback_support(self, *, timeout: float | None = None) -> bool: + "Reports whether this Windows host's BaseContainer implementation can reach the host's loopback interface directly, which is what a local-network policy needs to avoid routing through the egress proxy. Like `sandbox.checkPlatformSupport`, the answer is a property of the machine's OS build rather than of any setting, and resolving it the first time spawns a platform probe. A host that offers the direct local-network option on a machine that lacks the capability produces a session whose sandboxed commands cannot reach local services. Always false off Windows.\n\nReturns:\n True when the sandbox on this host can reach host loopback directly.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + return bool(await self._client.request("sandbox.checkWindowsHostLoopbackSupport", {}, **_timeout_kwargs(timeout))) + + async def _get_unsupported_message(self, *, timeout: float | None = None) -> str: + "The explanation a host shows when it refuses an explicit request to turn the sandbox on for a machine that cannot run one. Carries the platform-specific remedy — install bubblewrap, update Windows — and the documentation link, so a host that got `false` from `sandbox.checkPlatformSupport` does not have to compose its own reason and cannot describe the same machine differently from the runtime's own spawn path.\n\nReturns:\n The user-facing refusal, including the platform remedy and the documentation link.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + return str(await self._client.request("sandbox.getUnsupportedMessage", {}, **_timeout_kwargs(timeout))) + + async def _get_unsupported_setting_disabled_notice(self, *, timeout: float | None = None) -> str: + "The notice a host shows when a stored `sandbox` setting is being ignored for this session because the machine cannot enforce it. Distinct from `sandbox.getUnsupportedMessage`, which refuses an explicit request: this one reports that a setting the user already saved is inert, states that commands will run unsandboxed, and confirms the stored setting itself is left alone. A host that stays silent here leaves the user believing a sandbox is active.\n\nReturns:\n The user-facing notice that a saved sandbox setting is inert for this session.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + return str(await self._client.request("sandbox.getUnsupportedSettingDisabledNotice", {}, **_timeout_kwargs(timeout))) + + async def _get_unsupported_startup_notice(self, params: _SandboxUnsupportedStartupNoticeParams, *, timeout: float | None = None) -> _SandboxUnsupportedStartupNoticeResult: + "The warning a host prints at startup when a session asked for a sandbox on a machine that cannot run one. The third of the unsupported notices, and the only one that depends on the policy in force: it names the remedy the reader can actually act on, which is the stored setting for an unmanaged host, an administrator for a managed one, and waiting for the policy to resolve when the sandbox stayed on only because the policy could not be determined. Returns no notice when the machine does support a sandbox, so a host can call it unconditionally on the startup path. A host that composes its own warning tells a managed user to change a setting their policy will overwrite.\n\nArgs:\n params: The managed sandbox policy in force, which selects which remedy the notice offers.\n\nReturns:\n The startup warning, absent when the machine can run a sandbox.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _SandboxUnsupportedStartupNoticeResult.from_dict(await self._client.request("sandbox.getUnsupportedStartupNotice", params_dict, **_timeout_kwargs(timeout))) + + async def _check_enforcement_command(self, params: _SandboxEnforcementCommandAllowedParams, *, timeout: float | None = None) -> bool: + "Whether one slash command stays reachable while sandbox enforcement is unavailable and the session is otherwise blocked. The permitted set is deliberately narrow — commands that only report state, and the few that let the user repair or leave the situation — and it is keyed on the arguments as well as the name, so `/sandbox status` is admitted where `/sandbox enable` is not. A host must ask rather than keep its own list: a command this returns false for is one the runtime would refuse anyway, and a divergent list either strands the user with no way out or admits a command that acts on an unenforced session.\n\nArgs:\n params: One slash command, as typed, to test against the enforcement-block allowlist.\n\nReturns:\n True when the command stays available while enforcement is blocked.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return bool(await self._client.request("sandbox.checkEnforcementCommand", params_dict, **_timeout_kwargs(timeout))) + + async def _get_docs_url(self, *, timeout: float | None = None) -> SandboxDocsURLResult: + "Returns the documentation URL a host should point a user at when it declines or downgrades a sandbox setting. The runtime owns the address so every surface cites the same page and a host does not hard-code a link that later moves.\n\nReturns:\n The documentation URL a host cites when it declines or downgrades a sandbox setting.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + return SandboxDocsURLResult.from_dict(await self._client.request("sandbox.getDocsUrl", {}, **_timeout_kwargs(timeout))) + + +# Experimental: this API group is experimental and may change or be removed. +class _InternalServerPersistenceApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def _write_raw_json_locked(self, params: PersistenceWriteRawJSONLockedRequest, *, timeout: float | None = None) -> PersistenceWriteRawJSONLockedResult: + "Atomically replaces a JSON file's entire contents while holding the runtime's per-path lock. The lock lives in the runtime process, so a host that writes these files itself takes no part in it and can tear a concurrent runtime write; route the write here instead. Unlike a merging write this never reads or parses the existing file, so a previously corrupted snapshot is replaced wholesale rather than failing every later write. Use it only for callers that always persist a complete snapshot.\n\nArgs:\n params: A complete JSON snapshot to write under the runtime's per-path file lock.\n\nReturns:\n The outcome of a locked snapshot write.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return PersistenceWriteRawJSONLockedResult.from_dict(await self._client.request("persistence.writeRawJsonLocked", params_dict, **_timeout_kwargs(timeout))) + + +# Experimental: this API group is experimental and may change or be removed. +class _InternalServerUserSettingsApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def _set_hook_disabled(self, params: _UserSettingsSetHookDisabledRequest, *, timeout: float | None = None) -> _UserSettingsSetHookDisabledResult: + "Adds or removes one hook key in the user `disabledHooks` setting, rewriting settings.json in place and leaving every other setting untouched. Reports a typed outcome rather than failing the call, so a host can tell an unparseable settings file apart from a write that could not complete.\n\nArgs:\n params: One hook to disable or re-enable.\n\nReturns:\n Outcome of rewriting the `disabledHooks` setting.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _UserSettingsSetHookDisabledResult.from_dict(await self._client.request("user.settings.setHookDisabled", params_dict, **_timeout_kwargs(timeout))) + + async def _load_for_config_dir(self, params: _UserSettingsLoadForConfigDirRequest, *, timeout: float | None = None) -> dict: + "Reads the user's settings document exactly as `user.settings.load` does, but from a caller-supplied configuration directory instead of the one the server resolved for itself. Use this when a consumer scopes a session to its own Copilot home — the SDK's per-session `configDir` override — so the settings read match the directory that session actually uses. An absent or empty `configDir` resolves the server's own home, making this identical to `user.settings.load`. Hook-validation relaxations are deliberately not caller-supplied: they continue to come from the server's environment, so a consumer cannot widen the host's hook policy through this method.\n\nArgs:\n params: Selects the configuration directory whose user settings to read.\n\nReturns:\n The stored user settings document, keyed by setting name.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return dict(await self._client.request("user.settings.loadForConfigDir", params_dict, **_timeout_kwargs(timeout))) + + async def _load_repo(self, params: UserSettingsLoadRepoRequest, *, timeout: float | None = None) -> UserSettingsLoadRepoResult: + "Reads a repository's checked-in settings document as stored, normalized, together with any diagnostic raised while reading it. This is the repository half of the layering `user.settings.get` reports: `user.settings.load` reads the user's own document, and this reads the one a repository checks in to govern the keys `user.settings.governanceKeys` lists as repo-governable. A document that fails to parse, or that sets a key a repository may not govern, is reported through `warning` while the settings that did load are still returned, so a consumer surfaces the diagnostic and continues rather than failing the session. When `repoRoot` is the user's home directory the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as repository policy.\n\nArgs:\n params: Selects the repository whose checked-in settings to read.\n\nReturns:\n A repository's settings as stored, together with any diagnostic raised while reading them.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return UserSettingsLoadRepoResult.from_dict(await self._client.request("user.settings.loadRepo", params_dict, **_timeout_kwargs(timeout))) + + async def _load_and_merge_repo(self, params: _UserSettingsLoadAndMergeRepoRequest, *, timeout: float | None = None) -> _UserSettingsLoadAndMergeRepoResult: + "Reads a repository's settings and merges them over a supplied user layer in one step, returning the settings a consumer should act on inside that repository. Use this rather than reading the two layers separately: the merge is per setting and collection-aware, so a repository adds to the collections it is allowed to influence without replacing the user's own entries, and a whole-document overlay would get that wrong. Any diagnostic raised while reading the repository layer is returned rather than printed, so the consumer decides how to surface it; the settings that did load are merged regardless.\n\nArgs:\n params: A repository to read settings from, and the user layer they are merged over.\n\nReturns:\n The settings a consumer should act on inside a repository, together with any diagnostic raised while reading the repository layer.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _UserSettingsLoadAndMergeRepoResult.from_dict(await self._client.request("user.settings.loadAndMergeRepo", params_dict, **_timeout_kwargs(timeout))) + + async def _get_path(self, *, timeout: float | None = None) -> UserSettingsPathResult: + "Reports the on-disk path of the settings document `user.settings.load` and `user.settings.set` read and write. Resolved the same way those methods resolve it, so a host that shows or opens the settings file names the file the runtime actually uses, including the extensionless legacy `settings` file when that is what is present.\n\nReturns:\n The on-disk location of the user's settings document.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + return UserSettingsPathResult.from_dict(await self._client.request("user.settings.getPath", {}, **_timeout_kwargs(timeout))) + + async def _load_with_warning(self, *, timeout: float | None = None) -> UserSettingsLoadWithWarningResult: + "Reads the user's stored settings together with the diagnostic raised while reading them. This is `user.settings.load` plus the reason part of the document was ignored: that one answers the document alone, so a caller cannot tell a clean read from a salvaged one. Read this when the caller is about to write the file back, where accepting a partial parse would discard every value the loader could not read. The settings that did load are still reported alongside the warning, so a consumer may surface it and continue instead of failing.\n\nReturns:\n The user's stored settings, together with any diagnostic raised while reading them.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + return UserSettingsLoadWithWarningResult.from_dict(await self._client.request("user.settings.loadWithWarning", {}, **_timeout_kwargs(timeout))) + + async def _merge_managed_and_user(self, params: _UserSettingsMergeManagedAndUserParams, *, timeout: float | None = None) -> UserSettingsMergeManagedAndUserResult: + "Folds a user settings layer over a managed (enterprise policy) layer and returns the merged settings. The managed layer's governance keys win, `autoTier` resolves through its overridable form, and the two per-entry control maps (`enabledPlugins`, `extraKnownMarketplaces`) union across the layers and are then stamped back from the managed layer, so each entry an administrator declares wins while the user keeps control of the rest. The parameters are named for their layers rather than being a generic base/override pair: nothing about a settings object identifies which layer produced it, so the runtime cannot detect a transposed call, and transposing one resolves the governance keys in the user's favour instead of the administrator's. Supplying only one layer returns it unchanged, and supplying neither returns an empty object. Rejects a managed `autoTier` that is neither a user-configurable tier nor a single-key overridable form, rather than silently dropping it.\n\nArgs:\n params: The managed (enterprise policy) layer and the user layer to fold together. The field names carry the layer identity: nothing about a settings object identifies which layer produced it, so a generic base/override pair would let a caller transpose them and silently resolve the governance keys in the user's favour.\n\nReturns:\n The user layer folded over the managed layer.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return UserSettingsMergeManagedAndUserResult.from_dict(await self._client.request("user.settings.mergeManagedAndUser", params_dict, **_timeout_kwargs(timeout))) + + async def _merge_repo_value(self, params: _UserSettingsMergeRepoValueParams, *, timeout: float | None = None) -> UserSettingsMergeRepoValueResult: + "Folds a repository's settings layer into the user layer. Each repo-overridable key carries a directional policy chosen so a repository can only add restrictions and never relax the user's own. The two per-entry managed control maps are the exception those directional rules cannot express — a repository may legitimately enable plugins and declare marketplaces — so they are re-stamped afterwards from the runtime's ambient managed policy. That makes the result depend on the runtime process's managed state and not on the arguments alone: a host must call this rather than reimplement the fold, or a repository could relax a restriction the administrator imposed. Rejects when either layer is not a JSON object.\n\nArgs:\n params: The user layer and the repository layer to fold together.\n\nReturns:\n The repository layer folded into the user layer.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return UserSettingsMergeRepoValueResult.from_dict(await self._client.request("user.settings.mergeRepoValue", params_dict, **_timeout_kwargs(timeout))) + + async def _migrate_staff_update_channel_once(self, params: UserSettingsHostContext, *, timeout: float | None = None) -> _UserSettingsMigrateStaffUpdateChannelOnceResult: + "Runs the one-time migration that moves a staff account's update channel to stable, and records that it ran. Idempotent and self-gating: it takes a lock over the global-state file, re-reads the completion stamp inside it, and returns `current` rather than migrating twice, so two hosts racing at startup cannot both migrate. Only a `migrated` status means the persisted settings changed and the caller should reload them. An account on the experimental channel is deliberately left alone and reported as `excluded-experimental`.\n\nArgs:\n params: The filesystem and environment facts a user-settings file is resolved from. Passed explicitly rather than read from the runtime's own process, so a host whose configuration directory differs from its process environment resolves the file it means.\n\nReturns:\n The outcome of the one-time staff update-channel migration.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _UserSettingsMigrateStaffUpdateChannelOnceResult.from_dict(await self._client.request("user.settings.migrateStaffUpdateChannelOnce", params_dict, **_timeout_kwargs(timeout))) + + async def _reset_staff_model_selection_once(self, params: _UserSettingsResetStaffModelSelectionOnceRequest, *, timeout: float | None = None) -> _UserSettingsResetStaffModelSelectionOnceResult: + "Runs the one-time reset that clears a staff account's pinned model selection, and reports the timestamp the host should record. Idempotent and self-gating: the reset is gated on a fixed cutoff, so a caller that passes back the timestamp it recorded gets `didReset: false` rather than a second reset. It applies to staff accounts only; any other account is reported as not reset without the settings document being opened. Only `didReset: true` means the persisted settings changed, and only then are the updated settings returned for the host to adopt.\n\nArgs:\n params: Selects the configuration directory to run the one-time staff model-selection reset against, and supplies the caller's record of whether it has already run.\n\nReturns:\n The outcome of the one-time staff model-selection reset.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _UserSettingsResetStaffModelSelectionOnceResult.from_dict(await self._client.request("user.settings.resetStaffModelSelectionOnce", params_dict, **_timeout_kwargs(timeout))) + + async def _get_unknown_keys_warning(self, params: _UserSettingsUnknownKeysWarningRequest, *, timeout: float | None = None) -> _UserSettingsUnknownKeysWarningResult: + "Reports the top-level keys in the user settings document that the runtime does not recognize, phrased for display to the user. This is a separate question from the warning `user.settings.loadWithWarning` returns: that one describes parts of the document the loader had to ignore to load the rest, whereas an unknown key parses cleanly and is simply not a setting, so a host that surfaces only the load warning silently accepts a misspelled key that will never take effect. Nothing is reported when the document is absent, unreadable, or failed to load, because an unknown-key list derived from a document the runtime could not read would be misleading rather than helpful. Inspection never modifies the document.\n\nArgs:\n params: Selects the configuration directory whose user settings document should be inspected for unrecognized top-level keys.\n\nReturns:\n The unrecognized top-level keys found in the user settings document, already phrased for display.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _UserSettingsUnknownKeysWarningResult.from_dict(await self._client.request("user.settings.getUnknownKeysWarning", params_dict, **_timeout_kwargs(timeout))) + + async def _build_runtime(self, params: _UserSettingsBuildRuntimeRequest, *, timeout: float | None = None) -> dict: + "Resolves the effective runtime settings for a host that is about to start a session, layering the given overrides over the settings documents, the environment and the platform defaults. A host cannot assemble this itself: the precedence between a user document, a repository document, the managed layers and the environment is the runtime's own rule, and a host that re-implements it drifts from the server it is configuring. The working directory, environment and platform are taken as arguments rather than read from the server process, so a host resolving settings for a directory other than its own gets that directory's answer. Nothing is written; this only computes.\n\nArgs:\n params: The overrides and host context to resolve effective runtime settings from.\n\nReturns:\n The effective runtime settings, keyed by setting name. Keys this runtime does not recognize are preserved rather than dropped, so a caller reading a document written by a newer runtime keeps every value.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return dict(await self._client.request("user.settings.buildRuntime", params_dict, **_timeout_kwargs(timeout))) + + async def _migrate_staff_log_level_once(self, params: _UserSettingsMigrateStaffLogLevelOnceRequest, *, timeout: float | None = None) -> _UserSettingsMigrateStaffLogLevelOnceResult: + "Runs the one-time migration that moves a staff account's log level to the current default, and records that it ran. Idempotent and self-gating: it takes a lock over the global-state file and re-reads the completion stamp inside it, so two hosts racing at startup cannot both migrate. Only `refreshed` can have changed the persisted settings, and the settings it returns are the document re-read after the write, so a host should adopt them rather than reloading separately and racing the next writer.\n\nArgs:\n params: Selects the configuration directory to run the one-time staff log-level migration against, and supplies the caller's record of whether it has already run.\n\nReturns:\n The outcome of the one-time staff log-level migration.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _UserSettingsMigrateStaffLogLevelOnceResult.from_dict(await self._client.request("user.settings.migrateStaffLogLevelOnce", params_dict, **_timeout_kwargs(timeout))) + + async def _migrate_obsolete_on_disk(self, params: _UserSettingsMigrateObsoleteOnDiskRequest, *, timeout: float | None = None) -> _UserSettingsMigrateObsoleteOnDiskResult: + "Runs the one-time cleanup that removes obsolete CLI-owned settings and legacy rubber-duck keys from the user's settings document, and reports what it did. Idempotent and safe to call on every startup: with nothing obsolete left it reports `unchanged` and writes nothing. The cleanup preserves every key it does not recognize, so a setting written by a newer host is never dropped by an older one, and a document that fails to parse is reported `invalid` and left untouched rather than rewritten from a partial read. The cleaned document is not returned: it is written before this replies, so `user.settings.load` reads it authoritatively. A host that surfaces unrecognized keys through `user.settings.unknownKeys` wants this first, because the keys this retires would otherwise be shown to the user as if they were misspelled settings.\n\nArgs:\n params: Selects the configuration directory whose settings document to clean.\n\nReturns:\n The outcome of the one-time obsolete-settings cleanup.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _UserSettingsMigrateObsoleteOnDiskResult.from_dict(await self._client.request("user.settings.migrateObsoleteOnDisk", params_dict, **_timeout_kwargs(timeout))) + + async def _get_paths(self, params: UserSettingsGetPathsRequest, *, timeout: float | None = None) -> UserSettingsGetPathsResult: + "Resolves the on-disk locations of the settings files this runtime reads, so a consumer can show or open them. The user path is the same file `user.settings.get`, `user.settings.load`, and `user.settings.set` operate on. Supply `repoRoot` to also resolve that repository's checked-in and local settings paths. A path is reported whether or not the file exists.\n\nArgs:\n params: Selects which settings file paths to resolve.\n\nReturns:\n On-disk locations of the settings files this runtime reads. A path is reported whether or not the file exists.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return UserSettingsGetPathsResult.from_dict(await self._client.request("user.settings.getPaths", params_dict, **_timeout_kwargs(timeout))) + + async def _list_governance_keys(self, *, timeout: float | None = None) -> UserSettingsGovernanceKeysResult: + "Lists the top-level user-setting keys by who is allowed to govern them: `repo` keys a repository may override through `.github/copilot/settings.json`, `claudeRepo` keys a repository may override through a Claude-compatible config, and `managed` keys an enterprise policy may fix. The lists are static for a given runtime build and fail closed: a key absent from a list cannot be governed that way.\n\nReturns:\n Top-level user-setting keys grouped by who may govern them.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + return UserSettingsGovernanceKeysResult.from_dict(await self._client.request("user.settings.listGovernanceKeys", {}, **_timeout_kwargs(timeout))) + + async def _edit(self, params: _UserSettingsEditRequest, *, timeout: float | None = None) -> _SettingsEditResult: + "Atomically edits one canonical user setting inside its settings-file lock. Reads, canonicalizes touched aliases, applies the edit, validates the resulting top-level setting and writes before releasing the lock. An explicit autoUpdatesChannel set completes the staff migration in the same transaction. Only a malformed existing file returns `invalid`; refused keys, invalid values and I/O errors reject the call.\n\nArgs:\n params: One atomic edit of a canonical setting in settings.json.\n\nReturns:\n Outcome of an atomic user or repository settings edit.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = params.to_dict() + return _SettingsEditResult.from_dict(await self._client.request("user.settings.edit", params_dict, **_timeout_kwargs(timeout))) + + async def _normalize(self, params: UserSettingsNormalizeRequest, *, timeout: float | None = None) -> UserSettingsNormalizeResult: + "Rewrites legacy and snake_case setting names in a settings object to their canonical spelling. A caller editing settings.json must normalize before writing: a legacy key left in place survives the write, is re-normalized on the next load, and silently shadows the canonical value the write just stored.\n\nArgs:\n params: Settings object whose key names should be canonicalized.\n\nReturns:\n Settings object with canonical key names.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return UserSettingsNormalizeResult.from_dict(await self._client.request("user.settings.normalize", params_dict, **_timeout_kwargs(timeout))) + + async def _diagnose_problems(self, params: UserSettingsProblemsRequest, *, timeout: float | None = None) -> UserSettingsProblemsResult: + "Diagnoses a set of already-loaded settings layers, reporting each key that will not take effect and why. Settings load tolerantly so that one bad key does not stop a session from starting; this method surfaces what was dropped so a caller can report it instead of silently ignoring the user's intent. Takes the layers as given rather than reading them, so a caller can diagnose exactly the content it is showing, including unsaved edits. Never echoes a setting's value, because a value may be a token or another secret. Marked internal because it exists to carry a CLI call site off the native addon, not to serve a consumer-facing need; it becomes public once an SDK consumer needs to inspect settings health itself.\n\nArgs:\n params: The settings layers to diagnose.\n\nReturns:\n The settings that will not take effect across the given layers.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return UserSettingsProblemsResult.from_dict(await self._client.request("user.settings.diagnoseProblems", params_dict, **_timeout_kwargs(timeout))) + + async def _apply_top_key(self, params: UserSettingsApplyTopKeyRequest, *, timeout: float | None = None) -> UserSettingsApplyTopKeyResult: + "Validates one top-level setting subtree and writes just that key to settings.json as a single step. Doing both here closes the race a caller cannot close itself: between a separate preflight read and the write, the file may change. Rewriting only the touched key keeps legacy siblings out of settings.json. Answers a status rather than failing, so a validation problem and a write problem stay distinguishable.\n\nArgs:\n params: A single top-level setting subtree to validate and write.\n\nReturns:\n Outcome of validating and writing one top-level setting subtree.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = params.to_dict() + return UserSettingsApplyTopKeyResult.from_dict(await self._client.request("user.settings.applyTopKey", params_dict, **_timeout_kwargs(timeout))) + + async def _write_all(self, params: UserSettingsWriteAllRequest, *, timeout: float | None = None) -> None: + "Replaces the user settings file's entire content in one write. A key absent from `settings` is removed, which is what distinguishes this from `user.settings.set`: that one merges, so it can never clear a key the caller has dropped. For a caller saving the result of a raw edit, a merge would silently resurrect every key the user deleted. Records the same one-time mutation marks a per-key write records, so a setting the user has now chosen explicitly stops being migrated for them.\n\nArgs:\n params: The whole content to store in the user settings file.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + await self._client.request("user.settings.writeAll", params_dict, **_timeout_kwargs(timeout)) + + async def _update(self, params: _UserSettingsUpdateRequest, *, timeout: float | None = None) -> _UserSettingsUpdateResult: + "Merges a partial object into one top-level user setting, re-reading the stored value inside this runtime process's settings.json write lock so that concurrent writers in this process to different sub-fields of the same key do not clobber each other. Unlike `user.settings.set`, which replaces a key's whole value with what the caller last read, this keeps sub-fields the caller did not name when both the stored value and supplied value are objects; otherwise the supplied value replaces the stored value. Use it whenever two independent surfaces own different sub-fields of one setting. Returns the key's stored value after the write, in `value`.\n\nArgs:\n params: Names the user setting to merge into, and the partial object to merge.\n\nReturns:\n The stored value of the user setting after the merge.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _UserSettingsUpdateResult.from_dict(await self._client.request("user.settings.update", params_dict, **_timeout_kwargs(timeout))) + + async def _load_for_edit(self, *, timeout: float | None = None) -> UserSettingsLoadForEditResult: + "Reads settings.json as stored for a caller that is about to edit it. Unlike `user.settings.get`, this returns file values rather than per-key metadata and defaults. Reports `missing` for an absent file and `invalid` when the existing file will not parse. Retired config.json and extensionless files are not read.\n\nReturns:\n Contents of settings.json as stored, for a caller about to rewrite it.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + return UserSettingsLoadForEditResult.from_dict(await self._client.request("user.settings.loadForEdit", {}, **_timeout_kwargs(timeout))) + + async def _validate(self, params: UserSettingsValidateRequest, *, timeout: float | None = None) -> UserSettingsValidateResult: + "Validates one top-level setting subtree without writing it, reporting each problem with the path it applies to. Scoped to a single top-level key on purpose: validating the whole file would reject an edit whenever an unrelated pre-existing field is malformed, locking the user out of the very tool that could fix it.\n\nArgs:\n params: A single top-level setting subtree to validate.\n\nReturns:\n Outcome of validating one top-level setting subtree.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return UserSettingsValidateResult.from_dict(await self._client.request("user.settings.validate", params_dict, **_timeout_kwargs(timeout))) + + +# Experimental: this API group is experimental and may change or be removed. +class _InternalServerUserApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + self.settings = _InternalServerUserSettingsApi(client) + + +# Experimental: this API group is experimental and may change or be removed. +class _InternalServerRepoSettingsApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def _edit(self, params: _RepoSettingsEditRequest, *, timeout: float | None = None) -> _SettingsEditResult: + "Atomically edits one allowed top-level repository setting. Reads the raw file, preserves unrelated keys, applies one scalar or list edit, validates the result and writes under one file lock, so concurrent sibling or list edits are not lost. A malformed or unsafe existing file returns `invalid` without a write; rejected keys, invalid values and I/O errors reject the call.\n\nArgs:\n params: One atomic edit of an allowed top-level repository setting.\n\nReturns:\n Outcome of an atomic user or repository settings edit.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _SettingsEditResult.from_dict(await self._client.request("repo.settings.edit", params_dict, **_timeout_kwargs(timeout))) + + async def _read_raw(self, params: _RepoSettingsReadRawRequest, *, timeout: float | None = None) -> _RepoSettingsReadRawResult: + "Reads one repository settings file without settings normalization or layering. The existing JSONC parser accepts comments and trailing commas and applies its prototype-safety rules. Missing or blank files return an empty valid config. Invalid files return an empty config with invalid=true; other read failures reject.\n\nArgs:\n params: Which repository settings file to read.\n\nReturns:\n Parsed repository settings without normalization or layering.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _RepoSettingsReadRawResult.from_dict(await self._client.request("repo.settings.readRaw", params_dict, **_timeout_kwargs(timeout))) + + async def _write_key(self, params: _RepoSettingsWriteKeyRequest, *, timeout: float | None = None) -> None: + "Writes or removes one allowed top-level repository setting through the existing validator and file lock. Preserves unrelated stored keys. Invalid keys, values, existing documents, and I/O errors reject without replacing the file. Deletion requires delete=true; otherwise value must be present.\n\nArgs:\n params: One key to write or remove in a repository settings file.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = params.to_dict() + await self._client.request("repo.settings.writeKey", params_dict, **_timeout_kwargs(timeout)) + + async def _write_all(self, params: _RepoSettingsWriteAllRequest, *, timeout: float | None = None) -> None: + "Replaces the repository-overridable settings in one locked write. Allowed keys present in settings are validated and written; allowed keys absent from settings are removed. Other input keys are ignored, and unknown keys already stored in the file remain unchanged. Invalid values or an invalid existing file reject without a partial write.\n\nArgs:\n params: The complete set of repository-overridable settings to store.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + await self._client.request("repo.settings.writeAll", params_dict, **_timeout_kwargs(timeout)) + + +# Experimental: this API group is experimental and may change or be removed. +class _InternalServerRepoApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + self.settings = _InternalServerRepoSettingsApi(client) + + +# Experimental: this API group is experimental and may change or be removed. +class _InternalServerFeatureFlagsApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def _resolve_startup_gates(self, params: _FeatureFlagsResolveStartupGatesRequest, *, timeout: float | None = None) -> dict: + "Resolves named gates against this installation's cached online-experiment assignment, for the account the runtime is already authenticated as. Unlike `featureFlags.resolve`, which layers static availability with the populations supplied, this reads the experiment assignment the runtime cached for its own current authentication, so a launch can honor a rollout before any session exists. The account is never taken from the request: naming one would read another account's cached assignments. The cached assignment answers immediately and any network refresh happens behind it, so this call does not wait on the network. Not available to an extension, which cannot carry the user's consent to read their assignment.\n\nArgs:\n params: Caller population and startup inputs to resolve named online-experiment gates for. Carries no account: the runtime resolves the assignment for the authentication it already holds.\n\nReturns:\n The resolved gates, keyed by flag name.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return dict(await self._client.request("featureFlags.resolveStartupGates", params_dict, **_timeout_kwargs(timeout))) + + async def _list_metadata(self, *, timeout: float | None = None) -> _FeatureFlagsMetadataResult: + "Lists every feature flag this runtime declares, with the population each one is declared for, its experimental description, and the online-experiment flag it maps to. This is the static catalog: it describes how each flag is defined, not whether it is on for anyone. Use `featureFlags.resolve` for static values with caller overrides, not active runtime values or experiment assignments.\n\nReturns:\n Every feature flag this runtime declares, with the shape each one was declared with.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + return _FeatureFlagsMetadataResult.from_dict(await self._client.request("featureFlags.listMetadata", {}, **_timeout_kwargs(timeout))) + + async def _resolve(self, params: _FeatureFlagsResolveRequest, *, timeout: float | None = None) -> dict: + "Computes static feature flags from the supplied population and overrides without changing runtime state or verifying audience membership. Starts from declared availability, then applies direct feature-flag environment values, user settings, and explicit `flagOverrides`. It does not apply `COPILOT_EXP_*` experiment assignments, authenticated startup gates, or active runtime state. Settings include `enabledFeatureFlags`, the legacy `feature_flags.enabled` list, and supported convenience settings. Supply `baseFlags` to use an existing flag set instead of declared availability. Omit `isStaffGitHub` or `isStaffMicrosoft` when membership was never recorded: a legacy staff account then counts as both populations.\n\nArgs:\n params: Caller population and overrides for static feature-flag resolution, independent of experiment assignments and active runtime state.\n\nReturns:\n The resolved feature flags, keyed by flag name.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return dict(await self._client.request("featureFlags.resolve", params_dict, **_timeout_kwargs(timeout))) + + +# Experimental: this API group is experimental and may change or be removed. +class _InternalServerPermissionsLocationsApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def _cleanup_orphaned(self, *, timeout: float | None = None) -> _LocationPermissionsCleanupResult: + "Drops stored per-location permission grants whose directory no longer exists, and reports which location keys were removed. Runs against the permission store under the runtime's own Copilot home, the same store `session.permissions.locations.resolve` reads. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. It can become public once an SDK consumer needs to prune its own permission store.\n\nReturns:\n Which stored location permissions were dropped because their directory is gone.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + return _LocationPermissionsCleanupResult.from_dict(await self._client.request("permissions.locations.cleanupOrphaned", {}, **_timeout_kwargs(timeout))) + + +# Experimental: this API group is experimental and may change or be removed. +class _InternalServerPermissionsFolderTrustApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def _check_trust(self, params: _FolderTrustIsTrustedParams, *, timeout: float | None = None) -> FolderTrustCheckResult: + "Reports whether a folder is trusted, reading the persisted trusted-folders list directly rather than through a session. Use this from a host that has no session yet, such as a one-shot command deciding whether to honor a checkout's own settings. It differs from the session-scoped check in two ways that matter: it takes the configuration directory to read the list from, instead of inheriting the session's, and it answers only from the persisted list, so trust a user granted for the lifetime of one session is not visible here. A host that has a session should prefer the session-scoped check, which also covers session-only trust.\n\nArgs:\n params: A folder to check against a persisted trusted-folders list, and the configuration directory holding that list.\n\nReturns:\n Folder trust check result.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return FolderTrustCheckResult.from_dict(await self._client.request("permissions.folderTrust.checkTrust", params_dict, **_timeout_kwargs(timeout))) + + +# Experimental: this API group is experimental and may change or be removed. +class _InternalServerPermissionsApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + self.locations = _InternalServerPermissionsLocationsApi(client) + self.folder_trust = _InternalServerPermissionsFolderTrustApi(client) + + async def _evaluate_managed_policy(self, params: _PermissionsEvaluateManagedPolicyParams, *, timeout: float | None = None) -> PermissionsEvaluateManagedPolicyResult: + "Interprets a verbatim managed `permissions` slice into the three policy questions a host asks before granting elevated permissions: whether bypass-permissions mode is forbidden, whether a policy exists that this build could not determine, and whether the layer supplies permission rules the session must enforce. An absent or empty slice means no managed policy applies. The runtime and its permission service share one policy type, so a new managed permission setting is interpreted in exactly one place; a host that reimplements the reading would silently diverge the first time that set grows. Hosts must fail closed on an undetermined policy rather than treating it as permission granted.\n\nArgs:\n params: The verbatim managed `permissions` slice to interpret.\n\nReturns:\n The policy questions a host asks before granting elevated permissions.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return PermissionsEvaluateManagedPolicyResult.from_dict(await self._client.request("permissions.evaluateManagedPolicy", params_dict, **_timeout_kwargs(timeout))) + + +# Experimental: this API group is experimental and may change or be removed. +class _InternalServerManagedSettingsApi: + def __init__(self, client: "JsonRpcClient"): + self._client = client + + async def _read_device(self, *, timeout: float | None = None) -> _ManagedSettingsReadDeviceResult: + "Discovers device-managed settings the way the runtime's own device layer does, and reports the sandbox floor and the load outcome alongside the validated document. This differs from `managedSettings.read` in three ways a policy-enforcing host depends on: a document that validates to an empty object is reported as absent rather than as an empty policy, a discovery error does not suppress a document that still validates, and a failure is reported as a flag rather than only as error text. Hosts that compose the device layer into an effective policy use this, because `managedSettings.read` cannot distinguish \"no device policy\" from \"device policy could not be read\" and would silently hand the user's own layer the win.\n\nReturns:\n The device-managed settings layer, with the sandbox floor and the load outcome a host needs to compose it into an effective policy.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + return _ManagedSettingsReadDeviceResult.from_dict(await self._client.request("managedSettings.readDevice", {}, **_timeout_kwargs(timeout))) + + async def _retain_policy(self, params: _ManagedSettingsRetainPolicyParams, *, timeout: float | None = None) -> None: + "Retains the supplied managed layers as this runtime process's startup policy and re-applies the result to every live session. Hosts that own their own short-lived process policy use this, so a guarded mutation is checked against the policy the host actually fetched. Retaining is a whole-process replacement rather than a merge, so a host that already resolved a good policy must not retain a partial one over it. The failure flags are honest inputs rather than assumptions: reporting a fetch or load that failed keeps the layers already retained, and the interim fail-closed state, instead of clearing them.\n\nArgs:\n params: The managed layers to retain as this process's startup policy, with the outcome of fetching each one.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + await self._client.request("managedSettings.retainPolicy", params_dict, **_timeout_kwargs(timeout)) + + async def _apply_controls(self, params: _ManagedSettingsApplyControlsParams, *, timeout: float | None = None) -> _ManagedSettingsApplyControlsResult: + "Stamps an effective managed policy's individually-controlled entries onto a user settings document, returning the settings a host should actually act on. The managed layer wins on every plugin spec and marketplace name it names, and leaves everything it does not name as the user wrote it. Hosts use this rather than merging the two documents themselves, because the merge is per entry rather than per document and a whole-document overlay would either discard the user's unmanaged entries or let a user entry outrank a managed one. Omitting the managed layer returns the settings unchanged, which is what an unmanaged host wants. Rejects when either document is present but is not a JSON object rather than treating it as absent, since silently dropping a malformed policy hands the user's layer the win on exactly the entries the policy exists to control.\n\nArgs:\n params: A user settings document and the effective managed policy whose controlled entries should be stamped onto it.\n\nReturns:\n The user settings with the managed layer's controlled entries stamped on.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _ManagedSettingsApplyControlsResult.from_dict(await self._client.request("managedSettings.applyControls", params_dict, **_timeout_kwargs(timeout))) + + async def _parse_client_value(self, params: _ManagedSettingsParseClientValueParams, *, timeout: float | None = None) -> _ManagedSettingsParseClientValueResult: + "Validates the managed settings a client is supplying for a session it is about to open, and returns them reduced to the keys a client is allowed to set. A client-supplied policy is not the same thing as an administrator's: it may only narrow permissions, so this accepts `permissions` and rejects every other key outright rather than ignoring it. Rejecting is the point — a host that silently dropped an unsupported key would report a policy as applied while running without it. Hosts call this before opening the session rather than letting the open fail, so a malformed policy is reported against the request that carried it. The runtime applies the same rule again when the session starts, so this cannot be used to smuggle a wider document past it. An accepted document that sets nothing comes back as an empty object, which is distinct from supplying nothing at all.\n\nArgs:\n params: The client-supplied managed settings to validate and normalize. Omitting them is valid and yields no policy.\n\nReturns:\n The accepted managed settings, reduced to the keys a client is allowed to set.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _ManagedSettingsParseClientValueResult.from_dict(await self._client.request("managedSettings.parseClientValue", params_dict, **_timeout_kwargs(timeout))) + + async def _resolve_effective_value(self, params: _ManagedSettingsResolveEffectiveValueParams, *, timeout: float | None = None) -> _ManagedSettingsResolveEffectiveValueResult: + "Composes the supplied server, device/MDM, device sandbox floor and policy-helper layers into the single effective managed policy a host should enforce, resolving each key across the layers by the runtime's own precedence rules. Hosts that assemble managed layers themselves use this so their precedence matches the runtime's exactly instead of reimplementing it. The composition is not a pure function of its inputs: an advisory sandbox force-on that arrived over the server channel is declined when this host cannot run a sandbox, so the result reflects the runtime host's capabilities, and the returned settings carry `sandboxAdvisoryFloorDeclined: true` when that happened. Enforced channels (device/MDM and policy helper) are never declined, and a server force-on carrying `failIfUnavailable` is preserved so the session fails loudly instead of quietly running unsandboxed. Rejects when a supplied layer is present but is not a JSON object, rather than treating it as unmanaged, because silently dropping a malformed policy would hand the user's own layer the win on exactly the keys the policy exists to control.\n\nArgs:\n params: The managed-settings layers to compose into an effective policy. Every layer is optional; omitting all of them yields no effective policy.\n\nReturns:\n The effective managed policy composed from the supplied layers.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _ManagedSettingsResolveEffectiveValueResult.from_dict(await self._client.request("managedSettings.resolveEffectiveValue", params_dict, **_timeout_kwargs(timeout))) + + async def _resolve_bypass_disable_transition(self, params: _ManagedSettingsResolveBypassDisableTransitionParams, *, timeout: float | None = None) -> _ManagedSettingsResolveBypassDisableTransitionResult: + "Decides what a host must do to its bypass-permissions state after a managed-policy resolution lands, given the state already in force and the account now signed in. A host holds two pieces of state — which layer disabled bypass mode, and for a server-delivered disable, the account it was pinned to — and cannot decide the next step from the new policy alone. Three rules make that so, and each one is a control rather than a preference. A device/MDM disable outranks the account, so a later server answer never lifts it. An unknown policy, which is what a failed fetch or a refusal this build cannot enforce yields, preserves whatever is in force instead of reverting to permissive. And a server disable is lifted only when the account it was pinned to is no longer the signed-in one, which is what makes signing in to an unrestricted account recover without a restart while a reconnect on the same restricted account does not. Hosts call this rather than reimplementing it because getting the pinning backwards either strands a disable on an account that never carried one or drops one that still applies. `setDisabledState` is omitted when the host must leave its stored flag untouched, which is distinct from being told to set it to false.\n\nArgs:\n params: The bypass-permissions state a host holds today, the account now signed in, and what the managed-policy resolution said.\n\nReturns:\n The bypass-permissions state a host should hold after the resolution, and what it must do to get there.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _ManagedSettingsResolveBypassDisableTransitionResult.from_dict(await self._client.request("managedSettings.resolveBypassDisableTransition", params_dict, **_timeout_kwargs(timeout))) + + async def _ingest(self, params: _ManagedSettingsIngestParams, *, timeout: float | None = None) -> _ManagedSettingsIngestResult: + "Resolves managed (enterprise policy) settings for a host from every layer at once: the account's server-delivered policy, the device/MDM layer, and a platform policy helper. Hosts use this instead of fetching and composing the layers themselves, because the per-layer precedence and the fail-closed rules that apply when a layer cannot be confirmed are the runtime's own and must match the policy a session will later enforce. It does not retain or apply anything to process-global policy state, so a host may call it before any session exists — which is the point, since plugin activation and one-shot commands resolve policy before a session is available to carry it. The returned per-layer outcome flags are load-bearing rather than diagnostic: a host must distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. Reports its diagnostics in `logMessages` rather than logging them, so a host that runs before a log sink exists still sees them.\n\nArgs:\n params: Inputs describing the host and account an ingestion should resolve managed policy for.\n\nReturns:\n The managed policy layers an ingestion resolved, together with the per-layer outcome flags a host needs to decide how much to trust the result. The flags are reported rather than folded into the settings because a host must be able to distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _ManagedSettingsIngestResult.from_dict(await self._client.request("managedSettings.ingest", params_dict, **_timeout_kwargs(timeout))) + + async def _resolve_startup_policy(self, params: _ManagedSettingsResolveStartupPolicyParams, *, timeout: float | None = None) -> _ManagedSettingsResolveStartupPolicyResult: + "Resolves the managed (enterprise policy) settings a host must enforce from startup, and judges the account against the enterprise sign-in pin in the same pass. This composes the layers the way `managedSettings.ingest` does and then answers the two questions a host cannot answer for itself: which fail-closed floors apply when a layer could not be confirmed, and whether this credential is allowed to sign in at all. The sign-in verdict is the reason a host must not assemble this itself from `managedSettings.ingest` — a pinned organization is an access control, and a host that composed the layers but skipped the pin would let a developer sign in with a personal or another enterprise's account and escape every control that keys off the signed-in identity. The verdict is computed on every resolution, including one that is not retained, so declining to apply policy never widens access. Set `retainAndApply` to keep the resolved policy as this runtime process's startup policy; leave it false to resolve without side effects.\n\nArgs:\n params: Inputs describing the host and account a startup policy resolution should run for. Mirrors `managedSettings.ingest`, and adds the decision of whether the resolved policy is retained for this runtime process.\n\nReturns:\n The startup policy a resolution composed, the per-layer outcome flags a host needs to decide how much to trust it, and the enterprise sign-in verdict for the credential it ran against. The flags are reported rather than folded into the settings because a host must distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _ManagedSettingsResolveStartupPolicyResult.from_dict(await self._client.request("managedSettings.resolveStartupPolicy", params_dict, **_timeout_kwargs(timeout))) + + async def _load_remote_control(self, params: _ManagedSettingsLoadRemoteControlParams, *, timeout: float | None = None) -> _ManagedSettingsLoadRemoteControlResult: + "Resolves the managed `remoteControl` policy for an account on its own, for a host deciding whether a remote-control session may start. Composes the same layers as `managedSettings.ingest` and returns only that one key, so a host does not have to know which layer won. An absent policy means the account is unmanaged for this capability and the host may proceed; that default is safe only while absence really does mean \"no policy\", so a service refusal that says an account policy exists which this client is too old to enforce resolves to an explicit disabled policy instead of to absence. A resolution that cannot be completed is rejected rather than answered as absence, for the same reason.\n\nArgs:\n params: Inputs describing the host and account whose managed remote-control policy should be resolved. Mirrors `managedSettings.ingest`, and deliberately carries no retention decision: reading this gate never becomes this runtime process's startup policy.\n\nReturns:\n The managed remote-control policy in force for an account, if any. An absent policy means the account is unmanaged for this capability, which a host reads as allowed — so absence here is a positive statement that no policy applies, never a stand-in for a resolution that failed. A resolution that cannot be completed is rejected instead.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _ManagedSettingsLoadRemoteControlResult.from_dict(await self._client.request("managedSettings.loadRemoteControl", params_dict, **_timeout_kwargs(timeout))) + + async def _resolve_device_force_login_orgs_gate(self, params: _ManagedSettingsResolveDeviceForceLoginOrgsGateParams, *, timeout: float | None = None) -> _ForceLoginOrgsDecision: + "Evaluates the device-channel enterprise sign-in pin (MDM plist, registry, or managed-settings file) against a credential, without resolving any server-delivered policy. This is the gate an entry point runs before it branches, and the only one that can refuse a developer's first sign-in: it is local, needs no credential, and a server-delivered pin only ever reaches accounts already inside the organization. It fails closed by construction — a discovery that cannot determine whether a pin exists refuses rather than allows, because a control that fails open under a triggerable condition is not a control. Hosts that also want the server channel should call `managedSettings.resolveStartupPolicy`, which folds both channels into one verdict.\n\nArgs:\n params: The credential and environment to evaluate the device-channel sign-in pin against.\n\nReturns:\n The verdict of the `forceLoginOrgs` enterprise sign-in pin for one credential. A managed device may pin Copilot to an approved set of GitHub organizations so a developer cannot sign in with a personal — or another enterprise's — account and escape every control that keys off the signed-in identity. A host must refuse to proceed when `allowed` is false; the remaining fields explain the refusal rather than qualifying it.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + return _ForceLoginOrgsDecision.from_dict(await self._client.request("managedSettings.resolveDeviceForceLoginOrgsGate", params_dict, **_timeout_kwargs(timeout))) + + # Experimental: this API group is experimental and may change or be removed. class _InternalServerHostApi: def __init__(self, client: "JsonRpcClient"): @@ -58104,110 +61581,6 @@ async def _write_key(self, params: _GlobalStateWriteKeyRequest, *, timeout: floa await self._client.request("globalState.writeKey", params_dict, **_timeout_kwargs(timeout)) -# Experimental: this API group is experimental and may change or be removed. -class _InternalServerUserSettingsApi: - def __init__(self, client: "JsonRpcClient"): - self._client = client - - async def _get_paths(self, params: UserSettingsGetPathsRequest, *, timeout: float | None = None) -> UserSettingsGetPathsResult: - "Resolves the on-disk locations of the settings files this runtime reads, so a consumer can show or open them. The user path is the same file `user.settings.get`, `user.settings.load`, and `user.settings.set` operate on. Supply `repoRoot` to also resolve that repository's checked-in and local settings paths. A path is reported whether or not the file exists.\n\nArgs:\n params: Selects which settings file paths to resolve.\n\nReturns:\n On-disk locations of the settings files this runtime reads. A path is reported whether or not the file exists.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return UserSettingsGetPathsResult.from_dict(await self._client.request("user.settings.getPaths", params_dict, **_timeout_kwargs(timeout))) - - async def _list_governance_keys(self, *, timeout: float | None = None) -> UserSettingsGovernanceKeysResult: - "Lists the top-level user-setting keys by who is allowed to govern them: `repo` keys a repository may override through `.github/copilot/settings.json`, `claudeRepo` keys a repository may override through a Claude-compatible config, and `managed` keys an enterprise policy may fix. The lists are static for a given runtime build and fail closed: a key absent from a list cannot be governed that way.\n\nReturns:\n Top-level user-setting keys grouped by who may govern them.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." - return UserSettingsGovernanceKeysResult.from_dict(await self._client.request("user.settings.listGovernanceKeys", {}, **_timeout_kwargs(timeout))) - - async def _edit(self, params: _UserSettingsEditRequest, *, timeout: float | None = None) -> _SettingsEditResult: - "Atomically edits one canonical user setting inside its settings-file lock. Reads, canonicalizes touched aliases, applies the edit, validates the resulting top-level setting and writes before releasing the lock. An explicit autoUpdatesChannel set completes the staff migration in the same transaction. Only a malformed existing file returns `invalid`; refused keys, invalid values and I/O errors reject the call.\n\nArgs:\n params: One atomic edit of a canonical setting in settings.json.\n\nReturns:\n Outcome of an atomic user or repository settings edit.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." - params_dict = params.to_dict() - return _SettingsEditResult.from_dict(await self._client.request("user.settings.edit", params_dict, **_timeout_kwargs(timeout))) - - async def _normalize(self, params: UserSettingsNormalizeRequest, *, timeout: float | None = None) -> UserSettingsNormalizeResult: - "Rewrites legacy and snake_case setting names in a settings object to their canonical spelling. A caller editing settings.json must normalize before writing: a legacy key left in place survives the write, is re-normalized on the next load, and silently shadows the canonical value the write just stored.\n\nArgs:\n params: Settings object whose key names should be canonicalized.\n\nReturns:\n Settings object with canonical key names.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return UserSettingsNormalizeResult.from_dict(await self._client.request("user.settings.normalize", params_dict, **_timeout_kwargs(timeout))) - - async def _diagnose_problems(self, params: UserSettingsProblemsRequest, *, timeout: float | None = None) -> UserSettingsProblemsResult: - "Diagnoses a set of already-loaded settings layers, reporting each key that will not take effect and why. Settings load tolerantly so that one bad key does not stop a session from starting; this method surfaces what was dropped so a caller can report it instead of silently ignoring the user's intent. Takes the layers as given rather than reading them, so a caller can diagnose exactly the content it is showing, including unsaved edits. Never echoes a setting's value, because a value may be a token or another secret. Marked internal because it exists to carry a CLI call site off the native addon, not to serve a consumer-facing need; it becomes public once an SDK consumer needs to inspect settings health itself.\n\nArgs:\n params: The settings layers to diagnose.\n\nReturns:\n The settings that will not take effect across the given layers.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return UserSettingsProblemsResult.from_dict(await self._client.request("user.settings.diagnoseProblems", params_dict, **_timeout_kwargs(timeout))) - - async def _apply_top_key(self, params: UserSettingsApplyTopKeyRequest, *, timeout: float | None = None) -> UserSettingsApplyTopKeyResult: - "Validates one top-level setting subtree and writes just that key to settings.json as a single step. Doing both here closes the race a caller cannot close itself: between a separate preflight read and the write, the file may change. Rewriting only the touched key keeps legacy siblings out of settings.json. Answers a status rather than failing, so a validation problem and a write problem stay distinguishable.\n\nArgs:\n params: A single top-level setting subtree to validate and write.\n\nReturns:\n Outcome of validating and writing one top-level setting subtree.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." - params_dict = params.to_dict() - return UserSettingsApplyTopKeyResult.from_dict(await self._client.request("user.settings.applyTopKey", params_dict, **_timeout_kwargs(timeout))) - - async def _write_all(self, params: UserSettingsWriteAllRequest, *, timeout: float | None = None) -> None: - "Replaces the user settings file's entire content in one write. A key absent from `settings` is removed, which is what distinguishes this from `user.settings.set`: that one merges, so it can never clear a key the caller has dropped. For a caller saving the result of a raw edit, a merge would silently resurrect every key the user deleted. Records the same one-time mutation marks a per-key write records, so a setting the user has now chosen explicitly stops being migrated for them.\n\nArgs:\n params: The whole content to store in the user settings file.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - await self._client.request("user.settings.writeAll", params_dict, **_timeout_kwargs(timeout)) - - async def _update(self, params: _UserSettingsUpdateRequest, *, timeout: float | None = None) -> _UserSettingsUpdateResult: - "Merges a partial object into one top-level user setting, re-reading the stored value inside this runtime process's settings.json write lock so that concurrent writers in this process to different sub-fields of the same key do not clobber each other. Unlike `user.settings.set`, which replaces a key's whole value with what the caller last read, this keeps sub-fields the caller did not name when both the stored value and supplied value are objects; otherwise the supplied value replaces the stored value. Use it whenever two independent surfaces own different sub-fields of one setting. Returns the key's stored value after the write, in `value`.\n\nArgs:\n params: Names the user setting to merge into, and the partial object to merge.\n\nReturns:\n The stored value of the user setting after the merge.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return _UserSettingsUpdateResult.from_dict(await self._client.request("user.settings.update", params_dict, **_timeout_kwargs(timeout))) - - async def _load_for_edit(self, *, timeout: float | None = None) -> UserSettingsLoadForEditResult: - "Reads settings.json as stored for a caller that is about to edit it. Unlike `user.settings.get`, this returns file values rather than per-key metadata and defaults. Reports `missing` for an absent file and `invalid` when the existing file will not parse. Retired config.json and extensionless files are not read.\n\nReturns:\n Contents of settings.json as stored, for a caller about to rewrite it.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." - return UserSettingsLoadForEditResult.from_dict(await self._client.request("user.settings.loadForEdit", {}, **_timeout_kwargs(timeout))) - - async def _validate(self, params: UserSettingsValidateRequest, *, timeout: float | None = None) -> UserSettingsValidateResult: - "Validates one top-level setting subtree without writing it, reporting each problem with the path it applies to. Scoped to a single top-level key on purpose: validating the whole file would reject an edit whenever an unrelated pre-existing field is malformed, locking the user out of the very tool that could fix it.\n\nArgs:\n params: A single top-level setting subtree to validate.\n\nReturns:\n Outcome of validating one top-level setting subtree.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return UserSettingsValidateResult.from_dict(await self._client.request("user.settings.validate", params_dict, **_timeout_kwargs(timeout))) - - -# Experimental: this API group is experimental and may change or be removed. -class _InternalServerUserApi: - def __init__(self, client: "JsonRpcClient"): - self._client = client - self.settings = _InternalServerUserSettingsApi(client) - - -# Experimental: this API group is experimental and may change or be removed. -class _InternalServerFeatureFlagsApi: - def __init__(self, client: "JsonRpcClient"): - self._client = client - - async def _list_metadata(self, *, timeout: float | None = None) -> _FeatureFlagsMetadataResult: - "Lists every feature flag this runtime declares, with the population each one is declared for, its experimental description, and the online-experiment flag it maps to. This is the static catalog: it describes how each flag is defined, not whether it is on for anyone. Use `featureFlags.resolve` for static values with caller overrides, not active runtime values or experiment assignments.\n\nReturns:\n Every feature flag this runtime declares, with the shape each one was declared with.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." - return _FeatureFlagsMetadataResult.from_dict(await self._client.request("featureFlags.listMetadata", {}, **_timeout_kwargs(timeout))) - - async def _resolve(self, params: _FeatureFlagsResolveRequest, *, timeout: float | None = None) -> dict: - "Computes static feature flags from the supplied population and overrides without changing runtime state or verifying audience membership. Starts from declared availability, then applies direct feature-flag environment values, user settings, and explicit `flagOverrides`. It does not apply `COPILOT_EXP_*` experiment assignments, authenticated startup gates, or active runtime state. Settings include `enabledFeatureFlags`, the legacy `feature_flags.enabled` list, and supported convenience settings. Supply `baseFlags` to use an existing flag set instead of declared availability. Omit `isStaffGitHub` or `isStaffMicrosoft` when membership was never recorded: a legacy staff account then counts as both populations.\n\nArgs:\n params: Caller population and overrides for static feature-flag resolution, independent of experiment assignments and active runtime state.\n\nReturns:\n The resolved feature flags, keyed by flag name.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return dict(await self._client.request("featureFlags.resolve", params_dict, **_timeout_kwargs(timeout))) - - -# Experimental: this API group is experimental and may change or be removed. -class _InternalServerRepoSettingsApi: - def __init__(self, client: "JsonRpcClient"): - self._client = client - - async def _read_raw(self, params: _RepoSettingsReadRawRequest, *, timeout: float | None = None) -> _RepoSettingsReadRawResult: - "Reads one repository settings file without settings normalization or layering. The existing JSONC parser accepts comments and trailing commas and applies its prototype-safety rules. Missing or blank files return an empty valid config. Invalid files return an empty config with invalid=true; other read failures reject.\n\nArgs:\n params: Which repository settings file to read.\n\nReturns:\n Parsed repository settings without normalization or layering.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - return _RepoSettingsReadRawResult.from_dict(await self._client.request("repo.settings.readRaw", params_dict, **_timeout_kwargs(timeout))) - - async def _write_key(self, params: _RepoSettingsWriteKeyRequest, *, timeout: float | None = None) -> None: - "Writes or removes one allowed top-level repository setting through the existing validator and file lock. Preserves unrelated stored keys. Invalid keys, values, existing documents, and I/O errors reject without replacing the file. Deletion requires delete=true; otherwise value must be present.\n\nArgs:\n params: One key to write or remove in a repository settings file.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." - params_dict = params.to_dict() - await self._client.request("repo.settings.writeKey", params_dict, **_timeout_kwargs(timeout)) - - async def _write_all(self, params: _RepoSettingsWriteAllRequest, *, timeout: float | None = None) -> None: - "Replaces the repository-overridable settings in one locked write. Allowed keys present in settings are validated and written; allowed keys absent from settings are removed. Other input keys are ignored, and unknown keys already stored in the file remain unchanged. Invalid values or an invalid existing file reject without a partial write.\n\nArgs:\n params: The complete set of repository-overridable settings to store.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." - params_dict = {k: v for k, v in params.to_dict().items() if v is not None} - await self._client.request("repo.settings.writeAll", params_dict, **_timeout_kwargs(timeout)) - - -# Experimental: this API group is experimental and may change or be removed. -class _InternalServerRepoApi: - def __init__(self, client: "JsonRpcClient"): - self._client = client - self.settings = _InternalServerRepoSettingsApi(client) - - # Experimental: this API group is experimental and may change or be removed. class _InternalServerGitHubRepositoryApi: def __init__(self, client: "JsonRpcClient"): @@ -58320,15 +61693,19 @@ class _InternalServerRpc: """Internal SDK server-scoped RPC methods. Not part of the public API.""" def __init__(self, client: "JsonRpcClient"): self._client = client + self.sandbox = _InternalServerSandboxApi(client) + self.persistence = _InternalServerPersistenceApi(client) + self.user = _InternalServerUserApi(client) + self.repo = _InternalServerRepoApi(client) + self.feature_flags = _InternalServerFeatureFlagsApi(client) + self.permissions = _InternalServerPermissionsApi(client) + self.managed_settings = _InternalServerManagedSettingsApi(client) self.host = _InternalServerHostApi(client) self.account = _InternalServerAccountApi(client) self.mcp = _InternalServerMcpApi(client) self.instructions = _InternalServerInstructionsApi(client) self.agents = _InternalServerAgentsApi(client) self.global_state = _InternalServerGlobalStateApi(client) - self.user = _InternalServerUserApi(client) - self.feature_flags = _InternalServerFeatureFlagsApi(client) - self.repo = _InternalServerRepoApi(client) self.git_hub_repository = _InternalServerGitHubRepositoryApi(client) self.git_hub_owners = _InternalServerGitHubOwnersApi(client) self.git = _InternalServerGitApi(client) @@ -61585,6 +64962,7 @@ async def handle_installations_confirm(params: dict) -> dict | None: "ExternalToolTextResultForLlmContentText", "ExternalToolTextResultForLlmContentType", "FeatureFlagsResolveResult", + "FeatureFlagsResolveStartupGatesResult", "FilterMapping", "FleetApi", "FleetStartRequest", @@ -62181,6 +65559,7 @@ async def handle_installations_confirm(params: dict) -> dict | None: "PermissionsConfigureAdditionalContentExclusionPolicyScope", "PermissionsConfigureParams", "PermissionsConfigureResult", + "PermissionsEvaluateManagedPolicyResult", "PermissionsFolderTrustAddTrustedResult", "PermissionsFolderTrustApi", "PermissionsGetModeRequest", @@ -62219,6 +65598,8 @@ async def handle_installations_confirm(params: dict) -> dict | None: "PermissionsSetRequiredResult", "PermissionsUrlsApi", "PermissionsUrlsSetUnrestrictedModeResult", + "PersistenceWriteRawJSONLockedRequest", + "PersistenceWriteRawJSONLockedResult", "Phase", "PingRequest", "PingResult", @@ -62406,6 +65787,10 @@ async def handle_installations_confirm(params: dict) -> dict | None: "ResponseFormatType", "ReviewClass", "SandboxApi", + "SandboxApplyDefaultsRequest", + "SandboxCheckEnforcementCommandResult", + "SandboxCheckPlatformSupportResult", + "SandboxCheckWindowsHostLoopbackSupportResult", "SandboxConfig", "SandboxConfigAuth", "SandboxConfigSource", @@ -62421,7 +65806,10 @@ async def handle_installations_confirm(params: dict) -> dict | None: "SandboxCredentialsConfig", "SandboxDisableForSessionRequest", "SandboxDisableForSessionResult", + "SandboxDocsURLResult", "SandboxEnforcementStatus", + "SandboxGetUnsupportedMessageResult", + "SandboxGetUnsupportedSettingDisabledNoticeResult", "SandboxGrantPathForRequestRequest", "SandboxGrantPathForRequestResult", "SandboxHostCapability", @@ -62432,7 +65820,15 @@ async def handle_installations_confirm(params: dict) -> dict | None: "SandboxProxyCARequest", "SandboxProxyCAState", "SandboxProxyCAStatus", + "SandboxProxyCaCheckInstallationSupportResult", + "SandboxProxyCaCheckRelevanceResult", + "SandboxProxySecretGetResult", + "SandboxProxySecretLocation", + "SandboxProxySecretSaveRequest", + "SandboxProxySecretSaveResult", + "SandboxResolveFlooredConfigResult", "SandboxSessionChange", + "SandboxSettingsApplyDefaultsResult", "Saved", "ScheduleAddAtRequest", "ScheduleAddCronRequest", @@ -62794,6 +66190,8 @@ async def handle_installations_confirm(params: dict) -> dict | None: "SlashCommandTextResult", "SlashCommandTimelineEntry", "SourceClass", + "StaffLogLevelMigrationStatus", + "StaffUpdateChannelMigrationStatus", "SubagentSettings", "SubagentSettingsEntry", "SubagentSettingsEntryContextTier", @@ -62928,13 +66326,22 @@ async def handle_installations_confirm(params: dict) -> dict | None: "UserSettingMetadata", "UserSettingsApplyTopKeyRequest", "UserSettingsApplyTopKeyResult", + "UserSettingsBuildRuntimeResult", "UserSettingsGetPathsRequest", "UserSettingsGetPathsResult", "UserSettingsGetResult", "UserSettingsGovernanceKeysResult", + "UserSettingsHostContext", + "UserSettingsLoadForConfigDirResult", "UserSettingsLoadForEditResult", + "UserSettingsLoadRepoRequest", + "UserSettingsLoadRepoResult", + "UserSettingsLoadWithWarningResult", + "UserSettingsMergeManagedAndUserResult", + "UserSettingsMergeRepoValueResult", "UserSettingsNormalizeRequest", "UserSettingsNormalizeResult", + "UserSettingsPathResult", "UserSettingsProblem", "UserSettingsProblemLocation", "UserSettingsProblemSource", diff --git a/rust/src/generated/api_types.rs b/rust/src/generated/api_types.rs index 6c28002b9a..823e5055a0 100644 --- a/rust/src/generated/api_types.rs +++ b/rust/src/generated/api_types.rs @@ -23,6 +23,170 @@ use crate::types::{RequestId, SessionEvent, SessionId}; /// JSON-RPC method name constants. pub mod rpc_methods { + /// `sandbox.proxyCa.checkInstallationSupport` + pub const SANDBOX_PROXYCA_CHECKINSTALLATIONSUPPORT: &str = + "sandbox.proxyCa.checkInstallationSupport"; + /// `sandbox.proxyCa.checkRelevance` + pub const SANDBOX_PROXYCA_CHECKRELEVANCE: &str = "sandbox.proxyCa.checkRelevance"; + /// `sandbox.proxyCa.getStatus` + pub const SANDBOX_PROXYCA_GETSTATUS: &str = "sandbox.proxyCa.getStatus"; + /// `sandbox.proxyCa.create` + pub const SANDBOX_PROXYCA_CREATE: &str = "sandbox.proxyCa.create"; + /// `sandbox.proxyCa.rotate` + pub const SANDBOX_PROXYCA_ROTATE: &str = "sandbox.proxyCa.rotate"; + /// `sandbox.proxyCa.trust` + pub const SANDBOX_PROXYCA_TRUST: &str = "sandbox.proxyCa.trust"; + /// `sandbox.proxyCa.remove` + pub const SANDBOX_PROXYCA_REMOVE: &str = "sandbox.proxyCa.remove"; + /// `sandbox.proxySecret.getLocation` + pub const SANDBOX_PROXYSECRET_GETLOCATION: &str = "sandbox.proxySecret.getLocation"; + /// `sandbox.proxySecret.get` + pub const SANDBOX_PROXYSECRET_GET: &str = "sandbox.proxySecret.get"; + /// `sandbox.proxySecret.save` + pub const SANDBOX_PROXYSECRET_SAVE: &str = "sandbox.proxySecret.save"; + /// `sandbox.proxySecret.delete` + pub const SANDBOX_PROXYSECRET_DELETE: &str = "sandbox.proxySecret.delete"; + /// `sandbox.settings.applyDefaults` + pub const SANDBOX_SETTINGS_APPLYDEFAULTS: &str = "sandbox.settings.applyDefaults"; + /// `sandbox.resolveFlooredConfig` + pub const SANDBOX_RESOLVEFLOOREDCONFIG: &str = "sandbox.resolveFlooredConfig"; + /// `sandbox.preparePickerPolicy` + pub const SANDBOX_PREPAREPICKERPOLICY: &str = "sandbox.preparePickerPolicy"; + /// `sandbox.filterPickerCandidates` + pub const SANDBOX_FILTERPICKERCANDIDATES: &str = "sandbox.filterPickerCandidates"; + /// `sandbox.resolveForOptional` + pub const SANDBOX_RESOLVEFOROPTIONAL: &str = "sandbox.resolveForOptional"; + /// `sandbox.checkPlatformSupport` + pub const SANDBOX_CHECKPLATFORMSUPPORT: &str = "sandbox.checkPlatformSupport"; + /// `sandbox.checkWindowsHostLoopbackSupport` + pub const SANDBOX_CHECKWINDOWSHOSTLOOPBACKSUPPORT: &str = + "sandbox.checkWindowsHostLoopbackSupport"; + /// `sandbox.getUnsupportedMessage` + pub const SANDBOX_GETUNSUPPORTEDMESSAGE: &str = "sandbox.getUnsupportedMessage"; + /// `sandbox.getUnsupportedSettingDisabledNotice` + pub const SANDBOX_GETUNSUPPORTEDSETTINGDISABLEDNOTICE: &str = + "sandbox.getUnsupportedSettingDisabledNotice"; + /// `sandbox.getUnsupportedStartupNotice` + pub const SANDBOX_GETUNSUPPORTEDSTARTUPNOTICE: &str = "sandbox.getUnsupportedStartupNotice"; + /// `sandbox.checkEnforcementCommand` + pub const SANDBOX_CHECKENFORCEMENTCOMMAND: &str = "sandbox.checkEnforcementCommand"; + /// `sandbox.getDocsUrl` + pub const SANDBOX_GETDOCSURL: &str = "sandbox.getDocsUrl"; + /// `sandbox.getHostSupport` + pub const SANDBOX_GETHOSTSUPPORT: &str = "sandbox.getHostSupport"; + /// `persistence.writeRawJsonLocked` + pub const PERSISTENCE_WRITERAWJSONLOCKED: &str = "persistence.writeRawJsonLocked"; + /// `user.settings.setHookDisabled` + pub const USER_SETTINGS_SETHOOKDISABLED: &str = "user.settings.setHookDisabled"; + /// `user.settings.loadForConfigDir` + pub const USER_SETTINGS_LOADFORCONFIGDIR: &str = "user.settings.loadForConfigDir"; + /// `user.settings.loadRepo` + pub const USER_SETTINGS_LOADREPO: &str = "user.settings.loadRepo"; + /// `user.settings.loadAndMergeRepo` + pub const USER_SETTINGS_LOADANDMERGEREPO: &str = "user.settings.loadAndMergeRepo"; + /// `user.settings.getPath` + pub const USER_SETTINGS_GETPATH: &str = "user.settings.getPath"; + /// `user.settings.loadWithWarning` + pub const USER_SETTINGS_LOADWITHWARNING: &str = "user.settings.loadWithWarning"; + /// `user.settings.mergeManagedAndUser` + pub const USER_SETTINGS_MERGEMANAGEDANDUSER: &str = "user.settings.mergeManagedAndUser"; + /// `user.settings.mergeRepoValue` + pub const USER_SETTINGS_MERGEREPOVALUE: &str = "user.settings.mergeRepoValue"; + /// `user.settings.migrateStaffUpdateChannelOnce` + pub const USER_SETTINGS_MIGRATESTAFFUPDATECHANNELONCE: &str = + "user.settings.migrateStaffUpdateChannelOnce"; + /// `user.settings.resetStaffModelSelectionOnce` + pub const USER_SETTINGS_RESETSTAFFMODELSELECTIONONCE: &str = + "user.settings.resetStaffModelSelectionOnce"; + /// `user.settings.getUnknownKeysWarning` + pub const USER_SETTINGS_GETUNKNOWNKEYSWARNING: &str = "user.settings.getUnknownKeysWarning"; + /// `user.settings.buildRuntime` + pub const USER_SETTINGS_BUILDRUNTIME: &str = "user.settings.buildRuntime"; + /// `user.settings.migrateStaffLogLevelOnce` + pub const USER_SETTINGS_MIGRATESTAFFLOGLEVELONCE: &str = + "user.settings.migrateStaffLogLevelOnce"; + /// `user.settings.migrateObsoleteOnDisk` + pub const USER_SETTINGS_MIGRATEOBSOLETEONDISK: &str = "user.settings.migrateObsoleteOnDisk"; + /// `user.settings.get` + pub const USER_SETTINGS_GET: &str = "user.settings.get"; + /// `user.settings.getPaths` + pub const USER_SETTINGS_GETPATHS: &str = "user.settings.getPaths"; + /// `user.settings.set` + pub const USER_SETTINGS_SET: &str = "user.settings.set"; + /// `user.settings.listGovernanceKeys` + pub const USER_SETTINGS_LISTGOVERNANCEKEYS: &str = "user.settings.listGovernanceKeys"; + /// `user.settings.edit` + pub const USER_SETTINGS_EDIT: &str = "user.settings.edit"; + /// `user.settings.normalize` + pub const USER_SETTINGS_NORMALIZE: &str = "user.settings.normalize"; + /// `user.settings.diagnoseProblems` + pub const USER_SETTINGS_DIAGNOSEPROBLEMS: &str = "user.settings.diagnoseProblems"; + /// `user.settings.applyTopKey` + pub const USER_SETTINGS_APPLYTOPKEY: &str = "user.settings.applyTopKey"; + /// `user.settings.writeAll` + pub const USER_SETTINGS_WRITEALL: &str = "user.settings.writeAll"; + /// `user.settings.update` + pub const USER_SETTINGS_UPDATE: &str = "user.settings.update"; + /// `user.settings.loadForEdit` + pub const USER_SETTINGS_LOADFOREDIT: &str = "user.settings.loadForEdit"; + /// `user.settings.validate` + pub const USER_SETTINGS_VALIDATE: &str = "user.settings.validate"; + /// `repo.settings.edit` + pub const REPO_SETTINGS_EDIT: &str = "repo.settings.edit"; + /// `repo.settings.readRaw` + pub const REPO_SETTINGS_READRAW: &str = "repo.settings.readRaw"; + /// `repo.settings.writeKey` + pub const REPO_SETTINGS_WRITEKEY: &str = "repo.settings.writeKey"; + /// `repo.settings.writeAll` + pub const REPO_SETTINGS_WRITEALL: &str = "repo.settings.writeAll"; + /// `featureFlags.resolveStartupGates` + pub const FEATUREFLAGS_RESOLVESTARTUPGATES: &str = "featureFlags.resolveStartupGates"; + /// `featureFlags.listMetadata` + pub const FEATUREFLAGS_LISTMETADATA: &str = "featureFlags.listMetadata"; + /// `featureFlags.resolve` + pub const FEATUREFLAGS_RESOLVE: &str = "featureFlags.resolve"; + /// `permissions.locations.cleanupOrphaned` + pub const PERMISSIONS_LOCATIONS_CLEANUPORPHANED: &str = "permissions.locations.cleanupOrphaned"; + /// `permissions.folderTrust.checkTrust` + pub const PERMISSIONS_FOLDERTRUST_CHECKTRUST: &str = "permissions.folderTrust.checkTrust"; + /// `permissions.evaluateManagedPolicy` + pub const PERMISSIONS_EVALUATEMANAGEDPOLICY: &str = "permissions.evaluateManagedPolicy"; + /// `managedSettings.readDevice` + pub const MANAGEDSETTINGS_READDEVICE: &str = "managedSettings.readDevice"; + /// `managedSettings.retainPolicy` + pub const MANAGEDSETTINGS_RETAINPOLICY: &str = "managedSettings.retainPolicy"; + /// `managedSettings.applyControls` + pub const MANAGEDSETTINGS_APPLYCONTROLS: &str = "managedSettings.applyControls"; + /// `managedSettings.parseClientValue` + pub const MANAGEDSETTINGS_PARSECLIENTVALUE: &str = "managedSettings.parseClientValue"; + /// `managedSettings.resolveEffectiveValue` + pub const MANAGEDSETTINGS_RESOLVEEFFECTIVEVALUE: &str = "managedSettings.resolveEffectiveValue"; + /// `managedSettings.resolveBypassDisableTransition` + pub const MANAGEDSETTINGS_RESOLVEBYPASSDISABLETRANSITION: &str = + "managedSettings.resolveBypassDisableTransition"; + /// `managedSettings.ingest` + pub const MANAGEDSETTINGS_INGEST: &str = "managedSettings.ingest"; + /// `managedSettings.resolveStartupPolicy` + pub const MANAGEDSETTINGS_RESOLVESTARTUPPOLICY: &str = "managedSettings.resolveStartupPolicy"; + /// `managedSettings.loadRemoteControl` + pub const MANAGEDSETTINGS_LOADREMOTECONTROL: &str = "managedSettings.loadRemoteControl"; + /// `managedSettings.resolveDeviceForceLoginOrgsGate` + pub const MANAGEDSETTINGS_RESOLVEDEVICEFORCELOGINORGSGATE: &str = + "managedSettings.resolveDeviceForceLoginOrgsGate"; + /// `managedSettings.read` + pub const MANAGEDSETTINGS_READ: &str = "managedSettings.read"; + /// `managedSettings.clearCache` + pub const MANAGEDSETTINGS_CLEARCACHE: &str = "managedSettings.clearCache"; + /// `managedSettings.resolve` + pub const MANAGEDSETTINGS_RESOLVE: &str = "managedSettings.resolve"; + /// `managedSettings.permissions.evaluate` + pub const MANAGEDSETTINGS_PERMISSIONS_EVALUATE: &str = "managedSettings.permissions.evaluate"; + /// `managedSettings.schema` + pub const MANAGEDSETTINGS_SCHEMA: &str = "managedSettings.schema"; + /// `managedSettings.validate` + pub const MANAGEDSETTINGS_VALIDATE: &str = "managedSettings.validate"; + /// `managedSettings.compose` + pub const MANAGEDSETTINGS_COMPOSE: &str = "managedSettings.compose"; /// `environments.list` pub const ENVIRONMENTS_LIST: &str = "environments.list"; /// `environments.get` @@ -57,18 +221,6 @@ pub mod rpc_methods { pub const MODELS_LIST: &str = "models.list"; /// `models.getBuiltInCatalog` pub const MODELS_GETBUILTINCATALOG: &str = "models.getBuiltInCatalog"; - /// `sandbox.getHostSupport` - pub const SANDBOX_GETHOSTSUPPORT: &str = "sandbox.getHostSupport"; - /// `sandbox.proxyCa.getStatus` - pub const SANDBOX_PROXYCA_GETSTATUS: &str = "sandbox.proxyCa.getStatus"; - /// `sandbox.proxyCa.create` - pub const SANDBOX_PROXYCA_CREATE: &str = "sandbox.proxyCa.create"; - /// `sandbox.proxyCa.rotate` - pub const SANDBOX_PROXYCA_ROTATE: &str = "sandbox.proxyCa.rotate"; - /// `sandbox.proxyCa.trust` - pub const SANDBOX_PROXYCA_TRUST: &str = "sandbox.proxyCa.trust"; - /// `sandbox.proxyCa.remove` - pub const SANDBOX_PROXYCA_REMOVE: &str = "sandbox.proxyCa.remove"; /// `tools.list` pub const TOOLS_LIST: &str = "tools.list"; /// `account.getQuota` @@ -232,40 +384,6 @@ pub mod rpc_methods { pub const GLOBALSTATE_WRITEKEY: &str = "globalState.writeKey"; /// `commands.list` pub const COMMANDS_LIST: &str = "commands.list"; - /// `user.settings.get` - pub const USER_SETTINGS_GET: &str = "user.settings.get"; - /// `user.settings.getPaths` - pub const USER_SETTINGS_GETPATHS: &str = "user.settings.getPaths"; - /// `user.settings.set` - pub const USER_SETTINGS_SET: &str = "user.settings.set"; - /// `user.settings.listGovernanceKeys` - pub const USER_SETTINGS_LISTGOVERNANCEKEYS: &str = "user.settings.listGovernanceKeys"; - /// `user.settings.edit` - pub const USER_SETTINGS_EDIT: &str = "user.settings.edit"; - /// `user.settings.normalize` - pub const USER_SETTINGS_NORMALIZE: &str = "user.settings.normalize"; - /// `user.settings.diagnoseProblems` - pub const USER_SETTINGS_DIAGNOSEPROBLEMS: &str = "user.settings.diagnoseProblems"; - /// `user.settings.applyTopKey` - pub const USER_SETTINGS_APPLYTOPKEY: &str = "user.settings.applyTopKey"; - /// `user.settings.writeAll` - pub const USER_SETTINGS_WRITEALL: &str = "user.settings.writeAll"; - /// `user.settings.update` - pub const USER_SETTINGS_UPDATE: &str = "user.settings.update"; - /// `user.settings.loadForEdit` - pub const USER_SETTINGS_LOADFOREDIT: &str = "user.settings.loadForEdit"; - /// `user.settings.validate` - pub const USER_SETTINGS_VALIDATE: &str = "user.settings.validate"; - /// `featureFlags.listMetadata` - pub const FEATUREFLAGS_LISTMETADATA: &str = "featureFlags.listMetadata"; - /// `featureFlags.resolve` - pub const FEATUREFLAGS_RESOLVE: &str = "featureFlags.resolve"; - /// `repo.settings.readRaw` - pub const REPO_SETTINGS_READRAW: &str = "repo.settings.readRaw"; - /// `repo.settings.writeKey` - pub const REPO_SETTINGS_WRITEKEY: &str = "repo.settings.writeKey"; - /// `repo.settings.writeAll` - pub const REPO_SETTINGS_WRITEALL: &str = "repo.settings.writeAll"; /// `gitHubRepository.atPath` pub const GITHUBREPOSITORY_ATPATH: &str = "gitHubRepository.atPath"; /// `gitHubOwners.nextRequestId` @@ -280,20 +398,6 @@ pub mod rpc_methods { pub const GIT_WORKINGDIRECTORYCONTEXT: &str = "git.workingDirectoryContext"; /// `git.reposFromRemotes` pub const GIT_REPOSFROMREMOTES: &str = "git.reposFromRemotes"; - /// `managedSettings.read` - pub const MANAGEDSETTINGS_READ: &str = "managedSettings.read"; - /// `managedSettings.clearCache` - pub const MANAGEDSETTINGS_CLEARCACHE: &str = "managedSettings.clearCache"; - /// `managedSettings.resolve` - pub const MANAGEDSETTINGS_RESOLVE: &str = "managedSettings.resolve"; - /// `managedSettings.permissions.evaluate` - pub const MANAGEDSETTINGS_PERMISSIONS_EVALUATE: &str = "managedSettings.permissions.evaluate"; - /// `managedSettings.schema` - pub const MANAGEDSETTINGS_SCHEMA: &str = "managedSettings.schema"; - /// `managedSettings.validate` - pub const MANAGEDSETTINGS_VALIDATE: &str = "managedSettings.validate"; - /// `managedSettings.compose` - pub const MANAGEDSETTINGS_COMPOSE: &str = "managedSettings.compose"; /// `runtime.shutdown` pub const RUNTIME_SHUTDOWN: &str = "runtime.shutdown"; /// `sessionFs.setProvider` @@ -8583,6 +8687,46 @@ pub(crate) struct FeatureFlagsResolveRequest { pub is_team: bool, } +/// Caller population and startup inputs to resolve named online-experiment gates for. Carries no account: the runtime resolves the assignment for the authentication it already holds. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct FeatureFlagsResolveStartupGatesRequest { + /// User settings document whose `featureFlags` block is layered on top of the resolved set. + #[serde(skip_serializing_if = "Option::is_none")] + pub config: Option, + /// Environment to read flag overrides from. Defaults to this runtime process's own environment. + #[serde(skip_serializing_if = "Option::is_none")] + pub environment: Option>, + /// When this installation first launched, in milliseconds since the Unix epoch. Experiments that segment on installation age read it. Omit when the first launch was never recorded. + #[serde(skip_serializing_if = "Option::is_none")] + pub first_launch_at_millis: Option, + /// The feature flags to resolve. A name this runtime does not declare is reported as an error rather than as a disabled flag. + pub flags: Vec, + /// Whether the caller is in an experimental population. + pub is_experimental: bool, + /// Whether the caller is GitHub or Microsoft staff. + pub is_staff: bool, + /// GitHub-staff membership. Omit when it was never recorded: a legacy staff account then counts as both staff populations and keeps every staff feature. + #[serde(skip_serializing_if = "Option::is_none")] + pub is_staff_github: Option, + /// Microsoft-staff membership. Omitted the same way as `isStaffGitHub`. + #[serde(skip_serializing_if = "Option::is_none")] + pub is_staff_microsoft: Option, + /// Whether the caller belongs to a team plan. + pub is_team: bool, + /// Whether the runtime may refresh the cached assignment over the network without an active session. The refresh never blocks this call: the answer comes from the cache either way, so a refresh only affects a later launch. + pub refresh_without_session: bool, + /// Whether streamer mode is on, which withholds the populations an experiment would otherwise segment on. + pub streamer_mode: bool, +} + /// Parameters for starting fleet orchestration: an optional user prompt combined with the fleet instructions, plus the send options forwarded to the resulting turn. /// ///
@@ -8669,6 +8813,54 @@ pub struct FolderTrustCheckResult { pub trusted: bool, } +/// A folder to check against a persisted trusted-folders list, and the configuration directory holding that list. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct FolderTrustIsTrustedParams { + /// Configuration directory to read the trusted-folders list from. Omit it to read the default location; supply it when the host has redirected its configuration, or the check answers from a list the host is not using. + #[serde(skip_serializing_if = "Option::is_none")] + pub config_dir: Option, + /// Folder to check. A folder counts as trusted when it is itself listed, when an ancestor is listed, or when its git root is listed. + pub path: String, +} + +/// The verdict of the `forceLoginOrgs` enterprise sign-in pin for one credential. A managed device may pin Copilot to an approved set of GitHub organizations so a developer cannot sign in with a personal — or another enterprise's — account and escape every control that keys off the signed-in identity. A host must refuse to proceed when `allowed` is false; the remaining fields explain the refusal rather than qualifying it. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ForceLoginOrgsDecision { + /// Whether the client may proceed. True whenever no pin is in force, so an unmanaged host is never blocked. + pub allowed: bool, + /// A stable kebab-case reason code when refused: `org-not-approved`, `unverifiable-credential`, `policy-undetermined`, `policy-invalid`, `not-signed-in`, or `membership-unknown`. Omitted when allowed. Treat an unrecognized code as a refusal rather than mapping it to an allow: a code this host has not been taught about still denied the credential. + #[serde(skip_serializing_if = "Option::is_none")] + pub denial: Option, + /// Whether a pin applies at all. Distinguishes "allowed because unmanaged" from "allowed because the account is approved", which a diagnostics surface needs and which also decides whether a bring-your-own-key provider may serve inference. + pub enforced: bool, + /// The approved organization the account matched, when allowed under a pin. + #[serde(skip_serializing_if = "Option::is_none")] + pub matched_org: Option, + /// A developer-facing explanation of the refusal. Omitted when allowed. + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, + /// Error-level detail from managed-policy discovery — which file failed to load, which field failed validation. Carried on the decision rather than left to the log because a refusal can exit the process before a log sink exists, which would discard the only actionable diagnostic a misconfigured managed device produces. + pub policy_diagnostics: Vec, + /// The approved organization logins, as configured. Enterprise configuration rather than user data, so it is safe to name in a message or a log line. + pub required_orgs: Vec, +} + /// The remote the checked-out branch tracks. /// ///
@@ -11611,6 +11803,21 @@ pub struct LocalSessionMetadataValue { pub summary: Option, } +/// Which stored location permissions were dropped because their directory is gone. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct LocationPermissionsCleanupResult { + /// Location keys whose grants were removed. Empty when every stored location still exists. + pub removed_location_keys: Vec, +} + /// Message text, optional severity level, persistence flag, optional follow-up URL, and optional tip. /// ///
@@ -11810,6 +12017,39 @@ pub struct ManagedSettingMeta { pub source: String, } +/// A user settings document and the effective managed policy whose controlled entries should be stamped onto it. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ManagedSettingsApplyControlsParams { + /// The effective managed policy, as composed by `managedSettings.resolveEffectiveValue`. Omit it on an unmanaged host: the settings then come back unchanged. + #[serde(skip_serializing_if = "Option::is_none")] + pub managed: Option, + /// The user settings document to stamp. Entries the managed layer does not name are returned exactly as supplied. + pub settings: serde_json::Value, +} + +/// The user settings with the managed layer's controlled entries stamped on. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ManagedSettingsApplyControlsResult { + /// The resulting settings document. + pub settings_json: serde_json::Value, +} + /// One candidate channel; absent settings represents a channel that delivered no document. /// ///
@@ -11998,6 +12238,272 @@ pub struct ManagedSettingsComposeResult { pub values: Option, } +/// Inputs describing the host and account an ingestion should resolve managed policy for. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ManagedSettingsIngestParams { + /// The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched. + #[serde(skip_serializing_if = "Option::is_none")] + pub auth_info: Option, + /// Whether to ignore a cached server policy when reading, forcing the resolution to come from a live fetch. + #[serde(skip_serializing_if = "Option::is_none")] + pub bypass_cache_read: Option, + /// Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. Omit it and the runtime reports a generic identity; the runtime version sent alongside is the gate that actually matters. + #[serde(skip_serializing_if = "Option::is_none")] + pub client_name: Option, + /// A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + #[serde(skip_serializing_if = "Option::is_none")] + pub device_response: Option, + /// The host's environment variables, read for cache location and policy overrides. Supplied by the host rather than read from the runtime process so a command that selected its own configuration home is honored. + pub environment: serde_json::Value, + /// Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. + #[serde(skip_serializing_if = "Option::is_none")] + pub has_device_response: Option, + /// The host's home directory, used to resolve cache and managed-file locations. + pub home_directory: String, + /// The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. + pub platform: String, + /// Whether a configured platform policy helper may be run to produce an enforced helper layer. + #[serde(skip_serializing_if = "Option::is_none")] + pub policy_helper_enabled: Option, + /// The policy-helper invocation reason. Defaults to sessionStart. + #[doc(hidden)] + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) policy_helper_reason: Option, + /// Directory the policy helper runs in when this ingestion is not owned by a registered session. A host resolving policy before its session exists must pass this, or a directory-sensitive helper judges the wrong repository. + #[serde(skip_serializing_if = "Option::is_none")] + pub policy_helper_working_directory: Option, + /// Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. + #[serde(skip_serializing_if = "Option::is_none")] + pub self_fetch: Option, + /// How this ingestion may use the on-disk server-policy cache. Defaults to the runtime's own policy when omitted. + #[doc(hidden)] + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) server_policy_cache_mode: Option, + /// The session whose credential store and working directory the policy helper should use. Omit it when no session exists yet and the process-wide store applies. + #[serde(skip_serializing_if = "Option::is_none")] + pub session_id: Option, + /// User agent to send with the policy fetch. + pub user_agent: String, +} + +/// One diagnostic emitted while ingesting managed settings. Returned rather than logged by the runtime so the host decides where ingestion diagnostics go, which matters because an ingestion runs before a session exists to carry a log sink. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ManagedSettingsLogMessage { + /// Severity of this diagnostic. + #[doc(hidden)] + pub(crate) level: ManagedSettingsLogLevel, + /// Human-readable diagnostic text. + pub message: String, +} + +/// The managed policy layers an ingestion resolved, together with the per-layer outcome flags a host needs to decide how much to trust the result. The flags are reported rather than folded into the settings because a host must be able to distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ManagedSettingsIngestResult { + /// The device layer could not be read, so it is unconfirmed rather than known-absent. + pub device_load_failed: bool, + /// The device layer discovered from the machine, when one exists. + #[serde(skip_serializing_if = "Option::is_none")] + pub device_response: Option, + /// The sandbox floor contributed by the device layer. + #[serde(skip_serializing_if = "Option::is_none")] + pub device_sandbox_floor: Option, + /// Whether the device layer's sandbox intent could not be determined, so a consumer must not read its absence as permission to run unsandboxed. + pub device_sandbox_undetermined: bool, + /// A device-managed policy is known to exist. + pub device_source_found: bool, + /// Diagnostics emitted while resolving the layers, in the order they occurred. + #[doc(hidden)] + pub(crate) log_messages: Vec, + /// The effective managed permissions layer, when the resolved policy carries one. + #[serde(skip_serializing_if = "Option::is_none")] + pub permissions: Option, + /// Which channel registered the policy helper that produced the helper layer. + #[doc(hidden)] + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) policy_helper_authority: Option, + /// A policy helper is configured for this host. + pub policy_helper_configured: bool, + /// The policy helper's failure must be treated as fail-closed rather than ignored. + pub policy_helper_fail_closed: bool, + /// The policy helper was configured but could not be run or its output could not be read. + pub policy_helper_load_failed: bool, + /// The layer produced by the platform policy helper, when one ran. + #[serde(skip_serializing_if = "Option::is_none")] + pub policy_helper_response: Option, + /// A live fetch failed but a recent cached entry was served in its place, so `serverFetchFailed` stays false. Lets a consumer distinguish a clean fetch from a cache-backed fallback. + pub server_cache_fallback: bool, + /// Minimum client version requested by a successful response. Advisory only; the delivered policy remains active. + #[serde(skip_serializing_if = "Option::is_none")] + pub server_client_update_requested: Option, + /// The server refused to deliver a policy because this client is too old to enforce it, carrying the user-facing sentence describing the refusal. No retry will help; the remedy is a client update. Gates that exist only because of managed policy should deny on this rather than falling back to their unmanaged default. + #[serde(skip_serializing_if = "Option::is_none")] + pub server_client_update_required: Option, + /// The error that made the server fetch fail, when one did. + #[serde(skip_serializing_if = "Option::is_none")] + pub server_fetch_error: Option, + /// The server fetch failed and no cached entry stood in for it, so the server layer is unconfirmed and fail-closed gates apply. + pub server_fetch_failed: bool, + /// The server fetch failed while a policy demanded a fresh confirmation, which is the strict posture an enterprise opted into rather than an ordinary transient failure. + pub server_forced_refresh_failure: bool, + /// The synthesized fail-closed permissions layer applied in place of a policy a refused client may not enforce. + #[serde(skip_serializing_if = "Option::is_none")] + pub server_permissions_floor: Option, + /// How the server layer was resolved. + #[doc(hidden)] + pub(crate) server_resolution: ManagedSettingsServerPolicyResolution, + /// The account's server-delivered policy, when one was resolved. + #[serde(skip_serializing_if = "Option::is_none")] + pub server_response: Option, + /// The server fetch failed in a way a later retry could succeed at, as opposed to a refusal that no retry will change. + pub server_retryable_failure: bool, + /// The sandbox object from a cached server policy that a forced refresh declined to serve in full. Folded back into the effective sandbox layer so an outage during a forced refresh still synthesizes the fail-closed sandbox floor from the administrator's known intent. + #[serde(skip_serializing_if = "Option::is_none")] + pub server_sandbox_floor: Option, + /// A server-managed policy is known to exist even though `serverResponse` is intentionally unset. Consumers should OR this with the presence of `serverResponse` when deciding whether the device is managed, so a fresh start during an outage still applies the fail-closed gates instead of treating the device as unmanaged. + pub server_source_found: bool, + /// No usable token was available, so no server fetch was attempted. + pub server_token_unavailable: bool, + /// The effective managed settings composed from every resolved layer. Omitted when no layer set anything, so an unmanaged host locks nothing. + #[serde(skip_serializing_if = "Option::is_none")] + pub settings: Option, +} + +/// Inputs describing the host and account whose managed remote-control policy should be resolved. Mirrors `managedSettings.ingest`, and deliberately carries no retention decision: reading this gate never becomes this runtime process's startup policy. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ManagedSettingsLoadRemoteControlParams { + /// The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched. + #[serde(skip_serializing_if = "Option::is_none")] + pub auth_info: Option, + /// Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. That refusal is exactly what turns into an explicit `disabled` below, so a host that omits this field forfeits the protection. + #[serde(skip_serializing_if = "Option::is_none")] + pub client_name: Option, + /// A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + #[serde(skip_serializing_if = "Option::is_none")] + pub device_response: Option, + /// The host's environment variables, read for cache location and policy overrides. + pub environment: serde_json::Value, + /// Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. + #[serde(skip_serializing_if = "Option::is_none")] + pub has_device_response: Option, + /// The host's home directory, used to resolve cache and managed-file locations. + pub home_directory: String, + /// The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. + pub platform: String, + /// Whether a configured platform policy helper may be run to produce an enforced helper layer. + #[serde(skip_serializing_if = "Option::is_none")] + pub policy_helper_enabled: Option, + /// The policy-helper invocation reason. Defaults to sessionStart. + #[doc(hidden)] + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) policy_helper_reason: Option, + /// Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. + #[serde(skip_serializing_if = "Option::is_none")] + pub self_fetch: Option, + /// User agent to send with the policy fetch. + pub user_agent: String, +} + +/// The managed remote-control policy in force for an account, if any. An absent policy means the account is unmanaged for this capability, which a host reads as allowed — so absence here is a positive statement that no policy applies, never a stand-in for a resolution that failed. A resolution that cannot be completed is rejected instead. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ManagedSettingsLoadRemoteControlResult { + /// The account's `remoteControl` policy document. Absent when no managed policy governs remote control for this account. Reported as an explicit disabled policy, rather than as absence, when the service refused to deliver a policy this client is too old to enforce. + #[serde(skip_serializing_if = "Option::is_none")] + pub remote_control: Option, +} + +/// The client-supplied managed settings to validate and normalize. Omitting them is valid and yields no policy. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ManagedSettingsParseClientValueParams { + /// The managed settings a client is supplying for a session it is about to open. Omit them when the client is imposing no policy of its own. + #[serde(skip_serializing_if = "Option::is_none")] + pub settings: Option, +} + +/// The accepted managed settings, reduced to the keys a client is allowed to set. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ManagedSettingsParseClientValueResult { + /// The normalized settings. Omitted when the client supplied none. An accepted document that sets nothing comes back as an empty object, which is distinct from omission. + #[serde(skip_serializing_if = "Option::is_none")] + pub settings_json: Option, +} + +/// The device-managed settings layer, with the sandbox floor and the load outcome a host needs to compose it into an effective policy. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ManagedSettingsReadDeviceResult { + /// Whether discovery or validation failed. A host must treat this as "policy unknown" rather than "no policy": absent settings with this set false mean the device genuinely has none. + pub load_failed: bool, + /// Sandbox floor read from the discovered document before validation, so a document that is otherwise rejected can still raise the floor it declared. + #[serde(skip_serializing_if = "Option::is_none")] + pub sandbox_floor: Option, + /// Validated, canonical device-managed settings. Omitted when no device policy was discovered, when the discovered document failed validation, or when it validated to an empty object — an empty document carries no policy, and reporting it as present would outrank layers that do. + #[serde(skip_serializing_if = "Option::is_none")] + pub settings: Option, +} + /// Validated device-managed settings discovered before a session exists. /// ///
@@ -12017,6 +12523,115 @@ pub struct ManagedSettingsReadResult { pub settings_json: Option, } +/// The bypass-permissions state a host holds today, the account now signed in, and what the managed-policy resolution said. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ManagedSettingsResolveBypassDisableTransitionParams { + /// The account signed in now. A `managed` disable pinned to a different account is lifted. + pub active_identity: String, + /// The account a `managed` disable is pinned to. Omit it when the current source is not `managed`; it is ignored for the other sources. + #[serde(skip_serializing_if = "Option::is_none")] + pub current_managed_identity: Option, + /// Which layer currently disables bypass mode. Omit it when nothing does. + #[doc(hidden)] + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) current_source: Option, + /// What the resolution said about bypass mode. Send `unknown` rather than omitting the field when there is no verdict. + #[doc(hidden)] + pub(crate) policy: ManagedSettingsBypassPolicyResolution, +} + +/// The bypass-permissions state a host should hold after the resolution, and what it must do to get there. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ManagedSettingsResolveBypassDisableTransitionResult { + /// The account the returned `managed` source is pinned to. Store it alongside `source`; the next call needs it to decide whether an account switch lifts the disable. + #[serde(skip_serializing_if = "Option::is_none")] + pub managed_identity: Option, + /// The value to store in the host's own bypass-disabled flag. Omitted means leave it exactly as it is, which is not the same as being told to store `false`. + #[serde(skip_serializing_if = "Option::is_none")] + pub set_disabled_state: Option, + /// Which layer disables bypass mode after this resolution. Omitted when none does, which is what a lifted disable looks like. + #[doc(hidden)] + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) source: Option, + /// Whether a bypass-permissions session already running must be turned off. True only when this resolution newly disables bypass mode, so a host that is already compliant is not interrupted. + pub suppress_runtime_allow_all: bool, +} + +/// The credential and environment to evaluate the device-channel sign-in pin against. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ManagedSettingsResolveDeviceForceLoginOrgsGateParams { + /// The authenticated identity to judge. Omitted when signed out, which is the case the device channel exists to serve: it can refuse a first sign-in before any credential exists. + #[serde(skip_serializing_if = "Option::is_none")] + pub auth_info: Option, + /// The host's environment variables. Read for the variables that would make an identity's membership snapshot forgeable, so a credential whose provenance cannot be trusted is refused rather than accepted. + pub environment: serde_json::Value, +} + +/// The managed-settings layers to compose into an effective policy. Every layer is optional; omitting all of them yields no effective policy. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ManagedSettingsResolveEffectiveValueParams { + /// The device sandbox floor, folded into the device layer under `sandbox` before composition. + #[serde(skip_serializing_if = "Option::is_none")] + pub device_sandbox_floor: Option, + /// The device layer: native MDM and managed-file settings describing the machine rather than the account. + #[serde(skip_serializing_if = "Option::is_none")] + pub mdm: Option, + /// The policy-helper layer, an enforced channel sourced from a platform policy helper process. + #[serde(skip_serializing_if = "Option::is_none")] + pub policy_helper: Option, + /// The account's server-delivered org policy, as returned by a managed-settings fetch. Omitted before sign-in or when the fetch has not landed. + #[serde(skip_serializing_if = "Option::is_none")] + pub server: Option, +} + +/// The effective managed policy composed from the supplied layers. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ManagedSettingsResolveEffectiveValueResult { + /// The composed effective managed settings. Omitted when no layer sets anything, so an unmanaged host locks nothing. Carries `sandboxAdvisoryFloorDeclined: true` when an advisory server force-on was dropped because this host cannot run the sandbox. + #[serde(skip_serializing_if = "Option::is_none")] + pub settings_json: Option, +} + /// Optional opaque account selection or GitHub token whose managed settings are resolved. /// ///
@@ -12073,6 +12688,172 @@ pub struct ManagedSettingsResolveResult { pub values: Option, } +/// Inputs describing the host and account a startup policy resolution should run for. Mirrors `managedSettings.ingest`, and adds the decision of whether the resolved policy is retained for this runtime process. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ManagedSettingsResolveStartupPolicyParams { + /// The authenticated identity to resolve policy for. Omitted before sign-in, in which case no server layer is fetched and the sign-in pin is evaluated against no credential. + #[serde(skip_serializing_if = "Option::is_none")] + pub auth_info: Option, + /// Whether to ignore a cached server policy when reading, forcing the resolution to come from a live fetch. + #[serde(skip_serializing_if = "Option::is_none")] + pub bypass_cache_read: Option, + /// Name of the embedding client, reported to the managed-settings service as `client_id` so it can refuse to deliver a policy this client is too old to enforce. + #[serde(skip_serializing_if = "Option::is_none")] + pub client_name: Option, + /// A device layer supplied by the host instead of discovered from the machine. Pair it with `hasDeviceResponse` so an explicit absence is distinguishable from an omitted override. + #[serde(skip_serializing_if = "Option::is_none")] + pub device_response: Option, + /// The host's environment variables, read for cache location, policy overrides, and the variables that would make a membership snapshot forgeable. + pub environment: serde_json::Value, + /// Whether `deviceResponse` is an override at all. True with a null `deviceResponse` asserts the device layer is empty; false discovers it from the machine. + #[serde(skip_serializing_if = "Option::is_none")] + pub has_device_response: Option, + /// The host's home directory, used to resolve cache and managed-file locations. + pub home_directory: String, + /// The host's platform, in Node's `process.platform` spelling, used to locate platform-specific cache and policy paths. + pub platform: String, + /// Whether a configured platform policy helper may be run to produce an enforced helper layer. + #[serde(skip_serializing_if = "Option::is_none")] + pub policy_helper_enabled: Option, + /// The policy-helper invocation reason. Defaults to sessionStart. + #[doc(hidden)] + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) policy_helper_reason: Option, + /// Directory the policy helper runs in when this resolution is not owned by a registered session. A host resolving policy before its session exists must pass this, or a directory-sensitive helper judges the wrong repository. + #[serde(skip_serializing_if = "Option::is_none")] + pub policy_helper_working_directory: Option, + /// Whether to retain the resolved policy as this runtime process's startup policy, so later work in the process enforces it. Set false to resolve without side effects, which is what a protocol host wants before session creation: its sessions apply the complete policy through the normal lifecycle, and retaining here would let a readiness credential affect unrelated sessions. The returned verdict is identical either way — this decides only whether the process keeps it. + pub retain_and_apply: bool, + /// Whether to run ingestion. Omit or set false to return an empty result without discovering or fetching policy. + #[serde(skip_serializing_if = "Option::is_none")] + pub self_fetch: Option, + /// How this resolution may use the on-disk server-policy cache. Defaults to the runtime's own policy when omitted. Rejected when combined with `bypassCacheRead`, because the two express the same decision and accepting both would leave the caller unsure which one the runtime honored. + #[doc(hidden)] + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) server_policy_cache_mode: Option, + /// The session whose credential store, working directory and client kind the resolution should use. Omit it when no session exists yet and the process-wide store applies. A resolution whose session names a credential other than `authInfo` is returned but not retained, so a stale sign-in cannot apply policy for an account that has already been switched away from. + #[serde(skip_serializing_if = "Option::is_none")] + pub session_id: Option, + /// User agent to send with the policy fetch. + pub user_agent: String, +} + +/// The startup policy a resolution composed, the per-layer outcome flags a host needs to decide how much to trust it, and the enterprise sign-in verdict for the credential it ran against. The flags are reported rather than folded into the settings because a host must distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ManagedSettingsResolveStartupPolicyResult { + /// Advisory minimum client version from a successful server response. + #[serde(skip_serializing_if = "Option::is_none")] + pub client_update_requested: Option, + /// The server refused to deliver a policy because this client is too old to enforce it, carrying the user-facing sentence describing the refusal. No retry will help; the remedy is a client update. + #[serde(skip_serializing_if = "Option::is_none")] + pub client_update_required: Option, + /// The device layer could not be read, so it is unconfirmed rather than known-absent. + pub device_load_failed: bool, + /// The device layer discovered from the machine, when one exists. + #[serde(skip_serializing_if = "Option::is_none")] + pub device_response: Option, + /// The sandbox floor contributed by the device layer. + #[serde(skip_serializing_if = "Option::is_none")] + pub device_sandbox_floor: Option, + /// The enterprise sign-in verdict for the credential this resolution ran against, evaluated over the effective policy so a server-delivered pin is honored alongside a device one. Computed on every resolution, including one that was not retained, so a host that declines to apply policy still cannot proceed past a pin. + #[doc(hidden)] + pub(crate) force_login_orgs: ForceLoginOrgsDecision, + /// A managed policy is known to apply to this host, from a discovered source or a resolved document. + pub managed_policy_present: bool, + /// The permissions layer specifically could not be confirmed, so permission gates apply their fail-closed posture. + pub permission_policy_undetermined: bool, + /// The policy helper was configured but could not be run, or its output could not be read. + pub policy_helper_load_failed: bool, + /// The layer produced by the platform policy helper, when one ran. + #[serde(skip_serializing_if = "Option::is_none")] + pub policy_helper_response: Option, + /// Some layer of the policy could not be confirmed, so its absence must not be read as permission. Folds in a failed server fetch as well as an unreadable device layer. + pub policy_undetermined: bool, + /// The sandbox was enabled because policy could not be confirmed rather than because an administrator asked for it. Lets a host explain a sandbox the user did not configure. + pub sandbox_enabled_by_undetermined_policy: bool, + /// The effective sandbox floor composed across every layer, which a host must apply rather than its own default. + #[serde(skip_serializing_if = "Option::is_none")] + pub sandbox_floor: Option, + /// The server fetch failed and no cached entry stood in for it, so the server layer is unconfirmed and fail-closed gates apply. + pub server_fetch_failed: bool, + /// How the current runtime resolved the server layer. + #[doc(hidden)] + pub(crate) server_resolution: ManagedSettingsServerPolicyResolution, + /// The account's server-delivered policy, when one was resolved. + #[serde(skip_serializing_if = "Option::is_none")] + pub server_response: Option, + /// Telemetry describing which layers answered and how, for the host to report alongside its own startup events. + pub telemetry: serde_json::Value, + /// Warnings raised while resolving, in the order they occurred. + pub warnings: Vec, +} + +/// The managed layers to retain as this process's startup policy, with the outcome of fetching each one. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ManagedSettingsRetainPolicyParams { + /// Whether the device load failed. Report it honestly, for the same reason as `serverFetchFailed`. + pub device_load_failed: bool, + /// The device/MDM policy layer. + #[serde(skip_serializing_if = "Option::is_none")] + pub device_response: Option, + /// Sandbox floor declared by the device layer, carried separately so a document that failed validation can still raise the floor. + #[serde(skip_serializing_if = "Option::is_none")] + pub device_sandbox_floor: Option, + /// Whether the device sandbox intent is unreadable independently of its other settings. + pub device_sandbox_undetermined: bool, + /// Whether a device policy source demonstrably exists. This, not a read error, is the evidence a device is managed, so a fail-closed policy gates on it. + pub device_source_found: bool, + /// Whether any managed policy source exists, independently of fetch failures. + pub managed_policy_present: bool, + /// Whether permission policy is undetermined. Sandbox-only uncertainty does not imply this flag. + pub permission_policy_undetermined: bool, + /// The policy helper's response: the third managed layer that a process owning its startup policy resolves. It is retained with the other two so that every ambient read in this process, including the mutation guards and the governed marketplace allowlist that the `plugins.*` handlers derive, sees the whole policy the process fetched. A session-owning process omits it, because it resolves a helper per session against that session's working directory. + #[serde(skip_serializing_if = "Option::is_none")] + pub policy_helper_response: Option, + /// Preserve the retained server layer during a device-only resolution. + pub preserve_server_state: bool, + /// Whether uncertainty alone enabled the shared sandbox floor. + pub sandbox_enabled_by_undetermined_policy: bool, + /// Whether the shared sandbox policy is undetermined. Diagnostic errors alone do not imply this flag. + pub sandbox_floor_undetermined: bool, + /// Whether the server fetch failed. Report it honestly: true keeps the already-retained server layer rather than replacing it with an absent one. + pub server_fetch_failed: bool, + /// Whether a required fresh server-policy confirmation failed. + pub server_forced_refresh_failure: bool, + /// The resolved server policy. A known source can lack a response after a forced-refresh failure. + #[serde(skip_serializing_if = "Option::is_none")] + pub server_response: Option, + /// Whether the server policy source exists, even when its response is unavailable. + pub server_source_found: bool, + /// Shared server/device sandbox floor, excluding session-local helper policy. + #[serde(skip_serializing_if = "Option::is_none")] + pub shared_sandbox_floor: Option, +} + /// The authoring JSON schema for managed settings recognized by this runtime. /// ///
@@ -19087,6 +19868,41 @@ pub struct PermissionsConfigureResult { pub success: bool, } +/// The verbatim managed `permissions` slice to interpret. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct PermissionsEvaluateManagedPolicyParams { + /// The `permissions` object from a managed settings layer, for example `{"disableBypassPermissionsMode":"disable"}`. Omitted or null means no managed policy applies. + #[serde(skip_serializing_if = "Option::is_none")] + pub permissions: Option, +} + +/// The policy questions a host asks before granting elevated permissions. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PermissionsEvaluateManagedPolicyResult { + /// True when managed policy forbids bypass-permissions mode, so allow-all style flags must not take effect. + pub bypass_permissions_disabled: bool, + /// True when the managed layer supplies permission rules that the session must enforce. + pub permission_rules_active: bool, + /// True when a managed policy exists but this build could not determine its meaning. Hosts fail closed on it rather than assuming permission was granted. + pub policy_undetermined: bool, +} + /// Indicates whether the operation succeeded. /// ///
@@ -19414,6 +20230,44 @@ pub struct PermissionUrlsSetUnrestrictedModeParams { pub enabled: bool, } +/// A complete JSON snapshot to write under the runtime's per-path file lock. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PersistenceWriteRawJsonLockedRequest { + /// The serialized JSON document to write. It replaces the file's contents entirely; nothing is merged. + pub data_json: String, + /// Comment lines to emit above the document, for a format that tolerates them. Omit for strict JSON. + #[serde(skip_serializing_if = "Option::is_none")] + pub file_header: Option, + /// Absolute path of the file to replace. Parent directories are created when missing. + pub path: String, +} + +/// The outcome of a locked snapshot write. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PersistenceWriteRawJsonLockedResult { + /// Why the write failed. Absent when `success` is true. A lock the runtime could not acquire in time reports here rather than raising. + #[serde(skip_serializing_if = "Option::is_none")] + pub error: Option, + /// Whether the file now holds the requested contents. + pub success: bool, +} + /// Optional message to echo back to the caller. /// ///
@@ -21739,6 +22593,32 @@ pub struct RemoteSessionRepository { pub owner: String, } +/// One atomic edit of an allowed top-level repository setting. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct RepoSettingsEditRequest { + /// One canonical top-level repository setting that the allowlist permits. + pub key: String, + /// Set a scalar, add or remove a string list item, or remove the setting. The handler rejects a missing or incompatible value. + #[doc(hidden)] + pub(crate) operation: SettingsEditOperation, + /// Absolute path of the repository root. + pub repo_root: String, + /// Shared or local repository settings file. + #[doc(hidden)] + pub(crate) scope: RepoSettingsEditScope, + /// Required boolean, string or number for set, required string for add-item and remove-item, and forbidden for remove. The runtime rejects all other JSON values. + #[serde(skip_serializing_if = "Option::is_none")] + pub value: Option, +} + /// Which repository settings file to read. /// ///
@@ -21834,6 +22714,21 @@ pub struct ResponseFormat { pub r#type: ResponseFormatType, } +/// The stored sandbox settings to resolve against the defaults. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SandboxApplyDefaultsRequest { + /// The sandbox settings as stored in the settings file. An empty object resolves to the defaults alone. + pub stored: serde_json::Value, +} + /// Credential-injection capability flags applied while the sandbox is enabled. For the same capability independent of sandboxing, and matched to the credential's GitHub host, see `shell.credentials`; the two are additive. /// ///
@@ -22144,6 +23039,71 @@ pub struct SandboxDisableForSessionResult { pub success: bool, } +/// The documentation URL a host cites when it declines or downgrades a sandbox setting. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SandboxDocsUrlResult { + /// Documentation URL describing the sandbox and the settings that control it. + pub url: String, +} + +/// A sandbox config and the per-feature routing flag to resolve it for. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct SandboxEffectiveForOptionalParams { + /// The routing flag naming the feature being launched, such as `sandboxMcpServers` or `sandboxLspServers`. + pub routing_flag: String, + /// The session's resolved `sandbox` slice. Omitted when the host has none, which yields a disabled sandbox rather than an error. + #[serde(skip_serializing_if = "Option::is_none")] + pub sandbox: Option, +} + +/// The sandbox a named feature actually launches under. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct SandboxEffectiveForOptionalResult { + /// The effective sandbox config for the requested feature, or a disabled sandbox when the feature is routed out of it. + pub sandbox_json: serde_json::Value, +} + +/// One slash command, as typed, to test against the enforcement-block allowlist. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct SandboxEnforcementCommandAllowedParams { + /// The command's arguments, in order. Pass an empty array for a bare command: several entries in the allowlist admit the bare form and refuse every argument. + pub args: Vec, + /// The command name as the user typed it, with or without its leading slash. + pub command_name: String, +} + /// Managed sandbox enforcement state for a session. /// ///
@@ -22164,6 +23124,59 @@ pub struct SandboxEnforcementStatus { pub required: bool, } +/// One file-picker suggestion offered up for the sandbox filesystem check. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct SandboxPickerCandidate { + /// Whether the suggestion is a directory. A directory the policy does not itself allow may still be needed as a waypoint to an allowed subtree. + pub is_directory: bool, + /// Absolute path the suggestion would attach. + pub path: String, +} + +/// A batch of file-picker candidates to check against a prepared policy. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct SandboxFilterPickerCandidatesParams { + /// The candidates to check, in the order the answers are returned. + #[doc(hidden)] + pub(crate) candidates: Vec, + /// The session's working directory, matching the one the policy was prepared from. + pub cwd: String, + /// The policy returned by `sandbox.preparePickerPolicy`. Omitted keeps every candidate. + #[serde(skip_serializing_if = "Option::is_none")] + pub sandbox: Option, +} + +/// Per-candidate allow decisions, positionally aligned with the request. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct SandboxFilterPickerCandidatesResult { + /// One decision per candidate, in the same order. Always the same length as the request's `candidates`. + pub allowed: Vec, +} + /// Request to accept the sandbox path grant offered on an active sandbox escalation permission prompt. /// ///
@@ -22237,6 +23250,40 @@ pub struct SandboxHostSupport { pub supported: bool, } +/// The working directory and sandbox settings to build a file-picker policy from. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct SandboxPreparePickerPolicyParams { + /// The session's working directory. Git discovery and grant canonicalization are resolved against it. + pub cwd: String, + /// The session's resolved `sandbox` slice. Omitted, or disabled, yields no policy and every candidate is kept. + #[serde(skip_serializing_if = "Option::is_none")] + pub sandbox: Option, +} + +/// The prepared file-picker policy, or none when the sandbox is disabled. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct SandboxPreparePickerPolicyResult { + /// The prepared policy to pass back to `sandbox.filterPickerCandidates`. Absent when the sandbox is disabled or absent, in which case filtering keeps every candidate. + #[serde(skip_serializing_if = "Option::is_none")] + pub sandbox_json: Option, +} + /// Result of creating the persistent certificate authority of the sandbox credential proxy. /// ///
@@ -22288,6 +23335,138 @@ pub struct SandboxProxyCaStatus { pub state: SandboxProxyCaState, } +/// The stored sandbox proxy password, if one is present. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SandboxProxySecretGetResult { + /// The stored password. Absent when no entry exists in either the keychain or the on-disk fallback store. + #[serde(skip_serializing_if = "Option::is_none")] + pub value: Option, +} + +/// Where this runtime keeps the sandbox proxy password. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SandboxProxySecretLocation { + /// Absolute path of the credential store holding the sandbox proxy password. The proxy password belongs to no MCP server, so it is kept in its own directory rather than in the MCP secret store. + pub config_dir: String, + /// Identifier of the proxy password entry within that store. Derived from the configuration directory, so two Copilot homes on one machine never share an entry. Use it to recognize a `${secret:…}` reference in stored settings as this runtime's own proxy password. + pub secret_id: String, +} + +/// The sandbox proxy password to store. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SandboxProxySecretSaveRequest { + /// The password to store for the sandbox proxy. + pub value: String, +} + +/// Where the sandbox proxy password was stored. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SandboxProxySecretSaveResult { + /// Whether the OS keychain accepted the value. False means it was written to the on-disk fallback store instead, which is still readable by `sandbox.proxySecret.get`. + pub stored_in_keychain: bool, +} + +/// The user's sandbox settings and the managed sandbox floor to raise them to. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct SandboxResolveFlooredConfigParams { + /// The effective managed `sandbox` slice acting as a floor. Omitted when no administrator policy applies, in which case the user's own settings stand unchanged. + #[serde(skip_serializing_if = "Option::is_none")] + pub managed_sandbox: Option, + /// The user's own `sandbox` settings slice. Omitted when the user has configured none, which still yields the managed floor rather than a disabled sandbox. + #[serde(skip_serializing_if = "Option::is_none")] + pub user_sandbox: Option, +} + +/// The user's sandbox settings raised to the managed floor. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SandboxResolveFlooredConfigResult { + /// The floored sandbox config, normalized through the declared sandbox shape so only declared fields in a fixed order are present. + pub sandbox_json: serde_json::Value, +} + +/// The managed sandbox policy in force, which selects which remedy the notice offers. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct SandboxUnsupportedStartupNoticeParams { + /// True when the sandbox stayed on only because the managed policy could not be determined. Distinguishes a policy that positively enforces the sandbox from one that merely failed to resolve, which is the difference between telling the user to contact an administrator and telling them to wait. Defaults to false. + #[serde(skip_serializing_if = "Option::is_none")] + pub enabled_by_undetermined_policy: Option, + /// The managed `sandbox` slice, when a policy supplies one. The notice treats the sandbox as enforced only when this both enables it and sets `failIfUnavailable`, because a managed sandbox that tolerates being unavailable still leaves the user able to turn it off. + #[serde(skip_serializing_if = "Option::is_none")] + pub managed_sandbox: Option, +} + +/// The startup warning, absent when the machine can run a sandbox. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct SandboxUnsupportedStartupNoticeResult { + /// The user-facing warning, carrying the platform remedy and the recovery the policy in force actually allows. Absent when this machine supports a sandbox, so a host can call unconditionally and print only what it gets. + #[serde(skip_serializing_if = "Option::is_none")] + pub notice: Option, +} + /// Register an absolute-time scheduled prompt. /// ///
@@ -29671,6 +30850,28 @@ pub struct UserSettingsApplyTopKeyResult { pub status: String, } +/// The overrides and host context to resolve effective runtime settings from. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsBuildRuntimeRequest { + /// The environment to read settings-bearing variables from. Passed explicitly rather than read from the server process so a host can resolve settings for an environment it is about to create rather than the one it runs in. + pub environment: HashMap, + /// Settings that take precedence over every document and environment layer, such as the values a host derived from its own command line. Keyed by setting name, with each value carried verbatim, so a host may pass keys this runtime does not recognize. Absent when the host contributes no overrides of its own. + #[serde(skip_serializing_if = "Option::is_none")] + pub overrides: Option>, + /// The platform to apply platform-specific defaults for, in the same spelling the host's own runtime reports. + pub platform: String, + /// The directory the settings are being resolved for. This selects the repository-scoped document, so a host resolving settings for a directory other than its own process working directory must pass that directory here. + pub working_directory: String, +} + /// One atomic edit of a canonical setting in settings.json. /// ///
@@ -29766,6 +30967,77 @@ pub struct UserSettingsGovernanceKeysResult { pub repo: Vec, } +/// The filesystem and environment facts a user-settings file is resolved from. Passed explicitly rather than read from the runtime's own process, so a host whose configuration directory differs from its process environment resolves the file it means. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsHostContext { + /// The Copilot configuration directory, when the host set one. Takes precedence over `COPILOT_HOME` and the home directory. + #[serde(skip_serializing_if = "Option::is_none")] + pub config_dir: Option, + /// The host's environment variables. `COPILOT_HOME` is read from here, as are the variables a settings hook may expand. + pub environment: serde_json::Value, + /// The user's home directory, used when neither a configuration directory nor `COPILOT_HOME` is set. + pub home_directory: String, +} + +/// A repository to read settings from, and the user layer they are merged over. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsLoadAndMergeRepoRequest { + /// Absolute path of the repository root whose settings to read. When this is the user's home directory, the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as if it were repository policy. + pub repo_root: String, + /// The user's own settings, keyed by setting name. The repository layer is merged over this; a repository may only add to the collection settings it is allowed to influence, so a user setting it does not name survives unchanged. + pub user_settings: HashMap, +} + +/// The settings a consumer should act on inside a repository, together with any diagnostic raised while reading the repository layer. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsLoadAndMergeRepoResult { + /// The merged settings document, keyed by setting name. Equals the supplied user layer when the repository declares no settings. + pub settings: HashMap, + /// Why part of the repository document was ignored, as a single human-readable string joining every diagnostic with `; `. Null when it loaded cleanly. The settings that did load are still merged, so a consumer should surface this and continue rather than treat it as a failure. + #[serde(skip_serializing_if = "Option::is_none")] + pub warning: Option, +} + +/// Selects the configuration directory whose user settings to read. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsLoadForConfigDirRequest { + /// Copilot configuration directory to read the settings document from, taking precedence over the server's own `COPILOT_HOME` and default home. Omit it, or pass an empty string, to read the directory the server resolved for itself. + #[serde(skip_serializing_if = "Option::is_none")] + pub config_dir: Option, +} + /// Contents of settings.json as stored, for a caller about to rewrite it. /// ///
@@ -29784,6 +31056,213 @@ pub struct UserSettingsLoadForEditResult { pub status: String, } +/// Selects the repository whose checked-in settings to read. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsLoadRepoRequest { + /// Absolute path of the repository root whose settings to read. When this is the user's home directory, the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as if it were repository policy. + pub repo_root: String, +} + +/// A repository's settings as stored, together with any diagnostic raised while reading them. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsLoadRepoResult { + /// The repository's settings document, keyed by setting name, with each value carried verbatim. Null when the repository declares no settings. + #[serde(skip_serializing_if = "Option::is_none")] + pub settings: Option>, + /// Why part of the document was ignored, as a single human-readable string joining every diagnostic with `; `. Null when the document loaded cleanly. The settings that did load are still reported, so a consumer should surface this and continue rather than treat it as a failure. + #[serde(skip_serializing_if = "Option::is_none")] + pub warning: Option, +} + +/// The user's stored settings, together with any diagnostic raised while reading them. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsLoadWithWarningResult { + /// The stored user settings document, keyed by setting name, with each value carried verbatim. Empty when the file could not be read at all. + pub settings: HashMap, + /// Why part of the document was ignored, phrased for display to the user. Null when the document loaded cleanly. The settings that did load are still reported, so a consumer may surface this and continue rather than treat it as a failure. + #[serde(skip_serializing_if = "Option::is_none")] + pub warning: Option, +} + +/// The managed (enterprise policy) layer and the user layer to fold together. The field names carry the layer identity: nothing about a settings object identifies which layer produced it, so a generic base/override pair would let a caller transpose them and silently resolve the governance keys in the user's favour. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsMergeManagedAndUserParams { + /// The managed layer. Its governance keys win, and the per-entry `enabledPlugins` and `extraKnownMarketplaces` control maps are stamped back from it after the union. Omitted when the host is unmanaged. + #[serde(skip_serializing_if = "Option::is_none")] + pub managed: Option, + /// The user's own settings layer. Wins on every key the managed layer does not govern. Omitted when the user has no settings yet. + #[serde(skip_serializing_if = "Option::is_none")] + pub user: Option, +} + +/// The user layer folded over the managed layer. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsMergeManagedAndUserResult { + /// The merged settings. An empty object when neither layer was supplied, so an unmanaged host with no user settings governs nothing. + pub settings_json: serde_json::Value, +} + +/// The user layer and the repository layer to fold together. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsMergeRepoValueParams { + /// The repository's checked-in settings layer. + pub repo_settings: serde_json::Value, + /// The user's settings, already resolved against any managed layer. + pub user_settings: serde_json::Value, +} + +/// The repository layer folded into the user layer. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsMergeRepoValueResult { + /// The merged settings, with the per-entry managed control maps re-stamped from the runtime's ambient managed policy. + pub settings_json: serde_json::Value, +} + +/// Selects the configuration directory whose settings document to clean. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsMigrateObsoleteOnDiskRequest { + /// The configuration directory holding the settings document to clean. A host that scopes a session to its own Copilot home passes that directory here; omit it to clean the document under the home the server resolved for itself. The home directory and environment are deliberately not caller-supplied: they decide only the settings path root and the two hook-parsing flags, and those describe the process doing the reading rather than the caller. + #[serde(skip_serializing_if = "Option::is_none")] + pub config_dir: Option, +} + +/// The outcome of the one-time obsolete-settings cleanup. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsMigrateObsoleteOnDiskResult { + /// What the cleanup did. Only `changed` rewrote the document. The cleaned settings are not returned here: the document is written before this replies, so `user.settings.load` reads it authoritatively. + #[doc(hidden)] + pub(crate) status: UserSettingsMigrateObsoleteOnDiskStatus, +} + +/// Selects the configuration directory to run the one-time staff log-level migration against, and supplies the caller's record of whether it has already run. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsMigrateStaffLogLevelOnceRequest { + /// When the caller last recorded this migration, as an ISO-8601 timestamp. Supplying it lets the runtime answer `current` without re-running the evaluation. + #[serde(skip_serializing_if = "Option::is_none")] + pub cached_completed_at: Option, + /// The configuration directory, home directory and environment to resolve the settings and global-state documents from. A host that scopes a session to its own Copilot home must pass that directory here, or the migration is evaluated against the server's own home instead. + pub context: UserSettingsHostContext, +} + +/// The outcome of the one-time staff log-level migration. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsMigrateStaffLogLevelOnceResult { + /// When the migration was recorded as done, as an ISO-8601 timestamp. Absent only for `ineligible`, which records nothing. + #[serde(skip_serializing_if = "Option::is_none")] + pub completed_at: Option, + /// The settings document as it stands after the migration, keyed by setting name. Present only for `refreshed`, and only when the document could be re-read cleanly. + #[serde(skip_serializing_if = "Option::is_none")] + pub settings: Option, + /// What the migration did. Only `refreshed` can have changed the persisted settings. + pub status: StaffLogLevelMigrationStatus, +} + +/// The outcome of the one-time staff update-channel migration. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsMigrateStaffUpdateChannelOnceResult { + /// When the migration was recorded as done, as an ISO-8601 timestamp. Absent only for `ineligible`, which records nothing. + #[serde(skip_serializing_if = "Option::is_none")] + pub completed_at: Option, + /// What the migration did. Only `migrated` means the persisted settings changed. + pub status: StaffUpdateChannelMigrationStatus, +} + /// Settings object whose key names should be canonicalized. /// ///
@@ -29814,6 +31293,21 @@ pub struct UserSettingsNormalizeResult { pub settings: serde_json::Value, } +/// The on-disk location of the user's settings document. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsPathResult { + /// Absolute path to the settings file this runtime reads and writes. Normally `settings.json` under the Copilot configuration directory; an extensionless legacy `settings` file is reported instead when it exists and `settings.json` does not. + pub path: String, +} + /// The settings layer a problem was found in. /// ///
@@ -29916,6 +31410,87 @@ pub struct UserSettingsProblemsResult { pub problems: Option>, } +/// Selects the configuration directory to run the one-time staff model-selection reset against, and supplies the caller's record of whether it has already run. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsResetStaffModelSelectionOnceRequest { + /// The configuration directory, home directory and environment to resolve the settings and global-state documents from. A host that scopes a session to its own Copilot home must pass that directory here, or the reset is evaluated against the server's own home instead. + pub context: UserSettingsHostContext, + /// Whether the signed-in account is a staff account. The reset applies only to staff, so anything other than `true` returns `didReset: false` without touching the settings document. + #[serde(skip_serializing_if = "Option::is_none")] + pub staff: Option, + /// When the caller last recorded this reset, as an ISO-8601 timestamp. A timestamp at or after the cutoff means the reset already ran and is returned unchanged. + #[serde(skip_serializing_if = "Option::is_none")] + pub staff_model_reset_at: Option, +} + +/// The outcome of the one-time staff model-selection reset. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsResetStaffModelSelectionOnceResult { + /// The cutoff this reset is gated on, as an ISO-8601 timestamp. A recorded timestamp at or after it means the reset is already done. + pub cutoff: String, + /// Whether the persisted model selection was cleared. Only `true` means the settings document changed and the host should adopt the returned settings. + pub did_reset: bool, + /// The timestamp the host should now record, as an ISO-8601 timestamp. Carries the caller's own value back unchanged when nothing was reset. + #[serde(skip_serializing_if = "Option::is_none")] + pub reset_at: Option, + /// The settings document as it stands after the reset, keyed by setting name. Present only when `didReset` is true. + #[serde(skip_serializing_if = "Option::is_none")] + pub settings: Option, +} + +/// One hook to disable or re-enable. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsSetHookDisabledRequest { + /// True adds the key to `disabledHooks`, false removes it. + pub disabled: bool, + /// Durable content-hash key of the hook, as `hooks.loadResources` reports it. + pub disable_key: String, + /// Path of the settings.json to rewrite. + pub settings_path: String, +} + +/// Outcome of rewriting the `disabledHooks` setting. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsSetHookDisabledResult { + /// Why the write failed. Absent when the status is `ok`. + #[serde(skip_serializing_if = "Option::is_none")] + pub error_message: Option, + /// `ok` when the setting was written, `invalid` when settings.json could not be parsed and was left alone, `error` when the write itself failed. + pub status: String, +} + /// Partial user settings to write to settings.json. Each top-level key is written individually, replacing the existing value; a key whose value is null is removed. /// ///
@@ -29931,6 +31506,37 @@ pub struct UserSettingsSetRequest { pub settings: serde_json::Value, } +/// Selects the configuration directory whose user settings document should be inspected for unrecognized top-level keys. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsUnknownKeysWarningRequest { + /// The configuration directory, home directory and environment to resolve the settings document from. A host that scopes a session to its own Copilot home must pass that directory here, or the server's own home is inspected instead. + pub context: UserSettingsHostContext, +} + +/// The unrecognized top-level keys found in the user settings document, already phrased for display. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsUnknownKeysWarningResult { + /// The warning to show the user, naming the unrecognized keys and the file they were found in. Absent when every top-level key is recognized, and also when the document is missing or could not be read, because an unknown-key list taken from a document the runtime could not load would name keys that may not be there. + #[serde(skip_serializing_if = "Option::is_none")] + pub warning: Option, +} + /// Names the user setting to merge into, and the partial object to merge. /// ///
@@ -31697,7 +33303,7 @@ pub struct WorkspacesWriteAutopilotObjectiveResult { pub operation: String, } -/// The resident session the application has materialized on its own connection. +/// Status of the persistent certificate authority of the sandbox credential proxy. /// ///
/// @@ -31707,12 +33313,17 @@ pub struct WorkspacesWriteAutopilotObjectiveResult { ///
#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct HostCreateSessionResult { - /// Runtime session UUID materialized on the application's SDK connection. - pub session_id: SessionId, +pub struct SandboxProxyCaGetStatusResult { + /// Whether this process can add the certificate authority to OS trust without credentials from a different user. False where OS trust is unsupported, and on Windows when the process cannot elevate itself to write the machine trust store. When false, do not offer to set up the certificate authority. + pub can_install: bool, + /// Human-readable reason for the state. On `installed` or `notInstalled`, present only when the certificate authority must be rotated, and then says why. + #[serde(skip_serializing_if = "Option::is_none")] + pub detail: Option, + /// The state of the certificate authority. + pub state: SandboxProxyCaState, } -/// Empty acknowledgement for a completed host lifecycle operation. +/// Status of the persistent certificate authority of the sandbox credential proxy. /// ///
/// @@ -31722,9 +33333,17 @@ pub struct HostCreateSessionResult { ///
#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct HostReleaseSessionResult {} +pub struct SandboxProxyCaRotateResult { + /// Whether this process can add the certificate authority to OS trust without credentials from a different user. False where OS trust is unsupported, and on Windows when the process cannot elevate itself to write the machine trust store. When false, do not offer to set up the certificate authority. + pub can_install: bool, + /// Human-readable reason for the state. On `installed` or `notInstalled`, present only when the certificate authority must be rotated, and then says why. + #[serde(skip_serializing_if = "Option::is_none")] + pub detail: Option, + /// The state of the certificate authority. + pub state: SandboxProxyCaState, +} -/// Empty acknowledgement for a completed host lifecycle operation. +/// Status of the persistent certificate authority of the sandbox credential proxy. /// ///
/// @@ -31734,9 +33353,17 @@ pub struct HostReleaseSessionResult {} ///
#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct HostDisposeResult {} +pub struct SandboxProxyCaTrustResult { + /// Whether this process can add the certificate authority to OS trust without credentials from a different user. False where OS trust is unsupported, and on Windows when the process cannot elevate itself to write the machine trust store. When false, do not offer to set up the certificate authority. + pub can_install: bool, + /// Human-readable reason for the state. On `installed` or `notInstalled`, present only when the certificate authority must be rotated, and then says why. + #[serde(skip_serializing_if = "Option::is_none")] + pub detail: Option, + /// The state of the certificate authority. + pub state: SandboxProxyCaState, +} -/// Private credentials delivered only to a runtime-owned Mission Control hosting participant. +/// Status of the persistent certificate authority of the sandbox credential proxy. /// ///
/// @@ -31746,18 +33373,17 @@ pub struct HostDisposeResult {} ///
#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct HostGetEnvironmentCredentialsResult { - /// GitHub API base URL for the authenticated service. - pub github_api_url: String, - /// Hostname of the authenticated GitHub service. - pub github_host: String, - /// Mission Control API origin for environment registration and management. - pub mission_control_url: String, - /// Current bearer token for the authenticated GitHub identity. - pub token: String, +pub struct SandboxProxyCaRemoveResult { + /// Whether this process can add the certificate authority to OS trust without credentials from a different user. False where OS trust is unsupported, and on Windows when the process cannot elevate itself to write the machine trust store. When false, do not offer to set up the certificate authority. + pub can_install: bool, + /// Human-readable reason for the state. On `installed` or `notInstalled`, present only when the certificate authority must be rotated, and then says why. + #[serde(skip_serializing_if = "Option::is_none")] + pub detail: Option, + /// The state of the certificate authority. + pub state: SandboxProxyCaState, } -/// Normalized listener settings delivered only to the supervised hosting participant. +/// Where this runtime keeps the sandbox proxy password. /// ///
/// @@ -31767,20 +33393,14 @@ pub struct HostGetEnvironmentCredentialsResult { ///
#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct HostGetConfigurationResult { - /// Requested GitHub Mission Control registration. - #[serde(skip_serializing_if = "Option::is_none")] - pub github_environment: Option, - /// Normalized local listener settings, absent for relay-only hosts. - #[serde(skip_serializing_if = "Option::is_none")] - pub local_server: Option, - /// Whether app-owned durable sessions are resumed by the owning application. - pub resume_factory: bool, - /// Whether session materialization is delegated to the owning application. - pub session_factory: bool, +pub struct SandboxProxySecretGetLocationResult { + /// Absolute path of the credential store holding the sandbox proxy password. The proxy password belongs to no MCP server, so it is kept in its own directory rather than in the MCP secret store. + pub config_dir: String, + /// Identifier of the proxy password entry within that store. Derived from the configuration directory, so two Copilot homes on one machine never share an entry. Use it to recognize a `${secret:…}` reference in stored settings as this runtime's own proxy password. + pub secret_id: String, } -/// Empty acknowledgement for a completed host lifecycle operation. +/// The sandbox a named feature actually launches under. /// ///
/// @@ -31790,9 +33410,12 @@ pub struct HostGetConfigurationResult { ///
#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct HostReadyResult {} +pub(crate) struct SandboxResolveForOptionalResult { + /// The effective sandbox config for the requested feature, or a disabled sandbox when the feature is routed out of it. + pub sandbox_json: serde_json::Value, +} -/// List of Copilot models available to the resolved user, including capabilities and billing metadata. +/// The startup warning, absent when the machine can run a sandbox. /// ///
/// @@ -31802,12 +33425,13 @@ pub struct HostReadyResult {} ///
#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct ModelsListResult { - /// List of available models with full metadata - pub models: Vec, +pub(crate) struct SandboxGetUnsupportedStartupNoticeResult { + /// The user-facing warning, carrying the platform remedy and the recovery the policy in force actually allows. Absent when this machine supports a sandbox, so a host can call unconditionally and print only what it gets. + #[serde(skip_serializing_if = "Option::is_none")] + pub notice: Option, } -/// The running runtime's complete catalog of well-known built-in model IDs, including supported models and additional IDs with built-in metadata. +/// The documentation URL a host cites when it declines or downgrades a sandbox setting. /// ///
/// @@ -31817,9 +33441,9 @@ pub struct ModelsListResult { ///
#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct ModelsGetBuiltInCatalogResult { - /// Built-in model entries. - pub models: Vec, +pub struct SandboxGetDocsUrlResult { + /// Documentation URL describing the sandbox and the settings that control it. + pub url: String, } /// Whether the host running this runtime can run the command sandbox. The runtime checks `supported` once per process. A capability answer can change while the process runs, for example after the user installs a missing package. @@ -31842,7 +33466,7 @@ pub struct SandboxGetHostSupportResult { pub supported: bool, } -/// Status of the persistent certificate authority of the sandbox credential proxy. +/// The on-disk location of the user's settings document. /// ///
/// @@ -31852,17 +33476,28 @@ pub struct SandboxGetHostSupportResult { ///
#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct SandboxProxyCaGetStatusResult { - /// Whether this process can add the certificate authority to OS trust without credentials from a different user. False where OS trust is unsupported, and on Windows when the process cannot elevate itself to write the machine trust store. When false, do not offer to set up the certificate authority. - pub can_install: bool, - /// Human-readable reason for the state. On `installed` or `notInstalled`, present only when the certificate authority must be rotated, and then says why. +pub struct UserSettingsGetPathResult { + /// Absolute path to the settings file this runtime reads and writes. Normally `settings.json` under the Copilot configuration directory; an extensionless legacy `settings` file is reported instead when it exists and `settings.json` does not. + pub path: String, +} + +/// The unrecognized top-level keys found in the user settings document, already phrased for display. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsGetUnknownKeysWarningResult { + /// The warning to show the user, naming the unrecognized keys and the file they were found in. Absent when every top-level key is recognized, and also when the document is missing or could not be read, because an unknown-key list taken from a document the runtime could not load would name keys that may not be there. #[serde(skip_serializing_if = "Option::is_none")] - pub detail: Option, - /// The state of the certificate authority. - pub state: SandboxProxyCaState, + pub warning: Option, } -/// Status of the persistent certificate authority of the sandbox credential proxy. +/// Top-level user-setting keys grouped by who may govern them. /// ///
/// @@ -31872,17 +33507,48 @@ pub struct SandboxProxyCaGetStatusResult { ///
#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct SandboxProxyCaRotateResult { - /// Whether this process can add the certificate authority to OS trust without credentials from a different user. False where OS trust is unsupported, and on Windows when the process cannot elevate itself to write the machine trust store. When false, do not offer to set up the certificate authority. - pub can_install: bool, - /// Human-readable reason for the state. On `installed` or `notInstalled`, present only when the certificate authority must be rotated, and then says why. +pub struct UserSettingsListGovernanceKeysResult { + /// Top-level keys a repository may override through a Claude-compatible repository config. + pub claude_repo: Vec, + /// Top-level keys an enterprise policy may fix through managed settings. + pub managed: Vec, + /// Top-level keys a repository may override through `.github/copilot/settings.json` or `.github/copilot/settings.local.json`. + pub repo: Vec, +} + +/// Outcome of an atomic user or repository settings edit. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct UserSettingsEditResult { + /// Changed, unchanged or invalid existing file. Rejected input, validation failures and I/O errors remain RPC errors. + #[doc(hidden)] + pub(crate) status: SettingsEditStatus, +} + +/// The settings that will not take effect across the given layers. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserSettingsDiagnoseProblemsResult { + /// Each setting that will not take effect, and why. Empty when every layer is healthy. #[serde(skip_serializing_if = "Option::is_none")] - pub detail: Option, - /// The state of the certificate authority. - pub state: SandboxProxyCaState, + pub problems: Option>, } -/// Status of the persistent certificate authority of the sandbox credential proxy. +/// Outcome of an atomic user or repository settings edit. /// ///
/// @@ -31892,17 +33558,89 @@ pub struct SandboxProxyCaRotateResult { ///
#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct SandboxProxyCaTrustResult { - /// Whether this process can add the certificate authority to OS trust without credentials from a different user. False where OS trust is unsupported, and on Windows when the process cannot elevate itself to write the machine trust store. When false, do not offer to set up the certificate authority. - pub can_install: bool, - /// Human-readable reason for the state. On `installed` or `notInstalled`, present only when the certificate authority must be rotated, and then says why. +pub(crate) struct RepoSettingsEditResult { + /// Changed, unchanged or invalid existing file. Rejected input, validation failures and I/O errors remain RPC errors. + #[doc(hidden)] + pub(crate) status: SettingsEditStatus, +} + +/// Every feature flag this runtime declares, with the shape each one was declared with. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct FeatureFlagsListMetadataResult { + /// Declared feature flags keyed by flag name. + #[doc(hidden)] + pub(crate) flags: HashMap, +} + +/// Which stored location permissions were dropped because their directory is gone. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct PermissionsLocationsCleanupOrphanedResult { + /// Location keys whose grants were removed. Empty when every stored location still exists. + pub removed_location_keys: Vec, +} + +/// Folder trust check result. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PermissionsFolderTrustCheckTrustResult { + /// Whether the folder is trusted + pub trusted: bool, +} + +/// The verdict of the `forceLoginOrgs` enterprise sign-in pin for one credential. A managed device may pin Copilot to an approved set of GitHub organizations so a developer cannot sign in with a personal — or another enterprise's — account and escape every control that keys off the signed-in identity. A host must refuse to proceed when `allowed` is false; the remaining fields explain the refusal rather than qualifying it. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ManagedSettingsResolveDeviceForceLoginOrgsGateResult { + /// Whether the client may proceed. True whenever no pin is in force, so an unmanaged host is never blocked. + pub allowed: bool, + /// A stable kebab-case reason code when refused: `org-not-approved`, `unverifiable-credential`, `policy-undetermined`, `policy-invalid`, `not-signed-in`, or `membership-unknown`. Omitted when allowed. Treat an unrecognized code as a refusal rather than mapping it to an allow: a code this host has not been taught about still denied the credential. #[serde(skip_serializing_if = "Option::is_none")] - pub detail: Option, - /// The state of the certificate authority. - pub state: SandboxProxyCaState, + pub denial: Option, + /// Whether a pin applies at all. Distinguishes "allowed because unmanaged" from "allowed because the account is approved", which a diagnostics surface needs and which also decides whether a bring-your-own-key provider may serve inference. + pub enforced: bool, + /// The approved organization the account matched, when allowed under a pin. + #[serde(skip_serializing_if = "Option::is_none")] + pub matched_org: Option, + /// A developer-facing explanation of the refusal. Omitted when allowed. + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, + /// Error-level detail from managed-policy discovery — which file failed to load, which field failed validation. Carried on the decision rather than left to the log because a refusal can exit the process before a log sink exists, which would discard the only actionable diagnostic a misconfigured managed device produces. + pub policy_diagnostics: Vec, + /// The approved organization logins, as configured. Enterprise configuration rather than user data, so it is safe to name in a message or a log line. + pub required_orgs: Vec, } -/// Status of the persistent certificate authority of the sandbox credential proxy. +/// Ordered managed permission verdicts and the supplied policy's fail-closed posture. /// ///
/// @@ -31912,14 +33650,136 @@ pub struct SandboxProxyCaTrustResult { ///
#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct SandboxProxyCaRemoveResult { - /// Whether this process can add the certificate authority to OS trust without credentials from a different user. False where OS trust is unsupported, and on Windows when the process cannot elevate itself to write the machine trust store. When false, do not offer to set up the certificate authority. - pub can_install: bool, - /// Human-readable reason for the state. On `installed` or `notInstalled`, present only when the certificate authority must be rotated, and then says why. +pub struct ManagedSettingsPermissionsEvaluateResult { + /// Managed permission policy could not be determined; every operation is denied. + pub fail_closed: bool, + /// One verdict per input operation, in the same order, including duplicates. + pub results: Vec, +} + +/// The resident session the application has materialized on its own connection. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct HostCreateSessionResult { + /// Runtime session UUID materialized on the application's SDK connection. + pub session_id: SessionId, +} + +/// Empty acknowledgement for a completed host lifecycle operation. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct HostReleaseSessionResult {} + +/// Empty acknowledgement for a completed host lifecycle operation. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct HostDisposeResult {} + +/// Private credentials delivered only to a runtime-owned Mission Control hosting participant. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct HostGetEnvironmentCredentialsResult { + /// GitHub API base URL for the authenticated service. + pub github_api_url: String, + /// Hostname of the authenticated GitHub service. + pub github_host: String, + /// Mission Control API origin for environment registration and management. + pub mission_control_url: String, + /// Current bearer token for the authenticated GitHub identity. + pub token: String, +} + +/// Normalized listener settings delivered only to the supervised hosting participant. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct HostGetConfigurationResult { + /// Requested GitHub Mission Control registration. #[serde(skip_serializing_if = "Option::is_none")] - pub detail: Option, - /// The state of the certificate authority. - pub state: SandboxProxyCaState, + pub github_environment: Option, + /// Normalized local listener settings, absent for relay-only hosts. + #[serde(skip_serializing_if = "Option::is_none")] + pub local_server: Option, + /// Whether app-owned durable sessions are resumed by the owning application. + pub resume_factory: bool, + /// Whether session materialization is delegated to the owning application. + pub session_factory: bool, +} + +/// Empty acknowledgement for a completed host lifecycle operation. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct HostReadyResult {} + +/// List of Copilot models available to the resolved user, including capabilities and billing metadata. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ModelsListResult { + /// List of available models with full metadata + pub models: Vec, +} + +/// The running runtime's complete catalog of well-known built-in model IDs, including supported models and additional IDs with built-in metadata. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ModelsGetBuiltInCatalogResult { + /// Built-in model entries. + pub models: Vec, } /// Built-in tools available for the requested model, with their parameters and instructions. @@ -32349,73 +34209,6 @@ pub struct CommandsListResult { pub commands: Vec, } -/// Top-level user-setting keys grouped by who may govern them. -/// -///
-/// -/// **Experimental.** This type is part of an experimental wire-protocol surface -/// and may change or be removed in future SDK or CLI releases. -/// -///
-#[derive(Debug, Clone, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct UserSettingsListGovernanceKeysResult { - /// Top-level keys a repository may override through a Claude-compatible repository config. - pub claude_repo: Vec, - /// Top-level keys an enterprise policy may fix through managed settings. - pub managed: Vec, - /// Top-level keys a repository may override through `.github/copilot/settings.json` or `.github/copilot/settings.local.json`. - pub repo: Vec, -} - -/// Outcome of an atomic user or repository settings edit. -/// -///
-/// -/// **Experimental.** This type is part of an experimental wire-protocol surface -/// and may change or be removed in future SDK or CLI releases. -/// -///
-#[derive(Debug, Clone, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub(crate) struct UserSettingsEditResult { - /// Changed, unchanged or invalid existing file. Rejected input, validation failures and I/O errors remain RPC errors. - #[doc(hidden)] - pub(crate) status: SettingsEditStatus, -} - -/// The settings that will not take effect across the given layers. -/// -///
-/// -/// **Experimental.** This type is part of an experimental wire-protocol surface -/// and may change or be removed in future SDK or CLI releases. -/// -///
-#[derive(Debug, Clone, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct UserSettingsDiagnoseProblemsResult { - /// Each setting that will not take effect, and why. Empty when every layer is healthy. - #[serde(skip_serializing_if = "Option::is_none")] - pub problems: Option>, -} - -/// Every feature flag this runtime declares, with the shape each one was declared with. -/// -///
-/// -/// **Experimental.** This type is part of an experimental wire-protocol surface -/// and may change or be removed in future SDK or CLI releases. -/// -///
-#[derive(Debug, Clone, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub(crate) struct FeatureFlagsListMetadataResult { - /// Declared feature flags keyed by flag name. - #[doc(hidden)] - pub(crate) flags: HashMap, -} - /// A freshly registered request id. Registering it before the listing starts is what lets a cancel that races the request still find the owner listing slot. The id serves one listing only. Long-abandoned unused ids can be released by later allocations. /// ///
@@ -32467,23 +34260,6 @@ pub struct GitWorkingDirectoryContextResult { pub repository_host: Option, } -/// Ordered managed permission verdicts and the supplied policy's fail-closed posture. -/// -///
-/// -/// **Experimental.** This type is part of an experimental wire-protocol surface -/// and may change or be removed in future SDK or CLI releases. -/// -///
-#[derive(Debug, Clone, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct ManagedSettingsPermissionsEvaluateResult { - /// Managed permission policy could not be determined; every operation is denied. - pub fail_closed: bool, - /// One verdict per input operation, in the same order, including duplicates. - pub results: Vec, -} - /// Result of opening a session. /// ///
@@ -39635,7 +41411,7 @@ pub type SessionsGetClientMetadataResult = Vec; ///
pub type UIElicitationResponseContent = HashMap; -/// List of all authenticated users +/// True when this process can offer installing the sandbox credential-proxy certificate authority into OS trust. /// ///
/// @@ -39643,7 +41419,107 @@ pub type UIElicitationResponseContent = HashMap; /// and may change or be removed in future SDK or CLI releases. /// ///
-pub type AccountGetAllUsersResult = Vec; +pub type SandboxProxyCaCheckInstallationSupportResult = bool; + +/// True when the sandbox configuration uses the credential proxy and can need certificate-authority setup. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+pub type SandboxProxyCaCheckRelevanceResult = bool; + +/// The effective sandbox settings, with every unset value resolved to its default. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+pub type SandboxSettingsApplyDefaultsResult = HashMap; + +/// True when an OS-level sandbox can run on this host. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+pub type SandboxCheckPlatformSupportResult = bool; + +/// True when the sandbox on this host can reach host loopback directly. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+pub type SandboxCheckWindowsHostLoopbackSupportResult = bool; + +/// The user-facing refusal, including the platform remedy and the documentation link. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+pub type SandboxGetUnsupportedMessageResult = String; + +/// The user-facing notice that a saved sandbox setting is inert for this session. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+pub type SandboxGetUnsupportedSettingDisabledNoticeResult = String; + +/// True when the command stays available while enforcement is blocked. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+pub type SandboxCheckEnforcementCommandResult = bool; + +/// The stored user settings document, keyed by setting name. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+pub type UserSettingsLoadForConfigDirResult = HashMap; + +/// The effective runtime settings, keyed by setting name. Keys this runtime does not recognize are preserved rather than dropped, so a caller reading a document written by a newer runtime keeps every value. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+pub type UserSettingsBuildRuntimeResult = HashMap; + +/// The resolved gates, keyed by flag name. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+pub type FeatureFlagsResolveStartupGatesResult = HashMap; /// The resolved feature flags, keyed by flag name. /// @@ -39655,6 +41531,16 @@ pub type AccountGetAllUsersResult = Vec; ///
pub type FeatureFlagsResolveResult = HashMap; +/// List of all authenticated users +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+pub type AccountGetAllUsersResult = Vec; + /// The number of running background agents (task-registry agents) that were cancelled. /// ///
@@ -44355,6 +46241,56 @@ pub enum ManagedPluginRetryStatus { Unknown, } +/// Which layer disabled bypass-permissions mode. The layer matters because only a server-delivered disable is pinned to an account and can later be lifted by signing in elsewhere. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum ManagedSettingsBypassDisableSource { + /// The user turned bypass mode off themselves. + #[serde(rename = "user")] + User, + /// The account's server-delivered org policy disabled it. Pinned to the account named by `currentManagedIdentity`. + #[serde(rename = "managed")] + Managed, + /// The device/MDM layer disabled it. Outranks the account, so no server answer lifts it. + #[serde(rename = "mdm")] + Mdm, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + +/// What the managed-policy resolution said about bypass-permissions mode. `unknown` is a third answer rather than a missing one, and the caller must send it explicitly when it has no verdict. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum ManagedSettingsBypassPolicyResolution { + /// The policy resolved and does not disable bypass mode. + #[serde(rename = "allowed")] + Allowed, + /// The policy resolved and disables bypass mode. + #[serde(rename = "disabled")] + Disabled, + /// No verdict: the fetch failed, or the service declared a policy this build may not enforce. Whatever is in force is preserved, because reverting to permissive on an unreadable policy would widen access. + #[serde(rename = "unknown")] + UnknownValue, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + /// A channel accepted by managedSettings.compose. /// ///
@@ -44402,6 +46338,143 @@ pub enum ManagedSettingsDiagnosticSeverity { Unknown, } +/// The operation that requires a policy-helper response. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum ManagedSettingsPolicyHelperReason { + /// Resolve policy for session startup. + #[serde(rename = "sessionStart")] + SessionStart, + /// Resolve policy before plugin activation. + #[serde(rename = "pluginActivation")] + PluginActivation, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + +/// How an ingestion may use the on-disk server-policy cache. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum ManagedSettingsServerPolicyCacheMode { + /// Serve a recent cache entry before a live fetch. + #[serde(rename = "preferFresh")] + PreferFresh, + /// Read cached policy without a network request. + #[serde(rename = "cacheOnly")] + CacheOnly, + /// Serve a cached entry only as a fallback after a failed live fetch. + #[serde(rename = "fallbackOnly")] + FallbackOnly, + /// Ignore the cache entirely and rely on the live fetch alone. + #[serde(rename = "disabled")] + Disabled, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + +/// Severity of a diagnostic emitted while ingesting managed settings. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum ManagedSettingsLogLevel { + /// Detail useful only when diagnosing an ingestion. + #[serde(rename = "debug")] + Debug, + /// Ordinary progress worth surfacing under a verbose flag. + #[serde(rename = "info")] + Info, + /// A condition the operator should see but which did not stop the ingestion. + #[serde(rename = "warning")] + Warning, + /// A failure that changed the outcome of the ingestion. + #[serde(rename = "error")] + Error, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + +/// Which channel registered the policy helper that produced a helper layer. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum ManagedSettingsPolicyHelperAuthority { + /// The helper was registered by the device (MDM or managed file) layer. + #[serde(rename = "device")] + Device, + /// The helper was registered by the account's server-delivered policy. + #[serde(rename = "server")] + Server, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + +/// How the server layer of an ingestion was resolved. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum ManagedSettingsServerPolicyResolution { + /// A live fetch succeeded. + #[serde(rename = "live")] + Live, + /// A recent cached entry was served without a live fetch. + #[serde(rename = "freshCache")] + FreshCache, + /// No cached policy or confirmed no-policy result exists. + #[serde(rename = "cacheMiss")] + CacheMiss, + /// A live fetch failed and a cached entry was served in its place. + #[serde(rename = "fallbackCache")] + FallbackCache, + /// No policy could be resolved and the host proceeds unmanaged. + #[serde(rename = "failOpen")] + FailOpen, + /// No policy could be resolved and the host applies the fail-closed gates. + #[serde(rename = "failClosed")] + FailClosed, + /// No fetch was attempted because no usable token was available. + #[serde(rename = "skippedNoToken")] + SkippedNoToken, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + /// Allowed values for the `McpAppsHostContextDetailsAvailableDisplayMode` enumeration. /// ///
@@ -47200,6 +49273,56 @@ pub enum RemoteSessionMetadataTaskType { Unknown, } +/// One atomic settings mutation. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum SettingsEditOperation { + /// Set one scalar value. + #[serde(rename = "set")] + Set, + /// Add one string to a list, unless present. + #[serde(rename = "add-item")] + AddItem, + /// Remove one string from a list, unless absent. + #[serde(rename = "remove-item")] + RemoveItem, + /// Remove the setting without supplying a value. + #[serde(rename = "remove")] + Remove, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + +/// Which repository settings file to edit. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum RepoSettingsEditScope { + /// The shared repository settings file. + #[serde(rename = "repo")] + Repo, + /// The local repository settings file. + #[serde(rename = "local")] + Local, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + /// Output format discriminator. Currently only json_schema is supported. #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] pub enum ResponseFormatType { @@ -48135,34 +50258,6 @@ pub enum SessionVisibilityStatus { Unknown, } -/// One atomic settings mutation. -/// -///
-/// -/// **Experimental.** This type is part of an experimental wire-protocol surface -/// and may change or be removed in future SDK or CLI releases. -/// -///
-#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] -pub enum SettingsEditOperation { - /// Set one scalar value. - #[serde(rename = "set")] - Set, - /// Add one string to a list, unless present. - #[serde(rename = "add-item")] - AddItem, - /// Remove one string from a list, unless absent. - #[serde(rename = "remove-item")] - RemoveItem, - /// Remove the setting without supplying a value. - #[serde(rename = "remove")] - Remove, - /// Unknown variant for forward compatibility. - #[default] - #[serde(other)] - Unknown, -} - /// Whether one atomic settings edit changed a file. /// ///
@@ -48716,6 +50811,62 @@ pub enum SlashCommandInvocationResult { SetPlanModel(SlashCommandSetPlanModelResult), } +/// What the one-time staff log-level migration did. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum StaffLogLevelMigrationStatus { + /// The account is not a staff account, so the migration does not apply and nothing was recorded. + #[serde(rename = "ineligible")] + Ineligible, + /// The migration already ran; the stored completion timestamp is returned unchanged. + #[serde(rename = "current")] + Current, + /// The migration ran now. The persisted settings may have changed, so the host should adopt the returned settings when they are present. + #[serde(rename = "refreshed")] + Refreshed, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + +/// What the one-time staff update-channel migration did. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum StaffUpdateChannelMigrationStatus { + /// The account is not a staff account, so the migration does not apply and nothing was recorded. + #[serde(rename = "ineligible")] + Ineligible, + /// The migration already ran within the cutoff window; the stored completion timestamp is returned unchanged. + #[serde(rename = "current")] + Current, + /// The persisted update channel was changed to stable. Only this outcome requires the host to reload its configuration. + #[serde(rename = "migrated")] + Migrated, + /// The persisted channel was already stable, so nothing changed, but the migration is now recorded as done. + #[serde(rename = "completed")] + Completed, + /// The account is on the experimental channel, which the migration deliberately leaves alone, and the migration is recorded as done. + #[serde(rename = "excluded-experimental")] + ExcludedExperimental, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + /// Context tier override for matching subagents /// ///
@@ -49299,6 +51450,34 @@ pub enum UISessionLimitsExhaustedResponseAction { Unknown, } +/// What the one-time obsolete-settings cleanup did to the document. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum UserSettingsMigrateObsoleteOnDiskStatus { + /// No settings document exists, so there was nothing to clean. + #[serde(rename = "missing")] + Missing, + /// The document could not be parsed, so it was left untouched rather than rewritten from a partial read. + #[serde(rename = "invalid")] + Invalid, + /// The document parsed and held nothing obsolete, so nothing was written. + #[serde(rename = "unchanged")] + Unchanged, + /// Obsolete keys were removed and the document was rewritten. + #[serde(rename = "changed")] + Changed, + /// Unknown variant for forward compatibility. + #[default] + #[serde(other)] + Unknown, +} + /// Execution-critical workflow storage operation. /// ///
diff --git a/rust/src/generated/rpc.rs b/rust/src/generated/rpc.rs index fccafc3749..e085bf03ae 100644 --- a/rust/src/generated/rpc.rs +++ b/rust/src/generated/rpc.rs @@ -162,6 +162,20 @@ impl<'a> ClientRpc<'a> { } } + /// `permissions.*` sub-namespace. + pub fn permissions(&self) -> ClientRpcPermissions<'a> { + ClientRpcPermissions { + client: self.client, + } + } + + /// `persistence.*` sub-namespace. + pub fn persistence(&self) -> ClientRpcPersistence<'a> { + ClientRpcPersistence { + client: self.client, + } + } + /// `plugins.*` sub-namespace. pub fn plugins(&self) -> ClientRpcPlugins<'a> { ClientRpcPlugins { @@ -1360,6 +1374,40 @@ pub struct ClientRpcFeatureFlags<'a> { } impl<'a> ClientRpcFeatureFlags<'a> { + /// Resolves named gates against this installation's cached online-experiment assignment, for the account the runtime is already authenticated as. Unlike `featureFlags.resolve`, which layers static availability with the populations supplied, this reads the experiment assignment the runtime cached for its own current authentication, so a launch can honor a rollout before any session exists. The account is never taken from the request: naming one would read another account's cached assignments. The cached assignment answers immediately and any network refresh happens behind it, so this call does not wait on the network. Not available to an extension, which cannot carry the user's consent to read their assignment. + /// + /// Wire method: `featureFlags.resolveStartupGates`. + /// + /// # Parameters + /// + /// * `params` - Caller population and startup inputs to resolve named online-experiment gates for. Carries no account: the runtime resolves the assignment for the authentication it already holds. + /// + /// # Returns + /// + /// The resolved gates, keyed by flag name. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn resolve_startup_gates( + &self, + params: FeatureFlagsResolveStartupGatesRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call( + rpc_methods::FEATUREFLAGS_RESOLVESTARTUPGATES, + Some(wire_params), + ) + .await?; + Ok(serde_json::from_value(_value)?) + } + /// Lists every feature flag this runtime declares, with the population each one is declared for, its experimental description, and the online-experiment flag it maps to. This is the static catalog: it describes how each flag is defined, not whether it is on for anyone. Use `featureFlags.resolve` for static values with caller overrides, not active runtime values or experiment assignments. /// /// Wire method: `featureFlags.listMetadata`. @@ -2445,13 +2493,13 @@ impl<'a> ClientRpcManagedSettings<'a> { } } - /// Discovers device-managed settings from production MDM and managed-file sources, validates them against the runtime-owned managed-settings schema, and returns the canonical JSON without requiring a session. `managedSettings.resolve` returns the same device settings together with the account's server policy. + /// Discovers device-managed settings the way the runtime's own device layer does, and reports the sandbox floor and the load outcome alongside the validated document. This differs from `managedSettings.read` in three ways a policy-enforcing host depends on: a document that validates to an empty object is reported as absent rather than as an empty policy, a discovery error does not suppress a document that still validates, and a failure is reported as a flag rather than only as error text. Hosts that compose the device layer into an effective policy use this, because `managedSettings.read` cannot distinguish "no device policy" from "device policy could not be read" and would silently hand the user's own layer the win. /// - /// Wire method: `managedSettings.read`. + /// Wire method: `managedSettings.readDevice`. /// /// # Returns /// - /// Validated device-managed settings discovered before a session exists. + /// The device-managed settings layer, with the sandbox floor and the load outcome a host needs to compose it into an effective policy. /// ///
/// @@ -2460,18 +2508,22 @@ impl<'a> ClientRpcManagedSettings<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn read(&self) -> Result { + pub(crate) async fn read_device(&self) -> Result { let wire_params = serde_json::json!({}); let _value = self .client - .call(rpc_methods::MANAGEDSETTINGS_READ, Some(wire_params)) + .call(rpc_methods::MANAGEDSETTINGS_READDEVICE, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Force-refreshes enterprise managed settings for every account: wipes the persistent server-policy cache (the whole `/managed-settings` directory) and drops this runtime process's in-memory retained server policy. It does not itself fetch policy — the effect is that the next time a session resolves managed settings for an account, that resolution re-fetches the account's org policy from the network instead of serving a cached response. Note that `managedSettings.read` returns only device/MDM settings and never triggers the account server-policy fetch, so a host implementing "sync account policy" should call `managedSettings.resolve` or start a fresh session resolution rather than treat a subsequent `managedSettings.read` as the refreshed org policy. Mirrors the invalidation a sign-out performs, broadened from the one signing-out account to all of them; device/MDM layers describe the machine, not the account, and are left untouched. Rejects if the on-disk cache cannot be removed. + /// Retains the supplied managed layers as this runtime process's startup policy and re-applies the result to every live session. Hosts that own their own short-lived process policy use this, so a guarded mutation is checked against the policy the host actually fetched. Retaining is a whole-process replacement rather than a merge, so a host that already resolved a good policy must not retain a partial one over it. The failure flags are honest inputs rather than assumptions: reporting a fetch or load that failed keeps the layers already retained, and the interim fail-closed state, instead of clearing them. /// - /// Wire method: `managedSettings.clearCache`. + /// Wire method: `managedSettings.retainPolicy`. + /// + /// # Parameters + /// + /// * `params` - The managed layers to retain as this process's startup policy, with the outcome of fetching each one. /// ///
/// @@ -2480,22 +2532,29 @@ impl<'a> ClientRpcManagedSettings<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn clear_cache(&self) -> Result<(), Error> { - let wire_params = serde_json::json!({}); + pub(crate) async fn retain_policy( + &self, + params: ManagedSettingsRetainPolicyParams, + ) -> Result<(), Error> { + let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MANAGEDSETTINGS_CLEARCACHE, Some(wire_params)) + .call(rpc_methods::MANAGEDSETTINGS_RETAINPOLICY, Some(wire_params)) .await?; Ok(()) } - /// Resolves the effective enterprise managed settings without a session, from the device channel and, when an account is available, the account's server policy through the same per-account cache sessions use. A cached server policy less than an hour old is used without a fetch; otherwise the policy is fetched, and when the fetch fails a cached policy up to 24 hours old is used instead, unless `forceRemoteSettingsRefresh` requires a live fetch. With no account requested or signed in, it reports device policy only; signing out removes the account's cached policy. It can fetch server policy over the network when the cache is stale, so call it off latency-critical paths such as startup rather than before listing models. The policy helper is not run. `layers` lists each channel's document before merging, and `values` and `meta` carry typed effective values and their lock state for the keys typed so far. + /// Stamps an effective managed policy's individually-controlled entries onto a user settings document, returning the settings a host should actually act on. The managed layer wins on every plugin spec and marketplace name it names, and leaves everything it does not name as the user wrote it. Hosts use this rather than merging the two documents themselves, because the merge is per entry rather than per document and a whole-document overlay would either discard the user's unmanaged entries or let a user entry outrank a managed one. Omitting the managed layer returns the settings unchanged, which is what an unmanaged host wants. Rejects when either document is present but is not a JSON object rather than treating it as absent, since silently dropping a malformed policy hands the user's layer the win on exactly the entries the policy exists to control. /// - /// Wire method: `managedSettings.resolve`. + /// Wire method: `managedSettings.applyControls`. + /// + /// # Parameters + /// + /// * `params` - A user settings document and the effective managed policy whose controlled entries should be stamped onto it. /// /// # Returns /// - /// Effective enterprise managed settings for an account, resolved without a session. + /// The user settings with the managed layer's controlled entries stamped on. /// ///
/// @@ -2504,26 +2563,32 @@ impl<'a> ClientRpcManagedSettings<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn resolve(&self) -> Result { - let wire_params = serde_json::json!({}); + pub(crate) async fn apply_controls( + &self, + params: ManagedSettingsApplyControlsParams, + ) -> Result { + let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MANAGEDSETTINGS_RESOLVE, Some(wire_params)) + .call( + rpc_methods::MANAGEDSETTINGS_APPLYCONTROLS, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Resolves the effective enterprise managed settings without a session, from the device channel and, when an account is available, the account's server policy through the same per-account cache sessions use. A cached server policy less than an hour old is used without a fetch; otherwise the policy is fetched, and when the fetch fails a cached policy up to 24 hours old is used instead, unless `forceRemoteSettingsRefresh` requires a live fetch. With no account requested or signed in, it reports device policy only; signing out removes the account's cached policy. It can fetch server policy over the network when the cache is stale, so call it off latency-critical paths such as startup rather than before listing models. The policy helper is not run. `layers` lists each channel's document before merging, and `values` and `meta` carry typed effective values and their lock state for the keys typed so far. + /// Validates the managed settings a client is supplying for a session it is about to open, and returns them reduced to the keys a client is allowed to set. A client-supplied policy is not the same thing as an administrator's: it may only narrow permissions, so this accepts `permissions` and rejects every other key outright rather than ignoring it. Rejecting is the point — a host that silently dropped an unsupported key would report a policy as applied while running without it. Hosts call this before opening the session rather than letting the open fail, so a malformed policy is reported against the request that carried it. The runtime applies the same rule again when the session starts, so this cannot be used to smuggle a wider document past it. An accepted document that sets nothing comes back as an empty object, which is distinct from supplying nothing at all. /// - /// Wire method: `managedSettings.resolve`. + /// Wire method: `managedSettings.parseClientValue`. /// /// # Parameters /// - /// * `params` - Optional opaque account selection or GitHub token whose managed settings are resolved. + /// * `params` - The client-supplied managed settings to validate and normalize. Omitting them is valid and yields no policy. /// /// # Returns /// - /// Effective enterprise managed settings for an account, resolved without a session. + /// The accepted managed settings, reduced to the keys a client is allowed to set. /// ///
/// @@ -2532,25 +2597,32 @@ impl<'a> ClientRpcManagedSettings<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn resolve_with_params( + pub(crate) async fn parse_client_value( &self, - params: ManagedSettingsResolveRequest, - ) -> Result { + params: ManagedSettingsParseClientValueParams, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MANAGEDSETTINGS_RESOLVE, Some(wire_params)) + .call( + rpc_methods::MANAGEDSETTINGS_PARSECLIENTVALUE, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Returns the managed-settings authoring JSON schema with descriptive `x-composition` annotations aligned with the shared settings-engine vocabulary. These annotations are not a complete runtime composition contract: model, effortLevel, and contextTier remain coupled. Use `managedSettings.compose` for the runtime's effective result. Performs no I/O. + /// Composes the supplied server, device/MDM, device sandbox floor and policy-helper layers into the single effective managed policy a host should enforce, resolving each key across the layers by the runtime's own precedence rules. Hosts that assemble managed layers themselves use this so their precedence matches the runtime's exactly instead of reimplementing it. The composition is not a pure function of its inputs: an advisory sandbox force-on that arrived over the server channel is declined when this host cannot run a sandbox, so the result reflects the runtime host's capabilities, and the returned settings carry `sandboxAdvisoryFloorDeclined: true` when that happened. Enforced channels (device/MDM and policy helper) are never declined, and a server force-on carrying `failIfUnavailable` is preserved so the session fails loudly instead of quietly running unsandboxed. Rejects when a supplied layer is present but is not a JSON object, rather than treating it as unmanaged, because silently dropping a malformed policy would hand the user's own layer the win on exactly the keys the policy exists to control. /// - /// Wire method: `managedSettings.schema`. + /// Wire method: `managedSettings.resolveEffectiveValue`. + /// + /// # Parameters + /// + /// * `params` - The managed-settings layers to compose into an effective policy. Every layer is optional; omitting all of them yields no effective policy. /// /// # Returns /// - /// The authoring JSON schema for managed settings recognized by this runtime. + /// The effective managed policy composed from the supplied layers. /// ///
/// @@ -2559,26 +2631,32 @@ impl<'a> ClientRpcManagedSettings<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn schema(&self) -> Result { - let wire_params = serde_json::json!({}); + pub(crate) async fn resolve_effective_value( + &self, + params: ManagedSettingsResolveEffectiveValueParams, + ) -> Result { + let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MANAGEDSETTINGS_SCHEMA, Some(wire_params)) + .call( + rpc_methods::MANAGEDSETTINGS_RESOLVEEFFECTIVEVALUE, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Validates a candidate managed-settings document the way the runtime validates delivered policy, without applying it. Reports errors that would reject the document, warnings for content the runtime ignores, and the canonical document it would apply. Document text nested more than 64 levels deep is rejected. Performs no I/O. + /// Decides what a host must do to its bypass-permissions state after a managed-policy resolution lands, given the state already in force and the account now signed in. A host holds two pieces of state — which layer disabled bypass mode, and for a server-delivered disable, the account it was pinned to — and cannot decide the next step from the new policy alone. Three rules make that so, and each one is a control rather than a preference. A device/MDM disable outranks the account, so a later server answer never lifts it. An unknown policy, which is what a failed fetch or a refusal this build cannot enforce yields, preserves whatever is in force instead of reverting to permissive. And a server disable is lifted only when the account it was pinned to is no longer the signed-in one, which is what makes signing in to an unrestricted account recover without a restart while a reconnect on the same restricted account does not. Hosts call this rather than reimplementing it because getting the pinning backwards either strands a disable on an account that never carried one or drops one that still applies. `setDisabledState` is omitted when the host must leave its stored flag untouched, which is distinct from being told to set it to false. /// - /// Wire method: `managedSettings.validate`. + /// Wire method: `managedSettings.resolveBypassDisableTransition`. /// /// # Parameters /// - /// * `params` - A candidate managed-settings document to validate without applying it. + /// * `params` - The bypass-permissions state a host holds today, the account now signed in, and what the managed-policy resolution said. /// /// # Returns /// - /// Result of validating a managed-settings document. + /// The bypass-permissions state a host should hold after the resolution, and what it must do to get there. /// ///
/// @@ -2587,29 +2665,32 @@ impl<'a> ClientRpcManagedSettings<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn validate( + pub(crate) async fn resolve_bypass_disable_transition( &self, - params: ManagedSettingsValidateRequest, - ) -> Result { + params: ManagedSettingsResolveBypassDisableTransitionParams, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MANAGEDSETTINGS_VALIDATE, Some(wire_params)) + .call( + rpc_methods::MANAGEDSETTINGS_RESOLVEBYPASSDISABLETRANSITION, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Merges candidate managed-settings documents for the device, server, and policy-helper channels into the effective settings the runtime would enforce on this host, using the same precedence and composition rules as live resolution, without applying them. Like live resolution, a server's advisory sandbox force-enable is declined on a host that cannot run the sandbox. Does not fetch policy or read policy files, but may perform blocking OS or subprocess probes for sandbox support. Preview documents are limited to 1 MiB and 64 levels of nesting. + /// Resolves managed (enterprise policy) settings for a host from every layer at once: the account's server-delivered policy, the device/MDM layer, and a platform policy helper. Hosts use this instead of fetching and composing the layers themselves, because the per-layer precedence and the fail-closed rules that apply when a layer cannot be confirmed are the runtime's own and must match the policy a session will later enforce. It does not retain or apply anything to process-global policy state, so a host may call it before any session exists — which is the point, since plugin activation and one-shot commands resolve policy before a session is available to carry it. The returned per-layer outcome flags are load-bearing rather than diagnostic: a host must distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. Reports its diagnostics in `logMessages` rather than logging them, so a host that runs before a log sink exists still sees them. /// - /// Wire method: `managedSettings.compose`. + /// Wire method: `managedSettings.ingest`. /// /// # Parameters /// - /// * `params` - Candidate managed-settings documents to merge without applying them. + /// * `params` - Inputs describing the host and account an ingestion should resolve managed policy for. /// /// # Returns /// - /// The effective managed settings the runtime would enforce for the given documents, in the same shape `managedSettings.resolve` returns. + /// The managed policy layers an ingestion resolved, together with the per-layer outcome flags a host needs to decide how much to trust the result. The flags are reported rather than folded into the settings because a host must be able to distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. /// ///
/// @@ -2618,37 +2699,29 @@ impl<'a> ClientRpcManagedSettings<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn compose( + pub(crate) async fn ingest( &self, - params: ManagedSettingsComposeRequest, - ) -> Result { + params: ManagedSettingsIngestParams, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MANAGEDSETTINGS_COMPOSE, Some(wire_params)) + .call(rpc_methods::MANAGEDSETTINGS_INGEST, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } -} - -/// `managedSettings.permissions.*` RPCs. -#[derive(Clone, Copy)] -pub struct ClientRpcManagedSettingsPermissions<'a> { - pub(crate) client: &'a Client, -} -impl<'a> ClientRpcManagedSettingsPermissions<'a> { - /// Pure, sessionless evaluation of operations against a supplied permissionsContext. Performs no policy discovery, I/O, prompting, navigation, permission grants, or sandbox changes. Obtain the context from managedSettings.resolve or session.managedSettings.get, or reuse an in-memory context. Results preserve input order and duplicates. Consumers must block deny, obtain approval for ask, and use their normal permission flow for unmanaged. Unknown policy returns failClosed with every operation denied. This is not a substitute for user permissions or other security controls. + /// Resolves the managed (enterprise policy) settings a host must enforce from startup, and judges the account against the enterprise sign-in pin in the same pass. This composes the layers the way `managedSettings.ingest` does and then answers the two questions a host cannot answer for itself: which fail-closed floors apply when a layer could not be confirmed, and whether this credential is allowed to sign in at all. The sign-in verdict is the reason a host must not assemble this itself from `managedSettings.ingest` — a pinned organization is an access control, and a host that composed the layers but skipped the pin would let a developer sign in with a personal or another enterprise's account and escape every control that keys off the signed-in identity. The verdict is computed on every resolution, including one that is not retained, so declining to apply policy never widens access. Set `retainAndApply` to keep the resolved policy as this runtime process's startup policy; leave it false to resolve without side effects. /// - /// Wire method: `managedSettings.permissions.evaluate`. + /// Wire method: `managedSettings.resolveStartupPolicy`. /// /// # Parameters /// - /// * `params` - Managed policy context and ordered operations for pure, sessionless evaluation. + /// * `params` - Inputs describing the host and account a startup policy resolution should run for. Mirrors `managedSettings.ingest`, and adds the decision of whether the resolved policy is retained for this runtime process. /// /// # Returns /// - /// Ordered managed permission verdicts and the supplied policy's fail-closed posture. + /// The startup policy a resolution composed, the per-layer outcome flags a host needs to decide how much to trust it, and the enterprise sign-in verdict for the credential it ran against. The flags are reported rather than folded into the settings because a host must distinguish an unmanaged device from a managed device whose policy could not be confirmed, and apply its fail-closed gates in the second case. /// ///
/// @@ -2657,61 +2730,32 @@ impl<'a> ClientRpcManagedSettingsPermissions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn evaluate( + pub(crate) async fn resolve_startup_policy( &self, - params: ManagedPermissionsEvaluateRequest, - ) -> Result { + params: ManagedSettingsResolveStartupPolicyParams, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client .call( - rpc_methods::MANAGEDSETTINGS_PERMISSIONS_EVALUATE, + rpc_methods::MANAGEDSETTINGS_RESOLVESTARTUPPOLICY, Some(wire_params), ) .await?; Ok(serde_json::from_value(_value)?) } -} - -/// `mcp.*` RPCs. -#[derive(Clone, Copy)] -pub struct ClientRpcMcp<'a> { - pub(crate) client: &'a Client, -} - -impl<'a> ClientRpcMcp<'a> { - /// `mcp.config.*` sub-namespace. - pub fn config(&self) -> ClientRpcMcpConfig<'a> { - ClientRpcMcpConfig { - client: self.client, - } - } - - /// `mcp.installations.*` sub-namespace. - pub fn installations(&self) -> ClientRpcMcpInstallations<'a> { - ClientRpcMcpInstallations { - client: self.client, - } - } - - /// `mcp.registry.*` sub-namespace. - pub fn registry(&self) -> ClientRpcMcpRegistry<'a> { - ClientRpcMcpRegistry { - client: self.client, - } - } - /// Discovers MCP servers from user, workspace, plugin, and builtin sources. + /// Resolves the managed `remoteControl` policy for an account on its own, for a host deciding whether a remote-control session may start. Composes the same layers as `managedSettings.ingest` and returns only that one key, so a host does not have to know which layer won. An absent policy means the account is unmanaged for this capability and the host may proceed; that default is safe only while absence really does mean "no policy", so a service refusal that says an account policy exists which this client is too old to enforce resolves to an explicit disabled policy instead of to absence. A resolution that cannot be completed is rejected rather than answered as absence, for the same reason. /// - /// Wire method: `mcp.discover`. + /// Wire method: `managedSettings.loadRemoteControl`. /// /// # Parameters /// - /// * `params` - Optional working directory used as context for MCP server discovery. + /// * `params` - Inputs describing the host and account whose managed remote-control policy should be resolved. Mirrors `managedSettings.ingest`, and deliberately carries no retention decision: reading this gate never becomes this runtime process's startup policy. /// /// # Returns /// - /// MCP servers discovered from user, workspace, plugin, and built-in sources. + /// The managed remote-control policy in force for an account, if any. An absent policy means the account is unmanaged for this capability, which a host reads as allowed — so absence here is a positive statement that no policy applies, never a stand-in for a resolution that failed. A resolution that cannot be completed is rejected instead. /// ///
/// @@ -2720,22 +2764,32 @@ impl<'a> ClientRpcMcp<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn discover(&self, params: McpDiscoverRequest) -> Result { + pub(crate) async fn load_remote_control( + &self, + params: ManagedSettingsLoadRemoteControlParams, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MCP_DISCOVER, Some(wire_params)) + .call( + rpc_methods::MANAGEDSETTINGS_LOADREMOTECONTROL, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Lists the MCP servers the runtime supplies itself, so a host that disables the built-ins wholesale suppresses exactly the set the runtime would otherwise add. The names are fixed for a build and depend on no configuration, session or account. + /// Evaluates the device-channel enterprise sign-in pin (MDM plist, registry, or managed-settings file) against a credential, without resolving any server-delivered policy. This is the gate an entry point runs before it branches, and the only one that can refuse a developer's first sign-in: it is local, needs no credential, and a server-delivered pin only ever reaches accounts already inside the organization. It fails closed by construction — a discovery that cannot determine whether a pin exists refuses rather than allows, because a control that fails open under a triggerable condition is not a control. Hosts that also want the server channel should call `managedSettings.resolveStartupPolicy`, which folds both channels into one verdict. /// - /// Wire method: `mcp.listBuiltinServerNames`. + /// Wire method: `managedSettings.resolveDeviceForceLoginOrgsGate`. + /// + /// # Parameters + /// + /// * `params` - The credential and environment to evaluate the device-channel sign-in pin against. /// /// # Returns /// - /// Names of the MCP servers the runtime supplies itself. + /// The verdict of the `forceLoginOrgs` enterprise sign-in pin for one credential. A managed device may pin Copilot to an approved set of GitHub organizations so a developer cannot sign in with a personal — or another enterprise's — account and escape every control that keys off the signed-in identity. A host must refuse to proceed when `allowed` is false; the remaining fields explain the refusal rather than qualifying it. /// ///
/// @@ -2744,28 +2798,28 @@ impl<'a> ClientRpcMcp<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub(crate) async fn list_builtin_server_names( + pub(crate) async fn resolve_device_force_login_orgs_gate( &self, - ) -> Result { - let wire_params = serde_json::json!({}); + params: ManagedSettingsResolveDeviceForceLoginOrgsGateParams, + ) -> Result { + let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MCP_LISTBUILTINSERVERNAMES, Some(wire_params)) + .call( + rpc_methods::MANAGEDSETTINGS_RESOLVEDEVICEFORCELOGINORGSGATE, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Reports whether the gh-replaceable GitHub MCP tools may be clipped for a session, which a host feeds back as the `excludeGhReplaceableTools` build option. The tools are redundant only when the session can reach a shell *and* the host has the `gh` that would replace them, so both halves are decided here. The shell half runs the platform shell tool through the runtime's own tool-filter matcher, so entry forms like `builtin:bash` and `builtin:*` behave exactly as they do when a session builds its tool catalog. The host half probes for `gh`, and is skipped entirely when the filters already rule the shell out. Host presence alone is not enough: a session restricted to, say, `view` would otherwise lose the built-in issue-read fallback while having no shell to replace it with. The answer describes the host the runtime runs on, so it is never forwarded to a remote engine. - /// - /// Wire method: `mcp.shouldExcludeGitHubTools`. - /// - /// # Parameters + /// Discovers device-managed settings from production MDM and managed-file sources, validates them against the runtime-owned managed-settings schema, and returns the canonical JSON without requiring a session. `managedSettings.resolve` returns the same device settings together with the account's server policy. /// - /// * `params` - The session tool filters that decide whether the session still has a shell to run `gh` with. + /// Wire method: `managedSettings.read`. /// /// # Returns /// - /// Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by the request. + /// Validated device-managed settings discovered before a session exists. /// ///
/// @@ -2774,29 +2828,18 @@ impl<'a> ClientRpcMcp<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub(crate) async fn should_exclude_git_hub_tools( - &self, - params: McpShouldExcludeGitHubToolsRequest, - ) -> Result { - let wire_params = serde_json::to_value(params)?; + pub async fn read(&self) -> Result { + let wire_params = serde_json::json!({}); let _value = self .client - .call(rpc_methods::MCP_SHOULDEXCLUDEGITHUBTOOLS, Some(wire_params)) + .call(rpc_methods::MANAGEDSETTINGS_READ, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Requests a side-effect-free MCP install plan from a catalog candidate handle or a caller-supplied card. This host-implemented server method is available through SDK/TUI hosts; standalone and C-ABI runtimes whose host does not implement server-method dispatch return JSON-RPC MethodNotFound. A runtime with planning available returns a normalised plan and opaque single-use plan handle; a runtime without it returns the typed planning-unavailable result. A completed plan reports resource identity, provenance, eligible transport choices, the user-scope target, required typed values and secret placeholders, the policy result, the configuration changes installing would make, and whether a reload would be needed. Planning never writes configuration, stores a secret, or reloads MCP servers, so abandoning a plan needs no call and leaves nothing behind. - /// - /// Wire method: `mcp.planInstall`. - /// - /// # Parameters - /// - /// * `params` - A side-effect-free request for an MCP install plan. Computing a plan never writes configuration, stores a secret, or reloads MCP servers. - /// - /// # Returns + /// Force-refreshes enterprise managed settings for every account: wipes the persistent server-policy cache (the whole `/managed-settings` directory) and drops this runtime process's in-memory retained server policy. It does not itself fetch policy — the effect is that the next time a session resolves managed settings for an account, that resolution re-fetches the account's org policy from the network instead of serving a cached response. Note that `managedSettings.read` returns only device/MDM settings and never triggers the account server-policy fetch, so a host implementing "sync account policy" should call `managedSettings.resolve` or start a fresh session resolution rather than treat a subsequent `managedSettings.read` as the refreshed org policy. Mirrors the invalidation a sign-out performs, broadened from the one signing-out account to all of them; device/MDM layers describe the machine, not the account, and are left untouched. Rejects if the on-disk cache cannot be removed. /// - /// Outcome of an mcp.planInstall call: either a normalised plan, or one typed refusal. Nothing is written in either case. + /// Wire method: `managedSettings.clearCache`. /// ///
/// @@ -2805,29 +2848,22 @@ impl<'a> ClientRpcMcp<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn plan_install( - &self, - params: McpPlanInstallRequest, - ) -> Result { - let wire_params = serde_json::to_value(params)?; + pub async fn clear_cache(&self) -> Result<(), Error> { + let wire_params = serde_json::json!({}); let _value = self .client - .call(rpc_methods::MCP_PLANINSTALL, Some(wire_params)) + .call(rpc_methods::MANAGEDSETTINGS_CLEARCACHE, Some(wire_params)) .await?; - Ok(serde_json::from_value(_value)?) + Ok(()) } - /// Requests a side-effect-free MCP install plan from a catalog candidate handle or a caller-supplied card. This host-implemented server method is available through SDK/TUI hosts; standalone and C-ABI runtimes whose host does not implement server-method dispatch return JSON-RPC MethodNotFound. A runtime with planning available returns a normalised plan and opaque single-use plan handle; a runtime without it returns the typed planning-unavailable result. A completed plan reports resource identity, provenance, eligible transport choices, the user-scope target, required typed values and secret placeholders, the policy result, the configuration changes installing would make, and whether a reload would be needed. Planning never writes configuration, stores a secret, or reloads MCP servers, so abandoning a plan needs no call and leaves nothing behind. - /// - /// Wire method: `mcp.planInstall`. - /// - /// # Parameters + /// Resolves the effective enterprise managed settings without a session, from the device channel and, when an account is available, the account's server policy through the same per-account cache sessions use. A cached server policy less than an hour old is used without a fetch; otherwise the policy is fetched, and when the fetch fails a cached policy up to 24 hours old is used instead, unless `forceRemoteSettingsRefresh` requires a live fetch. With no account requested or signed in, it reports device policy only; signing out removes the account's cached policy. It can fetch server policy over the network when the cache is stale, so call it off latency-critical paths such as startup rather than before listing models. The policy helper is not run. `layers` lists each channel's document before merging, and `values` and `meta` carry typed effective values and their lock state for the keys typed so far. /// - /// * `params` - A side-effect-free request for an MCP install plan. Computing a plan never writes configuration, stores a secret, or reloads MCP servers. + /// Wire method: `managedSettings.resolve`. /// /// # Returns /// - /// Outcome of an mcp.planInstall call: either a normalised plan, or one typed refusal. Nothing is written in either case. + /// Effective enterprise managed settings for an account, resolved without a session. /// ///
/// @@ -2836,31 +2872,26 @@ impl<'a> ClientRpcMcp<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- /// - /// Accepts [`McpPlanInstallOptions`], including inputs added after [`McpPlanInstallRequest`]. - pub async fn plan_install_with_options( - &self, - params: McpPlanInstallOptions, - ) -> Result { - let wire_params = serde_json::to_value(params)?; + pub async fn resolve(&self) -> Result { + let wire_params = serde_json::json!({}); let _value = self .client - .call(rpc_methods::MCP_PLANINSTALL, Some(wire_params)) + .call(rpc_methods::MANAGEDSETTINGS_RESOLVE, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Consumes a bound catalogue plan and retains one exact fully resolved personal remote MCP operation requiring no supplied values or configured secrets. Returns its runtime operation ID and original expiry before any confirmation, activation, writer initialisation or installation effect. Register the original connection, operation and selected-session binding before calling applyInstall. Missing lower owned admission is unavailable, never a raw-config fallback. + /// Resolves the effective enterprise managed settings without a session, from the device channel and, when an account is available, the account's server policy through the same per-account cache sessions use. A cached server policy less than an hour old is used without a fetch; otherwise the policy is fetched, and when the fetch fails a cached policy up to 24 hours old is used instead, unless `forceRemoteSettingsRefresh` requires a live fetch. With no account requested or signed in, it reports device policy only; signing out removes the account's cached policy. It can fetch server policy over the network when the cache is stale, so call it off latency-critical paths such as startup rather than before listing models. The policy helper is not run. `layers` lists each channel's document before merging, and `values` and `meta` carry typed effective values and their lock state for the keys typed so far. /// - /// Wire method: `mcp.prepareInstall`. + /// Wire method: `managedSettings.resolve`. /// /// # Parameters /// - /// * `params` - Side-effect-free preparation of one original bound remote MCP choice. + /// * `params` - Optional opaque account selection or GitHub token whose managed settings are resolved. /// /// # Returns /// - /// Management result with contract receipt, or a typed request/negotiation refusal. + /// Effective enterprise managed settings for an account, resolved without a session. /// ///
/// @@ -2869,29 +2900,53 @@ impl<'a> ClientRpcMcp<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn prepare_install( + pub async fn resolve_with_params( &self, - params: McpPrepareInstallRequest, - ) -> Result { + params: ManagedSettingsResolveRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MCP_PREPAREINSTALL, Some(wire_params)) + .call(rpc_methods::MANAGEDSETTINGS_RESOLVE, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Consumes a retained prepared MCP operation once, revalidates its original authority, requests explicit human consent through installations.confirm on the original connection, then revalidates source and applies the sealed transaction. An uncertain result requires original-operation inspection or recovery, never replay. + /// Returns the managed-settings authoring JSON schema with descriptive `x-composition` annotations aligned with the shared settings-engine vocabulary. These annotations are not a complete runtime composition contract: model, effortLevel, and contextTier remain coupled. Use `managedSettings.compose` for the runtime's effective result. Performs no I/O. /// - /// Wire method: `mcp.applyInstall`. + /// Wire method: `managedSettings.schema`. + /// + /// # Returns + /// + /// The authoring JSON schema for managed settings recognized by this runtime. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn schema(&self) -> Result { + let wire_params = serde_json::json!({}); + let _value = self + .client + .call(rpc_methods::MANAGEDSETTINGS_SCHEMA, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Validates a candidate managed-settings document the way the runtime validates delivered policy, without applying it. Reports errors that would reject the document, warnings for content the runtime ignores, and the canonical document it would apply. Document text nested more than 64 levels deep is rejected. Performs no I/O. + /// + /// Wire method: `managedSettings.validate`. /// /// # Parameters /// - /// * `params` - Applies exactly one previously prepared operation on its original connection. + /// * `params` - A candidate managed-settings document to validate without applying it. /// /// # Returns /// - /// An installation result together with the exact honoured contract, or a negotiation refusal. + /// Result of validating a managed-settings document. /// ///
/// @@ -2900,29 +2955,29 @@ impl<'a> ClientRpcMcp<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn apply_install( + pub async fn validate( &self, - params: McpApplyInstallRequest, - ) -> Result { + params: ManagedSettingsValidateRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MCP_APPLYINSTALL, Some(wire_params)) + .call(rpc_methods::MANAGEDSETTINGS_VALIDATE, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Prepares a read-only removal plan for an exact owned receipt under the selected existing session. Returns the original operation ID before confirmation; neither planning nor abandonment changes configuration or shared OAuth credentials. + /// Merges candidate managed-settings documents for the device, server, and policy-helper channels into the effective settings the runtime would enforce on this host, using the same precedence and composition rules as live resolution, without applying them. Like live resolution, a server's advisory sandbox force-enable is declined on a host that cannot run the sandbox. Does not fetch policy or read policy files, but may perform blocking OS or subprocess probes for sandbox support. Preview documents are limited to 1 MiB and 64 levels of nesting. /// - /// Wire method: `mcp.planUninstall`. + /// Wire method: `managedSettings.compose`. /// /// # Parameters /// - /// * `params` - Read-only preparation of one owned removal under fresh selected-session authority. + /// * `params` - Candidate managed-settings documents to merge without applying them. /// /// # Returns /// - /// Management result with contract receipt, or a typed request/negotiation refusal. + /// The effective managed settings the runtime would enforce for the given documents, in the same shape `managedSettings.resolve` returns. /// ///
/// @@ -2931,29 +2986,37 @@ impl<'a> ClientRpcMcp<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn plan_uninstall( + pub async fn compose( &self, - params: McpPlanUninstallRequest, - ) -> Result { + params: ManagedSettingsComposeRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MCP_PLANUNINSTALL, Some(wire_params)) + .call(rpc_methods::MANAGEDSETTINGS_COMPOSE, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } +} - /// Consumes the original owned-removal plan once and requests fresh exact human confirmation on its original connection. Drift is refused; unrelated manual configuration and shared OAuth credentials are preserved. +/// `managedSettings.permissions.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcManagedSettingsPermissions<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcManagedSettingsPermissions<'a> { + /// Pure, sessionless evaluation of operations against a supplied permissionsContext. Performs no policy discovery, I/O, prompting, navigation, permission grants, or sandbox changes. Obtain the context from managedSettings.resolve or session.managedSettings.get, or reuse an in-memory context. Results preserve input order and duplicates. Consumers must block deny, obtain approval for ask, and use their normal permission flow for unmanaged. Unknown policy returns failClosed with every operation denied. This is not a substitute for user permissions or other security controls. /// - /// Wire method: `mcp.applyUninstall`. + /// Wire method: `managedSettings.permissions.evaluate`. /// /// # Parameters /// - /// * `params` - One-use application of the exact retained removal plan. + /// * `params` - Managed policy context and ordered operations for pure, sessionless evaluation. /// /// # Returns /// - /// An installation result together with the exact honoured contract, or a negotiation refusal. + /// Ordered managed permission verdicts and the supplied policy's fail-closed posture. /// ///
/// @@ -2962,33 +3025,61 @@ impl<'a> ClientRpcMcp<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn apply_uninstall( + pub async fn evaluate( &self, - params: McpApplyUninstallRequest, - ) -> Result { + params: ManagedPermissionsEvaluateRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MCP_APPLYUNINSTALL, Some(wire_params)) + .call( + rpc_methods::MANAGEDSETTINGS_PERMISSIONS_EVALUATE, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } } -/// `mcp.config.*` RPCs. +/// `mcp.*` RPCs. #[derive(Clone, Copy)] -pub struct ClientRpcMcpConfig<'a> { +pub struct ClientRpcMcp<'a> { pub(crate) client: &'a Client, } -impl<'a> ClientRpcMcpConfig<'a> { - /// Lists MCP servers from user configuration. +impl<'a> ClientRpcMcp<'a> { + /// `mcp.config.*` sub-namespace. + pub fn config(&self) -> ClientRpcMcpConfig<'a> { + ClientRpcMcpConfig { + client: self.client, + } + } + + /// `mcp.installations.*` sub-namespace. + pub fn installations(&self) -> ClientRpcMcpInstallations<'a> { + ClientRpcMcpInstallations { + client: self.client, + } + } + + /// `mcp.registry.*` sub-namespace. + pub fn registry(&self) -> ClientRpcMcpRegistry<'a> { + ClientRpcMcpRegistry { + client: self.client, + } + } + + /// Discovers MCP servers from user, workspace, plugin, and builtin sources. /// - /// Wire method: `mcp.config.list`. + /// Wire method: `mcp.discover`. + /// + /// # Parameters + /// + /// * `params` - Optional working directory used as context for MCP server discovery. /// /// # Returns /// - /// User-configured MCP servers, keyed by server name. + /// MCP servers discovered from user, workspace, plugin, and built-in sources. /// ///
/// @@ -2997,22 +3088,52 @@ impl<'a> ClientRpcMcpConfig<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn list(&self) -> Result { + pub async fn discover(&self, params: McpDiscoverRequest) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::MCP_DISCOVER, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Lists the MCP servers the runtime supplies itself, so a host that disables the built-ins wholesale suppresses exactly the set the runtime would otherwise add. The names are fixed for a build and depend on no configuration, session or account. + /// + /// Wire method: `mcp.listBuiltinServerNames`. + /// + /// # Returns + /// + /// Names of the MCP servers the runtime supplies itself. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn list_builtin_server_names( + &self, + ) -> Result { let wire_params = serde_json::json!({}); let _value = self .client - .call(rpc_methods::MCP_CONFIG_LIST, Some(wire_params)) + .call(rpc_methods::MCP_LISTBUILTINSERVERNAMES, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Adds an MCP server to user configuration. + /// Reports whether the gh-replaceable GitHub MCP tools may be clipped for a session, which a host feeds back as the `excludeGhReplaceableTools` build option. The tools are redundant only when the session can reach a shell *and* the host has the `gh` that would replace them, so both halves are decided here. The shell half runs the platform shell tool through the runtime's own tool-filter matcher, so entry forms like `builtin:bash` and `builtin:*` behave exactly as they do when a session builds its tool catalog. The host half probes for `gh`, and is skipped entirely when the filters already rule the shell out. Host presence alone is not enough: a session restricted to, say, `view` would otherwise lose the built-in issue-read fallback while having no shell to replace it with. The answer describes the host the runtime runs on, so it is never forwarded to a remote engine. /// - /// Wire method: `mcp.config.add`. + /// Wire method: `mcp.shouldExcludeGitHubTools`. /// /// # Parameters /// - /// * `params` - MCP server name and configuration to add to user configuration. + /// * `params` - The session tool filters that decide whether the session still has a shell to run `gh` with. + /// + /// # Returns + /// + /// Whether the gh-replaceable GitHub MCP tools may be clipped for the session described by the request. /// ///
/// @@ -3021,22 +3142,29 @@ impl<'a> ClientRpcMcpConfig<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn add(&self, params: McpConfigAddRequest) -> Result<(), Error> { + pub(crate) async fn should_exclude_git_hub_tools( + &self, + params: McpShouldExcludeGitHubToolsRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MCP_CONFIG_ADD, Some(wire_params)) + .call(rpc_methods::MCP_SHOULDEXCLUDEGITHUBTOOLS, Some(wire_params)) .await?; - Ok(()) + Ok(serde_json::from_value(_value)?) } - /// Updates an MCP server in user configuration. + /// Requests a side-effect-free MCP install plan from a catalog candidate handle or a caller-supplied card. This host-implemented server method is available through SDK/TUI hosts; standalone and C-ABI runtimes whose host does not implement server-method dispatch return JSON-RPC MethodNotFound. A runtime with planning available returns a normalised plan and opaque single-use plan handle; a runtime without it returns the typed planning-unavailable result. A completed plan reports resource identity, provenance, eligible transport choices, the user-scope target, required typed values and secret placeholders, the policy result, the configuration changes installing would make, and whether a reload would be needed. Planning never writes configuration, stores a secret, or reloads MCP servers, so abandoning a plan needs no call and leaves nothing behind. /// - /// Wire method: `mcp.config.update`. + /// Wire method: `mcp.planInstall`. /// /// # Parameters /// - /// * `params` - MCP server name and replacement configuration to write to user configuration. + /// * `params` - A side-effect-free request for an MCP install plan. Computing a plan never writes configuration, stores a secret, or reloads MCP servers. + /// + /// # Returns + /// + /// Outcome of an mcp.planInstall call: either a normalised plan, or one typed refusal. Nothing is written in either case. /// ///
/// @@ -3045,22 +3173,1313 @@ impl<'a> ClientRpcMcpConfig<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn update(&self, params: McpConfigUpdateRequest) -> Result<(), Error> { + pub async fn plan_install( + &self, + params: McpPlanInstallRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MCP_CONFIG_UPDATE, Some(wire_params)) + .call(rpc_methods::MCP_PLANINSTALL, Some(wire_params)) .await?; - Ok(()) + Ok(serde_json::from_value(_value)?) } - /// Removes an MCP server from user configuration. + /// Requests a side-effect-free MCP install plan from a catalog candidate handle or a caller-supplied card. This host-implemented server method is available through SDK/TUI hosts; standalone and C-ABI runtimes whose host does not implement server-method dispatch return JSON-RPC MethodNotFound. A runtime with planning available returns a normalised plan and opaque single-use plan handle; a runtime without it returns the typed planning-unavailable result. A completed plan reports resource identity, provenance, eligible transport choices, the user-scope target, required typed values and secret placeholders, the policy result, the configuration changes installing would make, and whether a reload would be needed. Planning never writes configuration, stores a secret, or reloads MCP servers, so abandoning a plan needs no call and leaves nothing behind. /// - /// Wire method: `mcp.config.remove`. + /// Wire method: `mcp.planInstall`. + /// + /// # Parameters + /// + /// * `params` - A side-effect-free request for an MCP install plan. Computing a plan never writes configuration, stores a secret, or reloads MCP servers. + /// + /// # Returns + /// + /// Outcome of an mcp.planInstall call: either a normalised plan, or one typed refusal. Nothing is written in either case. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ /// + /// Accepts [`McpPlanInstallOptions`], including inputs added after [`McpPlanInstallRequest`]. + pub async fn plan_install_with_options( + &self, + params: McpPlanInstallOptions, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::MCP_PLANINSTALL, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Consumes a bound catalogue plan and retains one exact fully resolved personal remote MCP operation requiring no supplied values or configured secrets. Returns its runtime operation ID and original expiry before any confirmation, activation, writer initialisation or installation effect. Register the original connection, operation and selected-session binding before calling applyInstall. Missing lower owned admission is unavailable, never a raw-config fallback. + /// + /// Wire method: `mcp.prepareInstall`. + /// + /// # Parameters + /// + /// * `params` - Side-effect-free preparation of one original bound remote MCP choice. + /// + /// # Returns + /// + /// Management result with contract receipt, or a typed request/negotiation refusal. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn prepare_install( + &self, + params: McpPrepareInstallRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::MCP_PREPAREINSTALL, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Consumes a retained prepared MCP operation once, revalidates its original authority, requests explicit human consent through installations.confirm on the original connection, then revalidates source and applies the sealed transaction. An uncertain result requires original-operation inspection or recovery, never replay. + /// + /// Wire method: `mcp.applyInstall`. /// /// # Parameters /// - /// * `params` - MCP server name to remove from user configuration. + /// * `params` - Applies exactly one previously prepared operation on its original connection. + /// + /// # Returns + /// + /// An installation result together with the exact honoured contract, or a negotiation refusal. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn apply_install( + &self, + params: McpApplyInstallRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::MCP_APPLYINSTALL, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Prepares a read-only removal plan for an exact owned receipt under the selected existing session. Returns the original operation ID before confirmation; neither planning nor abandonment changes configuration or shared OAuth credentials. + /// + /// Wire method: `mcp.planUninstall`. + /// + /// # Parameters + /// + /// * `params` - Read-only preparation of one owned removal under fresh selected-session authority. + /// + /// # Returns + /// + /// Management result with contract receipt, or a typed request/negotiation refusal. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn plan_uninstall( + &self, + params: McpPlanUninstallRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::MCP_PLANUNINSTALL, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Consumes the original owned-removal plan once and requests fresh exact human confirmation on its original connection. Drift is refused; unrelated manual configuration and shared OAuth credentials are preserved. + /// + /// Wire method: `mcp.applyUninstall`. + /// + /// # Parameters + /// + /// * `params` - One-use application of the exact retained removal plan. + /// + /// # Returns + /// + /// An installation result together with the exact honoured contract, or a negotiation refusal. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn apply_uninstall( + &self, + params: McpApplyUninstallRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::MCP_APPLYUNINSTALL, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } +} + +/// `mcp.config.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcMcpConfig<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcMcpConfig<'a> { + /// Lists MCP servers from user configuration. + /// + /// Wire method: `mcp.config.list`. + /// + /// # Returns + /// + /// User-configured MCP servers, keyed by server name. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn list(&self) -> Result { + let wire_params = serde_json::json!({}); + let _value = self + .client + .call(rpc_methods::MCP_CONFIG_LIST, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Adds an MCP server to user configuration. + /// + /// Wire method: `mcp.config.add`. + /// + /// # Parameters + /// + /// * `params` - MCP server name and configuration to add to user configuration. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn add(&self, params: McpConfigAddRequest) -> Result<(), Error> { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::MCP_CONFIG_ADD, Some(wire_params)) + .await?; + Ok(()) + } + + /// Updates an MCP server in user configuration. + /// + /// Wire method: `mcp.config.update`. + /// + /// # Parameters + /// + /// * `params` - MCP server name and replacement configuration to write to user configuration. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn update(&self, params: McpConfigUpdateRequest) -> Result<(), Error> { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::MCP_CONFIG_UPDATE, Some(wire_params)) + .await?; + Ok(()) + } + + /// Removes an MCP server from user configuration. + /// + /// Wire method: `mcp.config.remove`. + /// + /// # Parameters + /// + /// * `params` - MCP server name to remove from user configuration. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn remove(&self, params: McpConfigRemoveRequest) -> Result<(), Error> { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::MCP_CONFIG_REMOVE, Some(wire_params)) + .await?; + Ok(()) + } + + /// Enables MCP servers in user configuration for new sessions. + /// + /// Wire method: `mcp.config.enable`. + /// + /// # Parameters + /// + /// * `params` - MCP server names to enable for new sessions. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn enable(&self, params: McpConfigEnableRequest) -> Result<(), Error> { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::MCP_CONFIG_ENABLE, Some(wire_params)) + .await?; + Ok(()) + } + + /// Disables MCP servers in user configuration for new sessions. + /// + /// Wire method: `mcp.config.disable`. + /// + /// # Parameters + /// + /// * `params` - MCP server names to disable for new sessions. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn disable(&self, params: McpConfigDisableRequest) -> Result<(), Error> { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::MCP_CONFIG_DISABLE, Some(wire_params)) + .await?; + Ok(()) + } + + /// Drops this runtime process's in-memory MCP server-definition cache so the next MCP config read observes disk. + /// + /// Wire method: `mcp.config.reload`. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn reload(&self) -> Result<(), Error> { + let wire_params = serde_json::json!({}); + let _value = self + .client + .call(rpc_methods::MCP_CONFIG_RELOAD, Some(wire_params)) + .await?; + Ok(()) + } +} + +/// `mcp.installations.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcMcpInstallations<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcMcpInstallations<'a> { + /// Reads receipt-owned MCP inventory for the selected account and host without activating servers or reconstructing missing ownership. Configuration ownership does not prove session-specific usability. + /// + /// Wire method: `mcp.installations.list`. + /// + /// # Parameters + /// + /// * `params` - New-work inventory or recovery request under an explicitly selected existing session. + /// + /// # Returns + /// + /// Management result with contract receipt, or a typed request/negotiation refusal. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn list( + &self, + params: McpInstallationsRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::MCP_INSTALLATIONS_LIST, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Reconciles already-confirmed durable MCP transactions, then inspects owned inventory. Does not replay apply or reconstruct deleted ownership metadata; unresolved or unsafe evidence remains an explicit refusal. + /// + /// Wire method: `mcp.installations.recover`. + /// + /// # Parameters + /// + /// * `params` - New-work inventory or recovery request under an explicitly selected existing session. + /// + /// # Returns + /// + /// Management result with contract receipt, or a typed request/negotiation refusal. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn recover( + &self, + params: McpInstallationsRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::MCP_INSTALLATIONS_RECOVER, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Inspects a known operation only on its original connection. Remains available after account or selected-session loss; does not acquire new authority or rebind an operation. + /// + /// Wire method: `mcp.installations.status`. + /// + /// # Parameters + /// + /// * `params` - Existing-operation control. A new session selector is deliberately not accepted. + /// + /// # Returns + /// + /// Management result with contract receipt, or a typed request/negotiation refusal. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn status( + &self, + params: McpInstallationOperationRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::MCP_INSTALLATIONS_STATUS, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Requests cancellation of a known operation on its original connection, including before apply or confirmation. Already-started effects retain their transaction lease and report an honest terminal or recovery outcome. + /// + /// Wire method: `mcp.installations.cancel`. + /// + /// # Parameters + /// + /// * `params` - Existing-operation control. A new session selector is deliberately not accepted. + /// + /// # Returns + /// + /// Management result with contract receipt, or a typed request/negotiation refusal. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn cancel( + &self, + params: McpInstallationOperationRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::MCP_INSTALLATIONS_CANCEL, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } +} + +/// `mcp.registry.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcMcpRegistry<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcMcpRegistry<'a> { + /// Allocates an ID for one cancellable MCP registry search. The ID exists before the search starts, so callers can cancel before it starts. The networking stack supplies the cancellation namespace. The runtime retains at most 1,024 unused IDs. At capacity, another allocation can reclaim an unused ID. Active searches retain their IDs until they finish. + /// + /// Wire method: `mcp.registry.allocateRequestId`. + /// + /// # Returns + /// + /// Request id naming a cancellable registry search. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn allocate_request_id(&self) -> Result { + let wire_params = serde_json::json!({}); + let _value = self + .client + .call( + rpc_methods::MCP_REGISTRY_ALLOCATEREQUESTID, + Some(wire_params), + ) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Searches the MCP registry the supplied credential may read, resolving the registry endpoint from policy first. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. The runtime follows registry pages, keeps the newest entry per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub stars. Each server object is carried opaquely. + /// + /// Wire method: `mcp.registry.search`. + /// + /// # Parameters + /// + /// * `params` - Registry search terms, the credential to search under, and the request id that makes the search cancellable. + /// + /// # Returns + /// + /// Servers selected from the registry response. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn search( + &self, + params: McpRegistrySearchRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::MCP_REGISTRY_SEARCH, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Abandons the registry search that uses the given request ID. It acts only on IDs from `mcp.registry.allocateRequestId`, so it never cancels another component's request. Answers `canceled: true` when it stops a running search. Answers `canceled: false` for unknown or reclaimed IDs, completed or canceled searches, and unused reservations. It releases an unused reservation, so a later search with that ID is refused. + /// + /// Wire method: `mcp.registry.cancel`. + /// + /// # Parameters + /// + /// * `params` - Registry search to abandon. + /// + /// # Returns + /// + /// Whether the cancel reached a live search. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn cancel( + &self, + params: McpRegistryCancelRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::MCP_REGISTRY_CANCEL, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } +} + +/// `models.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcModels<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcModels<'a> { + /// Lists Copilot models available to the authenticated user. + /// + /// Wire method: `models.list`. + /// + /// # Returns + /// + /// List of Copilot models available to the resolved user, including capabilities and billing metadata. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn list(&self) -> Result { + let wire_params = serde_json::json!({}); + let _value = self + .client + .call(rpc_methods::MODELS_LIST, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Lists Copilot models available to the authenticated user. + /// + /// Wire method: `models.list`. + /// + /// # Parameters + /// + /// * `params` - Optional opaque account selection or compatibility GitHub token used to list models. + /// + /// # Returns + /// + /// List of Copilot models available to the resolved user, including capabilities and billing metadata. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn list_with_params(&self, params: ModelsListRequest) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::MODELS_LIST, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Returns the running runtime's complete catalog of well-known built-in model IDs without authentication or network access. + /// + /// Wire method: `models.getBuiltInCatalog`. + /// + /// # Returns + /// + /// The running runtime's complete catalog of well-known built-in model IDs, including supported models and additional IDs with built-in metadata. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn get_built_in_catalog(&self) -> Result { + let wire_params = serde_json::json!({}); + let _value = self + .client + .call(rpc_methods::MODELS_GETBUILTINCATALOG, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } +} + +/// `permissions.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcPermissions<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcPermissions<'a> { + /// `permissions.folderTrust.*` sub-namespace. + pub fn folder_trust(&self) -> ClientRpcPermissionsFolderTrust<'a> { + ClientRpcPermissionsFolderTrust { + client: self.client, + } + } + + /// `permissions.locations.*` sub-namespace. + pub fn locations(&self) -> ClientRpcPermissionsLocations<'a> { + ClientRpcPermissionsLocations { + client: self.client, + } + } + + /// Interprets a verbatim managed `permissions` slice into the three policy questions a host asks before granting elevated permissions: whether bypass-permissions mode is forbidden, whether a policy exists that this build could not determine, and whether the layer supplies permission rules the session must enforce. An absent or empty slice means no managed policy applies. The runtime and its permission service share one policy type, so a new managed permission setting is interpreted in exactly one place; a host that reimplements the reading would silently diverge the first time that set grows. Hosts must fail closed on an undetermined policy rather than treating it as permission granted. + /// + /// Wire method: `permissions.evaluateManagedPolicy`. + /// + /// # Parameters + /// + /// * `params` - The verbatim managed `permissions` slice to interpret. + /// + /// # Returns + /// + /// The policy questions a host asks before granting elevated permissions. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn evaluate_managed_policy( + &self, + params: PermissionsEvaluateManagedPolicyParams, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call( + rpc_methods::PERMISSIONS_EVALUATEMANAGEDPOLICY, + Some(wire_params), + ) + .await?; + Ok(serde_json::from_value(_value)?) + } +} + +/// `permissions.folderTrust.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcPermissionsFolderTrust<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcPermissionsFolderTrust<'a> { + /// Reports whether a folder is trusted, reading the persisted trusted-folders list directly rather than through a session. Use this from a host that has no session yet, such as a one-shot command deciding whether to honor a checkout's own settings. It differs from the session-scoped check in two ways that matter: it takes the configuration directory to read the list from, instead of inheriting the session's, and it answers only from the persisted list, so trust a user granted for the lifetime of one session is not visible here. A host that has a session should prefer the session-scoped check, which also covers session-only trust. + /// + /// Wire method: `permissions.folderTrust.checkTrust`. + /// + /// # Parameters + /// + /// * `params` - A folder to check against a persisted trusted-folders list, and the configuration directory holding that list. + /// + /// # Returns + /// + /// Folder trust check result. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn check_trust( + &self, + params: FolderTrustIsTrustedParams, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call( + rpc_methods::PERMISSIONS_FOLDERTRUST_CHECKTRUST, + Some(wire_params), + ) + .await?; + Ok(serde_json::from_value(_value)?) + } +} + +/// `permissions.locations.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcPermissionsLocations<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcPermissionsLocations<'a> { + /// Drops stored per-location permission grants whose directory no longer exists, and reports which location keys were removed. Runs against the permission store under the runtime's own Copilot home, the same store `session.permissions.locations.resolve` reads. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract; it is migration plumbing, not a surface consumers are meant to depend on. It can become public once an SDK consumer needs to prune its own permission store. + /// + /// Wire method: `permissions.locations.cleanupOrphaned`. + /// + /// # Returns + /// + /// Which stored location permissions were dropped because their directory is gone. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn cleanup_orphaned(&self) -> Result { + let wire_params = serde_json::json!({}); + let _value = self + .client + .call( + rpc_methods::PERMISSIONS_LOCATIONS_CLEANUPORPHANED, + Some(wire_params), + ) + .await?; + Ok(serde_json::from_value(_value)?) + } +} + +/// `persistence.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcPersistence<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcPersistence<'a> { + /// Atomically replaces a JSON file's entire contents while holding the runtime's per-path lock. The lock lives in the runtime process, so a host that writes these files itself takes no part in it and can tear a concurrent runtime write; route the write here instead. Unlike a merging write this never reads or parses the existing file, so a previously corrupted snapshot is replaced wholesale rather than failing every later write. Use it only for callers that always persist a complete snapshot. + /// + /// Wire method: `persistence.writeRawJsonLocked`. + /// + /// # Parameters + /// + /// * `params` - A complete JSON snapshot to write under the runtime's per-path file lock. + /// + /// # Returns + /// + /// The outcome of a locked snapshot write. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn write_raw_json_locked( + &self, + params: PersistenceWriteRawJsonLockedRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call( + rpc_methods::PERSISTENCE_WRITERAWJSONLOCKED, + Some(wire_params), + ) + .await?; + Ok(serde_json::from_value(_value)?) + } +} + +/// `plugins.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcPlugins<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcPlugins<'a> { + /// `plugins.builtin.*` sub-namespace. + pub fn builtin(&self) -> ClientRpcPluginsBuiltin<'a> { + ClientRpcPluginsBuiltin { + client: self.client, + } + } + + /// `plugins.marketplaces.*` sub-namespace. + pub fn marketplaces(&self) -> ClientRpcPluginsMarketplaces<'a> { + ClientRpcPluginsMarketplaces { + client: self.client, + } + } + + /// Lists plugins installed in user/global state. + /// + /// Wire method: `plugins.list`. + /// + /// # Returns + /// + /// Plugins installed in user/global state. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn list(&self) -> Result { + let wire_params = serde_json::json!({}); + let _value = self + .client + .call(rpc_methods::PLUGINS_LIST, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Installs a plugin from a marketplace, GitHub repo, URL, or local path. + /// + /// Wire method: `plugins.install`. + /// + /// # Parameters + /// + /// * `params` - Plugin source and optional working directory for relative-path resolution. + /// + /// # Returns + /// + /// Result of installing a plugin. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn install( + &self, + params: PluginsInstallRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::PLUGINS_INSTALL, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Uninstalls an installed plugin. + /// + /// Wire method: `plugins.uninstall`. + /// + /// # Parameters + /// + /// * `params` - Name (or spec) of the plugin to uninstall. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn uninstall(&self, params: PluginsUninstallRequest) -> Result<(), Error> { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::PLUGINS_UNINSTALL, Some(wire_params)) + .await?; + Ok(()) + } + + /// Updates an installed plugin to its latest published version. + /// + /// Wire method: `plugins.update`. + /// + /// # Parameters + /// + /// * `params` - Name (or spec) of the plugin to update. + /// + /// # Returns + /// + /// Result of updating a single plugin. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn update(&self, params: PluginsUpdateRequest) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::PLUGINS_UPDATE, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Updates every installed plugin to its latest published version. + /// + /// Wire method: `plugins.updateAll`. + /// + /// # Returns + /// + /// Result of updating all installed plugins. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn update_all(&self) -> Result { + let wire_params = serde_json::json!({}); + let _value = self + .client + .call(rpc_methods::PLUGINS_UPDATEALL, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Enables installed plugins for new sessions. + /// + /// Wire method: `plugins.enable`. + /// + /// # Parameters + /// + /// * `params` - Plugin names (or specs) to enable, plus the optional working directory the repository-controlled guard is evaluated against. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn enable(&self, params: PluginsEnableRequest) -> Result<(), Error> { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::PLUGINS_ENABLE, Some(wire_params)) + .await?; + Ok(()) + } + + /// Disables installed plugins for new sessions. + /// + /// Wire method: `plugins.disable`. + /// + /// # Parameters + /// + /// * `params` - Plugin names (or specs) to disable, plus the optional working directory the repository-controlled guard is evaluated against. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn disable(&self, params: PluginsDisableRequest) -> Result<(), Error> { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::PLUGINS_DISABLE, Some(wire_params)) + .await?; + Ok(()) + } +} + +/// `plugins.builtin.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcPluginsBuiltin<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcPluginsBuiltin<'a> { + /// Replaces this server's trusted built-in plugin directories while no sessions are active. + /// + /// Wire method: `plugins.builtin.set`. + /// + /// # Parameters + /// + /// * `params` - Trusted built-in plugin directories to use for this runtime process. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn set(&self, params: PluginsBuiltinSetRequest) -> Result<(), Error> { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::PLUGINS_BUILTIN_SET, Some(wire_params)) + .await?; + Ok(()) + } +} + +/// `plugins.marketplaces.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcPluginsMarketplaces<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcPluginsMarketplaces<'a> { + /// Lists all registered marketplaces (defaults + user-added). + /// + /// Wire method: `plugins.marketplaces.list`. + /// + /// # Returns + /// + /// All registered marketplaces, including built-in defaults. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn list(&self) -> Result { + let wire_params = serde_json::json!({}); + let _value = self + .client + .call(rpc_methods::PLUGINS_MARKETPLACES_LIST, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Registers a new marketplace from a source (owner/repo, URL, or local path). + /// + /// Wire method: `plugins.marketplaces.add`. + /// + /// # Parameters + /// + /// * `params` - Marketplace source and optional working directory for relative-path resolution. + /// + /// # Returns + /// + /// Result of registering a new marketplace. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn add( + &self, + params: PluginsMarketplacesAddRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::PLUGINS_MARKETPLACES_ADD, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Removes a previously-registered marketplace. When the marketplace has dependent plugins and `force` is not set, the marketplace is left intact and the result lists the dependents so the caller can decide whether to retry with `force=true`. + /// + /// Wire method: `plugins.marketplaces.remove`. + /// + /// # Parameters + /// + /// * `params` - Name of the marketplace to remove and an optional force flag. + /// + /// # Returns + /// + /// Outcome of the remove attempt, including dependent-plugin info when applicable. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn remove( + &self, + params: PluginsMarketplacesRemoveRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::PLUGINS_MARKETPLACES_REMOVE, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Lists plugins advertised by a registered marketplace. + /// + /// Wire method: `plugins.marketplaces.browse`. + /// + /// # Parameters + /// + /// * `params` - Name of the marketplace whose plugin catalog to fetch. + /// + /// # Returns + /// + /// Plugins advertised by the marketplace. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn browse( + &self, + params: PluginsMarketplacesBrowseRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::PLUGINS_MARKETPLACES_BROWSE, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Re-fetches one or all registered marketplace catalogs. + /// + /// Wire method: `plugins.marketplaces.refresh`. + /// + /// # Returns + /// + /// Result of refreshing one or more marketplace catalogs. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn refresh(&self) -> Result { + let wire_params = serde_json::json!({}); + let _value = self + .client + .call(rpc_methods::PLUGINS_MARKETPLACES_REFRESH, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Re-fetches one or all registered marketplace catalogs. + /// + /// Wire method: `plugins.marketplaces.refresh`. + /// + /// # Parameters + /// + /// * `params` - Optional marketplace name; omit to refresh all. + /// + /// # Returns + /// + /// Result of refreshing one or more marketplace catalogs. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn refresh_with_params( + &self, + params: PluginsMarketplacesRefreshRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::PLUGINS_MARKETPLACES_REFRESH, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } +} + +/// `repo.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcRepo<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcRepo<'a> { + /// `repo.settings.*` sub-namespace. + pub fn settings(&self) -> ClientRpcRepoSettings<'a> { + ClientRpcRepoSettings { + client: self.client, + } + } +} + +/// `repo.settings.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcRepoSettings<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcRepoSettings<'a> { + /// Atomically edits one allowed top-level repository setting. Reads the raw file, preserves unrelated keys, applies one scalar or list edit, validates the result and writes under one file lock, so concurrent sibling or list edits are not lost. A malformed or unsafe existing file returns `invalid` without a write; rejected keys, invalid values and I/O errors reject the call. + /// + /// Wire method: `repo.settings.edit`. + /// + /// # Parameters + /// + /// * `params` - One atomic edit of an allowed top-level repository setting. + /// + /// # Returns + /// + /// Outcome of an atomic user or repository settings edit. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn edit( + &self, + params: RepoSettingsEditRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::REPO_SETTINGS_EDIT, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// Reads one repository settings file without settings normalization or layering. The existing JSONC parser accepts comments and trailing commas and applies its prototype-safety rules. Missing or blank files return an empty valid config. Invalid files return an empty config with invalid=true; other read failures reject. + /// + /// Wire method: `repo.settings.readRaw`. + /// + /// # Parameters + /// + /// * `params` - Which repository settings file to read. + /// + /// # Returns + /// + /// Parsed repository settings without normalization or layering. /// ///
/// @@ -3069,22 +4488,25 @@ impl<'a> ClientRpcMcpConfig<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn remove(&self, params: McpConfigRemoveRequest) -> Result<(), Error> { + pub(crate) async fn read_raw( + &self, + params: RepoSettingsReadRawRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MCP_CONFIG_REMOVE, Some(wire_params)) + .call(rpc_methods::REPO_SETTINGS_READRAW, Some(wire_params)) .await?; - Ok(()) + Ok(serde_json::from_value(_value)?) } - /// Enables MCP servers in user configuration for new sessions. + /// Writes or removes one allowed top-level repository setting through the existing validator and file lock. Preserves unrelated stored keys. Invalid keys, values, existing documents, and I/O errors reject without replacing the file. Deletion requires delete=true; otherwise value must be present. /// - /// Wire method: `mcp.config.enable`. + /// Wire method: `repo.settings.writeKey`. /// /// # Parameters /// - /// * `params` - MCP server names to enable for new sessions. + /// * `params` - One key to write or remove in a repository settings file. /// ///
/// @@ -3093,22 +4515,22 @@ impl<'a> ClientRpcMcpConfig<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn enable(&self, params: McpConfigEnableRequest) -> Result<(), Error> { + pub(crate) async fn write_key(&self, params: RepoSettingsWriteKeyRequest) -> Result<(), Error> { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MCP_CONFIG_ENABLE, Some(wire_params)) + .call(rpc_methods::REPO_SETTINGS_WRITEKEY, Some(wire_params)) .await?; Ok(()) } - /// Disables MCP servers in user configuration for new sessions. + /// Replaces the repository-overridable settings in one locked write. Allowed keys present in settings are validated and written; allowed keys absent from settings are removed. Other input keys are ignored, and unknown keys already stored in the file remain unchanged. Invalid values or an invalid existing file reject without a partial write. /// - /// Wire method: `mcp.config.disable`. + /// Wire method: `repo.settings.writeAll`. /// /// # Parameters /// - /// * `params` - MCP server names to disable for new sessions. + /// * `params` - The complete set of repository-overridable settings to store. /// ///
/// @@ -3117,18 +4539,26 @@ impl<'a> ClientRpcMcpConfig<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn disable(&self, params: McpConfigDisableRequest) -> Result<(), Error> { + pub(crate) async fn write_all(&self, params: RepoSettingsWriteAllRequest) -> Result<(), Error> { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MCP_CONFIG_DISABLE, Some(wire_params)) + .call(rpc_methods::REPO_SETTINGS_WRITEALL, Some(wire_params)) .await?; Ok(()) } +} - /// Drops this runtime process's in-memory MCP server-definition cache so the next MCP config read observes disk. +/// `runtime.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcRuntime<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcRuntime<'a> { + /// Gracefully shuts down an SDK-owned runtime. The response is sent only after cleanup completes; callers may then terminate the owned runtime process. /// - /// Wire method: `mcp.config.reload`. + /// Wire method: `runtime.shutdown`. /// ///
/// @@ -3137,34 +4567,55 @@ impl<'a> ClientRpcMcpConfig<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn reload(&self) -> Result<(), Error> { + pub async fn shutdown(&self) -> Result<(), Error> { let wire_params = serde_json::json!({}); let _value = self .client - .call(rpc_methods::MCP_CONFIG_RELOAD, Some(wire_params)) + .call(rpc_methods::RUNTIME_SHUTDOWN, Some(wire_params)) .await?; Ok(()) } } -/// `mcp.installations.*` RPCs. +/// `sandbox.*` RPCs. #[derive(Clone, Copy)] -pub struct ClientRpcMcpInstallations<'a> { +pub struct ClientRpcSandbox<'a> { pub(crate) client: &'a Client, } -impl<'a> ClientRpcMcpInstallations<'a> { - /// Reads receipt-owned MCP inventory for the selected account and host without activating servers or reconstructing missing ownership. Configuration ownership does not prove session-specific usability. +impl<'a> ClientRpcSandbox<'a> { + /// `sandbox.proxyCa.*` sub-namespace. + pub fn proxy_ca(&self) -> ClientRpcSandboxProxyCa<'a> { + ClientRpcSandboxProxyCa { + client: self.client, + } + } + + /// `sandbox.proxySecret.*` sub-namespace. + pub fn proxy_secret(&self) -> ClientRpcSandboxProxySecret<'a> { + ClientRpcSandboxProxySecret { + client: self.client, + } + } + + /// `sandbox.settings.*` sub-namespace. + pub fn settings(&self) -> ClientRpcSandboxSettings<'a> { + ClientRpcSandboxSettings { + client: self.client, + } + } + + /// Raises a user's sandbox settings to an administrator's managed sandbox floor and returns the result a session should actually run under. The floor can only tighten: an enterprise force-on is reflected even when the user's own `enabled` is false, and a user cannot lower a setting the floor raised. The result is normalized through the declared sandbox shape, so a key reorder or an undeclared passthrough key is not mistaken for a policy change by callers that diff two results. A host must call this rather than merge the two layers itself, because reimplementing the direction of the fold is what turns an administrator's floor into a suggestion. /// - /// Wire method: `mcp.installations.list`. + /// Wire method: `sandbox.resolveFlooredConfig`. /// /// # Parameters /// - /// * `params` - New-work inventory or recovery request under an explicitly selected existing session. + /// * `params` - The user's sandbox settings and the managed sandbox floor to raise them to. /// /// # Returns /// - /// Management result with contract receipt, or a typed request/negotiation refusal. + /// The user's sandbox settings raised to the managed floor. /// ///
/// @@ -3173,29 +4624,29 @@ impl<'a> ClientRpcMcpInstallations<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn list( + pub(crate) async fn resolve_floored_config( &self, - params: McpInstallationsRequest, - ) -> Result { + params: SandboxResolveFlooredConfigParams, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MCP_INSTALLATIONS_LIST, Some(wire_params)) + .call(rpc_methods::SANDBOX_RESOLVEFLOOREDCONFIG, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Reconciles already-confirmed durable MCP transactions, then inspects owned inventory. Does not replay apply or reconstruct deleted ownership metadata; unresolved or unsafe evidence remains an explicit refusal. + /// Builds the effective filesystem policy one `@`-file picker checks its suggestions against, so Git discovery and grant canonicalization run once for the picker's lifetime instead of on every debounced keystroke. Returns no policy when the sandbox is absent or disabled, which the paired filter reads as "keep every candidate". A host must pair this with `sandbox.filterPickerCandidates` rather than resolve a grant list itself, because the picker's grants are narrower than a file tool's — the same path a built-in tool may read can be one the picker must not offer. /// - /// Wire method: `mcp.installations.recover`. + /// Wire method: `sandbox.preparePickerPolicy`. /// /// # Parameters /// - /// * `params` - New-work inventory or recovery request under an explicitly selected existing session. + /// * `params` - The working directory and sandbox settings to build a file-picker policy from. /// /// # Returns /// - /// Management result with contract receipt, or a typed request/negotiation refusal. + /// The prepared file-picker policy, or none when the sandbox is disabled. /// ///
/// @@ -3204,29 +4655,29 @@ impl<'a> ClientRpcMcpInstallations<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn recover( + pub(crate) async fn prepare_picker_policy( &self, - params: McpInstallationsRequest, - ) -> Result { + params: SandboxPreparePickerPolicyParams, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MCP_INSTALLATIONS_RECOVER, Some(wire_params)) + .call(rpc_methods::SANDBOX_PREPAREPICKERPOLICY, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Inspects a known operation only on its original connection. Remains available after account or selected-session loss; does not acquire new authority or rebind an operation. + /// Checks a batch of `@`-file picker suggestions against a policy prepared by `sandbox.preparePickerPolicy` and returns one allow decision per candidate, positionally aligned with the request. Batched deliberately: each check canonicalizes a path component-by-component through the real filesystem, so one call amortizes that over a single hop rather than dozens while the user types. A directory the policy does not itself allow can still be kept as a waypoint to an allowed subtree. An absent policy keeps every candidate. /// - /// Wire method: `mcp.installations.status`. + /// Wire method: `sandbox.filterPickerCandidates`. /// /// # Parameters /// - /// * `params` - Existing-operation control. A new session selector is deliberately not accepted. + /// * `params` - A batch of file-picker candidates to check against a prepared policy. /// /// # Returns /// - /// Management result with contract receipt, or a typed request/negotiation refusal. + /// Per-candidate allow decisions, positionally aligned with the request. /// ///
/// @@ -3235,29 +4686,32 @@ impl<'a> ClientRpcMcpInstallations<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn status( + pub(crate) async fn filter_picker_candidates( &self, - params: McpInstallationOperationRequest, - ) -> Result { + params: SandboxFilterPickerCandidatesParams, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MCP_INSTALLATIONS_STATUS, Some(wire_params)) + .call( + rpc_methods::SANDBOX_FILTERPICKERCANDIDATES, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Requests cancellation of a known operation on its original connection, including before apply or confirmation. Already-started effects retain their transaction lease and report an honest terminal or recovery outcome. + /// The sandbox a single named feature actually launches under, which is not the same as the session's sandbox. A feature is routed out of the sandbox by its own flag — `sandboxMcpServers`, `sandboxLspServers` — so an enabled session can still start one server confined and another free. Returns a disabled sandbox rather than an error when the host has no sandbox slice at all, so an absent config and an opted-out feature read alike at the launch site. A host must ask per feature rather than reuse the session config, because reading only `enabled` confines a server the user opted out of, or reports as sandboxed one that is not. /// - /// Wire method: `mcp.installations.cancel`. + /// Wire method: `sandbox.resolveForOptional`. /// /// # Parameters /// - /// * `params` - Existing-operation control. A new session selector is deliberately not accepted. + /// * `params` - A sandbox config and the per-feature routing flag to resolve it for. /// /// # Returns /// - /// Management result with contract receipt, or a typed request/negotiation refusal. + /// The sandbox a named feature actually launches under. /// ///
/// @@ -3266,33 +4720,51 @@ impl<'a> ClientRpcMcpInstallations<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn cancel( + pub(crate) async fn resolve_for_optional( &self, - params: McpInstallationOperationRequest, - ) -> Result { + params: SandboxEffectiveForOptionalParams, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MCP_INSTALLATIONS_CANCEL, Some(wire_params)) + .call(rpc_methods::SANDBOX_RESOLVEFOROPTIONAL, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } -} -/// `mcp.registry.*` RPCs. -#[derive(Clone, Copy)] -pub struct ClientRpcMcpRegistry<'a> { - pub(crate) client: &'a Client, -} + /// Reports whether this machine can run an OS-level command sandbox at all. A host must ask before it offers sandboxing, because the answer is a property of the machine rather than of any setting: on Linux it depends on bubblewrap being installed, and on Windows on the OS build supporting BaseContainer. Probing it requires spawning a process the first time, so the answer is cached for the life of the runtime. A host that assumes support and enables the sandbox anyway produces a session in which every shell command fails. + /// + /// Wire method: `sandbox.checkPlatformSupport`. + /// + /// # Returns + /// + /// True when an OS-level sandbox can run on this host. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn check_platform_support( + &self, + ) -> Result { + let wire_params = serde_json::json!({}); + let _value = self + .client + .call(rpc_methods::SANDBOX_CHECKPLATFORMSUPPORT, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } -impl<'a> ClientRpcMcpRegistry<'a> { - /// Allocates an ID for one cancellable MCP registry search. The ID exists before the search starts, so callers can cancel before it starts. The networking stack supplies the cancellation namespace. The runtime retains at most 1,024 unused IDs. At capacity, another allocation can reclaim an unused ID. Active searches retain their IDs until they finish. + /// Reports whether this Windows host's BaseContainer implementation can reach the host's loopback interface directly, which is what a local-network policy needs to avoid routing through the egress proxy. Like `sandbox.checkPlatformSupport`, the answer is a property of the machine's OS build rather than of any setting, and resolving it the first time spawns a platform probe. A host that offers the direct local-network option on a machine that lacks the capability produces a session whose sandboxed commands cannot reach local services. Always false off Windows. /// - /// Wire method: `mcp.registry.allocateRequestId`. + /// Wire method: `sandbox.checkWindowsHostLoopbackSupport`. /// /// # Returns /// - /// Request id naming a cancellable registry search. + /// True when the sandbox on this host can reach host loopback directly. /// ///
/// @@ -3301,29 +4773,56 @@ impl<'a> ClientRpcMcpRegistry<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub(crate) async fn allocate_request_id(&self) -> Result { + pub(crate) async fn check_windows_host_loopback_support( + &self, + ) -> Result { let wire_params = serde_json::json!({}); let _value = self .client .call( - rpc_methods::MCP_REGISTRY_ALLOCATEREQUESTID, + rpc_methods::SANDBOX_CHECKWINDOWSHOSTLOOPBACKSUPPORT, Some(wire_params), ) .await?; Ok(serde_json::from_value(_value)?) } - /// Searches the MCP registry the supplied credential may read, resolving the registry endpoint from policy first. Hosts usually send credential-free `AuthIdentity`; a `token` identity can be resolved only when it embeds a token, while `env` and `gh-cli` identities can use a token embedded in the request first. The runtime follows registry pages, keeps the newest entry per server name, cuts the list to `limit`, and sorts an empty-query result by GitHub stars. Each server object is carried opaquely. + /// The explanation a host shows when it refuses an explicit request to turn the sandbox on for a machine that cannot run one. Carries the platform-specific remedy — install bubblewrap, update Windows — and the documentation link, so a host that got `false` from `sandbox.checkPlatformSupport` does not have to compose its own reason and cannot describe the same machine differently from the runtime's own spawn path. /// - /// Wire method: `mcp.registry.search`. + /// Wire method: `sandbox.getUnsupportedMessage`. /// - /// # Parameters + /// # Returns /// - /// * `params` - Registry search terms, the credential to search under, and the request id that makes the search cancellable. + /// The user-facing refusal, including the platform remedy and the documentation link. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn get_unsupported_message( + &self, + ) -> Result { + let wire_params = serde_json::json!({}); + let _value = self + .client + .call( + rpc_methods::SANDBOX_GETUNSUPPORTEDMESSAGE, + Some(wire_params), + ) + .await?; + Ok(serde_json::from_value(_value)?) + } + + /// The notice a host shows when a stored `sandbox` setting is being ignored for this session because the machine cannot enforce it. Distinct from `sandbox.getUnsupportedMessage`, which refuses an explicit request: this one reports that a setting the user already saved is inert, states that commands will run unsandboxed, and confirms the stored setting itself is left alone. A host that stays silent here leaves the user believing a sandbox is active. + /// + /// Wire method: `sandbox.getUnsupportedSettingDisabledNotice`. /// /// # Returns /// - /// Servers selected from the registry response. + /// The user-facing notice that a saved sandbox setting is inert for this session. /// ///
/// @@ -3332,29 +4831,31 @@ impl<'a> ClientRpcMcpRegistry<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub(crate) async fn search( + pub(crate) async fn get_unsupported_setting_disabled_notice( &self, - params: McpRegistrySearchRequest, - ) -> Result { - let wire_params = serde_json::to_value(params)?; + ) -> Result { + let wire_params = serde_json::json!({}); let _value = self .client - .call(rpc_methods::MCP_REGISTRY_SEARCH, Some(wire_params)) + .call( + rpc_methods::SANDBOX_GETUNSUPPORTEDSETTINGDISABLEDNOTICE, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Abandons the registry search that uses the given request ID. It acts only on IDs from `mcp.registry.allocateRequestId`, so it never cancels another component's request. Answers `canceled: true` when it stops a running search. Answers `canceled: false` for unknown or reclaimed IDs, completed or canceled searches, and unused reservations. It releases an unused reservation, so a later search with that ID is refused. + /// The warning a host prints at startup when a session asked for a sandbox on a machine that cannot run one. The third of the unsupported notices, and the only one that depends on the policy in force: it names the remedy the reader can actually act on, which is the stored setting for an unmanaged host, an administrator for a managed one, and waiting for the policy to resolve when the sandbox stayed on only because the policy could not be determined. Returns no notice when the machine does support a sandbox, so a host can call it unconditionally on the startup path. A host that composes its own warning tells a managed user to change a setting their policy will overwrite. /// - /// Wire method: `mcp.registry.cancel`. + /// Wire method: `sandbox.getUnsupportedStartupNotice`. /// /// # Parameters /// - /// * `params` - Registry search to abandon. + /// * `params` - The managed sandbox policy in force, which selects which remedy the notice offers. /// /// # Returns /// - /// Whether the cancel reached a live search. + /// The startup warning, absent when the machine can run a sandbox. /// ///
/// @@ -3363,33 +4864,32 @@ impl<'a> ClientRpcMcpRegistry<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub(crate) async fn cancel( + pub(crate) async fn get_unsupported_startup_notice( &self, - params: McpRegistryCancelRequest, - ) -> Result { + params: SandboxUnsupportedStartupNoticeParams, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MCP_REGISTRY_CANCEL, Some(wire_params)) + .call( + rpc_methods::SANDBOX_GETUNSUPPORTEDSTARTUPNOTICE, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } -} - -/// `models.*` RPCs. -#[derive(Clone, Copy)] -pub struct ClientRpcModels<'a> { - pub(crate) client: &'a Client, -} -impl<'a> ClientRpcModels<'a> { - /// Lists Copilot models available to the authenticated user. + /// Whether one slash command stays reachable while sandbox enforcement is unavailable and the session is otherwise blocked. The permitted set is deliberately narrow — commands that only report state, and the few that let the user repair or leave the situation — and it is keyed on the arguments as well as the name, so `/sandbox status` is admitted where `/sandbox enable` is not. A host must ask rather than keep its own list: a command this returns false for is one the runtime would refuse anyway, and a divergent list either strands the user with no way out or admits a command that acts on an unenforced session. /// - /// Wire method: `models.list`. + /// Wire method: `sandbox.checkEnforcementCommand`. + /// + /// # Parameters + /// + /// * `params` - One slash command, as typed, to test against the enforcement-block allowlist. /// /// # Returns /// - /// List of Copilot models available to the resolved user, including capabilities and billing metadata. + /// True when the command stays available while enforcement is blocked. /// ///
/// @@ -3398,26 +4898,28 @@ impl<'a> ClientRpcModels<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn list(&self) -> Result { - let wire_params = serde_json::json!({}); + pub(crate) async fn check_enforcement_command( + &self, + params: SandboxEnforcementCommandAllowedParams, + ) -> Result { + let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::MODELS_LIST, Some(wire_params)) + .call( + rpc_methods::SANDBOX_CHECKENFORCEMENTCOMMAND, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Lists Copilot models available to the authenticated user. - /// - /// Wire method: `models.list`. - /// - /// # Parameters + /// Returns the documentation URL a host should point a user at when it declines or downgrades a sandbox setting. The runtime owns the address so every surface cites the same page and a host does not hard-code a link that later moves. /// - /// * `params` - Optional opaque account selection or compatibility GitHub token used to list models. + /// Wire method: `sandbox.getDocsUrl`. /// /// # Returns /// - /// List of Copilot models available to the resolved user, including capabilities and billing metadata. + /// The documentation URL a host cites when it declines or downgrades a sandbox setting. /// ///
/// @@ -3426,22 +4928,22 @@ impl<'a> ClientRpcModels<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn list_with_params(&self, params: ModelsListRequest) -> Result { - let wire_params = serde_json::to_value(params)?; + pub(crate) async fn get_docs_url(&self) -> Result { + let wire_params = serde_json::json!({}); let _value = self .client - .call(rpc_methods::MODELS_LIST, Some(wire_params)) + .call(rpc_methods::SANDBOX_GETDOCSURL, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Returns the running runtime's complete catalog of well-known built-in model IDs without authentication or network access. + /// Reports whether the host running this runtime can run the command sandbox, without starting a session or spawning a sandboxed command. /// - /// Wire method: `models.getBuiltInCatalog`. + /// Wire method: `sandbox.getHostSupport`. /// /// # Returns /// - /// The running runtime's complete catalog of well-known built-in model IDs, including supported models and additional IDs with built-in metadata. + /// Whether the host running this runtime can run the command sandbox. The runtime checks `supported` once per process. A capability answer can change while the process runs, for example after the user installs a missing package. /// ///
/// @@ -3450,44 +4952,30 @@ impl<'a> ClientRpcModels<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn get_built_in_catalog(&self) -> Result { + pub async fn get_host_support(&self) -> Result { let wire_params = serde_json::json!({}); let _value = self .client - .call(rpc_methods::MODELS_GETBUILTINCATALOG, Some(wire_params)) + .call(rpc_methods::SANDBOX_GETHOSTSUPPORT, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } } -/// `plugins.*` RPCs. +/// `sandbox.proxyCa.*` RPCs. #[derive(Clone, Copy)] -pub struct ClientRpcPlugins<'a> { +pub struct ClientRpcSandboxProxyCa<'a> { pub(crate) client: &'a Client, } -impl<'a> ClientRpcPlugins<'a> { - /// `plugins.builtin.*` sub-namespace. - pub fn builtin(&self) -> ClientRpcPluginsBuiltin<'a> { - ClientRpcPluginsBuiltin { - client: self.client, - } - } - - /// `plugins.marketplaces.*` sub-namespace. - pub fn marketplaces(&self) -> ClientRpcPluginsMarketplaces<'a> { - ClientRpcPluginsMarketplaces { - client: self.client, - } - } - - /// Lists plugins installed in user/global state. +impl<'a> ClientRpcSandboxProxyCa<'a> { + /// Reports whether this runtime process can offer installing the sandbox credential-proxy certificate authority into OS trust. /// - /// Wire method: `plugins.list`. + /// Wire method: `sandbox.proxyCa.checkInstallationSupport`. /// /// # Returns /// - /// Plugins installed in user/global state. + /// True when this process can offer installing the sandbox credential-proxy certificate authority into OS trust. /// ///
/// @@ -3496,26 +4984,31 @@ impl<'a> ClientRpcPlugins<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn list(&self) -> Result { + pub async fn check_installation_support( + &self, + ) -> Result { let wire_params = serde_json::json!({}); let _value = self .client - .call(rpc_methods::PLUGINS_LIST, Some(wire_params)) + .call( + rpc_methods::SANDBOX_PROXYCA_CHECKINSTALLATIONSUPPORT, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Installs a plugin from a marketplace, GitHub repo, URL, or local path. + /// Reports whether this sandbox configuration uses the credential proxy and can need certificate-authority setup. /// - /// Wire method: `plugins.install`. + /// Wire method: `sandbox.proxyCa.checkRelevance`. /// /// # Parameters /// - /// * `params` - Plugin source and optional working directory for relative-path resolution. + /// * `params` - Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. /// /// # Returns /// - /// Result of installing a plugin. + /// True when the sandbox configuration uses the credential proxy and can need certificate-authority setup. /// ///
/// @@ -3524,25 +5017,32 @@ impl<'a> ClientRpcPlugins<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn install( + pub async fn check_relevance( &self, - params: PluginsInstallRequest, - ) -> Result { + params: SandboxProxyCaRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::PLUGINS_INSTALL, Some(wire_params)) + .call( + rpc_methods::SANDBOX_PROXYCA_CHECKRELEVANCE, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Uninstalls an installed plugin. + /// Reports whether the persistent certificate authority of the sandbox credential proxy exists, whether OS trust includes it, and whether it must be rotated. Changes nothing. /// - /// Wire method: `plugins.uninstall`. + /// Wire method: `sandbox.proxyCa.getStatus`. /// /// # Parameters /// - /// * `params` - Name (or spec) of the plugin to uninstall. + /// * `params` - Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. + /// + /// # Returns + /// + /// Status of the persistent certificate authority of the sandbox credential proxy. /// ///
/// @@ -3551,26 +5051,29 @@ impl<'a> ClientRpcPlugins<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn uninstall(&self, params: PluginsUninstallRequest) -> Result<(), Error> { + pub async fn get_status( + &self, + params: SandboxProxyCaRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::PLUGINS_UNINSTALL, Some(wire_params)) + .call(rpc_methods::SANDBOX_PROXYCA_GETSTATUS, Some(wire_params)) .await?; - Ok(()) + Ok(serde_json::from_value(_value)?) } - /// Updates an installed plugin to its latest published version. + /// Creates the persistent certificate authority of the sandbox credential proxy if none is stored, without changing OS trust, and returns the path of its public certificate. Keeps an existing certificate authority, even one that must be rotated. Fails where OS trust is unsupported. Trust it with sandbox.proxyCa.trust: the CLI trusts only the hosts in the saved user settings, so it refuses a certificate authority that also covers hosts from sandboxConfig. /// - /// Wire method: `plugins.update`. + /// Wire method: `sandbox.proxyCa.create`. /// /// # Parameters /// - /// * `params` - Name (or spec) of the plugin to update. + /// * `params` - Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. /// /// # Returns /// - /// Result of updating a single plugin. + /// Result of creating the persistent certificate authority of the sandbox credential proxy. /// ///
/// @@ -3579,22 +5082,29 @@ impl<'a> ClientRpcPlugins<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn update(&self, params: PluginsUpdateRequest) -> Result { + pub async fn create( + &self, + params: SandboxProxyCaRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::PLUGINS_UPDATE, Some(wire_params)) + .call(rpc_methods::SANDBOX_PROXYCA_CREATE, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Updates every installed plugin to its latest published version. + /// Replaces the persistent certificate authority of the sandbox credential proxy with a new one for the current credential hosts. If OS trust included the old one, removes it and trusts the new one, which can show an OS authentication prompt. Running sandboxed tools keep the old certificate authority until they restart. /// - /// Wire method: `plugins.updateAll`. + /// Wire method: `sandbox.proxyCa.rotate`. + /// + /// # Parameters + /// + /// * `params` - Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. /// /// # Returns /// - /// Result of updating all installed plugins. + /// Status of the persistent certificate authority of the sandbox credential proxy. /// ///
/// @@ -3603,22 +5113,29 @@ impl<'a> ClientRpcPlugins<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn update_all(&self) -> Result { - let wire_params = serde_json::json!({}); + pub async fn rotate( + &self, + params: SandboxProxyCaRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::PLUGINS_UPDATEALL, Some(wire_params)) + .call(rpc_methods::SANDBOX_PROXYCA_ROTATE, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Enables installed plugins for new sessions. + /// Adds the persistent certificate authority of the sandbox credential proxy to OS trust, so sandboxed clients that read only OS trust accept the proxy. Call create first. Refuses a certificate authority that is not constrained to the current credential hosts. Can show an OS authentication prompt. /// - /// Wire method: `plugins.enable`. + /// Wire method: `sandbox.proxyCa.trust`. /// /// # Parameters /// - /// * `params` - Plugin names (or specs) to enable, plus the optional working directory the repository-controlled guard is evaluated against. + /// * `params` - Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. + /// + /// # Returns + /// + /// Status of the persistent certificate authority of the sandbox credential proxy. /// ///
/// @@ -3627,22 +5144,25 @@ impl<'a> ClientRpcPlugins<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn enable(&self, params: PluginsEnableRequest) -> Result<(), Error> { + pub async fn trust( + &self, + params: SandboxProxyCaRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::PLUGINS_ENABLE, Some(wire_params)) + .call(rpc_methods::SANDBOX_PROXYCA_TRUST, Some(wire_params)) .await?; - Ok(()) + Ok(serde_json::from_value(_value)?) } - /// Disables installed plugins for new sessions. + /// Removes the persistent certificate authority of the sandbox credential proxy from OS trust. Keeps the stored certificate authority. Can show an OS authentication prompt. Sandboxed clients that read only OS trust then reject the proxy; clients that read the per-process certificate bundle continue to work. /// - /// Wire method: `plugins.disable`. + /// Wire method: `sandbox.proxyCa.remove`. /// - /// # Parameters + /// # Returns /// - /// * `params` - Plugin names (or specs) to disable, plus the optional working directory the repository-controlled guard is evaluated against. + /// Status of the persistent certificate authority of the sandbox credential proxy. /// ///
/// @@ -3651,30 +5171,30 @@ impl<'a> ClientRpcPlugins<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn disable(&self, params: PluginsDisableRequest) -> Result<(), Error> { - let wire_params = serde_json::to_value(params)?; + pub async fn remove(&self) -> Result { + let wire_params = serde_json::json!({}); let _value = self .client - .call(rpc_methods::PLUGINS_DISABLE, Some(wire_params)) + .call(rpc_methods::SANDBOX_PROXYCA_REMOVE, Some(wire_params)) .await?; - Ok(()) + Ok(serde_json::from_value(_value)?) } } -/// `plugins.builtin.*` RPCs. +/// `sandbox.proxySecret.*` RPCs. #[derive(Clone, Copy)] -pub struct ClientRpcPluginsBuiltin<'a> { +pub struct ClientRpcSandboxProxySecret<'a> { pub(crate) client: &'a Client, } -impl<'a> ClientRpcPluginsBuiltin<'a> { - /// Replaces this server's trusted built-in plugin directories while no sessions are active. +impl<'a> ClientRpcSandboxProxySecret<'a> { + /// Reports where this runtime keeps the sandbox proxy password: the credential store directory and the entry identifier within it. Both are derived from the configuration directory this runtime was started with, so a host does not resolve them itself. Read this to recognize a `${secret:…}` value in stored sandbox settings as this runtime's own proxy password rather than a reference the user wrote by hand. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. /// - /// Wire method: `plugins.builtin.set`. + /// Wire method: `sandbox.proxySecret.getLocation`. /// - /// # Parameters + /// # Returns /// - /// * `params` - Trusted built-in plugin directories to use for this runtime process. + /// Where this runtime keeps the sandbox proxy password. /// ///
/// @@ -3683,30 +5203,25 @@ impl<'a> ClientRpcPluginsBuiltin<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn set(&self, params: PluginsBuiltinSetRequest) -> Result<(), Error> { - let wire_params = serde_json::to_value(params)?; + pub(crate) async fn get_location(&self) -> Result { + let wire_params = serde_json::json!({}); let _value = self .client - .call(rpc_methods::PLUGINS_BUILTIN_SET, Some(wire_params)) + .call( + rpc_methods::SANDBOX_PROXYSECRET_GETLOCATION, + Some(wire_params), + ) .await?; - Ok(()) + Ok(serde_json::from_value(_value)?) } -} - -/// `plugins.marketplaces.*` RPCs. -#[derive(Clone, Copy)] -pub struct ClientRpcPluginsMarketplaces<'a> { - pub(crate) client: &'a Client, -} -impl<'a> ClientRpcPluginsMarketplaces<'a> { - /// Lists all registered marketplaces (defaults + user-added). + /// Reads the stored sandbox proxy password from the credential store `sandbox.proxySecret.getLocation` names, preferring the OS keychain and falling back to the on-disk store. Reports an absent value rather than failing when no entry exists. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. /// - /// Wire method: `plugins.marketplaces.list`. + /// Wire method: `sandbox.proxySecret.get`. /// /// # Returns /// - /// All registered marketplaces, including built-in defaults. + /// The stored sandbox proxy password, if one is present. /// ///
/// @@ -3715,26 +5230,26 @@ impl<'a> ClientRpcPluginsMarketplaces<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn list(&self) -> Result { + pub(crate) async fn get(&self) -> Result { let wire_params = serde_json::json!({}); let _value = self .client - .call(rpc_methods::PLUGINS_MARKETPLACES_LIST, Some(wire_params)) + .call(rpc_methods::SANDBOX_PROXYSECRET_GET, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Registers a new marketplace from a source (owner/repo, URL, or local path). + /// Stores the sandbox proxy password in the credential store `sandbox.proxySecret.getLocation` names, replacing any existing entry. Reports whether the OS keychain accepted it or it fell back to the on-disk store. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. /// - /// Wire method: `plugins.marketplaces.add`. + /// Wire method: `sandbox.proxySecret.save`. /// /// # Parameters /// - /// * `params` - Marketplace source and optional working directory for relative-path resolution. + /// * `params` - The sandbox proxy password to store. /// /// # Returns /// - /// Result of registering a new marketplace. + /// Where the sandbox proxy password was stored. /// ///
/// @@ -3743,29 +5258,21 @@ impl<'a> ClientRpcPluginsMarketplaces<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn add( + pub(crate) async fn save( &self, - params: PluginsMarketplacesAddRequest, - ) -> Result { + params: SandboxProxySecretSaveRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::PLUGINS_MARKETPLACES_ADD, Some(wire_params)) + .call(rpc_methods::SANDBOX_PROXYSECRET_SAVE, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Removes a previously-registered marketplace. When the marketplace has dependent plugins and `force` is not set, the marketplace is left intact and the result lists the dependents so the caller can decide whether to retry with `force=true`. - /// - /// Wire method: `plugins.marketplaces.remove`. - /// - /// # Parameters - /// - /// * `params` - Name of the marketplace to remove and an optional force flag. + /// Removes the stored sandbox proxy password from the credential store `sandbox.proxySecret.getLocation` names. Succeeds when no entry exists, so it is safe to call while clearing a proxy password whose origin is unknown. Marked internal because it exists to carry a CLI call site off the napi boundary onto the SDK contract. /// - /// # Returns - /// - /// Outcome of the remove attempt, including dependent-plugin info when applicable. + /// Wire method: `sandbox.proxySecret.delete`. /// ///
/// @@ -3774,29 +5281,34 @@ impl<'a> ClientRpcPluginsMarketplaces<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn remove( - &self, - params: PluginsMarketplacesRemoveRequest, - ) -> Result { - let wire_params = serde_json::to_value(params)?; + pub(crate) async fn delete(&self) -> Result<(), Error> { + let wire_params = serde_json::json!({}); let _value = self .client - .call(rpc_methods::PLUGINS_MARKETPLACES_REMOVE, Some(wire_params)) + .call(rpc_methods::SANDBOX_PROXYSECRET_DELETE, Some(wire_params)) .await?; - Ok(serde_json::from_value(_value)?) + Ok(()) } +} - /// Lists plugins advertised by a registered marketplace. +/// `sandbox.settings.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcSandboxSettings<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcSandboxSettings<'a> { + /// Resolves a stored sandbox settings object into the effective one, filling every value the user left unset with its default. Read this to render or reason about the sandbox configuration a session would actually run under, rather than the sparse document the user wrote. /// - /// Wire method: `plugins.marketplaces.browse`. + /// Wire method: `sandbox.settings.applyDefaults`. /// /// # Parameters /// - /// * `params` - Name of the marketplace whose plugin catalog to fetch. + /// * `params` - The stored sandbox settings to resolve against the defaults. /// /// # Returns /// - /// Plugins advertised by the marketplace. + /// The effective sandbox settings, with every unset value resolved to its default. /// ///
/// @@ -3805,25 +5317,40 @@ impl<'a> ClientRpcPluginsMarketplaces<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn browse( + pub(crate) async fn apply_defaults( &self, - params: PluginsMarketplacesBrowseRequest, - ) -> Result { + params: SandboxApplyDefaultsRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::PLUGINS_MARKETPLACES_BROWSE, Some(wire_params)) + .call( + rpc_methods::SANDBOX_SETTINGS_APPLYDEFAULTS, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } +} - /// Re-fetches one or all registered marketplace catalogs. +/// `secrets.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcSecrets<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcSecrets<'a> { + /// Registers secret values for redaction in session logs and exports. The SDK calls this to inject dynamically generated secret values (e.g., OIDC tokens). /// - /// Wire method: `plugins.marketplaces.refresh`. + /// Wire method: `secrets.addFilterValues`. + /// + /// # Parameters + /// + /// * `params` - Secret values to add to the redaction filter. /// /// # Returns /// - /// Result of refreshing one or more marketplace catalogs. + /// Confirmation that the secret values were registered. /// ///
/// @@ -3832,26 +5359,37 @@ impl<'a> ClientRpcPluginsMarketplaces<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn refresh(&self) -> Result { - let wire_params = serde_json::json!({}); + pub async fn add_filter_values( + &self, + params: SecretsAddFilterValuesRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::PLUGINS_MARKETPLACES_REFRESH, Some(wire_params)) + .call(rpc_methods::SECRETS_ADDFILTERVALUES, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } +} - /// Re-fetches one or all registered marketplace catalogs. +/// `sessionFs.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcSessionFs<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcSessionFs<'a> { + /// Registers an SDK client as the session filesystem provider. /// - /// Wire method: `plugins.marketplaces.refresh`. + /// Wire method: `sessionFs.setProvider`. /// /// # Parameters /// - /// * `params` - Optional marketplace name; omit to refresh all. + /// * `params` - Initial working directory, session-state path layout, and path conventions used to register the calling SDK client as the session filesystem provider. A registered provider is authoritative for path interpretation and filesystem facts used by workspace permission validation. Paths are interpreted lexically; home-relative paths (`~` and `~/...`) and Windows drive-relative paths such as `C:foo` are unsupported. Until provider-side canonicalization is supported, providers must not expose symlinks inside allowed roots that escape those roots. /// /// # Returns /// - /// Result of refreshing one or more marketplace catalogs. + /// Indicates whether the calling client was registered as the session filesystem provider. /// ///
/// @@ -3860,52 +5398,61 @@ impl<'a> ClientRpcPluginsMarketplaces<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn refresh_with_params( + pub async fn set_provider( &self, - params: PluginsMarketplacesRefreshRequest, - ) -> Result { + params: SessionFsSetProviderRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::PLUGINS_MARKETPLACES_REFRESH, Some(wire_params)) + .call(rpc_methods::SESSIONFS_SETPROVIDER, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } } -/// `repo.*` RPCs. +/// `sessions.*` RPCs. #[derive(Clone, Copy)] -pub struct ClientRpcRepo<'a> { +pub struct ClientRpcSessions<'a> { pub(crate) client: &'a Client, } -impl<'a> ClientRpcRepo<'a> { - /// `repo.settings.*` sub-namespace. - pub fn settings(&self) -> ClientRpcRepoSettings<'a> { - ClientRpcRepoSettings { - client: self.client, - } +impl<'a> ClientRpcSessions<'a> { + /// Creates or resumes a local session and returns the opened session ID. + /// + /// Wire method: `sessions.open`. + /// + /// # Returns + /// + /// Result of opening a session. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn open(&self) -> Result { + let wire_params = serde_json::json!({}); + let _value = self + .client + .call(rpc_methods::SESSIONS_OPEN, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) } -} - -/// `repo.settings.*` RPCs. -#[derive(Clone, Copy)] -pub struct ClientRpcRepoSettings<'a> { - pub(crate) client: &'a Client, -} -impl<'a> ClientRpcRepoSettings<'a> { - /// Reads one repository settings file without settings normalization or layering. The existing JSONC parser accepts comments and trailing commas and applies its prototype-safety rules. Missing or blank files return an empty valid config. Invalid files return an empty config with invalid=true; other read failures reject. + /// Creates a new session by forking persisted history from an existing session. /// - /// Wire method: `repo.settings.readRaw`. + /// Wire method: `sessions.fork`. /// /// # Parameters /// - /// * `params` - Which repository settings file to read. + /// * `params` - Source session identifier to fork from, optional event-ID boundary, and optional friendly name for the new session. /// /// # Returns /// - /// Parsed repository settings without normalization or layering. + /// Identifier and optional friendly name assigned to the newly forked session. /// ///
/// @@ -3914,25 +5461,26 @@ impl<'a> ClientRpcRepoSettings<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub(crate) async fn read_raw( - &self, - params: RepoSettingsReadRawRequest, - ) -> Result { + pub async fn fork(&self, params: SessionsForkRequest) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::REPO_SETTINGS_READRAW, Some(wire_params)) + .call(rpc_methods::SESSIONS_FORK, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Writes or removes one allowed top-level repository setting through the existing validator and file lock. Preserves unrelated stored keys. Invalid keys, values, existing documents, and I/O errors reject without replacing the file. Deletion requires delete=true; otherwise value must be present. + /// Connects to an existing remote session and exposes it as an SDK session. /// - /// Wire method: `repo.settings.writeKey`. + /// Wire method: `sessions.connect`. /// /// # Parameters /// - /// * `params` - One key to write or remove in a repository settings file. + /// * `params` - Remote session connection parameters. + /// + /// # Returns + /// + /// Remote session connection result. /// ///
/// @@ -3941,22 +5489,25 @@ impl<'a> ClientRpcRepoSettings<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub(crate) async fn write_key(&self, params: RepoSettingsWriteKeyRequest) -> Result<(), Error> { + pub async fn connect( + &self, + params: ConnectRemoteSessionParams, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::REPO_SETTINGS_WRITEKEY, Some(wire_params)) + .call(rpc_methods::SESSIONS_CONNECT, Some(wire_params)) .await?; - Ok(()) + Ok(serde_json::from_value(_value)?) } - /// Replaces the repository-overridable settings in one locked write. Allowed keys present in settings are validated and written; allowed keys absent from settings are removed. Other input keys are ignored, and unknown keys already stored in the file remain unchanged. Invalid values or an invalid existing file reject without a partial write. + /// Lists sessions, optionally filtered by source and working-directory context. Returned entries are discriminated by `isRemote`: local entries carry only the lightweight `LocalSessionMetadataValue` shape; remote entries carry the full `RemoteSessionMetadataValue` shape (repository, PR number, taskType, etc.). /// - /// Wire method: `repo.settings.writeAll`. + /// Wire method: `sessions.list`. /// - /// # Parameters + /// # Returns /// - /// * `params` - The complete set of repository-overridable settings to store. + /// Sessions matching the filter, ordered most-recently-modified first. /// ///
/// @@ -3965,26 +5516,26 @@ impl<'a> ClientRpcRepoSettings<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub(crate) async fn write_all(&self, params: RepoSettingsWriteAllRequest) -> Result<(), Error> { - let wire_params = serde_json::to_value(params)?; + pub async fn list(&self) -> Result { + let wire_params = serde_json::json!({}); let _value = self .client - .call(rpc_methods::REPO_SETTINGS_WRITEALL, Some(wire_params)) + .call(rpc_methods::SESSIONS_LIST, Some(wire_params)) .await?; - Ok(()) + Ok(serde_json::from_value(_value)?) } -} - -/// `runtime.*` RPCs. -#[derive(Clone, Copy)] -pub struct ClientRpcRuntime<'a> { - pub(crate) client: &'a Client, -} -impl<'a> ClientRpcRuntime<'a> { - /// Gracefully shuts down an SDK-owned runtime. The response is sent only after cleanup completes; callers may then terminate the owned runtime process. + /// Lists sessions, optionally filtered by source and working-directory context. Returned entries are discriminated by `isRemote`: local entries carry only the lightweight `LocalSessionMetadataValue` shape; remote entries carry the full `RemoteSessionMetadataValue` shape (repository, PR number, taskType, etc.). /// - /// Wire method: `runtime.shutdown`. + /// Wire method: `sessions.list`. + /// + /// # Parameters + /// + /// * `params` - Optional source filter, metadata-load limit, and context filter applied to the returned sessions. + /// + /// # Returns + /// + /// Sessions matching the filter, ordered most-recently-modified first. /// ///
/// @@ -3993,37 +5544,29 @@ impl<'a> ClientRpcRuntime<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn shutdown(&self) -> Result<(), Error> { - let wire_params = serde_json::json!({}); + pub async fn list_with_params( + &self, + params: SessionsListRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::RUNTIME_SHUTDOWN, Some(wire_params)) + .call(rpc_methods::SESSIONS_LIST, Some(wire_params)) .await?; - Ok(()) - } -} - -/// `sandbox.*` RPCs. -#[derive(Clone, Copy)] -pub struct ClientRpcSandbox<'a> { - pub(crate) client: &'a Client, -} - -impl<'a> ClientRpcSandbox<'a> { - /// `sandbox.proxyCa.*` sub-namespace. - pub fn proxy_ca(&self) -> ClientRpcSandboxProxyCa<'a> { - ClientRpcSandboxProxyCa { - client: self.client, - } + Ok(serde_json::from_value(_value)?) } - /// Reports whether the host running this runtime can run the command sandbox, without starting a session or spawning a sandboxed command. + /// Reads lightweight persisted metadata for one local session without opening it. /// - /// Wire method: `sandbox.getHostSupport`. + /// Wire method: `sessions.getMetadata`. + /// + /// # Parameters + /// + /// * `params` - Session ID whose persisted metadata should be read. /// /// # Returns /// - /// Whether the host running this runtime can run the command sandbox. The runtime checks `supported` once per process. A capability answer can change while the process runs, for example after the user installs a missing package. + /// Persisted local session metadata when the session exists. /// ///
/// @@ -4032,34 +5575,29 @@ impl<'a> ClientRpcSandbox<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn get_host_support(&self) -> Result { - let wire_params = serde_json::json!({}); + pub(crate) async fn get_metadata( + &self, + params: SessionsGetMetadataRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SANDBOX_GETHOSTSUPPORT, Some(wire_params)) + .call(rpc_methods::SESSIONS_GETMETADATA, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } -} - -/// `sandbox.proxyCa.*` RPCs. -#[derive(Clone, Copy)] -pub struct ClientRpcSandboxProxyCa<'a> { - pub(crate) client: &'a Client, -} -impl<'a> ClientRpcSandboxProxyCa<'a> { - /// Reports whether the persistent certificate authority of the sandbox credential proxy exists, whether OS trust includes it, and whether it must be rotated. Changes nothing. + /// Reads client-owned metadata for multiple persisted local sessions without opening them. Results preserve request order and report missing, corrupt, unsupported, or temporarily unavailable sessions independently. /// - /// Wire method: `sandbox.proxyCa.getStatus`. + /// Wire method: `sessions.getClientMetadata`. /// /// # Parameters /// - /// * `params` - Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. + /// * `params` - Bounded batch request for client-owned metadata from persisted local sessions. /// /// # Returns /// - /// Status of the persistent certificate authority of the sandbox credential proxy. + /// Ordered client metadata outcomes for the requested local sessions. /// ///
/// @@ -4068,29 +5606,29 @@ impl<'a> ClientRpcSandboxProxyCa<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn get_status( + pub async fn get_client_metadata( &self, - params: SandboxProxyCaRequest, - ) -> Result { + params: SessionsGetClientMetadataRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SANDBOX_PROXYCA_GETSTATUS, Some(wire_params)) + .call(rpc_methods::SESSIONS_GETCLIENTMETADATA, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Creates the persistent certificate authority of the sandbox credential proxy if none is stored, without changing OS trust, and returns the path of its public certificate. Keeps an existing certificate authority, even one that must be rotated. Fails where OS trust is unsupported. Trust it with sandbox.proxyCa.trust: the CLI trusts only the hosts in the saved user settings, so it refuses a certificate authority that also covers hosts from sandboxConfig. + /// Reads a page of durable events directly from a local session's persisted journal without creating, resuming, or activating the session. The first read pins the currently opened journal generation and its byte-length boundary; opaque cursor continuations remain on that generation across runtime-owned compaction, truncation, and rewrite operations, which replace the live path atomically, and events appended after the boundary are excluded. For cold hydration, await the first successful page before activation and establish lossless live-event buffering before resume; merge subsequent live events by ID, preserving persisted order and letting live payloads win. Continuations are process-local, single-use capabilities bound to the originating session and storage context and must be paged sequentially; concurrent or repeated use of the same cursor expires that duplicate read rather than reading the generation twice. A complete snapshot has cursorStatus 'ok' and hasMore false. Snapshots expire after five idle minutes, with at most eight retained per process and idle-only eviction under pressure; completion and cancelled-worker exit release their handles. No transcript copy is created, but retained handles may keep replaced files' disk blocks alive until release. Pages have a soft 1 MiB serialized event-array budget including resolved binary assets; one oversized event is returned alone to guarantee progress. Working memory also includes a record/lookahead and asset resolution; resolving the first binary reference may scan the full pinned generation to build a bounded offset index. If the snapshot expires, is evicted, is cancelled before a continuation is established, or becomes unreadable after an observable unsupported in-place shortening, the continuation returns cursorStatus 'expired' with an empty terminal page and never falls back to a different generation. A missing or initially unreadable journal is an RPC error. Persisted history excludes ephemeral events and may omit payloads that are reconstructed only for an active session; use the active session event stream for post-resume live events. /// - /// Wire method: `sandbox.proxyCa.create`. + /// Wire method: `sessions.readPersistedEvents`. /// /// # Parameters /// - /// * `params` - Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. + /// * `params` - Pagination options for reading an inactive or active local session's persisted event journal. /// /// # Returns /// - /// Result of creating the persistent certificate authority of the sandbox credential proxy. + /// Batch of session events returned by a read, with cursor and continuation metadata. /// ///
/// @@ -4099,29 +5637,29 @@ impl<'a> ClientRpcSandboxProxyCa<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn create( + pub async fn read_persisted_events( &self, - params: SandboxProxyCaRequest, - ) -> Result { + params: SessionsReadPersistedEventsRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SANDBOX_PROXYCA_CREATE, Some(wire_params)) + .call(rpc_methods::SESSIONS_READPERSISTEDEVENTS, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Replaces the persistent certificate authority of the sandbox credential proxy with a new one for the current credential hosts. If OS trust included the old one, removes it and trusts the new one, which can show an OS authentication prompt. Running sandboxed tools keep the old certificate authority until they restart. + /// Lists recent local session IDs that contain user-visible history, omitting housekeeping-only sessions. /// - /// Wire method: `sandbox.proxyCa.rotate`. + /// Wire method: `sessions.listNonEmptySessionIds`. /// /// # Parameters /// - /// * `params` - Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. + /// * `params` - Limit for non-empty local session IDs. /// /// # Returns /// - /// Status of the persistent certificate authority of the sandbox credential proxy. + /// Recent local session IDs that contain user-visible history. /// ///
/// @@ -4130,29 +5668,32 @@ impl<'a> ClientRpcSandboxProxyCa<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn rotate( + pub(crate) async fn list_non_empty_session_ids( &self, - params: SandboxProxyCaRequest, - ) -> Result { + params: SessionsListNonEmptySessionIdsRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SANDBOX_PROXYCA_ROTATE, Some(wire_params)) + .call( + rpc_methods::SESSIONS_LISTNONEMPTYSESSIONIDS, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Adds the persistent certificate authority of the sandbox credential proxy to OS trust, so sandboxed clients that read only OS trust accept the proxy. Call create first. Refuses a certificate authority that is not constrained to the current credential hosts. Can show an OS authentication prompt. + /// Finds the local session bound to a GitHub task ID, if any. /// - /// Wire method: `sandbox.proxyCa.trust`. + /// Wire method: `sessions.findByTaskId`. /// /// # Parameters /// - /// * `params` - Identifies the credential hosts that the persistent certificate authority of the sandbox credential proxy must cover. The runtime always adds the hosts from the saved user settings. + /// * `params` - GitHub task ID to look up. /// /// # Returns /// - /// Status of the persistent certificate authority of the sandbox credential proxy. + /// ID of the local session bound to the given GitHub task, or omitted when none. /// ///
/// @@ -4161,25 +5702,29 @@ impl<'a> ClientRpcSandboxProxyCa<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn trust( + pub async fn find_by_task_id( &self, - params: SandboxProxyCaRequest, - ) -> Result { + params: SessionsFindByTaskIDRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SANDBOX_PROXYCA_TRUST, Some(wire_params)) + .call(rpc_methods::SESSIONS_FINDBYTASKID, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Removes the persistent certificate authority of the sandbox credential proxy from OS trust. Keeps the stored certificate authority. Can show an OS authentication prompt. Sandboxed clients that read only OS trust then reject the proxy; clients that read the per-process certificate bundle continue to work. + /// Resolves a UUID prefix to a unique session ID, if exactly one session matches. /// - /// Wire method: `sandbox.proxyCa.remove`. + /// Wire method: `sessions.findByPrefix`. + /// + /// # Parameters + /// + /// * `params` - UUID prefix to resolve to a unique session ID. /// /// # Returns /// - /// Status of the persistent certificate authority of the sandbox credential proxy. + /// Session ID matching the prefix, omitted when no unique match exists. /// ///
/// @@ -4188,34 +5733,29 @@ impl<'a> ClientRpcSandboxProxyCa<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn remove(&self) -> Result { - let wire_params = serde_json::json!({}); + pub async fn find_by_prefix( + &self, + params: SessionsFindByPrefixRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SANDBOX_PROXYCA_REMOVE, Some(wire_params)) + .call(rpc_methods::SESSIONS_FINDBYPREFIX, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } -} - -/// `secrets.*` RPCs. -#[derive(Clone, Copy)] -pub struct ClientRpcSecrets<'a> { - pub(crate) client: &'a Client, -} -impl<'a> ClientRpcSecrets<'a> { - /// Registers secret values for redaction in session logs and exports. The SDK calls this to inject dynamically generated secret values (e.g., OIDC tokens). + /// Returns the most-relevant prior session for a given working-directory context. /// - /// Wire method: `secrets.addFilterValues`. + /// Wire method: `sessions.getLastForContext`. /// /// # Parameters /// - /// * `params` - Secret values to add to the redaction filter. + /// * `params` - Optional working-directory context used to score session relevance. /// /// # Returns /// - /// Confirmation that the secret values were registered. + /// Most-relevant session ID for the supplied context, or omitted when no sessions exist. /// ///
/// @@ -4224,37 +5764,29 @@ impl<'a> ClientRpcSecrets<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn add_filter_values( + pub async fn get_last_for_context( &self, - params: SecretsAddFilterValuesRequest, - ) -> Result { + params: SessionsGetLastForContextRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SECRETS_ADDFILTERVALUES, Some(wire_params)) + .call(rpc_methods::SESSIONS_GETLASTFORCONTEXT, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } -} - -/// `sessionFs.*` RPCs. -#[derive(Clone, Copy)] -pub struct ClientRpcSessionFs<'a> { - pub(crate) client: &'a Client, -} -impl<'a> ClientRpcSessionFs<'a> { - /// Registers an SDK client as the session filesystem provider. + /// Computes the absolute path to a session's persisted events.jsonl file. Internal: filesystem paths are only meaningful in-process (CLI and runtime share a filesystem). Currently used by the CLI's contribution-graph feature to read historical events directly. Remote SDK consumers must not depend on this; a proper event-query API would replace it if the contribution graph ever needed to work over the wire. /// - /// Wire method: `sessionFs.setProvider`. + /// Wire method: `sessions.getEventFilePath`. /// /// # Parameters /// - /// * `params` - Initial working directory, session-state path layout, and path conventions used to register the calling SDK client as the session filesystem provider. A registered provider is authoritative for path interpretation and filesystem facts used by workspace permission validation. Paths are interpreted lexically; home-relative paths (`~` and `~/...`) and Windows drive-relative paths such as `C:foo` are unsupported. Until provider-side canonicalization is supported, providers must not expose symlinks inside allowed roots that escape those roots. + /// * `params` - Session ID whose event-log file path to compute. /// /// # Returns /// - /// Indicates whether the calling client was registered as the session filesystem provider. + /// Absolute path to the session's events.jsonl file on disk. /// ///
/// @@ -4263,33 +5795,25 @@ impl<'a> ClientRpcSessionFs<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn set_provider( + pub(crate) async fn get_event_file_path( &self, - params: SessionFsSetProviderRequest, - ) -> Result { + params: SessionsGetEventFilePathRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONFS_SETPROVIDER, Some(wire_params)) + .call(rpc_methods::SESSIONS_GETEVENTFILEPATH, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } -} - -/// `sessions.*` RPCs. -#[derive(Clone, Copy)] -pub struct ClientRpcSessions<'a> { - pub(crate) client: &'a Client, -} -impl<'a> ClientRpcSessions<'a> { - /// Creates or resumes a local session and returns the opened session ID. + /// Returns the on-disk byte size of each session's workspace directory. /// - /// Wire method: `sessions.open`. + /// Wire method: `sessions.getSizes`. /// /// # Returns /// - /// Result of opening a session. + /// Map of sessionId -> on-disk size in bytes for each session's workspace directory. /// ///
/// @@ -4298,26 +5822,26 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn open(&self) -> Result { + pub async fn get_sizes(&self) -> Result { let wire_params = serde_json::json!({}); let _value = self .client - .call(rpc_methods::SESSIONS_OPEN, Some(wire_params)) + .call(rpc_methods::SESSIONS_GETSIZES, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Creates a new session by forking persisted history from an existing session. + /// Returns the subset of the supplied session IDs that are currently held by another running process. /// - /// Wire method: `sessions.fork`. + /// Wire method: `sessions.checkInUse`. /// /// # Parameters /// - /// * `params` - Source session identifier to fork from, optional event-ID boundary, and optional friendly name for the new session. + /// * `params` - Session IDs to test for live in-use locks. /// /// # Returns /// - /// Identifier and optional friendly name assigned to the newly forked session. + /// Session IDs from the input set that are currently in use by another process. /// ///
/// @@ -4326,26 +5850,29 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn fork(&self, params: SessionsForkRequest) -> Result { + pub async fn check_in_use( + &self, + params: SessionsCheckInUseRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_FORK, Some(wire_params)) + .call(rpc_methods::SESSIONS_CHECKINUSE, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Connects to an existing remote session and exposes it as an SDK session. + /// Returns a session's persisted remote-steerable flag, if any has been recorded. Internal: this is CLI-specific book-keeping used by `--continue` / `--resume` to inherit the prior session's remote-steerable preference. SDK consumers that want similar behavior should manage their own persistence around start/stop calls rather than relying on this runtime-side flag. /// - /// Wire method: `sessions.connect`. + /// Wire method: `sessions.getPersistedRemoteSteerable`. /// /// # Parameters /// - /// * `params` - Remote session connection parameters. + /// * `params` - Session ID to look up the persisted remote-steerable flag for. /// /// # Returns /// - /// Remote session connection result. + /// The session's persisted remote-steerable flag, or omitted when no value has been persisted. /// ///
/// @@ -4354,25 +5881,32 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn connect( + pub(crate) async fn get_persisted_remote_steerable( &self, - params: ConnectRemoteSessionParams, - ) -> Result { + params: SessionsGetPersistedRemoteSteerableRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_CONNECT, Some(wire_params)) + .call( + rpc_methods::SESSIONS_GETPERSISTEDREMOTESTEERABLE, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Lists sessions, optionally filtered by source and working-directory context. Returned entries are discriminated by `isRemote`: local entries carry only the lightweight `LocalSessionMetadataValue` shape; remote entries carry the full `RemoteSessionMetadataValue` shape (repository, PR number, taskType, etc.). + /// Closes a session: emits shutdown, flushes pending events, releases the in-use lock, and disposes the active session. /// - /// Wire method: `sessions.list`. + /// Wire method: `sessions.close`. + /// + /// # Parameters + /// + /// * `params` - Session ID to close. /// /// # Returns /// - /// Sessions matching the filter, ordered most-recently-modified first. + /// Closes a session: emits shutdown, flushes pending events to disk, releases the in-use lock, disposes the active session. Idempotent: succeeds even if the session is not currently active. /// ///
/// @@ -4381,26 +5915,26 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn list(&self) -> Result { - let wire_params = serde_json::json!({}); + pub async fn close(&self, params: SessionsCloseRequest) -> Result { + let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_LIST, Some(wire_params)) + .call(rpc_methods::SESSIONS_CLOSE, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Lists sessions, optionally filtered by source and working-directory context. Returned entries are discriminated by `isRemote`: local entries carry only the lightweight `LocalSessionMetadataValue` shape; remote entries carry the full `RemoteSessionMetadataValue` shape (repository, PR number, taskType, etc.). + /// Closes, deactivates, and deletes a set of sessions, returning the bytes freed per session. /// - /// Wire method: `sessions.list`. + /// Wire method: `sessions.bulkDelete`. /// /// # Parameters /// - /// * `params` - Optional source filter, metadata-load limit, and context filter applied to the returned sessions. + /// * `params` - Session IDs to close, deactivate, and delete from disk. /// /// # Returns /// - /// Sessions matching the filter, ordered most-recently-modified first. + /// Map of sessionId -> bytes freed by removing the session's workspace directory. /// ///
/// @@ -4409,29 +5943,53 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn list_with_params( + pub async fn bulk_delete( &self, - params: SessionsListRequest, - ) -> Result { + params: SessionsBulkDeleteRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_LIST, Some(wire_params)) + .call(rpc_methods::SESSIONS_BULKDELETE, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Reads lightweight persisted metadata for one local session without opening it. + /// Deletes one local session from disk after running the same lifecycle hooks as the session manager. /// - /// Wire method: `sessions.getMetadata`. + /// Wire method: `sessions.delete`. /// /// # Parameters /// - /// * `params` - Session ID whose persisted metadata should be read. + /// * `params` - Session ID to delete from disk. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub(crate) async fn delete(&self, params: SessionsDeleteRequest) -> Result<(), Error> { + let wire_params = serde_json::to_value(params)?; + let _value = self + .client + .call(rpc_methods::SESSIONS_DELETE, Some(wire_params)) + .await?; + Ok(()) + } + + /// Deletes sessions older than the given threshold, with optional dry-run and exclusion list. + /// + /// Wire method: `sessions.pruneOld`. + /// + /// # Parameters + /// + /// * `params` - Age threshold and optional flags controlling which old sessions are pruned (or simulated when dryRun is true). /// /// # Returns /// - /// Persisted local session metadata when the session exists. + /// Outcome of the prune operation: deleted IDs, dry-run candidates, skipped IDs, total bytes freed, and the dry-run flag. /// ///
/// @@ -4440,29 +5998,29 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub(crate) async fn get_metadata( + pub async fn prune_old( &self, - params: SessionsGetMetadataRequest, - ) -> Result { + params: SessionsPruneOldRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_GETMETADATA, Some(wire_params)) + .call(rpc_methods::SESSIONS_PRUNEOLD, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Reads client-owned metadata for multiple persisted local sessions without opening them. Results preserve request order and report missing, corrupt, unsupported, or temporarily unavailable sessions independently. + /// Flushes a session's pending events to disk. /// - /// Wire method: `sessions.getClientMetadata`. + /// Wire method: `sessions.save`. /// /// # Parameters /// - /// * `params` - Bounded batch request for client-owned metadata from persisted local sessions. + /// * `params` - Session ID whose pending events should be flushed to disk. /// /// # Returns /// - /// Ordered client metadata outcomes for the requested local sessions. + /// Flush a session's pending events to disk. No-op when no writer exists for the session (e.g., already closed). /// ///
/// @@ -4471,29 +6029,26 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn get_client_metadata( - &self, - params: SessionsGetClientMetadataRequest, - ) -> Result { + pub async fn save(&self, params: SessionsSaveRequest) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_GETCLIENTMETADATA, Some(wire_params)) + .call(rpc_methods::SESSIONS_SAVE, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Reads a page of durable events directly from a local session's persisted journal without creating, resuming, or activating the session. The first read pins the currently opened journal generation and its byte-length boundary; opaque cursor continuations remain on that generation across runtime-owned compaction, truncation, and rewrite operations, which replace the live path atomically, and events appended after the boundary are excluded. For cold hydration, await the first successful page before activation and establish lossless live-event buffering before resume; merge subsequent live events by ID, preserving persisted order and letting live payloads win. Continuations are process-local, single-use capabilities bound to the originating session and storage context and must be paged sequentially; concurrent or repeated use of the same cursor expires that duplicate read rather than reading the generation twice. A complete snapshot has cursorStatus 'ok' and hasMore false. Snapshots expire after five idle minutes, with at most eight retained per process and idle-only eviction under pressure; completion and cancelled-worker exit release their handles. No transcript copy is created, but retained handles may keep replaced files' disk blocks alive until release. Pages have a soft 1 MiB serialized event-array budget including resolved binary assets; one oversized event is returned alone to guarantee progress. Working memory also includes a record/lookahead and asset resolution; resolving the first binary reference may scan the full pinned generation to build a bounded offset index. If the snapshot expires, is evicted, is cancelled before a continuation is established, or becomes unreadable after an observable unsupported in-place shortening, the continuation returns cursorStatus 'expired' with an empty terminal page and never falls back to a different generation. A missing or initially unreadable journal is an RPC error. Persisted history excludes ephemeral events and may omit payloads that are reconstructed only for an active session; use the active session event stream for post-resume live events. + /// Releases the in-use lock held by this process for a session. /// - /// Wire method: `sessions.readPersistedEvents`. + /// Wire method: `sessions.releaseLock`. /// /// # Parameters /// - /// * `params` - Pagination options for reading an inactive or active local session's persisted event journal. + /// * `params` - Session ID whose in-use lock should be released. /// /// # Returns /// - /// Batch of session events returned by a read, with cursor and continuation metadata. + /// Release the in-use lock held by this process for the given session. No-op when this process does not currently hold a lock for the session. /// ///
/// @@ -4502,29 +6057,29 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn read_persisted_events( + pub async fn release_lock( &self, - params: SessionsReadPersistedEventsRequest, - ) -> Result { + params: SessionsReleaseLockRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_READPERSISTEDEVENTS, Some(wire_params)) + .call(rpc_methods::SESSIONS_RELEASELOCK, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Lists recent local session IDs that contain user-visible history, omitting housekeeping-only sessions. + /// Backfills missing summary and context fields on the supplied session metadata records. /// - /// Wire method: `sessions.listNonEmptySessionIds`. + /// Wire method: `sessions.enrichMetadata`. /// /// # Parameters /// - /// * `params` - Limit for non-empty local session IDs. + /// * `params` - Session metadata records to enrich with summary and context information. /// /// # Returns /// - /// Recent local session IDs that contain user-visible history. + /// The enriched metadata records, with summary and context fields backfilled where available. Sessions confirmed empty and unnamed are omitted. /// ///
/// @@ -4533,32 +6088,29 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub(crate) async fn list_non_empty_session_ids( + pub async fn enrich_metadata( &self, - params: SessionsListNonEmptySessionIdsRequest, - ) -> Result { + params: SessionsEnrichMetadataRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call( - rpc_methods::SESSIONS_LISTNONEMPTYSESSIONIDS, - Some(wire_params), - ) + .call(rpc_methods::SESSIONS_ENRICHMETADATA, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Finds the local session bound to a GitHub task ID, if any. + /// Creates the workspace record for a session that has not been opened yet. A host that hands a session off to another application — writing the record and then launching that application against the session ID — needs the record on disk before any session exists to carry it, which the session-scoped workspace methods cannot do. Replaces any existing record and resets the checkpoint index. When writing to the local filesystem, a stored `fork_count` survives on disk. Returns the record it built, so a surviving stored `fork_count` can differ from the answer. /// - /// Wire method: `sessions.findByTaskId`. + /// Wire method: `sessions.createWorkspace`. /// /// # Parameters /// - /// * `params` - GitHub task ID to look up. + /// * `params` - Identity, state location and starting context for a workspace record. /// /// # Returns /// - /// ID of the local session bound to the given GitHub task, or omitted when none. + /// The workspace record that was written. /// ///
/// @@ -4567,29 +6119,29 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn find_by_task_id( + pub(crate) async fn create_workspace( &self, - params: SessionsFindByTaskIDRequest, - ) -> Result { + params: SessionsCreateWorkspaceRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_FINDBYTASKID, Some(wire_params)) + .call(rpc_methods::SESSIONS_CREATEWORKSPACE, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Resolves a UUID prefix to a unique session ID, if exactly one session matches. + /// Reads a session's workspace record straight from disk, without opening the session. Resuming by session ID has to know where the session lives before it can connect, so the lookup cannot come from the session-scoped workspace methods, which resolve their location from a live session's context. Returns no record when the file is absent. /// - /// Wire method: `sessions.findByPrefix`. + /// Wire method: `sessions.loadWorkspace`. /// /// # Parameters /// - /// * `params` - UUID prefix to resolve to a unique session ID. + /// * `params` - Where the session's state lives, as a root directory and the session ID under it. /// /// # Returns /// - /// Session ID matching the prefix, omitted when no unique match exists. + /// The workspace record on disk, omitted when the session has none. /// ///
/// @@ -4598,29 +6150,29 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn find_by_prefix( + pub(crate) async fn load_workspace( &self, - params: SessionsFindByPrefixRequest, - ) -> Result { + params: SessionsLoadWorkspaceRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_FINDBYPREFIX, Some(wire_params)) + .call(rpc_methods::SESSIONS_LOADWORKSPACE, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Returns the most-relevant prior session for a given working-directory context. + /// Merges fields into a session's workspace record on disk, creating the record when it is absent. The counterpart to `sessions.loadWorkspace`, for the same before-the-session-exists case. It preserves stored workspace-schema fields the request does not supply, does not preserve stored keys outside the workspace schema, and never replaces a stored `fork_count`. /// - /// Wire method: `sessions.getLastForContext`. + /// Wire method: `sessions.updateWorkspaceFields`. /// /// # Parameters /// - /// * `params` - Optional working-directory context used to score session relevance. + /// * `params` - Where the session's state lives, plus workspace-schema fields to merge into its workspace record. Stored keys outside the schema are not preserved, and a stored `fork_count` is never replaced. /// /// # Returns /// - /// Most-relevant session ID for the supplied context, or omitted when no sessions exist. + /// The merge completed. The record carries the supplied workspace-schema fields, but a stored `fork_count` stays. /// ///
/// @@ -4629,29 +6181,32 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn get_last_for_context( + pub(crate) async fn update_workspace_fields( &self, - params: SessionsGetLastForContextRequest, - ) -> Result { + params: SessionsUpdateWorkspaceFieldsRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_GETLASTFORCONTEXT, Some(wire_params)) + .call( + rpc_methods::SESSIONS_UPDATEWORKSPACEFIELDS, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Computes the absolute path to a session's persisted events.jsonl file. Internal: filesystem paths are only meaningful in-process (CLI and runtime share a filesystem). Currently used by the CLI's contribution-graph feature to read historical events directly. Remote SDK consumers must not depend on this; a proper event-query API would replace it if the contribution graph ever needed to work over the wire. + /// Reloads user, plugin, and (optionally) repo hooks on the active session. /// - /// Wire method: `sessions.getEventFilePath`. + /// Wire method: `sessions.reloadPluginHooks`. /// /// # Parameters /// - /// * `params` - Session ID whose event-log file path to compute. + /// * `params` - Active session ID and an optional flag for deferring repo-level hooks until folder trust. /// /// # Returns /// - /// Absolute path to the session's events.jsonl file on disk. + /// Reload all hooks (user, plugin, optionally repo) and apply them to the active session. Call after installing or removing plugins so their hooks take effect immediately. No-op when no active session matches the given sessionId. /// ///
/// @@ -4660,25 +6215,29 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub(crate) async fn get_event_file_path( + pub async fn reload_plugin_hooks( &self, - params: SessionsGetEventFilePathRequest, - ) -> Result { + params: SessionsReloadPluginHooksRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_GETEVENTFILEPATH, Some(wire_params)) + .call(rpc_methods::SESSIONS_RELOADPLUGINHOOKS, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Returns the on-disk byte size of each session's workspace directory. + /// Loads previously-deferred repo-level hooks on the active session, returning queued startup prompts. + /// + /// Wire method: `sessions.loadDeferredRepoHooks`. + /// + /// # Parameters /// - /// Wire method: `sessions.getSizes`. + /// * `params` - Active session ID whose deferred repo-level hooks should be loaded. /// /// # Returns /// - /// Map of sessionId -> on-disk size in bytes for each session's workspace directory. + /// Queued repo-level startup prompts and the total hook command count after loading. /// ///
/// @@ -4687,26 +6246,32 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn get_sizes(&self) -> Result { - let wire_params = serde_json::json!({}); + pub async fn load_deferred_repo_hooks( + &self, + params: SessionsLoadDeferredRepoHooksRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_GETSIZES, Some(wire_params)) + .call( + rpc_methods::SESSIONS_LOADDEFERREDREPOHOOKS, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Returns the subset of the supplied session IDs that are currently held by another running process. + /// Replaces the manager-wide additional plugins registered with the session manager. /// - /// Wire method: `sessions.checkInUse`. + /// Wire method: `sessions.setAdditionalPlugins`. /// /// # Parameters /// - /// * `params` - Session IDs to test for live in-use locks. + /// * `params` - Manager-wide additional plugins to register; replaces any previously-configured set. /// /// # Returns /// - /// Session IDs from the input set that are currently in use by another process. + /// Replace the manager-wide additional plugins. New session creations and subsequent hook reloads see the new set; already-running sessions keep their existing hook installation until the next reload. /// ///
/// @@ -4715,29 +6280,32 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn check_in_use( + pub async fn set_additional_plugins( &self, - params: SessionsCheckInUseRequest, - ) -> Result { + params: SessionsSetAdditionalPluginsRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_CHECKINUSE, Some(wire_params)) + .call( + rpc_methods::SESSIONS_SETADDITIONALPLUGINS, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Returns a session's persisted remote-steerable flag, if any has been recorded. Internal: this is CLI-specific book-keeping used by `--continue` / `--resume` to inherit the prior session's remote-steerable preference. SDK consumers that want similar behavior should manage their own persistence around start/stop calls rather than relying on this runtime-side flag. + /// Gets the dynamic-context board entry count associated with a session, when available. Internal: this exists solely so CLI telemetry events (`rem_spawn_gate`, `rem_consolidation_complete`) can pair START / END board counts around the detached rem-agent spawn. "Dynamic context board" is a runtime-internal concept that is not part of the public SDK contract; the long-term plan is to relocate the telemetry emission into the runtime so this method can be deleted entirely. /// - /// Wire method: `sessions.getPersistedRemoteSteerable`. + /// Wire method: `sessions.getBoardEntryCount`. /// /// # Parameters /// - /// * `params` - Session ID to look up the persisted remote-steerable flag for. + /// * `params` - Session ID whose board entry count should be returned. /// /// # Returns /// - /// The session's persisted remote-steerable flag, or omitted when no value has been persisted. + /// Dynamic-context board entry count, when available. /// ///
/// @@ -4746,32 +6314,29 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub(crate) async fn get_persisted_remote_steerable( + pub(crate) async fn get_board_entry_count( &self, - params: SessionsGetPersistedRemoteSteerableRequest, - ) -> Result { + params: SessionsGetBoardEntryCountRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call( - rpc_methods::SESSIONS_GETPERSISTEDREMOTESTEERABLE, - Some(wire_params), - ) + .call(rpc_methods::SESSIONS_GETBOARDENTRYCOUNT, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Closes a session: emits shutdown, flushes pending events, releases the in-use lock, and disposes the active session. + /// Attaches the runtime-managed remote-control singleton to a session, awaiting initial setup. If remote control is already attached to a different session, the singleton is transferred (preserving the underlying Mission Control connection). Returns the final status. /// - /// Wire method: `sessions.close`. + /// Wire method: `sessions.startRemoteControl`. /// /// # Parameters /// - /// * `params` - Session ID to close. + /// * `params` - Parameters for attaching the remote-control singleton to a session. /// /// # Returns /// - /// Closes a session: emits shutdown, flushes pending events to disk, releases the in-use lock, disposes the active session. Idempotent: succeeds even if the session is not currently active. + /// Wrapper for the singleton's current status. /// ///
/// @@ -4780,26 +6345,29 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn close(&self, params: SessionsCloseRequest) -> Result { + pub async fn start_remote_control( + &self, + params: SessionsStartRemoteControlRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_CLOSE, Some(wire_params)) + .call(rpc_methods::SESSIONS_STARTREMOTECONTROL, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Closes, deactivates, and deletes a set of sessions, returning the bytes freed per session. + /// Atomically rebinds the remote-control singleton to a different session, preserving the underlying Mission Control connection. When `expectedFromSessionId` is provided and does not match the singleton's current `attachedSessionId`, the transfer is rejected with `transferred: false` and the current status is returned unchanged. /// - /// Wire method: `sessions.bulkDelete`. + /// Wire method: `sessions.transferRemoteControl`. /// /// # Parameters /// - /// * `params` - Session IDs to close, deactivate, and delete from disk. + /// * `params` - Parameters for atomically rebinding the remote-control singleton. /// /// # Returns /// - /// Map of sessionId -> bytes freed by removing the session's workspace directory. + /// Outcome of a transferRemoteControl call. /// ///
/// @@ -4808,25 +6376,32 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn bulk_delete( + pub async fn transfer_remote_control( &self, - params: SessionsBulkDeleteRequest, - ) -> Result { + params: SessionsTransferRemoteControlRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_BULKDELETE, Some(wire_params)) + .call( + rpc_methods::SESSIONS_TRANSFERREMOTECONTROL, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Deletes one local session from disk after running the same lifecycle hooks as the session manager. + /// Patches the steering state of the active remote-control singleton. When remote control is off, this is a no-op and the off status is returned. Today only `enabled: true` is actionable on the underlying exporter; passing `false` is reserved for future use. /// - /// Wire method: `sessions.delete`. + /// Wire method: `sessions.setRemoteControlSteering`. /// /// # Parameters /// - /// * `params` - Session ID to delete from disk. + /// * `params` - Patch for the singleton's steering state. + /// + /// # Returns + /// + /// Wrapper for the singleton's current status. /// ///
/// @@ -4835,26 +6410,28 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub(crate) async fn delete(&self, params: SessionsDeleteRequest) -> Result<(), Error> { + pub async fn set_remote_control_steering( + &self, + params: SessionsSetRemoteControlSteeringRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_DELETE, Some(wire_params)) + .call( + rpc_methods::SESSIONS_SETREMOTECONTROLSTEERING, + Some(wire_params), + ) .await?; - Ok(()) + Ok(serde_json::from_value(_value)?) } - /// Deletes sessions older than the given threshold, with optional dry-run and exclusion list. - /// - /// Wire method: `sessions.pruneOld`. - /// - /// # Parameters + /// Stops the remote-control singleton. When `expectedSessionId` is provided and does not match the singleton's current `attachedSessionId`, the stop is rejected with `stopped: false` and the current status is returned unchanged (unless `force` is set, in which case the singleton is unconditionally torn down). /// - /// * `params` - Age threshold and optional flags controlling which old sessions are pruned (or simulated when dryRun is true). + /// Wire method: `sessions.stopRemoteControl`. /// /// # Returns /// - /// Outcome of the prune operation: deleted IDs, dry-run candidates, skipped IDs, total bytes freed, and the dry-run flag. + /// Outcome of a stopRemoteControl call. /// ///
/// @@ -4863,29 +6440,26 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn prune_old( - &self, - params: SessionsPruneOldRequest, - ) -> Result { - let wire_params = serde_json::to_value(params)?; + pub async fn stop_remote_control(&self) -> Result { + let wire_params = serde_json::json!({}); let _value = self .client - .call(rpc_methods::SESSIONS_PRUNEOLD, Some(wire_params)) + .call(rpc_methods::SESSIONS_STOPREMOTECONTROL, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Flushes a session's pending events to disk. + /// Stops the remote-control singleton. When `expectedSessionId` is provided and does not match the singleton's current `attachedSessionId`, the stop is rejected with `stopped: false` and the current status is returned unchanged (unless `force` is set, in which case the singleton is unconditionally torn down). /// - /// Wire method: `sessions.save`. + /// Wire method: `sessions.stopRemoteControl`. /// /// # Parameters /// - /// * `params` - Session ID whose pending events should be flushed to disk. + /// * `params` - Parameters for stopping the remote-control singleton. /// /// # Returns /// - /// Flush a session's pending events to disk. No-op when no writer exists for the session (e.g., already closed). + /// Outcome of a stopRemoteControl call. /// ///
/// @@ -4894,26 +6468,25 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn save(&self, params: SessionsSaveRequest) -> Result { + pub async fn stop_remote_control_with_params( + &self, + params: SessionsStopRemoteControlRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_SAVE, Some(wire_params)) + .call(rpc_methods::SESSIONS_STOPREMOTECONTROL, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Releases the in-use lock held by this process for a session. - /// - /// Wire method: `sessions.releaseLock`. - /// - /// # Parameters + /// Returns the current state of the remote-control singleton, including the attached session id and frontend URL when active. /// - /// * `params` - Session ID whose in-use lock should be released. + /// Wire method: `sessions.getRemoteControlStatus`. /// /// # Returns /// - /// Release the in-use lock held by this process for the given session. No-op when this process does not currently hold a lock for the session. + /// Wrapper for the singleton's current status. /// ///
/// @@ -4922,29 +6495,25 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn release_lock( - &self, - params: SessionsReleaseLockRequest, - ) -> Result { - let wire_params = serde_json::to_value(params)?; + pub async fn get_remote_control_status(&self) -> Result { + let wire_params = serde_json::json!({}); let _value = self .client - .call(rpc_methods::SESSIONS_RELEASELOCK, Some(wire_params)) + .call( + rpc_methods::SESSIONS_GETREMOTECONTROLSTATUS, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Backfills missing summary and context fields on the supplied session metadata records. + /// Attaches (or detaches) an in-process ExtensionController delegate for the given session in a local host adapter. Pass `controller: undefined` to detach. Internal because the controller cannot cross the JSON-RPC boundary; the runtime manages its own session extension service. /// - /// Wire method: `sessions.enrichMetadata`. + /// Wire method: `sessions.configureSessionExtensions`. /// /// # Parameters /// - /// * `params` - Session metadata records to enrich with summary and context information. - /// - /// # Returns - /// - /// The enriched metadata records, with summary and context fields backfilled where available. Sessions confirmed empty and unnamed are omitted. + /// * `params` - Params to attach or detach an in-process ExtensionController delegate. /// ///
/// @@ -4953,29 +6522,54 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn enrich_metadata( + pub(crate) async fn configure_session_extensions( &self, - params: SessionsEnrichMetadataRequest, - ) -> Result { + params: ConfigureSessionExtensionsParams, + ) -> Result<(), Error> { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_ENRICHMETADATA, Some(wire_params)) + .call( + rpc_methods::SESSIONS_CONFIGURESESSIONEXTENSIONS, + Some(wire_params), + ) .await?; - Ok(serde_json::from_value(_value)?) + Ok(()) } +} - /// Creates the workspace record for a session that has not been opened yet. A host that hands a session off to another application — writing the record and then launching that application against the session ID — needs the record on disk before any session exists to carry it, which the session-scoped workspace methods cannot do. Replaces any existing record and resets the checkpoint index. When writing to the local filesystem, a stored `fork_count` survives on disk. Returns the record it built, so a surviving stored `fork_count` can differ from the answer. +/// `skills.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcSkills<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcSkills<'a> { + /// `skills.config.*` sub-namespace. + pub fn config(&self) -> ClientRpcSkillsConfig<'a> { + ClientRpcSkillsConfig { + client: self.client, + } + } + + /// `skills.installations.*` sub-namespace. + pub fn installations(&self) -> ClientRpcSkillsInstallations<'a> { + ClientRpcSkillsInstallations { + client: self.client, + } + } + + /// Plans installation of a verified Agent Finder Skill candidate without writing files. The returned review is safe to present to a user and installing always leaves the Skill disabled until separately enabled. /// - /// Wire method: `sessions.createWorkspace`. + /// Wire method: `skills.planInstall`. /// /// # Parameters /// - /// * `params` - Identity, state location and starting context for a workspace record. + /// * `params` - Side-effect-free planning of one verified Agent Finder Skill candidate. /// /// # Returns /// - /// The workspace record that was written. + /// Skill installation management result with the honoured contract, or a typed refusal. /// ///
/// @@ -4984,29 +6578,29 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub(crate) async fn create_workspace( + pub async fn plan_install( &self, - params: SessionsCreateWorkspaceRequest, - ) -> Result { + params: SkillPlanInstallRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_CREATEWORKSPACE, Some(wire_params)) + .call(rpc_methods::SKILLS_PLANINSTALL, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Reads a session's workspace record straight from disk, without opening the session. Resuming by session ID has to know where the session lives before it can connect, so the lookup cannot come from the session-scoped workspace methods, which resolve their location from a live session's context. Returns no record when the file is absent. + /// Consumes one verified Skill installation plan, requests explicit human consent through installations.confirm on the original connection, then revalidates and installs the Skill disabled. /// - /// Wire method: `sessions.loadWorkspace`. + /// Wire method: `skills.applyInstall`. /// /// # Parameters /// - /// * `params` - Where the session's state lives, as a root directory and the session ID under it. + /// * `params` - Applies exactly one retained verified Skill installation plan. /// /// # Returns /// - /// The workspace record on disk, omitted when the session has none. + /// Skill installation result with the honoured contract, or a typed request/negotiation refusal. /// ///
/// @@ -5015,29 +6609,29 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub(crate) async fn load_workspace( + pub async fn apply_install( &self, - params: SessionsLoadWorkspaceRequest, - ) -> Result { + params: SkillApplyInstallRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_LOADWORKSPACE, Some(wire_params)) + .call(rpc_methods::SKILLS_APPLYINSTALL, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Merges fields into a session's workspace record on disk, creating the record when it is absent. The counterpart to `sessions.loadWorkspace`, for the same before-the-session-exists case. It preserves stored workspace-schema fields the request does not supply, does not preserve stored keys outside the workspace schema, and never replaces a stored `fork_count`. + /// Prepares a read-only removal plan for an owned verified Agent Finder Skill installation. Uninstall planning is never gated by the Skill-install feature flag. /// - /// Wire method: `sessions.updateWorkspaceFields`. + /// Wire method: `skills.planUninstall`. /// /// # Parameters /// - /// * `params` - Where the session's state lives, plus workspace-schema fields to merge into its workspace record. Stored keys outside the schema are not preserved, and a stored `fork_count` is never replaced. + /// * `params` - Read-only preparation of one owned Skill removal under fresh selected-session authority. /// /// # Returns /// - /// The merge completed. The record carries the supplied workspace-schema fields, but a stored `fork_count` stays. + /// Skill installation management result with the honoured contract, or a typed refusal. /// ///
/// @@ -5046,32 +6640,29 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub(crate) async fn update_workspace_fields( + pub async fn plan_uninstall( &self, - params: SessionsUpdateWorkspaceFieldsRequest, - ) -> Result { + params: SkillPlanUninstallRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call( - rpc_methods::SESSIONS_UPDATEWORKSPACEFIELDS, - Some(wire_params), - ) + .call(rpc_methods::SKILLS_PLANUNINSTALL, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Reloads user, plugin, and (optionally) repo hooks on the active session. + /// Consumes an owned Skill removal plan, requests explicit human consent through installations.confirm, refuses drift, and removes the exact owned files through quarantine. /// - /// Wire method: `sessions.reloadPluginHooks`. + /// Wire method: `skills.applyUninstall`. /// /// # Parameters /// - /// * `params` - Active session ID and an optional flag for deferring repo-level hooks until folder trust. + /// * `params` - One-use application of the exact retained Skill removal plan. /// /// # Returns /// - /// Reload all hooks (user, plugin, optionally repo) and apply them to the active session. Call after installing or removing plugins so their hooks take effect immediately. No-op when no active session matches the given sessionId. + /// Skill installation result with the honoured contract, or a typed request/negotiation refusal. /// ///
/// @@ -5080,29 +6671,29 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn reload_plugin_hooks( + pub async fn apply_uninstall( &self, - params: SessionsReloadPluginHooksRequest, - ) -> Result { + params: SkillApplyUninstallRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_RELOADPLUGINHOOKS, Some(wire_params)) + .call(rpc_methods::SKILLS_APPLYUNINSTALL, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Loads previously-deferred repo-level hooks on the active session, returning queued startup prompts. + /// Discovers skills across global and project sources. /// - /// Wire method: `sessions.loadDeferredRepoHooks`. + /// Wire method: `skills.discover`. /// /// # Parameters /// - /// * `params` - Active session ID whose deferred repo-level hooks should be loaded. + /// * `params` - Optional project paths and additional skill directories to include in discovery. /// /// # Returns /// - /// Queued repo-level startup prompts and the total hook command count after loading. + /// Skills discovered across global and project sources. /// ///
/// @@ -5111,32 +6702,26 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn load_deferred_repo_hooks( - &self, - params: SessionsLoadDeferredRepoHooksRequest, - ) -> Result { + pub async fn discover(&self, params: SkillsDiscoverRequest) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call( - rpc_methods::SESSIONS_LOADDEFERREDREPOHOOKS, - Some(wire_params), - ) + .call(rpc_methods::SKILLS_DISCOVER, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Replaces the manager-wide additional plugins registered with the session manager. + /// Returns the canonical directories where a client may create skills that the runtime will recognize, including ones that do not exist yet. Project directories become active once created. /// - /// Wire method: `sessions.setAdditionalPlugins`. + /// Wire method: `skills.getDiscoveryPaths`. /// /// # Parameters /// - /// * `params` - Manager-wide additional plugins to register; replaces any previously-configured set. + /// * `params` - Optional project paths to enumerate. /// /// # Returns /// - /// Replace the manager-wide additional plugins. New session creations and subsequent hook reloads see the new set; already-running sessions keep their existing hook installation until the next reload. + /// Canonical locations where skills can be created so the runtime will recognize them. /// ///
/// @@ -5145,32 +6730,29 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn set_additional_plugins( + pub async fn get_discovery_paths( &self, - params: SessionsSetAdditionalPluginsRequest, - ) -> Result { + params: SkillsGetDiscoveryPathsRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call( - rpc_methods::SESSIONS_SETADDITIONALPLUGINS, - Some(wire_params), - ) + .call(rpc_methods::SKILLS_GETDISCOVERYPATHS, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Gets the dynamic-context board entry count associated with a session, when available. Internal: this exists solely so CLI telemetry events (`rem_spawn_gate`, `rem_consolidation_complete`) can pair START / END board counts around the detached rem-agent spawn. "Dynamic context board" is a runtime-internal concept that is not part of the public SDK contract; the long-term plan is to relocate the telemetry emission into the runtime so this method can be deleted entirely. + /// Returns the canonical directories where a client may create skills that the runtime will recognize, including ones that do not exist yet. Project directories become active once created. /// - /// Wire method: `sessions.getBoardEntryCount`. + /// Wire method: `skills.getDiscoveryPaths`. /// /// # Parameters /// - /// * `params` - Session ID whose board entry count should be returned. + /// * `params` - Optional project paths to enumerate. /// /// # Returns /// - /// Dynamic-context board entry count, when available. + /// Canonical locations where skills can be created so the runtime will recognize them. /// ///
/// @@ -5179,29 +6761,35 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub(crate) async fn get_board_entry_count( + /// + /// Accepts [`SkillsGetDiscoveryPathsOptions`], including inputs added after [`SkillsGetDiscoveryPathsRequest`]. + pub async fn get_discovery_paths_with_options( &self, - params: SessionsGetBoardEntryCountRequest, - ) -> Result { + params: SkillsGetDiscoveryPathsOptions, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_GETBOARDENTRYCOUNT, Some(wire_params)) + .call(rpc_methods::SKILLS_GETDISCOVERYPATHS, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } +} - /// Attaches the runtime-managed remote-control singleton to a session, awaiting initial setup. If remote control is already attached to a different session, the singleton is transferred (preserving the underlying Mission Control connection). Returns the final status. +/// `skills.config.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcSkillsConfig<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcSkillsConfig<'a> { + /// Replaces the global list of disabled skills. /// - /// Wire method: `sessions.startRemoteControl`. + /// Wire method: `skills.config.setDisabledSkills`. /// /// # Parameters /// - /// * `params` - Parameters for attaching the remote-control singleton to a session. - /// - /// # Returns - /// - /// Wrapper for the singleton's current status. + /// * `params` - Skill names to mark as disabled in global configuration, replacing any previous list. /// ///
/// @@ -5210,29 +6798,28 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn start_remote_control( + pub async fn set_disabled_skills( &self, - params: SessionsStartRemoteControlRequest, - ) -> Result { + params: SkillsConfigSetDisabledSkillsRequest, + ) -> Result<(), Error> { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_STARTREMOTECONTROL, Some(wire_params)) + .call( + rpc_methods::SKILLS_CONFIG_SETDISABLEDSKILLS, + Some(wire_params), + ) .await?; - Ok(serde_json::from_value(_value)?) + Ok(()) } - /// Atomically rebinds the remote-control singleton to a different session, preserving the underlying Mission Control connection. When `expectedFromSessionId` is provided and does not match the singleton's current `attachedSessionId`, the transfer is rejected with `transferred: false` and the current status is returned unchanged. + /// Atomically adds or removes one skill from the disabled list. /// - /// Wire method: `sessions.transferRemoteControl`. + /// Wire method: `skills.config.setSkillDisabled`. /// /// # Parameters /// - /// * `params` - Parameters for atomically rebinding the remote-control singleton. - /// - /// # Returns - /// - /// Outcome of a transferRemoteControl call. + /// * `params` - Adds or removes a single skill from the global disabled list, leaving every other entry untouched. /// ///
/// @@ -5241,32 +6828,40 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn transfer_remote_control( + pub async fn set_skill_disabled( &self, - params: SessionsTransferRemoteControlRequest, - ) -> Result { + params: SkillsConfigSetSkillDisabledRequest, + ) -> Result<(), Error> { let wire_params = serde_json::to_value(params)?; let _value = self .client .call( - rpc_methods::SESSIONS_TRANSFERREMOTECONTROL, + rpc_methods::SKILLS_CONFIG_SETSKILLDISABLED, Some(wire_params), ) .await?; - Ok(serde_json::from_value(_value)?) + Ok(()) } +} - /// Patches the steering state of the active remote-control singleton. When remote control is off, this is a no-op and the off status is returned. Today only `enabled: true` is actionable on the underlying exporter; passing `false` is reserved for future use. +/// `skills.installations.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcSkillsInstallations<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcSkillsInstallations<'a> { + /// Lists owned verified Agent Finder Skill installations for the selected existing session. Listing is never gated by the Skill-install feature flag. /// - /// Wire method: `sessions.setRemoteControlSteering`. + /// Wire method: `skills.installations.list`. /// /// # Parameters /// - /// * `params` - Patch for the singleton's steering state. + /// * `params` - Inventory request under an explicitly selected existing session. /// /// # Returns /// - /// Wrapper for the singleton's current status. + /// Skill installation management result with the honoured contract, or a typed refusal. /// ///
/// @@ -5275,28 +6870,29 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn set_remote_control_steering( + pub async fn list( &self, - params: SessionsSetRemoteControlSteeringRequest, - ) -> Result { + params: SkillInstallationsRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call( - rpc_methods::SESSIONS_SETREMOTECONTROLSTEERING, - Some(wire_params), - ) + .call(rpc_methods::SKILLS_INSTALLATIONS_LIST, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Stops the remote-control singleton. When `expectedSessionId` is provided and does not match the singleton's current `attachedSessionId`, the stop is rejected with `stopped: false` and the current status is returned unchanged (unless `force` is set, in which case the singleton is unconditionally torn down). + /// Reconciles interrupted owned Skill installation work for the selected existing session, then inspects owned inventory. Recovery is never gated by the Skill-install feature flag. /// - /// Wire method: `sessions.stopRemoteControl`. + /// Wire method: `skills.installations.recover`. + /// + /// # Parameters + /// + /// * `params` - Inventory request under an explicitly selected existing session. /// /// # Returns /// - /// Outcome of a stopRemoteControl call. + /// Skill installation management result with the honoured contract, or a typed refusal. /// ///
/// @@ -5305,26 +6901,29 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn stop_remote_control(&self) -> Result { - let wire_params = serde_json::json!({}); + pub async fn recover( + &self, + params: SkillInstallationsRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_STOPREMOTECONTROL, Some(wire_params)) + .call(rpc_methods::SKILLS_INSTALLATIONS_RECOVER, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Stops the remote-control singleton. When `expectedSessionId` is provided and does not match the singleton's current `attachedSessionId`, the stop is rejected with `stopped: false` and the current status is returned unchanged (unless `force` is set, in which case the singleton is unconditionally torn down). + /// Inspects a known Skill installation operation on its original runtime connection. Status is never gated by the Skill-install feature flag. /// - /// Wire method: `sessions.stopRemoteControl`. + /// Wire method: `skills.installations.status`. /// /// # Parameters /// - /// * `params` - Parameters for stopping the remote-control singleton. + /// * `params` - Existing-operation control. A new session selector is deliberately not accepted. /// /// # Returns /// - /// Outcome of a stopRemoteControl call. + /// Skill installation management result with the honoured contract, or a typed refusal. /// ///
/// @@ -5333,25 +6932,29 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn stop_remote_control_with_params( + pub async fn status( &self, - params: SessionsStopRemoteControlRequest, - ) -> Result { + params: SkillInstallationOperationRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SESSIONS_STOPREMOTECONTROL, Some(wire_params)) + .call(rpc_methods::SKILLS_INSTALLATIONS_STATUS, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Returns the current state of the remote-control singleton, including the attached session id and frontend URL when active. + /// Requests cancellation of a known Skill installation operation before commit. Already-started durable work requires recovery instead of silent replay. /// - /// Wire method: `sessions.getRemoteControlStatus`. + /// Wire method: `skills.installations.cancel`. + /// + /// # Parameters + /// + /// * `params` - Existing-operation control. A new session selector is deliberately not accepted. /// /// # Returns /// - /// Wrapper for the singleton's current status. + /// Skill installation management result with the honoured contract, or a typed refusal. /// ///
/// @@ -5360,25 +6963,29 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn get_remote_control_status(&self) -> Result { - let wire_params = serde_json::json!({}); + pub async fn cancel( + &self, + params: SkillInstallationOperationRequest, + ) -> Result { + let wire_params = serde_json::to_value(params)?; let _value = self .client - .call( - rpc_methods::SESSIONS_GETREMOTECONTROLSTATUS, - Some(wire_params), - ) + .call(rpc_methods::SKILLS_INSTALLATIONS_CANCEL, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Attaches (or detaches) an in-process ExtensionController delegate for the given session in a local host adapter. Pass `controller: undefined` to detach. Internal because the controller cannot cross the JSON-RPC boundary; the runtime manages its own session extension service. + /// Atomically persists enablement for one owned Agent Finder Skill and reconciles the selected bound session. Enablement is installation-scoped by receipt identity and is never gated by the Skill-install feature flag. /// - /// Wire method: `sessions.configureSessionExtensions`. + /// Wire method: `skills.installations.setEnabled`. /// /// # Parameters /// - /// * `params` - Params to attach or detach an in-process ExtensionController delegate. + /// * `params` - Persisted enablement update for one owned Skill installation. + /// + /// # Returns + /// + /// Skill installation management result with the honoured contract, or a typed refusal. /// ///
/// @@ -5387,54 +6994,40 @@ impl<'a> ClientRpcSessions<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub(crate) async fn configure_session_extensions( + pub async fn set_enabled( &self, - params: ConfigureSessionExtensionsParams, - ) -> Result<(), Error> { + params: SkillSetEnabledRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client .call( - rpc_methods::SESSIONS_CONFIGURESESSIONEXTENSIONS, - Some(wire_params), - ) - .await?; - Ok(()) - } -} - -/// `skills.*` RPCs. -#[derive(Clone, Copy)] -pub struct ClientRpcSkills<'a> { - pub(crate) client: &'a Client, -} - -impl<'a> ClientRpcSkills<'a> { - /// `skills.config.*` sub-namespace. - pub fn config(&self) -> ClientRpcSkillsConfig<'a> { - ClientRpcSkillsConfig { - client: self.client, - } - } - - /// `skills.installations.*` sub-namespace. - pub fn installations(&self) -> ClientRpcSkillsInstallations<'a> { - ClientRpcSkillsInstallations { - client: self.client, - } + rpc_methods::SKILLS_INSTALLATIONS_SETENABLED, + Some(wire_params), + ) + .await?; + Ok(serde_json::from_value(_value)?) } +} - /// Plans installation of a verified Agent Finder Skill candidate without writing files. The returned review is safe to present to a user and installing always leaves the Skill disabled until separately enabled. +/// `tools.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcTools<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcTools<'a> { + /// Lists built-in tools available for a model. /// - /// Wire method: `skills.planInstall`. + /// Wire method: `tools.list`. /// /// # Parameters /// - /// * `params` - Side-effect-free planning of one verified Agent Finder Skill candidate. + /// * `params` - Optional model identifier whose tool overrides should be applied to the listing. /// /// # Returns /// - /// Skill installation management result with the honoured contract, or a typed refusal. + /// Built-in tools available for the requested model, with their parameters and instructions. /// ///
/// @@ -5443,29 +7036,49 @@ impl<'a> ClientRpcSkills<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn plan_install( - &self, - params: SkillPlanInstallRequest, - ) -> Result { + pub async fn list(&self, params: ToolsListRequest) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SKILLS_PLANINSTALL, Some(wire_params)) + .call(rpc_methods::TOOLS_LIST, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } +} - /// Consumes one verified Skill installation plan, requests explicit human consent through installations.confirm on the original connection, then revalidates and installs the Skill disabled. +/// `user.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcUser<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcUser<'a> { + /// `user.settings.*` sub-namespace. + pub fn settings(&self) -> ClientRpcUserSettings<'a> { + ClientRpcUserSettings { + client: self.client, + } + } +} + +/// `user.settings.*` RPCs. +#[derive(Clone, Copy)] +pub struct ClientRpcUserSettings<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientRpcUserSettings<'a> { + /// Adds or removes one hook key in the user `disabledHooks` setting, rewriting settings.json in place and leaving every other setting untouched. Reports a typed outcome rather than failing the call, so a host can tell an unparseable settings file apart from a write that could not complete. /// - /// Wire method: `skills.applyInstall`. + /// Wire method: `user.settings.setHookDisabled`. /// /// # Parameters /// - /// * `params` - Applies exactly one retained verified Skill installation plan. + /// * `params` - One hook to disable or re-enable. /// /// # Returns /// - /// Skill installation result with the honoured contract, or a typed request/negotiation refusal. + /// Outcome of rewriting the `disabledHooks` setting. /// ///
/// @@ -5474,29 +7087,32 @@ impl<'a> ClientRpcSkills<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn apply_install( + pub(crate) async fn set_hook_disabled( &self, - params: SkillApplyInstallRequest, - ) -> Result { + params: UserSettingsSetHookDisabledRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SKILLS_APPLYINSTALL, Some(wire_params)) + .call( + rpc_methods::USER_SETTINGS_SETHOOKDISABLED, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Prepares a read-only removal plan for an owned verified Agent Finder Skill installation. Uninstall planning is never gated by the Skill-install feature flag. + /// Reads the user's settings document exactly as `user.settings.load` does, but from a caller-supplied configuration directory instead of the one the server resolved for itself. Use this when a consumer scopes a session to its own Copilot home — the SDK's per-session `configDir` override — so the settings read match the directory that session actually uses. An absent or empty `configDir` resolves the server's own home, making this identical to `user.settings.load`. Hook-validation relaxations are deliberately not caller-supplied: they continue to come from the server's environment, so a consumer cannot widen the host's hook policy through this method. /// - /// Wire method: `skills.planUninstall`. + /// Wire method: `user.settings.loadForConfigDir`. /// /// # Parameters /// - /// * `params` - Read-only preparation of one owned Skill removal under fresh selected-session authority. + /// * `params` - Selects the configuration directory whose user settings to read. /// /// # Returns /// - /// Skill installation management result with the honoured contract, or a typed refusal. + /// The stored user settings document, keyed by setting name. /// ///
/// @@ -5505,29 +7121,32 @@ impl<'a> ClientRpcSkills<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn plan_uninstall( + pub(crate) async fn load_for_config_dir( &self, - params: SkillPlanUninstallRequest, - ) -> Result { + params: UserSettingsLoadForConfigDirRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SKILLS_PLANUNINSTALL, Some(wire_params)) + .call( + rpc_methods::USER_SETTINGS_LOADFORCONFIGDIR, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Consumes an owned Skill removal plan, requests explicit human consent through installations.confirm, refuses drift, and removes the exact owned files through quarantine. + /// Reads a repository's checked-in settings document as stored, normalized, together with any diagnostic raised while reading it. This is the repository half of the layering `user.settings.get` reports: `user.settings.load` reads the user's own document, and this reads the one a repository checks in to govern the keys `user.settings.governanceKeys` lists as repo-governable. A document that fails to parse, or that sets a key a repository may not govern, is reported through `warning` while the settings that did load are still returned, so a consumer surfaces the diagnostic and continues rather than failing the session. When `repoRoot` is the user's home directory the Claude-compatible configuration is skipped, so a home-directory session does not inherit a personal config as repository policy. /// - /// Wire method: `skills.applyUninstall`. + /// Wire method: `user.settings.loadRepo`. /// /// # Parameters /// - /// * `params` - One-use application of the exact retained Skill removal plan. + /// * `params` - Selects the repository whose checked-in settings to read. /// /// # Returns /// - /// Skill installation result with the honoured contract, or a typed request/negotiation refusal. + /// A repository's settings as stored, together with any diagnostic raised while reading them. /// ///
/// @@ -5536,29 +7155,29 @@ impl<'a> ClientRpcSkills<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn apply_uninstall( + pub(crate) async fn load_repo( &self, - params: SkillApplyUninstallRequest, - ) -> Result { + params: UserSettingsLoadRepoRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SKILLS_APPLYUNINSTALL, Some(wire_params)) + .call(rpc_methods::USER_SETTINGS_LOADREPO, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Discovers skills across global and project sources. + /// Reads a repository's settings and merges them over a supplied user layer in one step, returning the settings a consumer should act on inside that repository. Use this rather than reading the two layers separately: the merge is per setting and collection-aware, so a repository adds to the collections it is allowed to influence without replacing the user's own entries, and a whole-document overlay would get that wrong. Any diagnostic raised while reading the repository layer is returned rather than printed, so the consumer decides how to surface it; the settings that did load are merged regardless. /// - /// Wire method: `skills.discover`. + /// Wire method: `user.settings.loadAndMergeRepo`. /// /// # Parameters /// - /// * `params` - Optional project paths and additional skill directories to include in discovery. + /// * `params` - A repository to read settings from, and the user layer they are merged over. /// /// # Returns /// - /// Skills discovered across global and project sources. + /// The settings a consumer should act on inside a repository, together with any diagnostic raised while reading the repository layer. /// ///
/// @@ -5567,26 +7186,28 @@ impl<'a> ClientRpcSkills<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn discover(&self, params: SkillsDiscoverRequest) -> Result { + pub(crate) async fn load_and_merge_repo( + &self, + params: UserSettingsLoadAndMergeRepoRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SKILLS_DISCOVER, Some(wire_params)) + .call( + rpc_methods::USER_SETTINGS_LOADANDMERGEREPO, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Returns the canonical directories where a client may create skills that the runtime will recognize, including ones that do not exist yet. Project directories become active once created. - /// - /// Wire method: `skills.getDiscoveryPaths`. - /// - /// # Parameters + /// Reports the on-disk path of the settings document `user.settings.load` and `user.settings.set` read and write. Resolved the same way those methods resolve it, so a host that shows or opens the settings file names the file the runtime actually uses, including the extensionless legacy `settings` file when that is what is present. /// - /// * `params` - Optional project paths to enumerate. + /// Wire method: `user.settings.getPath`. /// /// # Returns /// - /// Canonical locations where skills can be created so the runtime will recognize them. + /// The on-disk location of the user's settings document. /// ///
/// @@ -5595,29 +7216,22 @@ impl<'a> ClientRpcSkills<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn get_discovery_paths( - &self, - params: SkillsGetDiscoveryPathsRequest, - ) -> Result { - let wire_params = serde_json::to_value(params)?; + pub(crate) async fn get_path(&self) -> Result { + let wire_params = serde_json::json!({}); let _value = self .client - .call(rpc_methods::SKILLS_GETDISCOVERYPATHS, Some(wire_params)) + .call(rpc_methods::USER_SETTINGS_GETPATH, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Returns the canonical directories where a client may create skills that the runtime will recognize, including ones that do not exist yet. Project directories become active once created. - /// - /// Wire method: `skills.getDiscoveryPaths`. + /// Reads the user's stored settings together with the diagnostic raised while reading them. This is `user.settings.load` plus the reason part of the document was ignored: that one answers the document alone, so a caller cannot tell a clean read from a salvaged one. Read this when the caller is about to write the file back, where accepting a partial parse would discard every value the loader could not read. The settings that did load are still reported alongside the warning, so a consumer may surface it and continue instead of failing. /// - /// # Parameters - /// - /// * `params` - Optional project paths to enumerate. + /// Wire method: `user.settings.loadWithWarning`. /// /// # Returns /// - /// Canonical locations where skills can be created so the runtime will recognize them. + /// The user's stored settings, together with any diagnostic raised while reading them. /// ///
/// @@ -5626,35 +7240,31 @@ impl<'a> ClientRpcSkills<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- /// - /// Accepts [`SkillsGetDiscoveryPathsOptions`], including inputs added after [`SkillsGetDiscoveryPathsRequest`]. - pub async fn get_discovery_paths_with_options( + pub(crate) async fn load_with_warning( &self, - params: SkillsGetDiscoveryPathsOptions, - ) -> Result { - let wire_params = serde_json::to_value(params)?; + ) -> Result { + let wire_params = serde_json::json!({}); let _value = self .client - .call(rpc_methods::SKILLS_GETDISCOVERYPATHS, Some(wire_params)) + .call( + rpc_methods::USER_SETTINGS_LOADWITHWARNING, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } -} - -/// `skills.config.*` RPCs. -#[derive(Clone, Copy)] -pub struct ClientRpcSkillsConfig<'a> { - pub(crate) client: &'a Client, -} -impl<'a> ClientRpcSkillsConfig<'a> { - /// Replaces the global list of disabled skills. + /// Folds a user settings layer over a managed (enterprise policy) layer and returns the merged settings. The managed layer's governance keys win, `autoTier` resolves through its overridable form, and the two per-entry control maps (`enabledPlugins`, `extraKnownMarketplaces`) union across the layers and are then stamped back from the managed layer, so each entry an administrator declares wins while the user keeps control of the rest. The parameters are named for their layers rather than being a generic base/override pair: nothing about a settings object identifies which layer produced it, so the runtime cannot detect a transposed call, and transposing one resolves the governance keys in the user's favour instead of the administrator's. Supplying only one layer returns it unchanged, and supplying neither returns an empty object. Rejects a managed `autoTier` that is neither a user-configurable tier nor a single-key overridable form, rather than silently dropping it. /// - /// Wire method: `skills.config.setDisabledSkills`. + /// Wire method: `user.settings.mergeManagedAndUser`. /// /// # Parameters /// - /// * `params` - Skill names to mark as disabled in global configuration, replacing any previous list. + /// * `params` - The managed (enterprise policy) layer and the user layer to fold together. The field names carry the layer identity: nothing about a settings object identifies which layer produced it, so a generic base/override pair would let a caller transpose them and silently resolve the governance keys in the user's favour. + /// + /// # Returns + /// + /// The user layer folded over the managed layer. /// ///
/// @@ -5663,28 +7273,32 @@ impl<'a> ClientRpcSkillsConfig<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn set_disabled_skills( + pub(crate) async fn merge_managed_and_user( &self, - params: SkillsConfigSetDisabledSkillsRequest, - ) -> Result<(), Error> { + params: UserSettingsMergeManagedAndUserParams, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client .call( - rpc_methods::SKILLS_CONFIG_SETDISABLEDSKILLS, + rpc_methods::USER_SETTINGS_MERGEMANAGEDANDUSER, Some(wire_params), ) .await?; - Ok(()) + Ok(serde_json::from_value(_value)?) } - /// Atomically adds or removes one skill from the disabled list. + /// Folds a repository's settings layer into the user layer. Each repo-overridable key carries a directional policy chosen so a repository can only add restrictions and never relax the user's own. The two per-entry managed control maps are the exception those directional rules cannot express — a repository may legitimately enable plugins and declare marketplaces — so they are re-stamped afterwards from the runtime's ambient managed policy. That makes the result depend on the runtime process's managed state and not on the arguments alone: a host must call this rather than reimplement the fold, or a repository could relax a restriction the administrator imposed. Rejects when either layer is not a JSON object. /// - /// Wire method: `skills.config.setSkillDisabled`. + /// Wire method: `user.settings.mergeRepoValue`. /// /// # Parameters /// - /// * `params` - Adds or removes a single skill from the global disabled list, leaving every other entry untouched. + /// * `params` - The user layer and the repository layer to fold together. + /// + /// # Returns + /// + /// The repository layer folded into the user layer. /// ///
/// @@ -5693,40 +7307,29 @@ impl<'a> ClientRpcSkillsConfig<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn set_skill_disabled( + pub(crate) async fn merge_repo_value( &self, - params: SkillsConfigSetSkillDisabledRequest, - ) -> Result<(), Error> { + params: UserSettingsMergeRepoValueParams, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call( - rpc_methods::SKILLS_CONFIG_SETSKILLDISABLED, - Some(wire_params), - ) + .call(rpc_methods::USER_SETTINGS_MERGEREPOVALUE, Some(wire_params)) .await?; - Ok(()) + Ok(serde_json::from_value(_value)?) } -} - -/// `skills.installations.*` RPCs. -#[derive(Clone, Copy)] -pub struct ClientRpcSkillsInstallations<'a> { - pub(crate) client: &'a Client, -} -impl<'a> ClientRpcSkillsInstallations<'a> { - /// Lists owned verified Agent Finder Skill installations for the selected existing session. Listing is never gated by the Skill-install feature flag. + /// Runs the one-time migration that moves a staff account's update channel to stable, and records that it ran. Idempotent and self-gating: it takes a lock over the global-state file, re-reads the completion stamp inside it, and returns `current` rather than migrating twice, so two hosts racing at startup cannot both migrate. Only a `migrated` status means the persisted settings changed and the caller should reload them. An account on the experimental channel is deliberately left alone and reported as `excluded-experimental`. /// - /// Wire method: `skills.installations.list`. + /// Wire method: `user.settings.migrateStaffUpdateChannelOnce`. /// /// # Parameters /// - /// * `params` - Inventory request under an explicitly selected existing session. + /// * `params` - The filesystem and environment facts a user-settings file is resolved from. Passed explicitly rather than read from the runtime's own process, so a host whose configuration directory differs from its process environment resolves the file it means. /// /// # Returns /// - /// Skill installation management result with the honoured contract, or a typed refusal. + /// The outcome of the one-time staff update-channel migration. /// ///
/// @@ -5735,29 +7338,32 @@ impl<'a> ClientRpcSkillsInstallations<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn list( + pub(crate) async fn migrate_staff_update_channel_once( &self, - params: SkillInstallationsRequest, - ) -> Result { + params: UserSettingsHostContext, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SKILLS_INSTALLATIONS_LIST, Some(wire_params)) + .call( + rpc_methods::USER_SETTINGS_MIGRATESTAFFUPDATECHANNELONCE, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Reconciles interrupted owned Skill installation work for the selected existing session, then inspects owned inventory. Recovery is never gated by the Skill-install feature flag. + /// Runs the one-time reset that clears a staff account's pinned model selection, and reports the timestamp the host should record. Idempotent and self-gating: the reset is gated on a fixed cutoff, so a caller that passes back the timestamp it recorded gets `didReset: false` rather than a second reset. It applies to staff accounts only; any other account is reported as not reset without the settings document being opened. Only `didReset: true` means the persisted settings changed, and only then are the updated settings returned for the host to adopt. /// - /// Wire method: `skills.installations.recover`. + /// Wire method: `user.settings.resetStaffModelSelectionOnce`. /// /// # Parameters /// - /// * `params` - Inventory request under an explicitly selected existing session. + /// * `params` - Selects the configuration directory to run the one-time staff model-selection reset against, and supplies the caller's record of whether it has already run. /// /// # Returns /// - /// Skill installation management result with the honoured contract, or a typed refusal. + /// The outcome of the one-time staff model-selection reset. /// ///
/// @@ -5766,29 +7372,32 @@ impl<'a> ClientRpcSkillsInstallations<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn recover( + pub(crate) async fn reset_staff_model_selection_once( &self, - params: SkillInstallationsRequest, - ) -> Result { + params: UserSettingsResetStaffModelSelectionOnceRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SKILLS_INSTALLATIONS_RECOVER, Some(wire_params)) + .call( + rpc_methods::USER_SETTINGS_RESETSTAFFMODELSELECTIONONCE, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Inspects a known Skill installation operation on its original runtime connection. Status is never gated by the Skill-install feature flag. + /// Reports the top-level keys in the user settings document that the runtime does not recognize, phrased for display to the user. This is a separate question from the warning `user.settings.loadWithWarning` returns: that one describes parts of the document the loader had to ignore to load the rest, whereas an unknown key parses cleanly and is simply not a setting, so a host that surfaces only the load warning silently accepts a misspelled key that will never take effect. Nothing is reported when the document is absent, unreadable, or failed to load, because an unknown-key list derived from a document the runtime could not read would be misleading rather than helpful. Inspection never modifies the document. /// - /// Wire method: `skills.installations.status`. + /// Wire method: `user.settings.getUnknownKeysWarning`. /// /// # Parameters /// - /// * `params` - Existing-operation control. A new session selector is deliberately not accepted. + /// * `params` - Selects the configuration directory whose user settings document should be inspected for unrecognized top-level keys. /// /// # Returns /// - /// Skill installation management result with the honoured contract, or a typed refusal. + /// The unrecognized top-level keys found in the user settings document, already phrased for display. /// ///
/// @@ -5797,29 +7406,32 @@ impl<'a> ClientRpcSkillsInstallations<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn status( + pub(crate) async fn get_unknown_keys_warning( &self, - params: SkillInstallationOperationRequest, - ) -> Result { + params: UserSettingsUnknownKeysWarningRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SKILLS_INSTALLATIONS_STATUS, Some(wire_params)) + .call( + rpc_methods::USER_SETTINGS_GETUNKNOWNKEYSWARNING, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } - /// Requests cancellation of a known Skill installation operation before commit. Already-started durable work requires recovery instead of silent replay. + /// Resolves the effective runtime settings for a host that is about to start a session, layering the given overrides over the settings documents, the environment and the platform defaults. A host cannot assemble this itself: the precedence between a user document, a repository document, the managed layers and the environment is the runtime's own rule, and a host that re-implements it drifts from the server it is configuring. The working directory, environment and platform are taken as arguments rather than read from the server process, so a host resolving settings for a directory other than its own gets that directory's answer. Nothing is written; this only computes. /// - /// Wire method: `skills.installations.cancel`. + /// Wire method: `user.settings.buildRuntime`. /// /// # Parameters /// - /// * `params` - Existing-operation control. A new session selector is deliberately not accepted. + /// * `params` - The overrides and host context to resolve effective runtime settings from. /// /// # Returns /// - /// Skill installation management result with the honoured contract, or a typed refusal. + /// The effective runtime settings, keyed by setting name. Keys this runtime does not recognize are preserved rather than dropped, so a caller reading a document written by a newer runtime keeps every value. /// ///
/// @@ -5828,29 +7440,29 @@ impl<'a> ClientRpcSkillsInstallations<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn cancel( + pub(crate) async fn build_runtime( &self, - params: SkillInstallationOperationRequest, - ) -> Result { + params: UserSettingsBuildRuntimeRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::SKILLS_INSTALLATIONS_CANCEL, Some(wire_params)) + .call(rpc_methods::USER_SETTINGS_BUILDRUNTIME, Some(wire_params)) .await?; Ok(serde_json::from_value(_value)?) } - /// Atomically persists enablement for one owned Agent Finder Skill and reconciles the selected bound session. Enablement is installation-scoped by receipt identity and is never gated by the Skill-install feature flag. + /// Runs the one-time migration that moves a staff account's log level to the current default, and records that it ran. Idempotent and self-gating: it takes a lock over the global-state file and re-reads the completion stamp inside it, so two hosts racing at startup cannot both migrate. Only `refreshed` can have changed the persisted settings, and the settings it returns are the document re-read after the write, so a host should adopt them rather than reloading separately and racing the next writer. /// - /// Wire method: `skills.installations.setEnabled`. + /// Wire method: `user.settings.migrateStaffLogLevelOnce`. /// /// # Parameters /// - /// * `params` - Persisted enablement update for one owned Skill installation. + /// * `params` - Selects the configuration directory to run the one-time staff log-level migration against, and supplies the caller's record of whether it has already run. /// /// # Returns /// - /// Skill installation management result with the honoured contract, or a typed refusal. + /// The outcome of the one-time staff log-level migration. /// ///
/// @@ -5859,40 +7471,32 @@ impl<'a> ClientRpcSkillsInstallations<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn set_enabled( + pub(crate) async fn migrate_staff_log_level_once( &self, - params: SkillSetEnabledRequest, - ) -> Result { + params: UserSettingsMigrateStaffLogLevelOnceRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client .call( - rpc_methods::SKILLS_INSTALLATIONS_SETENABLED, + rpc_methods::USER_SETTINGS_MIGRATESTAFFLOGLEVELONCE, Some(wire_params), ) .await?; Ok(serde_json::from_value(_value)?) } -} -/// `tools.*` RPCs. -#[derive(Clone, Copy)] -pub struct ClientRpcTools<'a> { - pub(crate) client: &'a Client, -} - -impl<'a> ClientRpcTools<'a> { - /// Lists built-in tools available for a model. + /// Runs the one-time cleanup that removes obsolete CLI-owned settings and legacy rubber-duck keys from the user's settings document, and reports what it did. Idempotent and safe to call on every startup: with nothing obsolete left it reports `unchanged` and writes nothing. The cleanup preserves every key it does not recognize, so a setting written by a newer host is never dropped by an older one, and a document that fails to parse is reported `invalid` and left untouched rather than rewritten from a partial read. The cleaned document is not returned: it is written before this replies, so `user.settings.load` reads it authoritatively. A host that surfaces unrecognized keys through `user.settings.unknownKeys` wants this first, because the keys this retires would otherwise be shown to the user as if they were misspelled settings. /// - /// Wire method: `tools.list`. + /// Wire method: `user.settings.migrateObsoleteOnDisk`. /// /// # Parameters /// - /// * `params` - Optional model identifier whose tool overrides should be applied to the listing. + /// * `params` - Selects the configuration directory whose settings document to clean. /// /// # Returns /// - /// Built-in tools available for the requested model, with their parameters and instructions. + /// The outcome of the one-time obsolete-settings cleanup. /// ///
/// @@ -5901,38 +7505,21 @@ impl<'a> ClientRpcTools<'a> { /// SDK and CLI versions if your code depends on it. /// ///
- pub async fn list(&self, params: ToolsListRequest) -> Result { + pub(crate) async fn migrate_obsolete_on_disk( + &self, + params: UserSettingsMigrateObsoleteOnDiskRequest, + ) -> Result { let wire_params = serde_json::to_value(params)?; let _value = self .client - .call(rpc_methods::TOOLS_LIST, Some(wire_params)) + .call( + rpc_methods::USER_SETTINGS_MIGRATEOBSOLETEONDISK, + Some(wire_params), + ) .await?; Ok(serde_json::from_value(_value)?) } -} - -/// `user.*` RPCs. -#[derive(Clone, Copy)] -pub struct ClientRpcUser<'a> { - pub(crate) client: &'a Client, -} - -impl<'a> ClientRpcUser<'a> { - /// `user.settings.*` sub-namespace. - pub fn settings(&self) -> ClientRpcUserSettings<'a> { - ClientRpcUserSettings { - client: self.client, - } - } -} - -/// `user.settings.*` RPCs. -#[derive(Clone, Copy)] -pub struct ClientRpcUserSettings<'a> { - pub(crate) client: &'a Client, -} -impl<'a> ClientRpcUserSettings<'a> { /// Lists every known user setting from settings.json, each with its effective value, its default, and whether it is at the default — so settings the user has never set still appear with their default value. Does not include repository- or enterprise-managed overrides that the runtime layers on top at session time. /// /// Wire method: `user.settings.get`. diff --git a/samples/startup-policy/README.md b/samples/startup-policy/README.md new file mode 100644 index 0000000000..4e9f902da3 --- /dev/null +++ b/samples/startup-policy/README.md @@ -0,0 +1,28 @@ +# Startup policy example + +This source example uses an isolated configuration directory and a local runtime. +It makes no model request and installs no certificate. +It does not read or write your settings or keychain. + +Prepare the same-checkout runtime and generated Node.js client with the +[SDK contributor guide](../../CONTRIBUTING.md#testing-an-unreleased-runtime-api). +From the SDK directory, run: + +```sh +npx --no-install tsx samples/startup-policy/read-settings.mts /absolute/path/to/runtime.node +``` + +The output shows `user-model`, then `repo-model`, and a `changed` repository edit. +The obsolete value in `config.json` does not override `settings.json`. +Managed plugin controls override the user value. +The startup override disables native web search. +The permission query reports the managed bypass restriction. +The ingestion request disables policy discovery and network access. +The managed sandbox floor stays enabled. +`proxyCaRelevant` is `true`; installation support depends on the host platform. + +The example imports internal host helpers directly from the source checkout. +Those helpers are not public SDK exports. +Applications can use `client.rpc.sandbox.proxyCa.checkRelevance` and +`client.rpc.sandbox.proxyCa.checkInstallationSupport` through the public client. +Neither query installs a certificate or requests elevation. diff --git a/samples/startup-policy/read-settings.mts b/samples/startup-policy/read-settings.mts new file mode 100644 index 0000000000..f0a2c9a883 --- /dev/null +++ b/samples/startup-policy/read-settings.mts @@ -0,0 +1,141 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import assert from "node:assert/strict"; +import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join, resolve } from "node:path"; +import { + createMessageConnection, + StreamMessageReader, + StreamMessageWriter, +} from "vscode-jsonrpc/node.js"; +import { FfiRuntimeHost } from "../../nodejs/src/ffiRuntimeHost.js"; +import { createInternalServerRpc, createServerRpc } from "../../nodejs/src/generated/rpc.js"; + +const library = process.argv[2]; +assert(library, "Pass the same-checkout runtime.node path as the first argument"); +const home = await mkdtemp(join(tmpdir(), "copilot-startup-policy-")); +let host: FfiRuntimeHost | undefined; +let connection: ReturnType | undefined; +const errors: unknown[] = []; +try { + const configDir = join(home, ".copilot"); + const repo = join(home, "project"); + await mkdir(configDir); + await mkdir(join(repo, ".github", "copilot"), { recursive: true }); + await writeFile(join(configDir, "settings.json"), JSON.stringify({ model: "user-model" })); + await writeFile(join(configDir, "config.json"), JSON.stringify({ model: "obsolete-model" })); + await writeFile( + join(repo, ".github", "copilot", "settings.json"), + JSON.stringify({ model: "repo-model" }) + ); + host = FfiRuntimeHost.create( + resolve(library), + undefined, + { + HOME: home, + USERPROFILE: home, + COPILOT_HOME: configDir, + COPILOT_CACHE_HOME: join(home, "cache"), + COPILOT_OFFLINE: "true", + COPILOT_USE_KEYCHAIN: "false", + }, + ["--no-auto-login"] + ); + await host.start(); + connection = createMessageConnection( + new StreamMessageReader(host.receiveStream), + new StreamMessageWriter(host.sendStream) + ); + connection.listen(); + const internal = createInternalServerRpc(connection); + const rpc = createServerRpc(connection); + const startupGates = await internal.featureFlags.resolveStartupGates({ + flags: ["NATIVE_WEB_SEARCH"], + isStaff: false, + isExperimental: false, + isTeam: false, + streamerMode: false, + refreshWithoutSession: false, + environment: {}, + config: { featureFlags: { NATIVE_WEB_SEARCH: false } }, + }); + assert.equal(startupGates.NATIVE_WEB_SEARCH, false); + const loaded = await internal.user.settings.loadWithWarning(); + assert.equal(loaded.settings.model, "user-model"); + const merged = await internal.user.settings.loadAndMergeRepo({ + repoRoot: repo, + userSettings: loaded.settings, + }); + assert.equal(merged.settings.model, "repo-model"); + const edit = await internal.repo.settings.edit({ + repoRoot: repo, + scope: "local", + key: "deniedUrls", + operation: "add-item", + value: "https://example.com", + }); + assert.equal(edit.status, "changed"); + const controls = await internal.managedSettings.applyControls({ + settings: { enabledPlugins: { required: false } }, + managed: { enabledPlugins: { required: true } }, + }); + assert.deepEqual(controls.settingsJson, { enabledPlugins: { required: true } }); + const permissions = await internal.permissions.evaluateManagedPolicy({ + permissions: { disableBypassPermissionsMode: "disable" }, + }); + assert.equal(permissions.bypassPermissionsDisabled, true); + const ingestion = await internal.managedSettings.ingest({ + selfFetch: false, + userAgent: "startup-policy-example", + environment: {}, + platform: process.platform, + homeDirectory: home, + }); + assert.equal(ingestion.serverFetchFailed, false); + const sandbox = await internal.sandbox.resolveFlooredConfig({ + userSandbox: { enabled: false }, + managedSandbox: { enabled: true, failIfUnavailable: true }, + }); + const relevant = await rpc.sandbox.proxyCa.checkRelevance({ + sandboxConfig: { enabled: true, auth: { gh: true } }, + }); + assert.equal(relevant, true); + console.log( + JSON.stringify( + { + userModel: loaded.settings.model, + repoModel: merged.settings.model, + repoEdit: edit.status, + startupGates, + managedControls: controls.settingsJson, + permissions, + ingestion: ingestion.serverResolution, + sandbox: sandbox.sandboxJson, + proxyCaRelevant: relevant, + proxyCaInstallationSupported: await rpc.sandbox.proxyCa.checkInstallationSupport(), + }, + null, + 2 + ) + ); +} catch (error) { + errors.push(error); +} finally { + connection?.dispose(); + try { + await host?.dispose(); + } catch (error) { + errors.push(error); + } + try { + await rm(home, { recursive: true, force: true }); + } catch (error) { + errors.push(error); + } +} +if (errors.length > 0) { + throw new AggregateError(errors, "Startup policy example failed"); +} diff --git a/scripts/codegen/csharp-dictionary-roundtrip.test.ts b/scripts/codegen/csharp-dictionary-roundtrip.test.ts new file mode 100644 index 0000000000..604ed86fc2 --- /dev/null +++ b/scripts/codegen/csharp-dictionary-roundtrip.test.ts @@ -0,0 +1,90 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import assert from "node:assert/strict"; +import { spawnSync } from "node:child_process"; +import { mkdtemp, rm, writeFile } from "node:fs/promises"; +import { join } from "node:path"; +import { test } from "node:test"; +import { generateRpcCode } from "./csharp.ts"; + +test("generated C# open dictionaries retain entries through System.Text.Json", async () => { + const directory = await mkdtemp(join(process.cwd(), ".csharp-dictionary-test-")); + let failure: unknown; + try { + const code = generateRpcCode({ + server: { + sample: { + read: { + rpcMethod: "sample.read", + params: null, + result: { + title: "SampleResult", + type: "object", + properties: { + environment: { type: "object", properties: {} }, + settings: { type: "object", properties: {} }, + }, + required: ["environment"], + }, + }, + }, + }, + }); + await writeFile(join(directory, "Rpc.cs"), code); + await writeFile( + join(directory, "Roundtrip.csproj"), + ` + + Exe + net10.0 + enable + enable + +` + ); + await writeFile( + join(directory, "Program.cs"), + `using System.Text.Json; +using System.Text.Json.Nodes; +using GitHub.Copilot.Rpc; + +const string json = """ +{"environment":{"COPILOT_HOME":"/isolated/config","EMPTY":""},"settings":{"model":"selected-model","enabled":false,"custom":{"nested":42}}} +"""; +var value = JsonSerializer.Deserialize(json)!; +var actual = JsonSerializer.Serialize(value); +if (!JsonNode.DeepEquals(JsonNode.Parse(json), JsonNode.Parse(actual))) + throw new Exception($"Dictionary entries lost: {actual}"); +Console.WriteLine("environment and settings dictionaries round-trip"); + +namespace GitHub.Copilot.Rpc +{ + internal sealed class JsonRpc; + internal static class CopilotClient + { + internal static Task InvokeRpcAsync(JsonRpc rpc, string method, object[] args, + CancellationToken cancellationToken) => throw new NotSupportedException("No RPC is expected"); + } +}` + ); + const result = spawnSync("dotnet", ["run", "--project", join(directory, "Roundtrip.csproj")], { + cwd: directory, + encoding: "utf8", + }); + if (result.error) throw result.error; + assert.equal(result.status, 0, `${result.stdout}\n${result.stderr}`); + assert.match(result.stdout, /environment and settings dictionaries round-trip/); + } catch (error) { + failure = error; + throw error; + } finally { + try { + await rm(directory, { recursive: true, force: true }); + } catch (cleanupError) { + if (failure) throw new AggregateError([failure, cleanupError], "Test and cleanup failed"); + throw cleanupError; + } + } +}); diff --git a/scripts/codegen/csharp.ts b/scripts/codegen/csharp.ts index 2ab2c3c7e7..fe7e8f185a 100644 --- a/scripts/codegen/csharp.ts +++ b/scripts/codegen/csharp.ts @@ -1894,9 +1894,12 @@ function resolveRpcType(schema: JSONSchema7, isRequired: boolean, parentClassNam if (isOpaqueJson(schema)) { return isRequired ? "JsonElement" : "JsonElement?"; } - if (schema.type === "object" && schema.additionalProperties === true && + if (schema.type === "object" && schema.additionalProperties !== false && (!schema.properties || Object.keys(schema.properties).length === 0)) { - return isRequired ? "IDictionary" : "IDictionary?"; + const valueType = typeof schema.additionalProperties === "object" + ? resolveRpcType(schema.additionalProperties, true, parentClassName, `${propName}Value`, classes) + : "JsonElement"; + return isRequired ? `IDictionary` : `IDictionary?`; } // Handle $ref by resolving against schema definitions and generating the referenced class if (schema.$ref) { @@ -1911,7 +1914,8 @@ function resolveRpcType(schema: JSONSchema7, isRequired: boolean, parentClassNam return isRequired ? enumName : `${enumName}?`; } - if (refSchema.type === "object" && refSchema.properties) { + if (refSchema.type === "object" && refSchema.properties && + (Object.keys(refSchema.properties).length > 0 || refSchema.additionalProperties === false)) { const cls = emitRpcClass(typeName, refSchema, "public", classes); if (cls) classes.push(cls); return isRequired ? typeName : `${typeName}?`; @@ -2005,7 +2009,8 @@ function resolveRpcType(schema: JSONSchema7, isRequired: boolean, parentClassNam } if (schema.type === "array" && schema.items) { const items = schema.items as JSONSchema7; - if (items.type === "object" && items.properties) { + if (items.type === "object" && items.properties && + (Object.keys(items.properties).length > 0 || items.additionalProperties === false)) { const itemClass = (items.title as string) ?? `${parentClassName}${singularPascal(propName)}`; classes.push(emitRpcClass(itemClass, items, "public", classes)); return isRequired ? `IList<${itemClass}>` : `IList<${itemClass}>?`; @@ -2013,11 +2018,6 @@ function resolveRpcType(schema: JSONSchema7, isRequired: boolean, parentClassNam const itemType = resolveRpcType(items, true, parentClassName, `${propName}Item`, classes); return isRequired ? `IList<${itemType}>` : `IList<${itemType}>?`; } - if (schema.type === "object" && schema.additionalProperties && typeof schema.additionalProperties === "object") { - const vs = schema.additionalProperties as JSONSchema7; - const valueType = resolveRpcType(vs, true, parentClassName, `${propName}Value`, classes); - return isRequired ? `IDictionary` : `IDictionary?`; - } return schemaTypeToCSharp(schema, isRequired, rpcKnownTypes, propName); } From b19d3ef043ebfeaeb794339173c39ad6c8eb29ca Mon Sep 17 00:00:00 2001 From: "copilot-cli-release-app[bot]" Date: Tue, 13 Oct 2026 01:16:18 +0000 Subject: [PATCH 9/9] Update SDK snapshot for Copilot CLI 1.0.97-2 --- nodejs/package.json | 2 +- nodejs/src/cliVersion.ts | 2 +- nodejs/test/e2e/rpc_server.e2e.test.ts | 32 ++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/nodejs/package.json b/nodejs/package.json index 559af6817e..d3b0dd5d52 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -5,7 +5,7 @@ "url": "https://github.com/github/copilot-sdk.git" }, "version": "0.0.0-dev", - "copilotCliVersion": "1.0.97-1", + "copilotCliVersion": "1.0.97-2", "description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC", "main": "./dist/cjs/index.js", "types": "./dist/index.d.ts", diff --git a/nodejs/src/cliVersion.ts b/nodejs/src/cliVersion.ts index 05901f9aee..58d20a7d2c 100644 --- a/nodejs/src/cliVersion.ts +++ b/nodejs/src/cliVersion.ts @@ -1,3 +1,3 @@ -export const COPILOT_CLI_VERSION = "1.0.97-1"; +export const COPILOT_CLI_VERSION = "1.0.97-2"; export const COPILOT_CLI_USE_NPM_PACKAGE = false; diff --git a/nodejs/test/e2e/rpc_server.e2e.test.ts b/nodejs/test/e2e/rpc_server.e2e.test.ts index 0b8049225e..16e3d1411a 100644 --- a/nodejs/test/e2e/rpc_server.e2e.test.ts +++ b/nodejs/test/e2e/rpc_server.e2e.test.ts @@ -4,6 +4,7 @@ import * as fs from "fs"; import * as path from "path"; +import { execFileSync } from "node:child_process"; import { randomUUID } from "node:crypto"; import { describe, expect, it, onTestFinished } from "vitest"; import { CopilotClient, RuntimeConnection } from "../../src/index.js"; @@ -690,6 +691,37 @@ describe("Server-scoped RPC", async () => { ); }); + it("should discover all 128 custom agents including deeply nested definitions", async () => { + const projectPath = createUniqueWorkDirectory("server-rpc-agents"); + execFileSync("git", ["init", "--quiet"], { + cwd: projectPath, + env, + windowsHide: true, + }); + const agentsDirectory = path.join(projectPath, ".github", "agents"); + const nestedDirectory = path.join(agentsDirectory, ...Array(12).fill("d")); + fs.mkdirSync(nestedDirectory, { recursive: true }); + const expectedNames = Array.from( + { length: 128 }, + (_, index) => `agent-${index.toString().padStart(3, "0")}` + ); + for (const [index, name] of expectedNames.entries()) { + const directory = index === 127 ? nestedDirectory : agentsDirectory; + fs.writeFileSync( + path.join(directory, `${name}.agent.md`), + `---\nname: ${name}\ndescription: Test agent.\n---\nAgent prompt.` + ); + } + + await client.start(); + const result = await client.rpc.agents.discover({ + projectPaths: [projectPath], + excludeHostAgents: true, + }); + + expect(result.agents.map((agent) => agent.name).sort()).toEqual(expectedNames); + }); + it("should discover server mcp and skills", async () => { await client.start();