diff --git a/.github/badges/jacoco-generated.svg b/.github/badges/jacoco-generated.svg
deleted file mode 100644
index bd7223a65..000000000
--- a/.github/badges/jacoco-generated.svg
+++ /dev/null
@@ -1,18 +0,0 @@
-
diff --git a/.github/badges/jacoco-handwritten.svg b/.github/badges/jacoco-handwritten.svg
deleted file mode 100644
index bfb6196f6..000000000
--- a/.github/badges/jacoco-handwritten.svg
+++ /dev/null
@@ -1,18 +0,0 @@
-
diff --git a/.github/scripts/generate-java-coverage-badge.sh b/.github/scripts/generate-java-coverage-badge.sh
deleted file mode 100755
index 3c68d830d..000000000
--- a/.github/scripts/generate-java-coverage-badge.sh
+++ /dev/null
@@ -1,104 +0,0 @@
-#!/usr/bin/env bash
-# Generates SVG coverage badges from a JaCoCo CSV report.
-#
-# Usage: generate-coverage-badge.sh [jacoco.csv] [output-dir]
-# jacoco.csv - Path to JaCoCo CSV report (default: target/site/jacoco-coverage/jacoco.csv)
-# output-dir - Directory for the badge SVG (default: .github/badges)
-set -euo pipefail
-
-CSV="${1:-target/site/jacoco-coverage/jacoco.csv}"
-BADGES_DIR="${2:-.github/badges}"
-GENERATED_PREFIX="com.github.copilot.generated"
-
-if [ ! -f "$CSV" ]; then
- echo "⚠️ No JaCoCo CSV report found at $CSV"
- exit 0
-fi
-
-calc_totals() {
- local scope=$1
- awk -F',' -v scope="$scope" -v generated_prefix="$GENERATED_PREFIX" '
- NR > 1 {
- is_generated = index($2, generated_prefix) == 1
- if (scope == "overall" ||
- (scope == "generated" && is_generated) ||
- (scope == "handwritten" && !is_generated)) {
- missed += $4
- covered += $5
- }
- }
- END { print missed + 0, covered + 0 }
- ' "$CSV"
-}
-
-format_pct() {
- local missed=$1
- local covered=$2
- local total=$((missed + covered))
- if [ "$total" -eq 0 ]; then
- echo "0"
- else
- awk "BEGIN { printf \"%.1f\", ($covered / $total) * 100 }" | sed 's/\.0$//'
- fi
-}
-
-pick_color() {
- local pct=$1
- local color="#e05d44" # red <60
- if awk "BEGIN{exit!($pct>=100)}"; then color="#4c1" # bright green
- elif awk "BEGIN{exit!($pct>=90)}"; then color="#97ca00" # green
- elif awk "BEGIN{exit!($pct>=80)}"; then color="#a4a61d" # yellow-green
- elif awk "BEGIN{exit!($pct>=70)}"; then color="#dfb317" # yellow
- elif awk "BEGIN{exit!($pct>=60)}"; then color="#fe7d37" # orange
- fi
- echo "$color"
-}
-
-generate_badge() {
- local label=$1
- local value=$2
- local output=$3
- local pct=${value%\%}
- local color
- color=$(pick_color "$pct")
- local lw=$(( ${#label} * 7 + 12 ))
- local vw=$(( ${#value} * 7 + 16 ))
- local tw=$((lw + vw))
-
- cat > "$output" <
-
-
-
-
-
-
-
-
-
-
-
- ${label}
- ${label}
- ${value}
- ${value}
-
-
-EOF
-}
-
-mkdir -p "$BADGES_DIR"
-
-read -r handwritten_missed handwritten_covered <<< "$(calc_totals handwritten)"
-read -r generated_missed generated_covered <<< "$(calc_totals generated)"
-
-handwritten_pct=$(format_pct "$handwritten_missed" "$handwritten_covered")
-generated_pct=$(format_pct "$generated_missed" "$generated_covered")
-
-echo "Handwritten coverage: ${handwritten_pct}%"
-echo "Generated coverage: ${generated_pct}%"
-
-generate_badge "coverage handwritten" "${handwritten_pct}%" "${BADGES_DIR}/jacoco-handwritten.svg"
-generate_badge "coverage generated" "${generated_pct}%" "${BADGES_DIR}/jacoco-generated.svg"
-
-echo "Badges generated in ${BADGES_DIR}"
diff --git a/.github/workflows/block-remove-before-merge.yml b/.github/workflows/block-remove-before-merge.yml
index f9df22ebe..0b491ea81 100644
--- a/.github/workflows/block-remove-before-merge.yml
+++ b/.github/workflows/block-remove-before-merge.yml
@@ -11,7 +11,7 @@ permissions:
jobs:
check-paths:
name: "No remove-before-merge directories"
- if: github.event_name == 'pull_request'
+ if: github.event_name == 'pull_request' && github.base_ref == 'main'
runs-on: ubuntu-latest
steps:
- name: Check for remove-before-merge paths in PR
diff --git a/.github/workflows/dotnet-sdk-tests.yml b/.github/workflows/dotnet-sdk-tests.yml
index d3b2ef162..dcf559228 100644
--- a/.github/workflows/dotnet-sdk-tests.yml
+++ b/.github/workflows/dotnet-sdk-tests.yml
@@ -28,7 +28,7 @@ permissions:
jobs:
test:
- name: ".NET SDK Tests"
+ name: ".NET SDK Tests (${{ matrix.os }}, ${{ matrix.transport }})"
if: github.event.repository.fork == false
env:
POWERSHELL_UPDATECHECK: Off
@@ -36,6 +36,11 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
+ transport: ["default", "inprocess"]
+ # TODO: Re-enable after fixing in-process sqlite file locking on shutdown on Windows
+ exclude:
+ - os: windows-latest
+ transport: "inprocess"
runs-on: ${{ matrix.os }}
defaults:
run:
@@ -80,6 +85,10 @@ jobs:
if: runner.os == 'Windows'
run: pwsh.exe -Command "Write-Host 'PowerShell ready'"
+ - name: Select inprocess transport
+ if: matrix.transport == 'inprocess'
+ run: echo "COPILOT_SDK_DEFAULT_CONNECTION=inprocess" >> "$GITHUB_ENV"
+
- name: Run .NET SDK tests
env:
COPILOT_HMAC_KEY: ${{ secrets.COPILOT_DEVELOPER_CLI_INTEGRATION_HMAC_KEY }}
diff --git a/.github/workflows/java-sdk-tests.yml b/.github/workflows/java-sdk-tests.yml
index e310fa8ba..948a986e5 100644
--- a/.github/workflows/java-sdk-tests.yml
+++ b/.github/workflows/java-sdk-tests.yml
@@ -31,9 +31,7 @@ on:
merge_group:
permissions:
- contents: write
- checks: write
- pull-requests: write
+ contents: read
jobs:
java-sdk:
@@ -77,12 +75,19 @@ jobs:
- name: Run spotless check
if: matrix.test-jdk == '25'
run: |
- mvn spotless:check
- if [ $? -ne 0 ]; then
- echo "❌ spotless:check failed. Please run 'mvn spotless:apply' in java"
- exit 1
- fi
- echo "✅ spotless:check passed"
+ max_attempts=3
+ for ((attempt=1; attempt<=max_attempts; attempt++)); do
+ if mvn spotless:check; then
+ echo "✅ spotless:check passed"
+ exit 0
+ fi
+ if [ "$attempt" -lt "$max_attempts" ]; then
+ echo "⚠️ spotless:check failed (attempt $attempt/$max_attempts), retrying in 10s..."
+ sleep 10
+ fi
+ done
+ echo "❌ spotless:check failed after $max_attempts attempts. Please run 'mvn spotless:apply' in java/"
+ exit 1
- name: Run Java SDK tests (JDK 25)
if: matrix.test-jdk == '25'
@@ -117,22 +122,6 @@ jobs:
java/target/surefire-reports-isolated/
retention-days: 1
- - name: Generate JaCoCo badge
- if: success() && github.ref == 'refs/heads/main' && matrix.test-jdk == '25'
- working-directory: .
- run: bash .github/scripts/generate-java-coverage-badge.sh java/target/site/jacoco-coverage/jacoco.csv .github/badges
-
- - name: Create PR for JaCoCo badge update
- if: success() && github.ref == 'refs/heads/main' && matrix.test-jdk == '25'
- uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v7
- with:
- commit-message: "Update Java JaCoCo coverage badge"
- title: "Update Java JaCoCo coverage badge"
- body: "Automated Java JaCoCo coverage badge update from CI."
- branch: auto/update-java-jacoco-badge
- add-paths: .github/badges/
- delete-branch: true
-
- name: Generate Test Report Summary
if: always()
uses: ./.github/actions/java-test-report
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 06461a734..acf014c53 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,82 @@ All notable changes to the Copilot SDK are documented in this file.
This changelog is automatically generated by an AI agent when stable releases are published.
See [GitHub Releases](https://github.com/github/copilot-sdk/releases) for the full list.
+## [java/v1.0.5-01](https://github.com/github/copilot-sdk/releases/tag/java/v1.0.5-01) (2026-07-01)
+
+### Feature: new session options — citations, agent exclusions, and credit limits
+
+Three new options are available on `SessionConfig` and `ResumeSessionConfig`. `enableCitations` (experimental) enables native model citations for supported providers; `excludedBuiltInAgents` hides named built-in agents from discovery; and `sessionLimits` sets a per-session AI-credit budget. ([#1865](https://github.com/github/copilot-sdk/pull/1865))
+
+```java
+SessionConfig config = new SessionConfig()
+ .setEnableCitations(true)
+ .setExcludedBuiltInAgents(List.of("copilot"))
+ .setSessionLimits(new SessionLimitsConfig(100.0));
+```
+
+### New contributors
+
+- @coleflennikenmsft made their first contribution in [#1854](https://github.com/github/copilot-sdk/pull/1854)
+- @szabta89 made their first contribution in [#1856](https://github.com/github/copilot-sdk/pull/1856)
+
+## [v1.0.5](https://github.com/github/copilot-sdk/releases/tag/v1.0.5) (2026-07-01)
+
+### Feature: MCP OAuth host token handlers
+
+SDK applications can now handle OAuth challenges from MCP servers that require host-provided authentication. Register an `onMcpAuthRequest` callback on the session config and the SDK will invoke it whenever an MCP server responds with a `401 WWW-Authenticate` challenge; return an access token (or cancel the request). Supports initial auth, refresh, reauth, and upscope flows across all SDKs. ([#1669](https://github.com/github/copilot-sdk/pull/1669))
+
+```ts
+const session = await client.createSession({
+ onMcpAuthRequest: async (request) => ({
+ accessToken: await myIdentityProvider.getToken(request.serverUrl),
+ }),
+});
+```
+
+```cs
+var session = await client.CreateSessionAsync(new SessionConfig
+{
+ OnMcpAuthRequest = async ctx =>
+ McpAuthResult.FromToken(new McpAuthToken
+ {
+ AccessToken = await myIdentityProvider.GetTokenAsync(ctx.ServerUrl)
+ }),
+});
+```
+
+### Feature: session options for citations, excluded agents, and spending limits
+
+Three additional session configuration options are now available across all SDKs. ([#1865](https://github.com/github/copilot-sdk/pull/1865))
+
+```ts
+const session = await client.createSession({
+ enableCitations: true,
+ excludedBuiltinAgents: ["github-search"],
+ sessionLimits: { maxAiCredits: 10 },
+});
+```
+
+```cs
+var session = await client.CreateSessionAsync(new SessionConfig
+{
+ EnableCitations = true,
+ ExcludedBuiltInAgents = ["github-search"],
+ SessionLimits = new SessionLimitsConfig { MaxAiCredits = 10 },
+});
+```
+
+### Other changes
+
+- improvement: **[All SDKs]** rename BYOK callback field `getBearerToken` → `bearerTokenProvider`; add `sessionId` to `ProviderTokenArgs` for per-session token scoping ([#1796](https://github.com/github/copilot-sdk/pull/1796))
+- bugfix: **[Node]** fix MCP OAuth `registerInterest` sent before `session.resume`, causing "Session not found" errors when resuming a session with `onMcpAuthRequest` ([#1861](https://github.com/github/copilot-sdk/pull/1861))
+- feature: **[Java]** `@CopilotTool` and `@CopilotToolParam` annotations with compile-time annotation processor for ergonomic tool registration via `ToolDefinition.fromObject()` ([#1792](https://github.com/github/copilot-sdk/pull/1792), [#1838](https://github.com/github/copilot-sdk/pull/1838))
+- feature: **[Java]** `ToolInvocation` parameter injection in `@CopilotTool` methods for accessing session context without exposing it to the LLM schema ([#1832](https://github.com/github/copilot-sdk/pull/1832))
+- feature: **[Rust]** add 9 GitHub-anchored variants to `Attachment` enum (`GitHubCommit`, `GitHubRelease`, `GitHubActionsJob`, `GitHubRepository`, `GitHubFileDiff`, `GitHubTreeComparison`, `GitHubUrl`, `GitHubFile`, `GitHubSnippet`) ([#1823](https://github.com/github/copilot-sdk/pull/1823))
+
+### New contributors
+
+- @pallaviraiturkar0 made their first contribution in [#1823](https://github.com/github/copilot-sdk/pull/1823)
+- @roji made their first contribution in [#1827](https://github.com/github/copilot-sdk/pull/1827)
## [java/v1.0.4](https://github.com/github/copilot-sdk/releases/tag/java/v1.0.4) (2026-06-25)
### Feature: HTTP request callback support
diff --git a/dotnet/src/Client.cs b/dotnet/src/Client.cs
index 71c7c8795..94b092199 100644
--- a/dotnet/src/Client.cs
+++ b/dotnet/src/Client.cs
@@ -8,6 +8,7 @@
using Microsoft.Extensions.Logging.Abstractions;
using System.Collections.Concurrent;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Net.Sockets;
using System.Runtime.ExceptionServices;
@@ -78,6 +79,7 @@ public sealed partial class CopilotClient : IDisposable, IAsyncDisposable
private readonly List _lifecycleHandlers = [];
private Task? _connectionTask;
+ private FfiRuntimeHost? _ffiHost;
private bool _disposed;
private int? _actualPort;
private int? _negotiatedProtocolVersion;
@@ -134,13 +136,16 @@ private sealed record LifecycleSubscription(Type EventType, Action
+ /// Validates environment-variable options against the resolved transport.
+ /// Per-client environment is only representable for child-process transports
+ /// (each client owns its own OS process). The in-process (FFI) transport
+ /// loads the native runtime into the shared host process, whose single
+ /// environment block cannot carry per-client values, so environment and
+ /// telemetry options that lower to environment variables are rejected there.
+ ///
+ private static void ValidateEnvironmentOptions(CopilotClientOptions options, RuntimeConnection connection)
+ {
+ if (connection is InProcessRuntimeConnection)
+ {
+ if (options.Environment is not null)
+ {
+ throw new ArgumentException(
+ $"{nameof(CopilotClientOptions)}.{nameof(CopilotClientOptions.Environment)} is not supported with " +
+ $"{nameof(RuntimeConnection)}.{nameof(RuntimeConnection.ForInProcess)}(): the in-process transport " +
+ "loads the native runtime into the shared host process, whose single environment block cannot carry " +
+ "per-client values. Set the variables on the host process environment instead.",
+ nameof(options));
+ }
+
+ if (options.Telemetry is not null)
+ {
+ throw new ArgumentException(
+ $"{nameof(CopilotClientOptions)}.{nameof(CopilotClientOptions.Telemetry)} is not supported with " +
+ $"{nameof(RuntimeConnection)}.{nameof(RuntimeConnection.ForInProcess)}(): telemetry configuration is " +
+ "lowered to environment variables read by native runtime code running in the shared host process, so " +
+ "per-client telemetry cannot be honored in-process. Configure telemetry via the host process " +
+ "environment, or use a child-process transport.",
+ nameof(options));
+ }
+
+ return;
+ }
+
+ if (connection is ChildProcessRuntimeConnection { Environment: not null } && options.Environment is not null)
+ {
+ throw new ArgumentException(
+ $"Set environment variables via either {nameof(CopilotClientOptions)}.{nameof(CopilotClientOptions.Environment)} " +
+ $"or {nameof(ChildProcessRuntimeConnection)}.{nameof(ChildProcessRuntimeConnection.Environment)}, not both. " +
+ $"Prefer {nameof(ChildProcessRuntimeConnection)}.{nameof(ChildProcessRuntimeConnection.Environment)} for " +
+ "child-process transports.",
+ nameof(options));
+ }
+ }
+
+ ///
+ /// Environment variable that overrides the transport used when the caller does not
+ /// specify . Accepts "inprocess"
+ /// or "stdio" (case-insensitive); unset preserves the default stdio transport.
+ /// Any other value is an error. Ignored when a is set
+ /// explicitly.
+ ///
+ internal const string DefaultConnectionEnvVar = "COPILOT_SDK_DEFAULT_CONNECTION";
+
+ ///
+ /// Resolves the default for the no-Connection case,
+ /// honoring .
+ ///
+ private static RuntimeConnection ResolveDefaultConnection(CopilotClientOptions options)
+ {
+ var value = options.Environment is not null
+ && options.Environment.TryGetValue(DefaultConnectionEnvVar, out var fromOptions)
+ ? fromOptions
+ : Environment.GetEnvironmentVariable(DefaultConnectionEnvVar);
+
+ if (string.IsNullOrEmpty(value) || string.Equals(value, "stdio", StringComparison.OrdinalIgnoreCase))
+ {
+ return RuntimeConnection.ForStdio();
+ }
+ if (string.Equals(value, "inprocess", StringComparison.OrdinalIgnoreCase))
+ {
+ return RuntimeConnection.ForInProcess();
+ }
+ throw new ArgumentException(
+ $"Invalid {DefaultConnectionEnvVar} value '{value}'. Expected 'inprocess', 'stdio', or unset.");
+ }
+
///
/// Parses a runtime URL into a URI with host and port.
///
@@ -250,7 +336,23 @@ async Task StartCoreAsync(CancellationToken ct)
try
{
- if (_connection is UriRuntimeConnection)
+ if (_connection is InProcessRuntimeConnection)
+ {
+ // In-process FFI hosting: load the Rust cdylib and let it spawn
+ // the CLI worker, instead of the SDK launching a CLI child process.
+ // The worker reads its configuration (telemetry export, etc.) from
+ // the environment passed here, so apply the same telemetry-derived
+ // vars the child-process path sets on its startInfo.Environment.
+ var ffiEnvironment = _options.Environment?.ToDictionary(kvp => kvp.Key, kvp => (string?)kvp.Value)
+ ?? new Dictionary();
+ ApplyTelemetryEnvironment(ffiEnvironment, _options.Telemetry);
+ var resolvedFfiEnvironment = ffiEnvironment.ToDictionary(kvp => kvp.Key, kvp => kvp.Value!);
+ var ffiHost = FfiRuntimeHost.Create(ResolveCliPathForFfi(), GetNapiPrebuildsFolderOrThrow(), resolvedFfiEnvironment, _logger);
+ _ffiHost = ffiHost;
+ await ffiHost.StartAsync(ct);
+ connection = await ConnectToServerAsync(null, null, null, null, ct, ffiHost);
+ }
+ else if (_connection is UriRuntimeConnection)
{
// External runtime
_actualPort = _optionsPort;
@@ -437,7 +539,7 @@ private async Task CleanupConnectionAsync(List? errors, bool graceful
private async Task CleanupConnectionAsync(Connection ctx, List? errors, bool gracefulRuntimeShutdown)
{
- if (gracefulRuntimeShutdown && ctx.CliProcess is not null)
+ if (gracefulRuntimeShutdown && (ctx.CliProcess is not null || ctx.FfiHost is not null))
{
var runtimeShutdownTimestamp = Stopwatch.GetTimestamp();
try
@@ -477,6 +579,13 @@ or IOException
{
await CleanupCliProcessAsync(childProcess, ctx.StderrPump, errors, _logger);
}
+
+ if (ctx.FfiHost is { } ffiHost)
+ {
+ try { ffiHost.Dispose(); }
+ catch (Exception ex) { AddCleanupError(errors, ex, _logger); }
+ _ffiHost = null;
+ }
}
private static async Task CleanupCliProcessAsync(Process childProcess, ProcessStderrPump? stderrPump, List? errors, ILogger? logger)
@@ -1037,7 +1146,8 @@ public async Task CreateSessionAsync(SessionConfig config, Cance
Providers: config.Providers,
Models: config.Models,
ToolFilterPrecedence: toolFilter.ToolFilterPrecedence,
- ExpAssignments: config.ExpAssignments);
+ ExpAssignments: config.ExpAssignments,
+ EnableGitHubTelemetryForwarding: _options.OnGitHubTelemetry != null ? true : null);
var rpcTimestamp = Stopwatch.GetTimestamp();
@@ -1246,7 +1356,8 @@ public async Task ResumeSessionAsync(string sessionId, ResumeSes
Providers: config.Providers,
Models: config.Models,
ToolFilterPrecedence: toolFilter.ToolFilterPrecedence,
- ExpAssignments: config.ExpAssignments);
+ ExpAssignments: config.ExpAssignments,
+ EnableGitHubTelemetryForwarding: _options.OnGitHubTelemetry != null ? true : null);
var rpcTimestamp = Stopwatch.GetTimestamp();
var response = await InvokeRpcAsync(
@@ -1724,21 +1835,24 @@ await Rpc.SessionFs.SetProviderAsync(
}
///
- /// Builds the client-global RPC handler bag at construction time. Currently
- /// only the LLM inference provider adapter is registered; returns null when no
+ /// Builds the client-global RPC handler bag at construction time. Registers
+ /// the LLM inference provider adapter and/or the GitHub telemetry adapter
+ /// depending on which options are configured; returns null when no
/// client-global API is configured so the registration is skipped entirely.
///
private ClientGlobalApiHandlers? BuildClientGlobalApis()
{
var handler = _options.RequestHandler;
- if (handler is null)
+ var onGitHubTelemetry = _options.OnGitHubTelemetry;
+ if (handler is null && onGitHubTelemetry is null)
{
return null;
}
return new ClientGlobalApiHandlers
{
- LlmInference = new LlmInferenceAdapter(handler, () => _serverRpc),
+ LlmInference = handler is null ? null : new LlmInferenceAdapter(handler, () => _serverRpc),
+ GitHubTelemetry = onGitHubTelemetry is null ? null : new GitHubTelemetryAdapter(onGitHubTelemetry, _logger),
};
}
@@ -1789,14 +1903,26 @@ private async Task VerifyProtocolVersionAsync(Connection connection, Cancellatio
int? serverVersion;
try
{
- var token = _connection switch
- {
- TcpRuntimeConnection tcp => tcp.ConnectionToken,
- UriRuntimeConnection uri => uri.ConnectionToken,
- _ => null,
- };
+ var token = _ffiHost is not null
+ ? null // FFI hosting is an ungated in-process connection; no token.
+ : _connection switch
+ {
+ TcpRuntimeConnection tcp => tcp.ConnectionToken,
+ UriRuntimeConnection uri => uri.ConnectionToken,
+ _ => null,
+ };
var connectResponse = await InvokeRpcAsync(
- connection.Rpc, "connect", [new ConnectRequest { Token = token }], connection.StderrBuffer, cancellationToken);
+ connection.Rpc,
+ "connect",
+ [new ConnectHandshakeRequest(
+ token,
+ // Opt in to GitHub telemetry forwarding at the connection level when a
+ // handler is registered (mirrors the runtime, which reads this flag on the
+ // `connect` handshake so the first session's un-replayable `session.start`
+ // event is forwarded). Also sent on session.create/resume for older CLIs.
+ _options.OnGitHubTelemetry != null ? true : null)],
+ connection.StderrBuffer,
+ cancellationToken);
serverVersion = (int)connectResponse.ProtocolVersion;
}
catch (IOException ex) when (ex.InnerException is RemoteRpcException remoteEx && IsUnsupportedConnectMethod(remoteEx))
@@ -1839,6 +1965,25 @@ private static bool IsUnsupportedConnectMethod(RemoteRpcException ex)
|| string.Equals(ex.Message, "Unhandled method connect", StringComparison.Ordinal);
}
+ // Applies the telemetry-derived environment variables the runtime reads to
+ // enable OTLP export. Shared by the stdio/tcp child-process path and the
+ // in-process FFI path so telemetry behaves identically across transports.
+ private static void ApplyTelemetryEnvironment(IDictionary environment, TelemetryConfig? telemetry)
+ {
+ if (telemetry is null)
+ {
+ return;
+ }
+
+ environment["COPILOT_OTEL_ENABLED"] = "true";
+ if (telemetry.OtlpEndpoint is not null) environment["OTEL_EXPORTER_OTLP_ENDPOINT"] = telemetry.OtlpEndpoint;
+ if (telemetry.OtlpProtocol is not null) environment["OTEL_EXPORTER_OTLP_PROTOCOL"] = telemetry.OtlpProtocol;
+ if (telemetry.FilePath is not null) environment["COPILOT_OTEL_FILE_EXPORTER_PATH"] = telemetry.FilePath;
+ if (telemetry.ExporterType is not null) environment["COPILOT_OTEL_EXPORTER_TYPE"] = telemetry.ExporterType;
+ if (telemetry.SourceName is not null) environment["COPILOT_OTEL_SOURCE_NAME"] = telemetry.SourceName;
+ if (telemetry.CaptureContent is { } capture) environment["OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT"] = capture ? "true" : "false";
+ }
+
private async Task<(Process Process, int? DetectedLocalhostTcpPort, ProcessStderrPump StderrPump)> StartCliServerAsync(CancellationToken cancellationToken)
{
var options = _options;
@@ -1847,9 +1992,12 @@ private static bool IsUnsupportedConnectMethod(RemoteRpcException ex)
var tcpConnection = _connection as TcpRuntimeConnection;
var useStdio = _connection is StdioRuntimeConnection;
- // Use explicit path, COPILOT_CLI_PATH env var (from options.Environment or process env), or bundled runtime - no PATH fallback
- var envCliPath = options.Environment is not null && options.Environment.TryGetValue("COPILOT_CLI_PATH", out var envValue) ? envValue
- : System.Environment.GetEnvironmentVariable("COPILOT_CLI_PATH");
+ // Use explicit path, COPILOT_CLI_PATH env var (from the connection's
+ // Environment, options.Environment, or process env), or bundled runtime - no PATH fallback
+ var envCliPath =
+ (childProcessConnection.Environment is not null && childProcessConnection.Environment.TryGetValue("COPILOT_CLI_PATH", out var connEnvValue) ? connEnvValue : null)
+ ?? (options.Environment is not null && options.Environment.TryGetValue("COPILOT_CLI_PATH", out var envValue) ? envValue : null)
+ ?? System.Environment.GetEnvironmentVariable("COPILOT_CLI_PATH");
var cliPath = childProcessConnection.Path
?? envCliPath
?? GetBundledCliPath(out var searchedPath)
@@ -1916,10 +2064,11 @@ private static bool IsUnsupportedConnectMethod(RemoteRpcException ex)
CreateNoWindow = true
};
- if (options.Environment != null)
+ var childEnvironment = options.Environment ?? childProcessConnection.Environment;
+ if (childEnvironment != null)
{
startInfo.Environment.Clear();
- foreach (var (key, value) in options.Environment)
+ foreach (var (key, value) in childEnvironment)
{
startInfo.Environment[key] = value;
}
@@ -1953,16 +2102,7 @@ private static bool IsUnsupportedConnectMethod(RemoteRpcException ex)
}
// Set telemetry environment variables if configured
- if (options.Telemetry is { } telemetry)
- {
- startInfo.Environment["COPILOT_OTEL_ENABLED"] = "true";
- if (telemetry.OtlpEndpoint is not null) startInfo.Environment["OTEL_EXPORTER_OTLP_ENDPOINT"] = telemetry.OtlpEndpoint;
- if (telemetry.OtlpProtocol is not null) startInfo.Environment["OTEL_EXPORTER_OTLP_PROTOCOL"] = telemetry.OtlpProtocol;
- if (telemetry.FilePath is not null) startInfo.Environment["COPILOT_OTEL_FILE_EXPORTER_PATH"] = telemetry.FilePath;
- if (telemetry.ExporterType is not null) startInfo.Environment["COPILOT_OTEL_EXPORTER_TYPE"] = telemetry.ExporterType;
- if (telemetry.SourceName is not null) startInfo.Environment["COPILOT_OTEL_SOURCE_NAME"] = telemetry.SourceName;
- if (telemetry.CaptureContent is { } capture) startInfo.Environment["OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT"] = capture ? "true" : "false";
- }
+ ApplyTelemetryEnvironment(startInfo.Environment, options.Telemetry);
var cliProcess = new Process { StartInfo = startInfo };
try
@@ -2071,6 +2211,57 @@ private static bool IsUnsupportedConnectMethod(RemoteRpcException ex)
return arch != null ? $"{os}-{arch}" : null;
}
+ private string ResolveCliPathForFfi()
+ {
+ var envCliPath = _options.Environment is not null && _options.Environment.TryGetValue("COPILOT_CLI_PATH", out var envValue)
+ ? envValue
+ : System.Environment.GetEnvironmentVariable("COPILOT_CLI_PATH");
+ if (!string.IsNullOrEmpty(envCliPath))
+ {
+ return envCliPath;
+ }
+
+ // Fall back to the bundled single-file CLI the same way stdio discovers it.
+ // It embeds its own Node and is spawned directly as `copilot --embedded-host`,
+ // with the sibling cdylib loaded in-process (FfiRuntimeHost.Create prefers the
+ // flat `libcopilot_runtime.so`/`copilot_runtime.dll` next to the CLI, falling
+ // back to the dev `prebuilds//runtime.node` layout).
+ var bundled = GetBundledCliPath(out var searchedPath);
+ return bundled
+ ?? throw new InvalidOperationException(
+ "In-process FFI hosting requires the Copilot CLI. Set the COPILOT_CLI_PATH "
+ + $"environment variable, or ensure the bundled CLI is present (looked in '{searchedPath}').");
+ }
+
+ ///
+ /// Returns the napi-rs prebuilds folder name for the current host — the
+ /// <node-platform>-<arch> convention (e.g. win32-x64,
+ /// darwin-arm64, linux-x64) under which the runtime ships
+ /// prebuilds/<folder>/runtime.node. This differs from the .NET RID
+ /// (win-x64/osx-x64) for Windows and macOS.
+ ///
+ private static string? GetNapiPrebuildsFolder()
+ {
+ string platform;
+ if (OperatingSystem.IsWindows()) platform = "win32";
+ else if (OperatingSystem.IsLinux()) platform = "linux";
+ else if (OperatingSystem.IsMacOS()) platform = "darwin";
+ else return null;
+
+ var arch = System.Runtime.InteropServices.RuntimeInformation.OSArchitecture switch
+ {
+ System.Runtime.InteropServices.Architecture.X64 => "x64",
+ System.Runtime.InteropServices.Architecture.Arm64 => "arm64",
+ _ => null,
+ };
+
+ return arch != null ? $"{platform}-{arch}" : null;
+ }
+
+ private static string GetNapiPrebuildsFolderOrThrow() =>
+ GetNapiPrebuildsFolder()
+ ?? throw new InvalidOperationException("Could not determine a napi-rs prebuilds folder for FFI hosting.");
+
private static (string FileName, IEnumerable Args) ResolveCliCommand(string cliPath, IEnumerable args)
{
var isJsFile = cliPath.EndsWith(".js", StringComparison.OrdinalIgnoreCase);
@@ -2083,7 +2274,7 @@ private static (string FileName, IEnumerable Args) ResolveCliCommand(str
return (cliPath, args);
}
- private async Task ConnectToServerAsync(Process? cliProcess, string? tcpHost, int? tcpPort, ProcessStderrPump? stderrPump, CancellationToken cancellationToken)
+ private async Task ConnectToServerAsync(Process? cliProcess, string? tcpHost, int? tcpPort, ProcessStderrPump? stderrPump, CancellationToken cancellationToken, FfiRuntimeHost? ffiHost = null)
{
var setupTimestamp = Stopwatch.GetTimestamp();
NetworkStream? networkStream = null;
@@ -2093,7 +2284,12 @@ private async Task ConnectToServerAsync(Process? cliProcess, string?
{
Stream inputStream, outputStream;
- if (_connection is StdioRuntimeConnection)
+ if (ffiHost is not null)
+ {
+ inputStream = ffiHost.ReceiveStream;
+ outputStream = ffiHost.SendStream;
+ }
+ else if (_connection is StdioRuntimeConnection)
{
if (cliProcess == null)
{
@@ -2159,7 +2355,7 @@ private async Task ConnectToServerAsync(Process? cliProcess, string?
"CopilotClient.ConnectToServerAsync transport setup complete. Elapsed={Elapsed}",
setupTimestamp);
- var connection = new Connection(rpc, cliProcess, networkStream, stderrPump);
+ var connection = new Connection(rpc, cliProcess, networkStream, stderrPump, ffiHost);
_serverRpc = connection.Server;
return connection;
@@ -2248,13 +2444,15 @@ public void Dispose()
///
/// A representing the asynchronous dispose operation.
///
- /// This method calls to immediately release all resources.
+ /// This method calls to gracefully shut down the runtime and
+ /// release all resources. Use for an immediate hard stop
+ /// that skips graceful runtime shutdown.
///
public async ValueTask DisposeAsync()
{
if (_disposed) return;
_disposed = true;
- await ForceStopAsync();
+ await StopAsync();
}
private class RpcHandler(CopilotClient client)
@@ -2362,7 +2560,8 @@ private class Connection(
JsonRpc rpc,
Process? cliProcess, // Set if we created the child process
NetworkStream? networkStream, // Set if using TCP
- ProcessStderrPump? stderrPump = null) // Captures stderr for error messages
+ ProcessStderrPump? stderrPump = null, // Captures stderr for error messages
+ FfiRuntimeHost? ffiHost = null) // Set if using in-process FFI hosting
{
public Process? CliProcess => cliProcess;
public JsonRpc Rpc => rpc;
@@ -2370,6 +2569,7 @@ private class Connection(
public NetworkStream? NetworkStream => networkStream;
public ProcessStderrPump? StderrPump => stderrPump;
public StringBuilder? StderrBuffer => stderrPump?.Buffer;
+ public FfiRuntimeHost? FfiHost => ffiHost;
}
private sealed class ProcessStderrPump
@@ -2495,7 +2695,8 @@ internal record CreateSessionRequest(
IList? Providers = null,
IList? Models = null,
OptionsUpdateToolFilterPrecedence? ToolFilterPrecedence = null,
- [property: JsonPropertyName("expAssignments")] JsonElement? ExpAssignments = null);
+ [property: JsonPropertyName("expAssignments")] JsonElement? ExpAssignments = null,
+ bool? EnableGitHubTelemetryForwarding = null);
#pragma warning restore GHCP001
internal record ToolDefinition(
@@ -2594,7 +2795,8 @@ internal record ResumeSessionRequest(
IList? Providers = null,
IList? Models = null,
OptionsUpdateToolFilterPrecedence? ToolFilterPrecedence = null,
- [property: JsonPropertyName("expAssignments")] JsonElement? ExpAssignments = null);
+ [property: JsonPropertyName("expAssignments")] JsonElement? ExpAssignments = null,
+ bool? EnableGitHubTelemetryForwarding = null);
#pragma warning restore GHCP001
internal record ResumeSessionResponse(
@@ -2631,6 +2833,10 @@ internal record GetSessionMetadataRequest(
internal record GetSessionMetadataResponse(
SessionMetadata? Session);
+ internal record ConnectHandshakeRequest(
+ string? Token,
+ [property: JsonPropertyName("enableGitHubTelemetryForwarding")] bool? EnableGitHubTelemetryForwarding = null);
+
internal record SetForegroundSessionRequest(
string SessionId);
@@ -2665,6 +2871,7 @@ internal record HooksInvokeResponse(
[JsonSerializable(typeof(ListSessionsResponse))]
[JsonSerializable(typeof(GetSessionMetadataRequest))]
[JsonSerializable(typeof(GetSessionMetadataResponse))]
+ [JsonSerializable(typeof(ConnectHandshakeRequest))]
[JsonSerializable(typeof(McpOAuthTokenStorageMode))]
[JsonSerializable(typeof(EmbeddingCacheStorageMode))]
[JsonSerializable(typeof(ModelCapabilitiesOverride))]
@@ -2713,3 +2920,28 @@ public sealed class ToolResultAIContent(ToolResultObject toolResult) : AIContent
///
public ToolResultObject Result => toolResult;
}
+
+///
+/// Bridges the generated client-global handler to
+/// the public OnGitHubTelemetry callback, forwarding the generated
+/// payload unchanged.
+///
+[Experimental(Diagnostics.Experimental)]
+internal sealed class GitHubTelemetryAdapter(Func callback, ILogger logger) : Rpc.IGitHubTelemetryHandler
+{
+ private readonly Func _callback = callback ?? throw new ArgumentNullException(nameof(callback));
+ private readonly ILogger _logger = logger ?? NullLogger.Instance;
+
+ public async Task EventAsync(Rpc.GitHubTelemetryNotification request, CancellationToken cancellationToken = default)
+ {
+ ArgumentNullException.ThrowIfNull(request);
+ try
+ {
+ await _callback(request).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, "Error handling gitHubTelemetry.event notification");
+ }
+ }
+}
diff --git a/dotnet/src/FfiRuntimeHost.cs b/dotnet/src/FfiRuntimeHost.cs
new file mode 100644
index 000000000..210819de6
--- /dev/null
+++ b/dotnet/src/FfiRuntimeHost.cs
@@ -0,0 +1,674 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ *--------------------------------------------------------------------------------------------*/
+
+using Microsoft.Extensions.Logging;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Text.Json;
+using System.Threading.Channels;
+
+namespace GitHub.Copilot;
+
+///
+/// Hosts the Copilot runtime in-process by loading the Rust cdylib (runtime.node)
+/// and speaking JSON-RPC over its C ABI (FFI) instead of spawning a CLI child process
+/// and communicating over stdio/TCP.
+///
+///
+/// The Rust host_start export spawns the residual TypeScript worker itself —
+/// typically the packaged single-file CLI (copilot --embedded-host, which embeds
+/// its own Node) or, for dev, node dist-cli/index.js --embedded-host — so the .NET
+/// host never launches Node directly. JSON-RPC frames are pumped across the ABI: writes go
+/// to connection_write; inbound frames arrive on a native callback that feeds
+/// .
+///
+/// The native interop layer has two implementations selected by target framework. On
+/// modern .NET it uses source-generated LibraryImport P/Invoke with an
+/// UnmanagedCallersOnly function-pointer callback, which is trim- and
+/// NativeAOT-compatible. On netstandard2.0 (which has neither LibraryImport
+/// nor NativeLibrary) it falls back to classic delegate-based P/Invoke over a
+/// hand-rolled dlopen/LoadLibrary loader. Because the library lives at a
+/// runtime-resolved absolute path, the modern path maps the logical
+/// via a resolver and the legacy path loads the absolute path
+/// directly.
+///
+///
+internal sealed partial class FfiRuntimeHost : IDisposable
+{
+ /// Logical name the native interop layer binds the cdylib to.
+ private const string LibraryName = "copilot_runtime";
+
+ private readonly ILogger _logger;
+ private readonly string _cliEntrypoint;
+ private readonly string _libraryPath;
+ private readonly IReadOnlyDictionary? _environment;
+
+ private readonly CallbackReceiveStream _receiveStream = new();
+ private CallbackSendStream? _sendStream;
+
+ private uint _serverId;
+ private uint _connectionId;
+ private bool _disposed;
+
+ private FfiRuntimeHost(string libraryPath, string cliEntrypoint, IReadOnlyDictionary? environment, ILogger logger)
+ {
+ _libraryPath = libraryPath;
+ _cliEntrypoint = cliEntrypoint;
+ _environment = environment;
+ _logger = logger;
+ }
+
+ /// The stream JSON-RPC reads server→client frames from.
+ public Stream ReceiveStream => _receiveStream;
+
+ /// The stream JSON-RPC writes client→server frames to.
+ public Stream SendStream => _sendStream
+ ?? throw new InvalidOperationException("FfiRuntimeHost has not been started.");
+
+ ///
+ /// Loads the cdylib next to the given CLI entrypoint and prepares the FFI host.
+ /// The entrypoint is either the packaged single-file CLI binary (e.g.
+ /// runtimes/<rid>/native/copilot) or, for dev, a .js file (e.g.
+ /// dist-cli/index.js) launched via node. The cdylib is resolved
+ /// relative to the entrypoint directory, preferring the flat, natural
+ /// shared-library name the .NET build emits (e.g. libcopilot_runtime.so)
+ /// and falling back to the dev tarball layout
+ /// prebuilds/<prebuildsFolder>/runtime.node, where
+ /// is the napi-rs
+ /// <node-platform>-<arch> folder name (e.g. win32-x64).
+ ///
+ public static FfiRuntimeHost Create(string cliEntrypoint, string prebuildsFolder, IReadOnlyDictionary? environment, ILogger logger)
+ {
+ var fullEntrypoint = Path.GetFullPath(cliEntrypoint);
+ var distDir = Path.GetDirectoryName(fullEntrypoint)
+ ?? throw new InvalidOperationException($"Could not determine directory for '{cliEntrypoint}'.");
+
+ // Bundled .NET layout: flat, natural shared-library name next to the CLI.
+ var flatLibraryPath = Path.Combine(distDir, GetRuntimeLibraryFileName());
+ // Dev/tarball layout: dist-cli/prebuilds/-/runtime.node.
+ var prebuildsLibraryPath = Path.Combine(distDir, "prebuilds", prebuildsFolder, "runtime.node");
+
+ var libraryPath = File.Exists(flatLibraryPath) ? flatLibraryPath
+ : File.Exists(prebuildsLibraryPath) ? prebuildsLibraryPath
+ : throw new InvalidOperationException(
+ $"FFI runtime library not found. Looked for '{flatLibraryPath}' and '{prebuildsLibraryPath}'.");
+
+ PrepareNativeLibrary(libraryPath);
+ return new FfiRuntimeHost(libraryPath, fullEntrypoint, environment, logger);
+ }
+
+ ///
+ /// The natural platform shared-library file name for the runtime cdylib, as
+ /// emitted by the .NET build (the .node file renamed to what the Rust cdylib
+ /// would be called on this OS).
+ ///
+ private static string GetRuntimeLibraryFileName()
+ {
+ if (OperatingSystem.IsWindows()) return "copilot_runtime.dll";
+ if (OperatingSystem.IsMacOS()) return "libcopilot_runtime.dylib";
+ return "libcopilot_runtime.so";
+ }
+
+ ///
+ /// Starts the in-process runtime: spawns the CLI worker via the Rust host,
+ /// waits for readiness, and opens the FFI JSON-RPC connection.
+ ///
+ public async Task StartAsync(CancellationToken cancellationToken)
+ {
+ // host_start blocks until the worker connects back and signals readiness
+ // (up to ~30s), and connection_open must run outside any async runtime, so
+ // perform the blocking FFI handshake on a background thread.
+ await Task.Run(() =>
+ {
+ var argvJson = BuildArgvJson(_cliEntrypoint);
+ var envJson = BuildEnvJson(_environment);
+
+ _serverId = NativeHostStart(argvJson, envJson);
+ if (_serverId == 0)
+ {
+ throw new InvalidOperationException(
+ $"copilot_runtime_host_start failed (library '{_libraryPath}', entrypoint '{_cliEntrypoint}').");
+ }
+
+ _connectionId = NativeOpenConnection(_serverId);
+ if (_connectionId == 0)
+ {
+ DisposeNativeCallback();
+ NativeHostShutdown(_serverId);
+ _serverId = 0;
+ throw new InvalidOperationException("copilot_runtime_connection_open failed.");
+ }
+
+ _sendStream = new CallbackSendStream(SendFrame);
+ }, cancellationToken).ConfigureAwait(false);
+
+ if (_logger.IsEnabled(LogLevel.Debug))
+ {
+ _logger.LogDebug(
+ "FfiRuntimeHost started. Library={Library}, ServerId={ServerId}, ConnectionId={ConnectionId}",
+ _libraryPath, _serverId, _connectionId);
+ }
+ }
+
+ private static byte[] BuildArgvJson(string cliEntrypoint)
+ {
+ // A .js entrypoint (dev / dist-cli) is launched via node; the packaged
+ // single-file CLI binary embeds its own Node and is invoked directly.
+ var isJsFile = cliEntrypoint.EndsWith(".js", StringComparison.OrdinalIgnoreCase);
+ using var stream = new MemoryStream();
+ using (var writer = new Utf8JsonWriter(stream))
+ {
+ writer.WriteStartArray();
+ if (isJsFile)
+ {
+ writer.WriteStringValue("node");
+ }
+ writer.WriteStringValue(cliEntrypoint);
+ writer.WriteStringValue("--embedded-host");
+ writer.WriteEndArray();
+ }
+ return stream.ToArray();
+ }
+
+ private static byte[]? BuildEnvJson(IReadOnlyDictionary? environment)
+ {
+ if (environment is null || environment.Count == 0)
+ {
+ return null;
+ }
+ using var stream = new MemoryStream();
+ using (var writer = new Utf8JsonWriter(stream))
+ {
+ writer.WriteStartObject();
+ foreach (var kvp in environment)
+ {
+ writer.WriteString(kvp.Key, kvp.Value);
+ }
+ writer.WriteEndObject();
+ }
+ return stream.ToArray();
+ }
+
+ ///
+ /// Writes one framed message to the native connection. The bytes are read
+ /// synchronously by the native side (it copies before returning), so the
+ /// span does not need to outlive the call — no allocation or copy on our side.
+ ///
+ private delegate bool FrameWriter(ReadOnlySpan frame);
+
+ private bool SendFrame(ReadOnlySpan frame)
+ {
+ if (_disposed || _connectionId == 0)
+ {
+ return false;
+ }
+ return NativeConnectionWrite(_connectionId, frame);
+ }
+
+ private void FeedInbound(IntPtr bytesPtr, UIntPtr bytesLen)
+ {
+ var length = checked((int)bytesLen.ToUInt64());
+ var buffer = new byte[length];
+ Marshal.Copy(bytesPtr, buffer, 0, length);
+ _receiveStream.Feed(buffer);
+ }
+
+ public void Dispose()
+ {
+ if (_disposed)
+ {
+ return;
+ }
+ _disposed = true;
+
+ try
+ {
+ if (_connectionId != 0)
+ {
+ NativeConnectionClose(_connectionId);
+ _connectionId = 0;
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogDebug(ex, "FfiRuntimeHost: connection_close failed");
+ }
+
+ try
+ {
+ if (_serverId != 0)
+ {
+ NativeHostShutdown(_serverId);
+ _serverId = 0;
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogDebug(ex, "FfiRuntimeHost: host_shutdown failed");
+ }
+
+ _receiveStream.Complete();
+ DisposeNativeCallback();
+ }
+
+ /// Length as the native pointer-sized unsigned integer the ABI expects.
+ private static UIntPtr Len(int value) => new((uint)value);
+
+#if NET
+ // ---- Modern interop: source-generated LibraryImport P/Invoke (trim/AOT-safe) ----
+
+ private static readonly object ResolverLock = new();
+ private static bool s_resolverRegistered;
+ private static string? s_resolvedLibraryPath;
+
+ // A normal (non-pinned) handle to this instance, passed to the native side as
+ // the callback's user_data so the static outbound callback can route back here.
+ private GCHandle _selfHandle;
+
+ ///
+ /// Registers (once) a process-wide
+ /// that maps to the absolute runtime.node path so the
+ /// stubs resolve. The resolved handle is cached by
+ /// the runtime after first use, so all in-process hosts share a single loaded library.
+ ///
+ private static void PrepareNativeLibrary(string libraryPath)
+ {
+ lock (ResolverLock)
+ {
+ if (s_resolvedLibraryPath is not null && s_resolvedLibraryPath != libraryPath)
+ {
+ throw new InvalidOperationException(
+ $"An in-process FFI runtime library is already loaded from '{s_resolvedLibraryPath}'; "
+ + $"loading a different library from '{libraryPath}' in the same process is not supported.");
+ }
+ s_resolvedLibraryPath = libraryPath;
+ if (!s_resolverRegistered)
+ {
+ NativeLibrary.SetDllImportResolver(typeof(FfiRuntimeHost).Assembly, Resolve);
+ s_resolverRegistered = true;
+ }
+ }
+ }
+
+ private static IntPtr Resolve(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
+ {
+ if (libraryName == LibraryName && s_resolvedLibraryPath is not null)
+ {
+ return NativeLibrary.Load(s_resolvedLibraryPath);
+ }
+ return IntPtr.Zero;
+ }
+
+ private static uint NativeHostStart(byte[] argvJson, byte[]? env) =>
+ HostStart(argvJson, Len(argvJson.Length), env, env is null ? UIntPtr.Zero : Len(env.Length));
+
+ private uint NativeOpenConnection(uint serverId)
+ {
+ _selfHandle = GCHandle.Alloc(this);
+ unsafe
+ {
+ return ConnectionOpen(
+ serverId,
+ &OnOutboundStatic,
+ GCHandle.ToIntPtr(_selfHandle),
+ null, UIntPtr.Zero,
+ null, UIntPtr.Zero,
+ null, UIntPtr.Zero);
+ }
+ }
+
+ private static bool NativeHostShutdown(uint serverId) => HostShutdown(serverId);
+
+ private static bool NativeConnectionWrite(uint connectionId, ReadOnlySpan frame) => ConnectionWrite(connectionId, frame, Len(frame.Length));
+
+ private static bool NativeConnectionClose(uint connectionId) => ConnectionClose(connectionId);
+
+ private void DisposeNativeCallback()
+ {
+ if (_selfHandle.IsAllocated)
+ {
+ _selfHandle.Free();
+ }
+ }
+
+ [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
+ private static void OnOutboundStatic(IntPtr userData, IntPtr bytesPtr, nuint bytesLen)
+ {
+ if (userData == IntPtr.Zero || bytesPtr == IntPtr.Zero || bytesLen == 0)
+ {
+ return;
+ }
+ if (GCHandle.FromIntPtr(userData).Target is FfiRuntimeHost self)
+ {
+ self.FeedInbound(bytesPtr, bytesLen);
+ }
+ }
+
+ [LibraryImport(LibraryName, EntryPoint = "copilot_runtime_host_start")]
+ [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })]
+ private static partial uint HostStart(
+ byte[] argvJson, nuint argvJsonLen,
+ byte[]? env, nuint envLen);
+
+ [LibraryImport(LibraryName, EntryPoint = "copilot_runtime_host_shutdown")]
+ [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })]
+ [return: MarshalAs(UnmanagedType.U1)]
+ private static partial bool HostShutdown(uint serverId);
+
+ [LibraryImport(LibraryName, EntryPoint = "copilot_runtime_connection_open")]
+ [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })]
+ private static unsafe partial uint ConnectionOpen(
+ uint serverId,
+ delegate* unmanaged[Cdecl] onOutbound,
+ IntPtr userData,
+ byte[]? extSource, nuint extSourceLen,
+ byte[]? extName, nuint extNameLen,
+ byte[]? connToken, nuint connTokenLen);
+
+ [LibraryImport(LibraryName, EntryPoint = "copilot_runtime_connection_write")]
+ [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })]
+ [return: MarshalAs(UnmanagedType.U1)]
+ private static partial bool ConnectionWrite(uint connectionId, ReadOnlySpan bytes, nuint bytesLen);
+
+ [LibraryImport(LibraryName, EntryPoint = "copilot_runtime_connection_close")]
+ [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })]
+ [return: MarshalAs(UnmanagedType.U1)]
+ private static partial bool ConnectionClose(uint connectionId);
+#else
+ // ---- Legacy interop: delegate-based P/Invoke for netstandard2.0 ----
+ // netstandard2.0 has neither LibraryImport, NativeLibrary, nor UnmanagedCallersOnly,
+ // so the cdylib is loaded through a hand-rolled dlopen/LoadLibrary shim and each
+ // export is bound to a [UnmanagedFunctionPointer] delegate. The outbound callback is
+ // an instance delegate kept alive in a field for the connection's lifetime.
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate uint HostStartDelegate(
+ byte[] argvJson, UIntPtr argvJsonLen,
+ byte[]? env, UIntPtr envLen);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.U1)]
+ private delegate bool HostShutdownDelegate(uint serverId);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate uint ConnectionOpenDelegate(
+ uint serverId,
+ OutboundCallbackDelegate onOutbound,
+ IntPtr userData,
+ byte[]? extSource, UIntPtr extSourceLen,
+ byte[]? extName, UIntPtr extNameLen,
+ byte[]? connToken, UIntPtr connTokenLen);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.U1)]
+ private delegate bool ConnectionWriteDelegate(uint connectionId, IntPtr bytes, UIntPtr bytesLen);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.U1)]
+ private delegate bool ConnectionCloseDelegate(uint connectionId);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate void OutboundCallbackDelegate(IntPtr userData, IntPtr bytesPtr, UIntPtr bytesLen);
+
+ private static readonly object NativeLock = new();
+ private static bool s_loaded;
+ private static string? s_loadedPath;
+ private static HostStartDelegate? s_hostStart;
+ private static HostShutdownDelegate? s_hostShutdown;
+ private static ConnectionOpenDelegate? s_connectionOpen;
+ private static ConnectionWriteDelegate? s_connectionWrite;
+ private static ConnectionCloseDelegate? s_connectionClose;
+
+ // Held for the connection's lifetime so the marshaled function pointer handed to the
+ // native side is not collected while Rust may still invoke it.
+ private OutboundCallbackDelegate? _outboundDelegate;
+
+ private static void PrepareNativeLibrary(string libraryPath)
+ {
+ lock (NativeLock)
+ {
+ if (s_loaded)
+ {
+ if (s_loadedPath != libraryPath)
+ {
+ throw new InvalidOperationException(
+ $"An in-process FFI runtime library is already loaded from '{s_loadedPath}'; "
+ + $"loading a different library from '{libraryPath}' in the same process is not supported.");
+ }
+ return;
+ }
+
+ var handle = NativeLoader.Load(libraryPath);
+ if (handle == IntPtr.Zero)
+ {
+ throw new InvalidOperationException($"Failed to load FFI runtime library '{libraryPath}'.");
+ }
+
+ s_hostStart = Bind(handle, "copilot_runtime_host_start");
+ s_hostShutdown = Bind(handle, "copilot_runtime_host_shutdown");
+ s_connectionOpen = Bind(handle, "copilot_runtime_connection_open");
+ s_connectionWrite = Bind(handle, "copilot_runtime_connection_write");
+ s_connectionClose = Bind(handle, "copilot_runtime_connection_close");
+ s_loaded = true;
+ s_loadedPath = libraryPath;
+ }
+ }
+
+ private static T Bind(IntPtr handle, string export) where T : Delegate
+ {
+ var symbol = NativeLoader.GetSymbol(handle, export);
+ if (symbol == IntPtr.Zero)
+ {
+ throw new InvalidOperationException($"FFI runtime library is missing the '{export}' export.");
+ }
+ return Marshal.GetDelegateForFunctionPointer(symbol);
+ }
+
+ private static uint NativeHostStart(byte[] argvJson, byte[]? env) =>
+ s_hostStart!(argvJson, Len(argvJson.Length), env, env is null ? UIntPtr.Zero : Len(env.Length));
+
+ private uint NativeOpenConnection(uint serverId)
+ {
+ _outboundDelegate = OnOutbound;
+ return s_connectionOpen!(
+ serverId,
+ _outboundDelegate,
+ IntPtr.Zero,
+ null, UIntPtr.Zero,
+ null, UIntPtr.Zero,
+ null, UIntPtr.Zero);
+ }
+
+ private static bool NativeHostShutdown(uint serverId) => s_hostShutdown!(serverId);
+
+ private static unsafe bool NativeConnectionWrite(uint connectionId, ReadOnlySpan frame)
+ {
+ fixed (byte* ptr = frame)
+ {
+ return s_connectionWrite!(connectionId, (IntPtr)ptr, Len(frame.Length));
+ }
+ }
+
+ private static bool NativeConnectionClose(uint connectionId) => s_connectionClose!(connectionId);
+
+ private void DisposeNativeCallback() => _outboundDelegate = null;
+
+ private void OnOutbound(IntPtr userData, IntPtr bytesPtr, UIntPtr bytesLen)
+ {
+ if (bytesPtr == IntPtr.Zero || bytesLen == UIntPtr.Zero)
+ {
+ return;
+ }
+ FeedInbound(bytesPtr, bytesLen);
+ }
+
+ ///
+ /// Minimal cross-platform native library loader for netstandard2.0, which lacks
+ /// NativeLibrary. Uses LoadLibrary/GetProcAddress on Windows
+ /// and dlopen/dlsym elsewhere (trying libdl.so.2 first, then
+ /// libdl for older Linux and macOS).
+ ///
+ private static class NativeLoader
+ {
+ public static IntPtr Load(string path) =>
+ RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? Windows.LoadLibrary(path) : Unix.Open(path);
+
+ public static IntPtr GetSymbol(IntPtr handle, string name) =>
+ RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? Windows.GetProcAddress(handle, name) : Unix.Sym(handle, name);
+
+ private static class Windows
+ {
+ [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true)]
+ public static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPWStr)] string path);
+
+ [DllImport("kernel32", SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
+ public static extern IntPtr GetProcAddress(IntPtr module, [MarshalAs(UnmanagedType.LPStr)] string name);
+ }
+
+ private static class Unix
+ {
+ private const int RtldNow = 2;
+
+ public static IntPtr Open(string path)
+ {
+ try { return Libdl2.dlopen(path, RtldNow); }
+ catch (DllNotFoundException) { return Libdl1.dlopen(path, RtldNow); }
+ }
+
+ public static IntPtr Sym(IntPtr handle, string name)
+ {
+ try { return Libdl2.dlsym(handle, name); }
+ catch (DllNotFoundException) { return Libdl1.dlsym(handle, name); }
+ }
+
+ private static class Libdl2
+ {
+ [DllImport("libdl.so.2", EntryPoint = "dlopen", CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)]
+ public static extern IntPtr dlopen([MarshalAs(UnmanagedType.LPStr)] string fileName, int flags);
+
+ [DllImport("libdl.so.2", EntryPoint = "dlsym", CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)]
+ public static extern IntPtr dlsym(IntPtr handle, [MarshalAs(UnmanagedType.LPStr)] string symbol);
+ }
+
+ private static class Libdl1
+ {
+ [DllImport("libdl", EntryPoint = "dlopen", CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)]
+ public static extern IntPtr dlopen([MarshalAs(UnmanagedType.LPStr)] string fileName, int flags);
+
+ [DllImport("libdl", EntryPoint = "dlsym", CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)]
+ public static extern IntPtr dlsym(IntPtr handle, [MarshalAs(UnmanagedType.LPStr)] string symbol);
+ }
+ }
+ }
+#endif
+
+ ///
+ /// A read-only stream fed by the native outbound callback. Chunks are queued on
+ /// an unbounded channel and drained in order by the JSON-RPC read loop.
+ ///
+ private sealed class CallbackReceiveStream : Stream
+ {
+ private readonly Channel _channel = Channel.CreateUnbounded(
+ new UnboundedChannelOptions { SingleReader = true, SingleWriter = false });
+ private ReadOnlyMemory _leftover;
+
+ public void Feed(byte[] data) => _channel.Writer.TryWrite(data);
+
+ public void Complete() => _channel.Writer.TryComplete();
+
+#if !NETSTANDARD2_0
+ public override async ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default)
+ {
+ return await ReadCoreAsync(buffer, cancellationToken).ConfigureAwait(false);
+ }
+#endif
+
+ private async ValueTask ReadCoreAsync(Memory buffer, CancellationToken cancellationToken)
+ {
+ if (_leftover.IsEmpty)
+ {
+ while (true)
+ {
+ if (!await _channel.Reader.WaitToReadAsync(cancellationToken).ConfigureAwait(false))
+ {
+ return 0; // EOF: channel completed.
+ }
+ if (_channel.Reader.TryRead(out var chunk))
+ {
+ _leftover = chunk;
+ break;
+ }
+ // Data was signalled but lost a race for it; wait again rather
+ // than reporting a spurious EOF.
+ }
+ }
+
+ var n = Math.Min(buffer.Length, _leftover.Length);
+ _leftover.Span.Slice(0, n).CopyTo(buffer.Span);
+ _leftover = _leftover.Slice(n);
+ return n;
+ }
+
+ public override int Read(byte[] buffer, int offset, int count) =>
+ ReadCoreAsync(buffer.AsMemory(offset, count), CancellationToken.None).AsTask().GetAwaiter().GetResult();
+
+ public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) =>
+ ReadCoreAsync(buffer.AsMemory(offset, count), cancellationToken).AsTask();
+
+ public override bool CanRead => true;
+ public override bool CanSeek => false;
+ public override bool CanWrite => false;
+ public override long Length => throw new NotSupportedException();
+ public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
+ public override void Flush() { }
+ public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
+ public override void SetLength(long value) => throw new NotSupportedException();
+ public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
+ }
+
+ ///
+ /// A write-only stream that forwards each frame to the native
+ /// connection_write export.
+ ///
+ private sealed class CallbackSendStream(FrameWriter write) : Stream
+ {
+ private void WriteFrame(ReadOnlySpan frame)
+ {
+ if (!write(frame))
+ {
+ throw new IOException("Failed to write a frame to the in-process runtime connection.");
+ }
+ }
+
+ public override void Write(byte[] buffer, int offset, int count) => WriteFrame(buffer.AsSpan(offset, count));
+
+#if !NETSTANDARD2_0
+ public override void Write(ReadOnlySpan buffer) => WriteFrame(buffer);
+
+ public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default)
+ {
+ WriteFrame(buffer.Span);
+ return ValueTask.CompletedTask;
+ }
+#endif
+
+ public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+ {
+ WriteFrame(buffer.AsSpan(offset, count));
+ return Task.CompletedTask;
+ }
+
+ public override bool CanRead => false;
+ public override bool CanSeek => false;
+ public override bool CanWrite => true;
+ public override long Length => throw new NotSupportedException();
+ public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
+ public override void Flush() { }
+ public override Task FlushAsync(CancellationToken cancellationToken) => Task.CompletedTask;
+ public override int Read(byte[] buffer, int offset, int count) => throw new NotSupportedException();
+ public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
+ public override void SetLength(long value) => throw new NotSupportedException();
+ }
+}
diff --git a/dotnet/src/Generated/Rpc.cs b/dotnet/src/Generated/Rpc.cs
index 065b64ecf..308d9bc0d 100644
--- a/dotnet/src/Generated/Rpc.cs
+++ b/dotnet/src/Generated/Rpc.cs
@@ -61,10 +61,14 @@ internal sealed class ConnectResult
public string Version { get; set; } = string.Empty;
}
-/// Optional connection token presented by the SDK client during the handshake.
+/// Parameters for the `server.connect` handshake: an optional connection token and optional connection-level opt-ins (e.g. GitHub telemetry forwarding).
[Experimental(Diagnostics.Experimental)]
internal sealed class ConnectRequest
{
+ /// Opt this connection in to GitHub telemetry forwarding for its lifetime. When set, the runtime forwards every internal telemetry event it emits — across all sessions, plus sessionless events — to this connection over the `gitHubTelemetry.event` notification, in addition to the runtime's normal GitHub/CTS emission (dual-write). 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.
+ [JsonPropertyName("enableGitHubTelemetryForwarding")]
+ public bool? EnableGitHubTelemetryForwarding { get; set; }
+
/// Connection token; required when the server was started with COPILOT_CONNECTION_TOKEN.
[JsonPropertyName("token")]
public string? Token { get; set; }
@@ -258,7 +262,7 @@ public sealed class ModelPolicy
public string? Terms { get; set; }
}
-/// Schema for the `Model` type.
+/// Copilot model metadata, including identifier, display name, capabilities, policy, billing, reasoning efforts, and picker categories.
[Experimental(Diagnostics.Experimental)]
public sealed class Model
{
@@ -317,7 +321,7 @@ internal sealed class ModelsListRequest
public string? GitHubToken { get; set; }
}
-/// Schema for the `Tool` type.
+/// Built-in tool metadata with identifier, optional namespaced name, description, input-parameter schema, and usage instructions.
[Experimental(Diagnostics.Experimental)]
public sealed class Tool
{
@@ -360,7 +364,7 @@ internal sealed class ToolsListRequest
public string? Model { get; set; }
}
-/// Schema for the `AccountQuotaSnapshot` type.
+/// Quota usage snapshot for a Copilot quota type, including entitlement, used requests, overage, reset date, and remaining percentage.
[Experimental(Diagnostics.Experimental)]
public sealed class AccountQuotaSnapshot
{
@@ -436,7 +440,7 @@ public partial class AuthInfo
}
-/// Schema for the `CopilotUserResponseEndpoints` type.
+/// Endpoint URLs from the raw Copilot `/copilot_internal/v2/token` user-response passthrough.
[Experimental(Diagnostics.Experimental)]
public sealed class CopilotUserResponseEndpoints
{
@@ -469,178 +473,178 @@ public sealed class CopilotUserResponseOrganizationListItem
public string? Name { get; set; }
}
-/// Schema for the `CopilotUserResponseQuotaSnapshotsChat` type.
+/// Chat quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields.
[Experimental(Diagnostics.Experimental)]
public sealed class CopilotUserResponseQuotaSnapshotsChat
{
- /// Gets or sets the entitlement value.
+ /// Number of requests/units included in the entitlement for this period; `-1` denotes an unlimited entitlement.
[JsonPropertyName("entitlement")]
public double? Entitlement { get; set; }
- /// Gets or sets the has_quota value.
+ /// 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; }
- /// Gets or sets the overage_count value.
+ /// Count of additional pay-per-request usage consumed this period beyond the entitlement.
[JsonPropertyName("overage_count")]
public double? OverageCount { get; set; }
- /// Gets or sets the overage_permitted value.
+ /// Whether usage may continue at pay-per-request rates once the entitlement is exhausted.
[JsonPropertyName("overage_permitted")]
public bool? OveragePermitted { get; set; }
- /// Gets or sets the percent_remaining value.
+ /// Percentage of the entitlement remaining at the snapshot timestamp.
[JsonPropertyName("percent_remaining")]
public double? PercentRemaining { get; set; }
- /// Gets or sets the quota_id value.
+ /// Identifier of the quota bucket this snapshot describes.
[JsonPropertyName("quota_id")]
public string? QuotaId { get; set; }
- /// Gets or sets the quota_remaining value.
+ /// Amount of quota remaining at the snapshot timestamp.
[JsonPropertyName("quota_remaining")]
public double? QuotaRemaining { get; set; }
- /// Gets or sets the quota_reset_at value.
+ /// Unix epoch time, in seconds, when this quota next resets.
[JsonPropertyName("quota_reset_at")]
public double? QuotaResetAt { get; set; }
- /// Gets or sets the remaining value.
+ /// Remaining entitlement/quota amount at the snapshot timestamp.
[JsonPropertyName("remaining")]
public double? Remaining { get; set; }
- /// Gets or sets the timestamp_utc value.
+ /// UTC timestamp when this snapshot was captured.
[JsonPropertyName("timestamp_utc")]
public string? TimestampUtc { get; set; }
- /// Gets or sets the token_based_billing value.
+ /// 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; }
- /// Gets or sets the unlimited value.
+ /// Whether the entitlement for this category is unlimited.
[JsonPropertyName("unlimited")]
public bool? Unlimited { get; set; }
}
-/// Schema for the `CopilotUserResponseQuotaSnapshotsCompletions` type.
+/// Completions quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields.
[Experimental(Diagnostics.Experimental)]
public sealed class CopilotUserResponseQuotaSnapshotsCompletions
{
- /// Gets or sets the entitlement value.
+ /// Number of requests/units included in the entitlement for this period; `-1` denotes an unlimited entitlement.
[JsonPropertyName("entitlement")]
public double? Entitlement { get; set; }
- /// Gets or sets the has_quota value.
+ /// 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; }
- /// Gets or sets the overage_count value.
+ /// Count of additional pay-per-request usage consumed this period beyond the entitlement.
[JsonPropertyName("overage_count")]
public double? OverageCount { get; set; }
- /// Gets or sets the overage_permitted value.
+ /// Whether usage may continue at pay-per-request rates once the entitlement is exhausted.
[JsonPropertyName("overage_permitted")]
public bool? OveragePermitted { get; set; }
- /// Gets or sets the percent_remaining value.
+ /// Percentage of the entitlement remaining at the snapshot timestamp.
[JsonPropertyName("percent_remaining")]
public double? PercentRemaining { get; set; }
- /// Gets or sets the quota_id value.
+ /// Identifier of the quota bucket this snapshot describes.
[JsonPropertyName("quota_id")]
public string? QuotaId { get; set; }
- /// Gets or sets the quota_remaining value.
+ /// Amount of quota remaining at the snapshot timestamp.
[JsonPropertyName("quota_remaining")]
public double? QuotaRemaining { get; set; }
- /// Gets or sets the quota_reset_at value.
+ /// Unix epoch time, in seconds, when this quota next resets.
[JsonPropertyName("quota_reset_at")]
public double? QuotaResetAt { get; set; }
- /// Gets or sets the remaining value.
+ /// Remaining entitlement/quota amount at the snapshot timestamp.
[JsonPropertyName("remaining")]
public double? Remaining { get; set; }
- /// Gets or sets the timestamp_utc value.
+ /// UTC timestamp when this snapshot was captured.
[JsonPropertyName("timestamp_utc")]
public string? TimestampUtc { get; set; }
- /// Gets or sets the token_based_billing value.
+ /// 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; }
- /// Gets or sets the unlimited value.
+ /// Whether the entitlement for this category is unlimited.
[JsonPropertyName("unlimited")]
public bool? Unlimited { get; set; }
}
-/// Schema for the `CopilotUserResponseQuotaSnapshotsPremiumInteractions` type.
+/// Premium-interactions quota snapshot from the raw Copilot user-response passthrough, with entitlement, overage, remaining quota, reset, and billing fields.
[Experimental(Diagnostics.Experimental)]
public sealed class CopilotUserResponseQuotaSnapshotsPremiumInteractions
{
- /// Gets or sets the entitlement value.
+ /// Number of requests/units included in the entitlement for this period; `-1` denotes an unlimited entitlement.
[JsonPropertyName("entitlement")]
public double? Entitlement { get; set; }
- /// Gets or sets the has_quota value.
+ /// 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; }
- /// Gets or sets the overage_count value.
+ /// Count of additional pay-per-request usage consumed this period beyond the entitlement.
[JsonPropertyName("overage_count")]
public double? OverageCount { get; set; }
- /// Gets or sets the overage_permitted value.
+ /// Whether usage may continue at pay-per-request rates once the entitlement is exhausted.
[JsonPropertyName("overage_permitted")]
public bool? OveragePermitted { get; set; }
- /// Gets or sets the percent_remaining value.
+ /// Percentage of the entitlement remaining at the snapshot timestamp.
[JsonPropertyName("percent_remaining")]
public double? PercentRemaining { get; set; }
- /// Gets or sets the quota_id value.
+ /// Identifier of the quota bucket this snapshot describes.
[JsonPropertyName("quota_id")]
public string? QuotaId { get; set; }
- /// Gets or sets the quota_remaining value.
+ /// Amount of quota remaining at the snapshot timestamp.
[JsonPropertyName("quota_remaining")]
public double? QuotaRemaining { get; set; }
- /// Gets or sets the quota_reset_at value.
+ /// Unix epoch time, in seconds, when this quota next resets.
[JsonPropertyName("quota_reset_at")]
public double? QuotaResetAt { get; set; }
- /// Gets or sets the remaining value.
+ /// Remaining entitlement/quota amount at the snapshot timestamp.
[JsonPropertyName("remaining")]
public double? Remaining { get; set; }
- /// Gets or sets the timestamp_utc value.
+ /// UTC timestamp when this snapshot was captured.
[JsonPropertyName("timestamp_utc")]
public string? TimestampUtc { get; set; }
- /// Gets or sets the token_based_billing value.
+ /// 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; }
- /// Gets or sets the unlimited value.
+ /// Whether the entitlement for this category is unlimited.
[JsonPropertyName("unlimited")]
public bool? Unlimited { get; set; }
}
-/// Schema for the `CopilotUserResponseQuotaSnapshots` type.
+/// Quota snapshot map from the raw Copilot user-response passthrough, with chat, completions, premium-interactions, and other entries.
[Experimental(Diagnostics.Experimental)]
public sealed class CopilotUserResponseQuotaSnapshots
{
- /// Schema for the `CopilotUserResponseQuotaSnapshotsChat` type.
+ /// 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; }
- /// Schema for the `CopilotUserResponseQuotaSnapshotsCompletions` type.
+ /// 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; }
- /// Schema for the `CopilotUserResponseQuotaSnapshotsPremiumInteractions` type.
+ /// 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; }
}
@@ -649,112 +653,112 @@ public sealed class CopilotUserResponseQuotaSnapshots
[Experimental(Diagnostics.Experimental)]
public sealed class CopilotUserResponse
{
- /// Gets or sets the access_type_sku value.
+ /// 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; }
- /// Gets or sets the analytics_tracking_id value.
+ /// Opaque analytics tracking identifier for the user, forwarded from the Copilot API.
[JsonPropertyName("analytics_tracking_id")]
public string? AnalyticsTrackingId { get; set; }
- /// Gets or sets the assigned_date value.
+ /// Date the Copilot seat was assigned to the user, if applicable.
[JsonPropertyName("assigned_date")]
public string? AssignedDate { get; set; }
- /// Gets or sets the can_signup_for_limited value.
+ /// Whether the user is eligible to sign up for the free/limited Copilot tier.
[JsonPropertyName("can_signup_for_limited")]
public bool? CanSignupForLimited { get; set; }
- /// Gets or sets the can_upgrade_plan value.
+ /// Whether the user is able to upgrade their Copilot plan.
[JsonPropertyName("can_upgrade_plan")]
public bool? CanUpgradePlan { get; set; }
- /// Gets or sets the chat_enabled value.
+ /// Whether Copilot chat is enabled for the user.
[JsonPropertyName("chat_enabled")]
public bool? ChatEnabled { get; set; }
- /// Gets or sets the cli_remote_control_enabled value.
+ /// Whether CLI remote control is enabled for the user.
[JsonPropertyName("cli_remote_control_enabled")]
public bool? CliRemoteControlEnabled { get; set; }
- /// Gets or sets the cloud_session_storage_enabled value.
+ /// Whether cloud session storage is enabled for the user.
[JsonPropertyName("cloud_session_storage_enabled")]
public bool? CloudSessionStorageEnabled { get; set; }
- /// Gets or sets the codex_agent_enabled value.
+ /// Whether the Codex agent is enabled for the user.
[JsonPropertyName("codex_agent_enabled")]
public bool? CodexAgentEnabled { get; set; }
- /// Gets or sets the copilot_plan value.
+ /// Copilot plan name for the user (e.g. `individual`, `business`, `enterprise`).
[JsonPropertyName("copilot_plan")]
public string? CopilotPlan { get; set; }
- /// Gets or sets the copilotignore_enabled value.
+ /// Whether `.copilotignore` content-exclusion support is enabled for the user.
[JsonPropertyName("copilotignore_enabled")]
public bool? CopilotignoreEnabled { get; set; }
- /// Schema for the `CopilotUserResponseEndpoints` type.
+ /// Endpoint URLs from the raw Copilot `/copilot_internal/v2/token` user-response passthrough.
[JsonPropertyName("endpoints")]
public CopilotUserResponseEndpoints? Endpoints { get; set; }
- /// Gets or sets the is_mcp_enabled value.
+ /// Whether MCP (Model Context Protocol) support is enabled for the user.
[JsonPropertyName("is_mcp_enabled")]
public bool? IsMcpEnabled { get; set; }
- /// Gets or sets the is_staff value.
+ /// Whether the user is a GitHub/Microsoft staff member.
[JsonPropertyName("is_staff")]
public bool? IsStaff { get; set; }
- /// Gets or sets the limited_user_quotas value.
+ /// Per-category quota allotments for free/limited-tier users, keyed by quota category.
[JsonPropertyName("limited_user_quotas")]
public IDictionary? LimitedUserQuotas { get; set; }
- /// Gets or sets the limited_user_reset_date value.
+ /// 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; }
- /// Gets or sets the login value.
+ /// GitHub login of the authenticated user.
[JsonPropertyName("login")]
public string? Login { get; set; }
- /// Gets or sets the monthly_quotas value.
+ /// Per-category monthly quota allotments, keyed by quota category.
[JsonPropertyName("monthly_quotas")]
public IDictionary? MonthlyQuotas { get; set; }
- /// Gets or sets the organization_list value.
+ /// Organizations the user belongs to, each with an optional login and display name.
[JsonPropertyName("organization_list")]
public IList? OrganizationList { get; set; }
- /// Gets or sets the organization_login_list value.
+ /// Logins of the organizations the user belongs to.
[JsonPropertyName("organization_login_list")]
public IList? OrganizationLoginList { get; set; }
- /// Gets or sets the quota_reset_date value.
+ /// 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; }
- /// Gets or sets the quota_reset_date_utc value.
+ /// 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; }
- /// Schema for the `CopilotUserResponseQuotaSnapshots` type.
+ /// 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; }
- /// Gets or sets the restricted_telemetry value.
+ /// Whether the user's telemetry is subject to restricted-data handling.
[JsonPropertyName("restricted_telemetry")]
public bool? RestrictedTelemetry { get; set; }
- /// Gets or sets the te value.
+ /// 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; }
- /// Gets or sets the token_based_billing value.
+ /// 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; }
}
-/// Schema for the `HMACAuthInfo` type.
+/// Authentication-info variant for GitHub-internal HMAC auth, carrying the public GitHub host and HMAC secret.
/// The hmac variant of .
[Experimental(Diagnostics.Experimental)]
public partial class AuthInfoHmac : AuthInfo
@@ -777,7 +781,7 @@ public partial class AuthInfoHmac : AuthInfo
public required string Host { get; set; }
}
-/// Schema for the `EnvAuthInfo` type.
+/// Authentication-info variant for a token sourced from an environment variable, with host, optional login, token, and env var name.
/// The env variant of .
[Experimental(Diagnostics.Experimental)]
public partial class AuthInfoEnv : AuthInfo
@@ -809,7 +813,7 @@ public partial class AuthInfoEnv : AuthInfo
public required string Token { get; set; }
}
-/// Schema for the `TokenAuthInfo` type.
+/// Authentication-info variant for SDK-configured token authentication, carrying host and the secret token value.
/// The token variant of .
[Experimental(Diagnostics.Experimental)]
public partial class AuthInfoToken : AuthInfo
@@ -832,7 +836,7 @@ public partial class AuthInfoToken : AuthInfo
public required string Token { get; set; }
}
-/// Schema for the `CopilotApiTokenAuthInfo` type.
+/// Authentication-info variant for direct Copilot API token auth sourced from environment variables, with public GitHub host.
/// The copilot-api-token variant of .
[Experimental(Diagnostics.Experimental)]
public partial class AuthInfoCopilotApiToken : AuthInfo
@@ -851,7 +855,7 @@ public partial class AuthInfoCopilotApiToken : AuthInfo
public required string Host { get; set; }
}
-/// Schema for the `UserAuthInfo` type.
+/// Authentication-info variant for OAuth user auth, with host and login; the token remains in the runtime secret store.
/// The user variant of .
[Experimental(Diagnostics.Experimental)]
public partial class AuthInfoUser : AuthInfo
@@ -874,7 +878,7 @@ public partial class AuthInfoUser : AuthInfo
public required string Login { get; set; }
}
-/// Schema for the `GhCliAuthInfo` type.
+/// Authentication-info variant for GitHub CLI credentials, carrying host, login, and the `gh auth token` value.
/// The gh-cli variant of .
[Experimental(Diagnostics.Experimental)]
public partial class AuthInfoGhCli : AuthInfo
@@ -901,7 +905,7 @@ public partial class AuthInfoGhCli : AuthInfo
public required string Token { get; set; }
}
-/// Schema for the `ApiKeyAuthInfo` type.
+/// Authentication-info variant for API-key authentication to a non-GitHub LLM provider, carrying the secret `apiKey` and host.
/// The api-key variant of .
[Experimental(Diagnostics.Experimental)]
public partial class AuthInfoApiKey : AuthInfo
@@ -937,7 +941,7 @@ public sealed class AccountGetCurrentAuthResult
public AuthInfo? AuthInfo { get; set; }
}
-/// Schema for the `AccountAllUsers` type.
+/// Authenticated account entry returned by `account.getAllUsers`, with auth info and an optional associated token.
[Experimental(Diagnostics.Experimental)]
public sealed class AccountAllUsers
{
@@ -1012,7 +1016,7 @@ internal sealed class SecretsAddFilterValuesRequest
public IList Values { get => field ??= []; set; }
}
-/// Schema for the `DiscoveredMcpServer` type.
+/// MCP server discovered by `mcp.discover`, with config source, optional plugin source, transport type, and enabled state.
[Experimental(Diagnostics.Experimental)]
public sealed class DiscoveredMcpServer
{
@@ -1240,7 +1244,7 @@ internal sealed class PluginsUpdateRequest
public string Name { get; set; } = string.Empty;
}
-/// Schema for the `PluginUpdateAllEntry` type.
+/// Per-plugin result from updating all plugins, with versions, skills installed, success flag, and optional error.
[Experimental(Diagnostics.Experimental)]
public sealed class PluginUpdateAllEntry
{
@@ -1401,7 +1405,7 @@ internal sealed class PluginsMarketplacesBrowseRequest
public string Name { get; set; } = string.Empty;
}
-/// Schema for the `MarketplaceRefreshEntry` type.
+/// Per-marketplace refresh result, including marketplace name, success flag, and optional failure error.
[Experimental(Diagnostics.Experimental)]
public sealed class MarketplaceRefreshEntry
{
@@ -1436,7 +1440,7 @@ internal sealed class PluginsMarketplacesRefreshRequest
public string? Name { get; set; }
}
-/// Schema for the `ServerSkill` type.
+/// Server-side skill metadata, including name, description, source, enabled/invocable state, path, project path, and argument hint.
[Experimental(Diagnostics.Experimental)]
public sealed class ServerSkill
{
@@ -1499,7 +1503,7 @@ internal sealed class SkillsDiscoverRequest
public IList? SkillDirectories { get; set; }
}
-/// Schema for the `SkillDiscoveryPath` type.
+/// Canonical directory where skills can be discovered or created, with scope, preference, and optional project path.
[Experimental(Diagnostics.Experimental)]
public sealed class SkillDiscoveryPath
{
@@ -1551,7 +1555,7 @@ internal sealed class SkillsConfigSetDisabledSkillsRequest
public IList DisabledSkills { get => field ??= []; set; }
}
-/// Schema for the `AgentInfo` type.
+/// Custom agent metadata, including identifiers, display details, source, tools, model, MCP servers, skills, and file path.
[Experimental(Diagnostics.Experimental)]
public sealed class AgentInfo
{
@@ -1623,7 +1627,7 @@ internal sealed class AgentsDiscoverRequest
public IList? ProjectPaths { get; set; }
}
-/// Schema for the `AgentDiscoveryPath` type.
+/// Canonical directory where custom agents can be discovered or created, with scope, preference, and optional project path.
[Experimental(Diagnostics.Experimental)]
public sealed class AgentDiscoveryPath
{
@@ -1666,7 +1670,7 @@ internal sealed class AgentsGetDiscoveryPathsRequest
public IList? ProjectPaths { get; set; }
}
-/// Schema for the `InstructionSource` type.
+/// Loaded instruction source for a session, including path, content, category, location, applicability, and optional description.
[Experimental(Diagnostics.Experimental)]
public sealed class InstructionSource
{
@@ -1733,7 +1737,7 @@ internal sealed class InstructionsDiscoverRequest
public IList? ProjectPaths { get; set; }
}
-/// Schema for the `InstructionDiscoveryPath` type.
+/// Canonical file or directory where custom instructions can be discovered or created, with location, kind, preference, and project path.
[Experimental(Diagnostics.Experimental)]
public sealed class InstructionDiscoveryPath
{
@@ -2052,7 +2056,7 @@ public sealed class RemoteSessionMetadataValue
public RemoteSessionMetadataTaskType? TaskType { get; set; }
}
-/// Schema for the `SessionsOpenProgress` type.
+/// `sessions.open` handoff progress update with step, status, and optional message.
[Experimental(Diagnostics.Experimental)]
public sealed class SessionsOpenProgress
{
@@ -2589,7 +2593,7 @@ internal sealed class SessionsReleaseLockRequest
public string SessionId { get; set; } = string.Empty;
}
-/// Schema for the `LocalSessionMetadataValue` type.
+/// Persisted local session metadata, including identifiers, timestamps, summary/name, client, context, detached state, and task ID.
[Experimental(Diagnostics.Experimental)]
public sealed class LocalSessionMetadataValue
{
@@ -2699,7 +2703,7 @@ public sealed class SessionsSetAdditionalPluginsResult
{
}
-/// Schema for the `InstalledPlugin` type.
+/// Installed plugin record from global state, with marketplace, version, install time, enabled state, cache path, and source.
[Experimental(Diagnostics.Experimental)]
public sealed class InstalledPlugin
{
@@ -2814,6 +2818,12 @@ public partial class RemoteControlStatusActive : RemoteControlStatus
[JsonPropertyName("attachedSessionId")]
public required string AttachedSessionId { 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")]
@@ -2974,42 +2984,6 @@ internal sealed class SessionsStopRemoteControlRequest
public bool? Force { get; set; }
}
-/// Schema for the `SessionsPollSpawnedSessionsEvent` type.
-[Experimental(Diagnostics.Experimental)]
-public sealed class SessionsPollSpawnedSessionsEvent
-{
- /// Session id of the newly-spawned session.
- [JsonPropertyName("sessionId")]
- public string SessionId { get; set; } = string.Empty;
-}
-
-/// Batch of spawn events plus a cursor for follow-up polls.
-[Experimental(Diagnostics.Experimental)]
-internal sealed class PollSpawnedSessionsResult
-{
- /// Opaque cursor to pass back to receive only events after this batch.
- [JsonPropertyName("cursor")]
- public string Cursor { get; set; } = string.Empty;
-
- /// Spawn events emitted since the supplied cursor.
- [JsonPropertyName("events")]
- public IList Events { get => field ??= []; set; }
-}
-
-/// RPC data type for SessionsPollSpawnedSessions operations.
-[Experimental(Diagnostics.Experimental)]
-internal sealed class SessionsPollSpawnedSessionsRequest
-{
- /// Opaque cursor returned by a previous poll. Omit on the first call to receive any spawn events buffered since the runtime started.
- [JsonPropertyName("cursor")]
- public string? Cursor { get; set; }
-
- /// Milliseconds to wait for new spawn events when the cursor is at the tail. 0 (default) returns immediately even if no events are buffered. Capped at 60000ms.
- [JsonConverter(typeof(MillisecondsTimeSpanConverter))]
- [JsonPropertyName("waitMs")]
- public TimeSpan? Wait { get; set; }
-}
-
/// Handle for releasing the extension tool registration.
[Experimental(Diagnostics.Experimental)]
internal sealed class RegisterExtensionToolsResult
@@ -3532,6 +3506,187 @@ internal sealed class SessionSetCredentialsParams
public string SessionId { get; set; } = string.Empty;
}
+/// A file included in the redacted debug bundle.
+[Experimental(Diagnostics.Experimental)]
+public sealed class DebugCollectLogsCollectedEntry
+{
+ /// 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; }
+
+ /// Source category for this entry.
+ [JsonPropertyName("source")]
+ public DebugCollectLogsSource Source { get; set; }
+}
+
+/// An optional debug bundle entry that could not be included.
+[Experimental(Diagnostics.Experimental)]
+public sealed class DebugCollectLogsSkippedEntry
+{
+ /// 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;
+}
+
+/// Result of collecting a redacted debug bundle.
+[Experimental(Diagnostics.Experimental)]
+public sealed class DebugCollectLogsResult
+{
+ /// Files included in the redacted bundle.
+ [JsonPropertyName("entries")]
+ public IList Entries { get => field ??= []; set; }
+
+ /// Destination kind that was written.
+ [JsonPropertyName("kind")]
+ public DebugCollectLogsResultKind Kind { 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;
+
+ /// Optional files or directories that could not be included.
+ [JsonPropertyName("skippedEntries")]
+ public IList? SkippedEntries { get; set; }
+}
+
+/// A caller-provided server-local file or directory to include in the debug bundle.
+[Experimental(Diagnostics.Experimental)]
+public sealed class DebugCollectLogsEntry
+{
+ /// Relative path to use inside the staged bundle/archive.
+ [JsonPropertyName("bundlePath")]
+ public string BundlePath { get; set; } = string.Empty;
+
+ /// Kind of source path to include.
+ [JsonPropertyName("kind")]
+ public DebugCollectLogsEntryKind Kind { get; set; }
+
+ /// Server-local source path to read.
+ [JsonPropertyName("path")]
+ public string Path { get; set; } = string.Empty;
+
+ /// How text content from this entry should be redacted. Defaults to plain-text.
+ [JsonPropertyName("redaction")]
+ public DebugCollectLogsRedaction? Redaction { 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; }
+}
+
+/// Destination for the redacted debug bundle.
+/// Polymorphic base type discriminated by kind.
+[Experimental(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 archive variant of .
+[Experimental(Diagnostics.Experimental)]
+public partial class DebugCollectLogsDestinationArchive : DebugCollectLogsDestination
+{
+ ///
+ [JsonIgnore]
+ public override string Kind => "archive";
+
+ /// 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; }
+
+ /// Absolute or server-relative path for the .tgz archive to create.
+ [JsonPropertyName("outputPath")]
+ public required string OutputPath { get; set; }
+}
+
+/// The directory variant of .
+[Experimental(Diagnostics.Experimental)]
+public partial class DebugCollectLogsDestinationDirectory : DebugCollectLogsDestination
+{
+ ///
+ [JsonIgnore]
+ public override string Kind => "directory";
+
+ /// Directory where redacted files should be staged. The directory is created if needed.
+ [JsonPropertyName("outputDirectory")]
+ public required string OutputDirectory { get; set; }
+}
+
+/// Built-in session diagnostics to include in the bundle. Omitted fields default to true.
+[Experimental(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; }
+}
+
+/// Options for collecting a redacted session debug bundle.
+[Experimental(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; }
+
+ /// Where the redacted bundle should be written. Use `archive` to produce a .tgz, or `directory` to stage redacted files for caller-managed upload/post-processing.
+ [JsonPropertyName("destination")]
+ public DebugCollectLogsDestination Destination { get => field ??= new(); set; }
+
+ /// Which built-in session diagnostics to include. Omitted fields default to true.
+ [JsonPropertyName("include")]
+ public DebugCollectLogsInclude? Include { get; set; }
+
+ /// Target session identifier.
+ [JsonPropertyName("sessionId")]
+ public string SessionId { get; set; } = string.Empty;
+}
+
/// 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(Diagnostics.Experimental)]
public sealed class CanvasAction
@@ -3855,6 +4010,10 @@ internal sealed class ModelSwitchToRequest
/// Target session identifier.
[JsonPropertyName("sessionId")]
public string SessionId { get; set; } = string.Empty;
+
+ /// Output verbosity level to request for supported models.
+ [JsonPropertyName("verbosity")]
+ public Verbosity? Verbosity { 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.
@@ -4267,7 +4426,7 @@ internal sealed class WorkspacesCreateFileRequest
public string SessionId { get; set; } = string.Empty;
}
-/// Schema for the `WorkspacesCheckpoints` type.
+/// Workspace checkpoint metadata with assigned number, human-readable title, and checkpoint filename.
[Experimental(Diagnostics.Experimental)]
public sealed class WorkspacesCheckpoints
{
@@ -4661,7 +4820,7 @@ internal sealed class TasksStartAgentRequest
public string SessionId { get; set; } = string.Empty;
}
-/// Schema for the `TaskInfo` type.
+/// Tracked task union returned by task APIs, containing either an agent task or a shell task.
/// Polymorphic base type discriminated by type.
[Experimental(Diagnostics.Experimental)]
[JsonPolymorphic(
@@ -4677,7 +4836,7 @@ public partial class TaskInfo
}
-/// Schema for the `TaskAgentInfo` type.
+/// Tracked background agent task metadata, including IDs, status, timing, agent type, prompt, model, result, and latest response.
/// The agent variant of .
[Experimental(Diagnostics.Experimental)]
public partial class TaskInfoAgent : TaskInfo
@@ -4771,7 +4930,7 @@ public partial class TaskInfoAgent : TaskInfo
public required string ToolCallId { get; set; }
}
-/// Schema for the `TaskShellInfo` type.
+/// Tracked shell task metadata, including ID, command, status, timing, attachment/execution mode, log path, and PID.
/// The shell variant of .
[Experimental(Diagnostics.Experimental)]
public partial class TaskInfoShell : TaskInfo
@@ -4892,7 +5051,7 @@ public partial class TasksGetProgressResultProgress
}
-/// Schema for the `TaskProgressLine` type.
+/// Timestamped display line for task progress output or recent agent activity.
[Experimental(Diagnostics.Experimental)]
public sealed class TaskProgressLine
{
@@ -4905,7 +5064,7 @@ public sealed class TaskProgressLine
public DateTimeOffset Timestamp { get; set; }
}
-/// Schema for the `TaskAgentProgress` type.
+/// Progress snapshot for an agent task, with recent activity lines and optional latest intent.
/// The agent variant of .
public partial class TasksGetProgressResultProgressAgent : TasksGetProgressResultProgress
{
@@ -4923,7 +5082,7 @@ public partial class TasksGetProgressResultProgressAgent : TasksGetProgressResul
public required IList RecentActivity { get; set; }
}
-/// Schema for the `TaskShellProgress` type.
+/// Progress snapshot for a shell task, with recent stdout/stderr output and optional process ID.
/// The shell variant of .
public partial class TasksGetProgressResultProgressShell : TasksGetProgressResultProgress
{
@@ -5099,7 +5258,7 @@ internal sealed class TasksSendMessageRequest
public string SessionId { get; set; } = string.Empty;
}
-/// Schema for the `Skill` type.
+/// Skill metadata available to a session, with name, description, source, enabled/invocable state, path, plugin, and argument hint.
[Experimental(Diagnostics.Experimental)]
public sealed class Skill
{
@@ -5154,7 +5313,7 @@ internal sealed class SessionSkillsListRequest
public string SessionId { get; set; } = string.Empty;
}
-/// Schema for the `SkillsInvokedSkill` type.
+/// Skill invocation record with name, path, content, allowed tools, and turn number.
[Experimental(Diagnostics.Experimental)]
public sealed class SkillsInvokedSkill
{
@@ -5309,7 +5468,7 @@ public sealed class McpHostState
public IList PendingConnections { get => field ??= []; set; }
}
-/// Schema for the `McpServer` type.
+/// MCP server status entry, including config source/plugin source and any connection error.
[Experimental(Diagnostics.Experimental)]
public sealed class McpServer
{
@@ -5363,7 +5522,7 @@ internal sealed class SessionMcpListRequest
public string SessionId { get; set; } = string.Empty;
}
-/// Schema for the `McpTools` type.
+/// MCP tool metadata with tool name and optional description.
[Experimental(Diagnostics.Experimental)]
public sealed class McpTools
{
@@ -5442,7 +5601,7 @@ internal sealed class SessionMcpReloadRequest
public string SessionId { get; set; } = string.Empty;
}
-/// Schema for the `McpAllowedServer` type.
+/// MCP server allowed by policy, with server name and optional PII-free explanatory note.
[Experimental(Diagnostics.Experimental)]
public sealed class McpAllowedServer
{
@@ -5455,7 +5614,7 @@ public sealed class McpAllowedServer
public string? RedactedNote { get; set; }
}
-/// Schema for the `McpFilteredServer` type.
+/// MCP server filtered by policy, with name, reason, optional redacted reason, and enterprise login.
[Experimental(Diagnostics.Experimental)]
public sealed class McpFilteredServer
{
@@ -5754,30 +5913,6 @@ internal sealed class McpIsServerRunningRequest
public string SessionId { get; set; } = string.Empty;
}
-/// Empty result after recording the MCP OAuth response.
-[Experimental(Diagnostics.Experimental)]
-internal sealed class McpOauthRespondResult
-{
-}
-
-/// MCP OAuth request id and optional provider response.
-[Experimental(Diagnostics.Experimental)]
-internal sealed class McpOauthRespondRequest
-{
- /// In-process OAuthClientProvider instance, or omitted to deny. Marked internal: cannot be serialized across the JSON-RPC boundary.
- [JsonInclude]
- [JsonPropertyName("provider")]
- internal JsonElement? Provider { get; set; }
-
- /// OAuth request identifier from mcp.oauth_required.
- [JsonPropertyName("requestId")]
- public string RequestId { get; set; } = string.Empty;
-
- /// Target session identifier.
- [JsonPropertyName("sessionId")]
- public string SessionId { get; set; } = string.Empty;
-}
-
/// Indicates whether the pending MCP OAuth response was accepted.
[Experimental(Diagnostics.Experimental)]
public sealed class McpOauthHandlePendingResult
@@ -5971,7 +6106,7 @@ internal sealed class McpHeadersHandlePendingHeadersRefreshRequestRequest
public string SessionId { get; set; } = string.Empty;
}
-/// Schema for the `McpAppsResourceContent` type.
+/// MCP Apps resource content with URI, optional MIME type, text or base64 blob, and resource metadata.
[Experimental(Diagnostics.Experimental)]
public sealed class McpAppsResourceContent
{
@@ -6252,7 +6387,7 @@ internal sealed class McpAppsDiagnoseRequest
public string SessionId { get; set; } = string.Empty;
}
-/// Schema for the `Plugin` type.
+/// Session plugin metadata, with name, marketplace, optional version, and enabled state.
[Experimental(Diagnostics.Experimental)]
public sealed class Plugin
{
@@ -6303,6 +6438,10 @@ public sealed class PluginsReloadRequest
[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; }
@@ -6324,6 +6463,10 @@ internal sealed class PluginsReloadRequestWithSession
[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; }
@@ -6545,7 +6688,7 @@ public sealed class SessionUpdateOptionsResult
public bool Success { get; set; }
}
-/// Schema for the `OptionsUpdateAdditionalContentExclusionPolicyRuleSource` type.
+/// Source descriptor for a `session.options.update` content-exclusion rule, with source name and type.
[Experimental(Diagnostics.Experimental)]
public sealed class OptionsUpdateAdditionalContentExclusionPolicyRuleSource
{
@@ -6558,7 +6701,7 @@ public sealed class OptionsUpdateAdditionalContentExclusionPolicyRuleSource
public string Type { get; set; } = string.Empty;
}
-/// Schema for the `OptionsUpdateAdditionalContentExclusionPolicyRule` type.
+/// Single content-exclusion rule supplied to `session.options.update`, with paths, match conditions, and source.
[Experimental(Diagnostics.Experimental)]
public sealed class OptionsUpdateAdditionalContentExclusionPolicyRule
{
@@ -6574,12 +6717,12 @@ public sealed class OptionsUpdateAdditionalContentExclusionPolicyRule
[JsonPropertyName("paths")]
public IList Paths { get => field ??= []; set; }
- /// Schema for the `OptionsUpdateAdditionalContentExclusionPolicyRuleSource` type.
+ /// Source descriptor for a `session.options.update` content-exclusion rule, with source name and type.
[JsonPropertyName("source")]
public OptionsUpdateAdditionalContentExclusionPolicyRuleSource Source { get => field ??= new(); set; }
}
-/// Schema for the `OptionsUpdateAdditionalContentExclusionPolicy` type.
+/// Content-exclusion policy supplied to `session.options.update`, with rules, last-updated data, and scope.
[Experimental(Diagnostics.Experimental)]
public sealed class OptionsUpdateAdditionalContentExclusionPolicy
{
@@ -6605,7 +6748,7 @@ public sealed class CapiSessionOptions
public bool? EnableWebSocketResponses { get; set; }
}
-/// Schema for the `SessionInstalledPlugin` type.
+/// Installed plugin record for a session, with marketplace, version, install time, enabled state, cache path, and source.
[Experimental(Diagnostics.Experimental)]
public sealed class SessionInstalledPlugin
{
@@ -6742,10 +6885,6 @@ public sealed class SandboxConfigUserPolicyFilesystem
[Experimental(Diagnostics.Experimental)]
public sealed class SandboxConfigUserPolicyNetwork
{
- /// Hosts allowed in addition to the base policy.
- [JsonPropertyName("allowedHosts")]
- public IList? AllowedHosts { get; set; }
-
/// Whether traffic to local/loopback addresses is allowed.
[JsonPropertyName("allowLocalNetwork")]
public bool? AllowLocalNetwork { get; set; }
@@ -6753,10 +6892,6 @@ public sealed class SandboxConfigUserPolicyNetwork
/// Whether outbound network traffic is allowed at all.
[JsonPropertyName("allowOutbound")]
public bool? AllowOutbound { get; set; }
-
- /// Hosts explicitly blocked.
- [JsonPropertyName("blockedHosts")]
- public IList? BlockedHosts { get; set; }
}
/// macOS seatbelt-specific options.
@@ -7023,6 +7158,10 @@ internal sealed class SessionUpdateOptionsParams
[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; }
@@ -7049,7 +7188,7 @@ internal sealed class LspInitializeRequest
public string? WorkingDirectory { get; set; }
}
-/// Schema for the `Extension` type.
+/// Discovered extension metadata, including source-qualified ID, name, discovery source, status, and optional process ID.
[Experimental(Diagnostics.Experimental)]
public sealed class Extension
{
@@ -7127,7 +7266,7 @@ internal sealed class SessionExtensionsReloadRequest
public string SessionId { get; set; } = string.Empty;
}
-/// Schema for the `PushAttachment` type.
+/// Attachment union accepted by push input, covering files, directories, GitHub objects, blobs, snippets, and extension context.
/// Polymorphic base type discriminated by type.
[Experimental(Diagnostics.Experimental)]
[JsonPolymorphic(
@@ -7796,10 +7935,27 @@ internal sealed class UpdateSubagentSettingsRequest
public UpdateSubagentSettingsRequestSubagents? Subagents { get; set; }
}
+/// A literal choice the command input accepts, with a human-facing description.
+[Experimental(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 unstructured input hint.
[Experimental(Diagnostics.Experimental)]
public sealed class SlashCommandInput
{
+ /// 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; }
@@ -7817,7 +7973,7 @@ public sealed class SlashCommandInput
public bool? Required { get; set; }
}
-/// Schema for the `SlashCommandInfo` type.
+/// Slash-command metadata with name, aliases, description, kind, input hint, execution allowance, and schedulability.
[Experimental(Diagnostics.Experimental)]
public sealed class SlashCommandInfo
{
@@ -7919,7 +8075,7 @@ public partial class SlashCommandInvocationResult
}
-/// Schema for the `SlashCommandTextResult` type.
+/// Slash-command invocation result containing text output plus Markdown/ANSI rendering flags.
/// The text variant of .
[Experimental(Diagnostics.Experimental)]
public partial class SlashCommandInvocationResultText : SlashCommandInvocationResult
@@ -7948,7 +8104,7 @@ public partial class SlashCommandInvocationResultText : SlashCommandInvocationRe
public required string Text { get; set; }
}
-/// Schema for the `SlashCommandAgentPromptResult` type.
+/// Slash-command invocation result that submits an agent prompt, with display prompt, optional mode, and settings-change flag.
/// The agent-prompt variant of .
[Experimental(Diagnostics.Experimental)]
public partial class SlashCommandInvocationResultAgentPrompt : SlashCommandInvocationResult
@@ -7976,7 +8132,7 @@ public partial class SlashCommandInvocationResultAgentPrompt : SlashCommandInvoc
public bool? RuntimeSettingsChanged { get; set; }
}
-/// Schema for the `SlashCommandCompletedResult` type.
+/// Slash-command invocation result indicating completion, with optional message and settings-change flag.
/// The completed variant of .
[Experimental(Diagnostics.Experimental)]
public partial class SlashCommandInvocationResultCompleted : SlashCommandInvocationResult
@@ -7996,7 +8152,7 @@ public partial class SlashCommandInvocationResultCompleted : SlashCommandInvocat
public bool? RuntimeSettingsChanged { get; set; }
}
-/// Schema for the `SlashCommandSelectSubcommandOption` type.
+/// Selectable slash-command subcommand option with name, description, and optional group label.
[Experimental(Diagnostics.Experimental)]
public sealed class SlashCommandSelectSubcommandOption
{
@@ -8013,7 +8169,7 @@ public sealed class SlashCommandSelectSubcommandOption
public string Name { get; set; } = string.Empty;
}
-/// Schema for the `SlashCommandSelectSubcommandResult` type.
+/// Slash-command invocation result asking the client to present subcommand options for a parent command.
/// The select-subcommand variant of .
[Experimental(Diagnostics.Experimental)]
public partial class SlashCommandInvocationResultSelectSubcommand : SlashCommandInvocationResult
@@ -8317,7 +8473,7 @@ public sealed class UIHandlePendingResult
public bool Success { get; set; }
}
-/// Schema for the `UIUserInputResponse` type.
+/// User response for a pending user-input request, with answer text and whether it was typed freeform.
[Experimental(Diagnostics.Experimental)]
public sealed class UIUserInputResponse
{
@@ -8338,7 +8494,7 @@ internal sealed class UIHandlePendingUserInputRequest
[JsonPropertyName("requestId")]
public string RequestId { get; set; } = string.Empty;
- /// Schema for the `UIUserInputResponse` type.
+ /// 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; }
@@ -8421,7 +8577,7 @@ internal sealed class UIHandlePendingSessionLimitsExhaustedRequest
public string SessionId { get; set; } = string.Empty;
}
-/// Schema for the `UIExitPlanModeResponse` type.
+/// User response for a pending exit-plan-mode request, with approval state, selected action, auto-approve flag, and feedback.
[Experimental(Diagnostics.Experimental)]
public sealed class UIExitPlanModeResponse
{
@@ -8450,7 +8606,7 @@ internal sealed class UIHandlePendingExitPlanModeRequest
[JsonPropertyName("requestId")]
public string RequestId { get; set; } = string.Empty;
- /// Schema for the `UIExitPlanModeResponse` type.
+ /// 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; }
@@ -8508,7 +8664,7 @@ public sealed class PermissionsConfigureResult
public bool Success { get; set; }
}
-/// Schema for the `PermissionsConfigureAdditionalContentExclusionPolicyRuleSource` type.
+/// Source descriptor for a `session.permissions.configure` content-exclusion rule, with source name and type.
[Experimental(Diagnostics.Experimental)]
public sealed class PermissionsConfigureAdditionalContentExclusionPolicyRuleSource
{
@@ -8521,7 +8677,7 @@ public sealed class PermissionsConfigureAdditionalContentExclusionPolicyRuleSour
public string Type { get; set; } = string.Empty;
}
-/// Schema for the `PermissionsConfigureAdditionalContentExclusionPolicyRule` type.
+/// Single content-exclusion rule supplied to `session.permissions.configure`, with paths, match conditions, and source.
[Experimental(Diagnostics.Experimental)]
public sealed class PermissionsConfigureAdditionalContentExclusionPolicyRule
{
@@ -8537,12 +8693,12 @@ public sealed class PermissionsConfigureAdditionalContentExclusionPolicyRule
[JsonPropertyName("paths")]
public IList Paths { get => field ??= []; set; }
- /// Schema for the `PermissionsConfigureAdditionalContentExclusionPolicyRuleSource` type.
+ /// Source descriptor for a `session.permissions.configure` content-exclusion rule, with source name and type.
[JsonPropertyName("source")]
public PermissionsConfigureAdditionalContentExclusionPolicyRuleSource Source { get => field ??= new(); set; }
}
-/// Schema for the `PermissionsConfigureAdditionalContentExclusionPolicy` type.
+/// Content-exclusion policy supplied to `session.permissions.configure`, with rules, last-updated data, and scope.
[Experimental(Diagnostics.Experimental)]
public sealed class PermissionsConfigureAdditionalContentExclusionPolicy
{
@@ -8677,7 +8833,7 @@ public partial class PermissionDecision
}
-/// Schema for the `PermissionDecisionApproveOnce` type.
+/// Permission-decision request variant to approve only the current permission request.
/// The approve-once variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApproveOnce : PermissionDecision
@@ -8710,7 +8866,7 @@ public partial class PermissionDecisionApproveForSessionApproval
}
-/// Schema for the `PermissionDecisionApproveForSessionApprovalCommands` type.
+/// Session-scoped approval details for specific command identifiers.
/// The commands variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApproveForSessionApprovalCommands : PermissionDecisionApproveForSessionApproval
@@ -8724,7 +8880,7 @@ public partial class PermissionDecisionApproveForSessionApprovalCommands : Permi
public required IList CommandIdentifiers { get; set; }
}
-/// Schema for the `PermissionDecisionApproveForSessionApprovalRead` type.
+/// Session-scoped approval details for read-only filesystem operations.
/// The read variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApproveForSessionApprovalRead : PermissionDecisionApproveForSessionApproval
@@ -8734,7 +8890,7 @@ public partial class PermissionDecisionApproveForSessionApprovalRead : Permissio
public override string Kind => "read";
}
-/// Schema for the `PermissionDecisionApproveForSessionApprovalWrite` type.
+/// Session-scoped approval details for filesystem write operations.
/// The write variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApproveForSessionApprovalWrite : PermissionDecisionApproveForSessionApproval
@@ -8744,7 +8900,7 @@ public partial class PermissionDecisionApproveForSessionApprovalWrite : Permissi
public override string Kind => "write";
}
-/// Schema for the `PermissionDecisionApproveForSessionApprovalMcp` type.
+/// Session-scoped approval details for an MCP server tool, or all tools on the server when `toolName` is null.
/// The mcp variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApproveForSessionApprovalMcp : PermissionDecisionApproveForSessionApproval
@@ -8762,7 +8918,7 @@ public partial class PermissionDecisionApproveForSessionApprovalMcp : Permission
public string? ToolName { get; set; }
}
-/// Schema for the `PermissionDecisionApproveForSessionApprovalMcpSampling` type.
+/// Session-scoped approval details for MCP sampling requests from a server.
/// The mcp-sampling variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApproveForSessionApprovalMcpSampling : PermissionDecisionApproveForSessionApproval
@@ -8776,7 +8932,7 @@ public partial class PermissionDecisionApproveForSessionApprovalMcpSampling : Pe
public required string ServerName { get; set; }
}
-/// Schema for the `PermissionDecisionApproveForSessionApprovalMemory` type.
+/// Session-scoped approval details for writes to long-term memory.
/// The memory variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApproveForSessionApprovalMemory : PermissionDecisionApproveForSessionApproval
@@ -8786,7 +8942,7 @@ public partial class PermissionDecisionApproveForSessionApprovalMemory : Permiss
public override string Kind => "memory";
}
-/// Schema for the `PermissionDecisionApproveForSessionApprovalCustomTool` type.
+/// Session-scoped approval details for a custom tool, keyed by tool name.
/// The custom-tool variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApproveForSessionApprovalCustomTool : PermissionDecisionApproveForSessionApproval
@@ -8800,7 +8956,7 @@ public partial class PermissionDecisionApproveForSessionApprovalCustomTool : Per
public required string ToolName { get; set; }
}
-/// Schema for the `PermissionDecisionApproveForSessionApprovalExtensionManagement` type.
+/// Session-scoped approval details for extension-management operations, optionally narrowed by operation.
/// The extension-management variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApproveForSessionApprovalExtensionManagement : PermissionDecisionApproveForSessionApproval
@@ -8815,7 +8971,7 @@ public partial class PermissionDecisionApproveForSessionApprovalExtensionManagem
public string? Operation { get; set; }
}
-/// Schema for the `PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess` type.
+/// Session-scoped approval details for an extension's permission-gated capability access, keyed by extension name.
/// The extension-permission-access variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess : PermissionDecisionApproveForSessionApproval
@@ -8829,7 +8985,7 @@ public partial class PermissionDecisionApproveForSessionApprovalExtensionPermiss
public required string ExtensionName { get; set; }
}
-/// Schema for the `PermissionDecisionApproveForSession` type.
+/// 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(Diagnostics.Experimental)]
public partial class PermissionDecisionApproveForSession : PermissionDecision
@@ -8872,7 +9028,7 @@ public partial class PermissionDecisionApproveForLocationApproval
}
-/// Schema for the `PermissionDecisionApproveForLocationApprovalCommands` type.
+/// Location-scoped approval details for specific command identifiers.
/// The commands variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApproveForLocationApprovalCommands : PermissionDecisionApproveForLocationApproval
@@ -8886,7 +9042,7 @@ public partial class PermissionDecisionApproveForLocationApprovalCommands : Perm
public required IList CommandIdentifiers { get; set; }
}
-/// Schema for the `PermissionDecisionApproveForLocationApprovalRead` type.
+/// Location-scoped approval details for read-only filesystem operations.
/// The read variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApproveForLocationApprovalRead : PermissionDecisionApproveForLocationApproval
@@ -8896,7 +9052,7 @@ public partial class PermissionDecisionApproveForLocationApprovalRead : Permissi
public override string Kind => "read";
}
-/// Schema for the `PermissionDecisionApproveForLocationApprovalWrite` type.
+/// Location-scoped approval details for filesystem write operations.
/// The write variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApproveForLocationApprovalWrite : PermissionDecisionApproveForLocationApproval
@@ -8906,7 +9062,7 @@ public partial class PermissionDecisionApproveForLocationApprovalWrite : Permiss
public override string Kind => "write";
}
-/// Schema for the `PermissionDecisionApproveForLocationApprovalMcp` type.
+/// Location-scoped approval details for an MCP server tool, or all tools on the server when `toolName` is null.
/// The mcp variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApproveForLocationApprovalMcp : PermissionDecisionApproveForLocationApproval
@@ -8924,7 +9080,7 @@ public partial class PermissionDecisionApproveForLocationApprovalMcp : Permissio
public string? ToolName { get; set; }
}
-/// Schema for the `PermissionDecisionApproveForLocationApprovalMcpSampling` type.
+/// Location-scoped approval details for MCP sampling requests from a server.
/// The mcp-sampling variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApproveForLocationApprovalMcpSampling : PermissionDecisionApproveForLocationApproval
@@ -8938,7 +9094,7 @@ public partial class PermissionDecisionApproveForLocationApprovalMcpSampling : P
public required string ServerName { get; set; }
}
-/// Schema for the `PermissionDecisionApproveForLocationApprovalMemory` type.
+/// Location-scoped approval details for writes to long-term memory.
/// The memory variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApproveForLocationApprovalMemory : PermissionDecisionApproveForLocationApproval
@@ -8948,7 +9104,7 @@ public partial class PermissionDecisionApproveForLocationApprovalMemory : Permis
public override string Kind => "memory";
}
-/// Schema for the `PermissionDecisionApproveForLocationApprovalCustomTool` type.
+/// Location-scoped approval details for a custom tool, keyed by tool name.
/// The custom-tool variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApproveForLocationApprovalCustomTool : PermissionDecisionApproveForLocationApproval
@@ -8962,7 +9118,7 @@ public partial class PermissionDecisionApproveForLocationApprovalCustomTool : Pe
public required string ToolName { get; set; }
}
-/// Schema for the `PermissionDecisionApproveForLocationApprovalExtensionManagement` type.
+/// Location-scoped approval details for extension-management operations, optionally narrowed by operation.
/// The extension-management variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApproveForLocationApprovalExtensionManagement : PermissionDecisionApproveForLocationApproval
@@ -8977,7 +9133,7 @@ public partial class PermissionDecisionApproveForLocationApprovalExtensionManage
public string? Operation { get; set; }
}
-/// Schema for the `PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess` type.
+/// Location-scoped approval details for an extension's permission-gated capability access, keyed by extension name.
/// The extension-permission-access variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess : PermissionDecisionApproveForLocationApproval
@@ -8991,7 +9147,7 @@ public partial class PermissionDecisionApproveForLocationApprovalExtensionPermis
public required string ExtensionName { get; set; }
}
-/// Schema for the `PermissionDecisionApproveForLocation` type.
+/// 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(Diagnostics.Experimental)]
public partial class PermissionDecisionApproveForLocation : PermissionDecision
@@ -9009,7 +9165,7 @@ public partial class PermissionDecisionApproveForLocation : PermissionDecision
public required string LocationKey { get; set; }
}
-/// Schema for the `PermissionDecisionApprovePermanently` type.
+/// Permission-decision request variant to permanently approve a URL domain across sessions.
/// The approve-permanently variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApprovePermanently : PermissionDecision
@@ -9023,7 +9179,7 @@ public partial class PermissionDecisionApprovePermanently : PermissionDecision
public required string Domain { get; set; }
}
-/// Schema for the `PermissionDecisionReject` type.
+/// Permission-decision request variant to reject a pending permission request, with optional feedback.
/// The reject variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionReject : PermissionDecision
@@ -9038,7 +9194,7 @@ public partial class PermissionDecisionReject : PermissionDecision
public string? Feedback { get; set; }
}
-/// Schema for the `PermissionDecisionUserNotAvailable` type.
+/// Permission-decision variant indicating no user was available to confirm the request.
/// The user-not-available variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionUserNotAvailable : PermissionDecision
@@ -9048,7 +9204,7 @@ public partial class PermissionDecisionUserNotAvailable : PermissionDecision
public override string Kind => "user-not-available";
}
-/// Schema for the `PermissionDecisionApproved` type.
+/// Permission-decision variant indicating the request was approved.
/// The approved variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApproved : PermissionDecision
@@ -9058,7 +9214,7 @@ public partial class PermissionDecisionApproved : PermissionDecision
public override string Kind => "approved";
}
-/// Schema for the `PermissionDecisionApprovedForSession` type.
+/// Permission-decision variant indicating approval was remembered for the session, with approval details.
/// The approved-for-session variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApprovedForSession : PermissionDecision
@@ -9072,7 +9228,7 @@ public partial class PermissionDecisionApprovedForSession : PermissionDecision
public required UserToolSessionApproval Approval { get; set; }
}
-/// Schema for the `PermissionDecisionApprovedForLocation` type.
+/// Permission-decision variant indicating approval was persisted for a project location, with approval details and location key.
/// The approved-for-location variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionApprovedForLocation : PermissionDecision
@@ -9090,7 +9246,7 @@ public partial class PermissionDecisionApprovedForLocation : PermissionDecision
public required string LocationKey { get; set; }
}
-/// Schema for the `PermissionDecisionCancelled` type.
+/// Permission-decision variant indicating the request was cancelled before use, with an optional reason.
/// The cancelled variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionCancelled : PermissionDecision
@@ -9105,7 +9261,7 @@ public partial class PermissionDecisionCancelled : PermissionDecision
public string? Reason { get; set; }
}
-/// Schema for the `PermissionDecisionDeniedByRules` type.
+/// Permission-decision variant indicating explicit denial by permission rules, with the matching rules.
/// The denied-by-rules variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionDeniedByRules : PermissionDecision
@@ -9119,7 +9275,7 @@ public partial class PermissionDecisionDeniedByRules : PermissionDecision
public required IList Rules { get; set; }
}
-/// Schema for the `PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser` type.
+/// 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(Diagnostics.Experimental)]
public partial class PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser : PermissionDecision
@@ -9129,7 +9285,7 @@ public partial class PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFro
public override string Kind => "denied-no-approval-rule-and-could-not-request-from-user";
}
-/// Schema for the `PermissionDecisionDeniedInteractivelyByUser` type.
+/// 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(Diagnostics.Experimental)]
public partial class PermissionDecisionDeniedInteractivelyByUser : PermissionDecision
@@ -9149,7 +9305,7 @@ public partial class PermissionDecisionDeniedInteractivelyByUser : PermissionDec
public bool? ForceReject { get; set; }
}
-/// Schema for the `PermissionDecisionDeniedByContentExclusionPolicy` type.
+/// Permission-decision variant indicating denial by content-exclusion policy, with path and message.
/// The denied-by-content-exclusion-policy variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionDecisionDeniedByContentExclusionPolicy : PermissionDecision
@@ -9167,7 +9323,7 @@ public partial class PermissionDecisionDeniedByContentExclusionPolicy : Permissi
public required string Path { get; set; }
}
-/// Schema for the `PermissionDecisionDeniedByPermissionRequestHook` type.
+/// 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(Diagnostics.Experimental)]
public partial class PermissionDecisionDeniedByPermissionRequestHook : PermissionDecision
@@ -9204,7 +9360,7 @@ internal sealed class PermissionDecisionRequest
public string SessionId { get; set; } = string.Empty;
}
-/// Schema for the `PendingPermissionRequest` type.
+/// Pending permission prompt reconstructed from event history, with request ID and user-facing prompt details.
[Experimental(Diagnostics.Experimental)]
public sealed class PendingPermissionRequest
{
@@ -9265,22 +9421,34 @@ internal sealed class PermissionsSetApproveAllRequest
[Experimental(Diagnostics.Experimental)]
public sealed class AllowAllPermissionSetResult
{
- /// Authoritative allow-all state after the mutation.
+ /// Authoritative full allow-all state after the mutation.
[JsonPropertyName("enabled")]
public bool Enabled { get; set; }
+ /// Authoritative allow-all mode after the mutation.
+ [JsonPropertyName("mode")]
+ public PermissionsAllowAllMode? Mode { get; set; }
+
/// Whether the operation succeeded.
[JsonPropertyName("success")]
public bool Success { get; set; }
}
-/// Whether to enable full allow-all permissions for the session.
+/// Allow-all mode to apply for the session.
[Experimental(Diagnostics.Experimental)]
internal sealed class PermissionsSetAllowAllRequest
{
- /// Whether to enable full allow-all permissions.
+ /// Legacy full allow-all toggle. Prefer `mode`; when `mode` is omitted, `enabled: true` is treated as `mode: "on"` and any other value is treated as `mode: "off"`.
[JsonPropertyName("enabled")]
- public bool Enabled { get; set; }
+ public bool? Enabled { get; set; }
+
+ /// Allow-all mode to apply. `on` enables full allow-all; `auto` enables advisory LLM auto-approval; `off` disables both.
+ [JsonPropertyName("mode")]
+ public PermissionsAllowAllMode? Mode { get; set; }
+
+ /// Optional model id for the `auto` mode auto-approval LLM judging. Only meaningful when `mode` is `auto`; ignored otherwise. When omitted, the session's active model is used.
+ [JsonPropertyName("model")]
+ public string? Model { get; set; }
/// Target session identifier.
[JsonPropertyName("sessionId")]
@@ -9291,13 +9459,17 @@ internal sealed class PermissionsSetAllowAllRequest
public PermissionsSetAllowAllSource? Source { get; set; }
}
-/// Current full allow-all permission state.
+/// Current allow-all permission mode.
[Experimental(Diagnostics.Experimental)]
public sealed class AllowAllPermissionState
{
/// Whether full allow-all permissions are currently active.
[JsonPropertyName("enabled")]
public bool Enabled { get; set; }
+
+ /// Current allow-all mode.
+ [JsonPropertyName("mode")]
+ public PermissionsAllowAllMode? Mode { get; set; }
}
/// No parameters.
@@ -9615,7 +9787,7 @@ public partial class PermissionsLocationsAddToolApprovalDetails
}
-/// Schema for the `PermissionsLocationsAddToolApprovalDetailsCommands` type.
+/// Location-persisted tool approval details for specific command identifiers.
/// The commands variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionsLocationsAddToolApprovalDetailsCommands : PermissionsLocationsAddToolApprovalDetails
@@ -9629,7 +9801,7 @@ public partial class PermissionsLocationsAddToolApprovalDetailsCommands : Permis
public required IList CommandIdentifiers { get; set; }
}
-/// Schema for the `PermissionsLocationsAddToolApprovalDetailsRead` type.
+/// Location-persisted tool approval details for read-only filesystem operations.
/// The read variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionsLocationsAddToolApprovalDetailsRead : PermissionsLocationsAddToolApprovalDetails
@@ -9639,7 +9811,7 @@ public partial class PermissionsLocationsAddToolApprovalDetailsRead : Permission
public override string Kind => "read";
}
-/// Schema for the `PermissionsLocationsAddToolApprovalDetailsWrite` type.
+/// Location-persisted tool approval details for filesystem write operations.
/// The write variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionsLocationsAddToolApprovalDetailsWrite : PermissionsLocationsAddToolApprovalDetails
@@ -9649,7 +9821,7 @@ public partial class PermissionsLocationsAddToolApprovalDetailsWrite : Permissio
public override string Kind => "write";
}
-/// Schema for the `PermissionsLocationsAddToolApprovalDetailsMcp` type.
+/// Location-persisted tool approval details for an MCP server tool, or all tools when `toolName` is null.
/// The mcp variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionsLocationsAddToolApprovalDetailsMcp : PermissionsLocationsAddToolApprovalDetails
@@ -9667,7 +9839,7 @@ public partial class PermissionsLocationsAddToolApprovalDetailsMcp : Permissions
public string? ToolName { get; set; }
}
-/// Schema for the `PermissionsLocationsAddToolApprovalDetailsMcpSampling` type.
+/// Location-persisted tool approval details for MCP sampling requests from a server.
/// The mcp-sampling variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionsLocationsAddToolApprovalDetailsMcpSampling : PermissionsLocationsAddToolApprovalDetails
@@ -9681,7 +9853,7 @@ public partial class PermissionsLocationsAddToolApprovalDetailsMcpSampling : Per
public required string ServerName { get; set; }
}
-/// Schema for the `PermissionsLocationsAddToolApprovalDetailsMemory` type.
+/// Location-persisted tool approval details for writes to long-term memory.
/// The memory variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionsLocationsAddToolApprovalDetailsMemory : PermissionsLocationsAddToolApprovalDetails
@@ -9691,7 +9863,7 @@ public partial class PermissionsLocationsAddToolApprovalDetailsMemory : Permissi
public override string Kind => "memory";
}
-/// Schema for the `PermissionsLocationsAddToolApprovalDetailsCustomTool` type.
+/// Location-persisted tool approval details for a custom tool, keyed by tool name.
/// The custom-tool variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionsLocationsAddToolApprovalDetailsCustomTool : PermissionsLocationsAddToolApprovalDetails
@@ -9705,7 +9877,7 @@ public partial class PermissionsLocationsAddToolApprovalDetailsCustomTool : Perm
public required string ToolName { get; set; }
}
-/// Schema for the `PermissionsLocationsAddToolApprovalDetailsExtensionManagement` type.
+/// Location-persisted tool approval details for extension-management operations, optionally narrowed by operation.
/// The extension-management variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionsLocationsAddToolApprovalDetailsExtensionManagement : PermissionsLocationsAddToolApprovalDetails
@@ -9720,7 +9892,7 @@ public partial class PermissionsLocationsAddToolApprovalDetailsExtensionManageme
public string? Operation { get; set; }
}
-/// Schema for the `PermissionsLocationsAddToolApprovalDetailsExtensionPermissionAccess` type.
+/// Location-persisted tool approval details for an extension's permission-gated capability access, keyed by extension name.
/// The extension-permission-access variant of .
[Experimental(Diagnostics.Experimental)]
public partial class PermissionsLocationsAddToolApprovalDetailsExtensionPermissionAccess : PermissionsLocationsAddToolApprovalDetails
@@ -10089,6 +10261,123 @@ internal sealed class MetadataContextInfoRequest
public string SessionId { get; set; } = string.Empty;
}
+/// Successful compaction history for the session.
+public sealed class MetadataContextAttributionResultContextAttributionCompactions
+{
+ /// Number of successful compactions in this session.
+ [JsonPropertyName("count")]
+ public long Count { get; set; }
+}
+
+/// RPC data type for MetadataContextAttributionResultContextAttributionEntry operations.
+public sealed class MetadataContextAttributionResultContextAttributionEntry
+{
+ /// 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;
+
+ /// 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;
+
+ /// 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;
+
+ /// 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; }
+
+ /// Token count currently in context attributable to this entry.
+ [JsonPropertyName("tokens")]
+ public long Tokens { get; 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
+{
+ /// Successful compaction history for the session.
+ [JsonPropertyName("compactions")]
+ public MetadataContextAttributionResultContextAttributionCompactions Compactions { get => field ??= new(); 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; }
+
+ /// 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; }
+}
+
+/// Per-source attribution breakdown for the session's current context window, or null if uninitialized.
+[Experimental(Diagnostics.Experimental)]
+public sealed class MetadataContextAttributionResult
+{
+ /// 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; }
+}
+
+/// Identifies the target session.
+[Experimental(Diagnostics.Experimental)]
+internal sealed class SessionMetadataGetContextAttributionRequest
+{
+ /// Target session identifier.
+ [JsonPropertyName("sessionId")]
+ public string SessionId { get; set; } = string.Empty;
+}
+
+/// A single large message currently in context.
+[Experimental(Diagnostics.Experimental)]
+public sealed class ContextHeaviestMessage
+{
+ /// Stable identifier for this message within the snapshot.
+ [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;
+
+ /// Role of the chat message (`user`, `assistant`, or `tool`).
+ [JsonPropertyName("role")]
+ public string Role { get; set; } = string.Empty;
+
+ /// Token count currently in context for this individual message.
+ [JsonPropertyName("tokens")]
+ public long Tokens { get; set; }
+}
+
+/// The heaviest individual messages in the session's context window, most-expensive first.
+[Experimental(Diagnostics.Experimental)]
+public sealed class MetadataContextHeaviestMessagesResult
+{
+ /// Heaviest messages, most-expensive first.
+ [JsonPropertyName("messages")]
+ public IList Messages { get => field ??= []; 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; }
+}
+
+/// Parameters for the heaviest-messages query.
+[Experimental(Diagnostics.Experimental)]
+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;
+}
+
/// 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).
[Experimental(Diagnostics.Experimental)]
public sealed class MetadataRecordContextChangeResult
@@ -10197,40 +10486,274 @@ internal sealed class MetadataRecomputeContextTokensRequest
public string SessionId { get; set; } = string.Empty;
}
-/// Identifier of the spawned process, used to correlate streamed output and exit notifications.
+/// Availability of built-in job tools surfaced to boundary consumers.
[Experimental(Diagnostics.Experimental)]
-public sealed class ShellExecResult
+public sealed class SessionSettingsBuiltInToolAvailabilitySnapshot
{
- /// Unique identifier for tracking streamed output.
- [JsonPropertyName("processId")]
- public string ProcessId { get; set; } = string.Empty;
+ /// Gets or sets the createPullRequest value.
+ [JsonPropertyName("createPullRequest")]
+ public bool? CreatePullRequest { get; set; }
+
+ /// Gets or sets the reportProgress value.
+ [JsonPropertyName("reportProgress")]
+ public bool? ReportProgress { get; set; }
}
-/// Shell command to run, with optional working directory and timeout in milliseconds.
+/// Redacted job settings for a session. The job nonce is excluded.
[Experimental(Diagnostics.Experimental)]
-internal sealed class ShellExecRequest
+public sealed class SessionSettingsJobSnapshot
{
- /// Shell command to execute.
- [JsonPropertyName("command")]
- public string Command { get; set; } = string.Empty;
-
- /// Working directory (defaults to session working directory).
- [JsonPropertyName("cwd")]
- public string? Cwd { get; set; }
+ /// Gets or sets the builtInToolAvailability value.
+ [JsonPropertyName("builtInToolAvailability")]
+ public SessionSettingsBuiltInToolAvailabilitySnapshot? BuiltInToolAvailability { get; set; }
- /// Target session identifier.
- [JsonPropertyName("sessionId")]
- public string SessionId { get; set; } = string.Empty;
+ /// Gets or sets the eventType value.
+ [JsonPropertyName("eventType")]
+ public string? EventType { get; set; }
- /// Timeout in milliseconds (default: 30000).
- [JsonConverter(typeof(MillisecondsTimeSpanConverter))]
- [JsonPropertyName("timeout")]
- public TimeSpan? Timeout { get; set; }
+ /// Gets or sets the isTriggerJob value.
+ [JsonPropertyName("isTriggerJob")]
+ public bool? IsTriggerJob { get; set; }
}
-/// Indicates whether the signal was delivered; false if the process was unknown or already exited.
+/// Redacted model routing settings for a session.
[Experimental(Diagnostics.Experimental)]
-public sealed class ShellKillResult
+public sealed class SessionSettingsModelSnapshot
+{
+ /// Gets or sets the callbackUrl value.
+ [JsonPropertyName("callbackUrl")]
+ public string? CallbackUrl { get; set; }
+
+ /// Gets or sets the defaultReasoningEffort value.
+ [JsonPropertyName("defaultReasoningEffort")]
+ public string? DefaultReasoningEffort { get; set; }
+
+ /// Gets or sets the instanceId value.
+ [JsonPropertyName("instanceId")]
+ public string? InstanceId { get; set; }
+
+ /// Gets or sets the model value.
+ [JsonPropertyName("model")]
+ public string? Model { get; set; }
+}
+
+/// Online-evaluation settings safe to expose across the SDK boundary.
+[Experimental(Diagnostics.Experimental)]
+public sealed class SessionSettingsOnlineEvaluationSnapshot
+{
+ /// Gets or sets the disableOnlineEvaluation value.
+ [JsonPropertyName("disableOnlineEvaluation")]
+ public bool? DisableOnlineEvaluation { get; set; }
+
+ /// Gets or sets the enableOnlineEvaluationOutputFile value.
+ [JsonPropertyName("enableOnlineEvaluationOutputFile")]
+ public bool? EnableOnlineEvaluationOutputFile { get; set; }
+}
+
+/// Redacted repository and GitHub host settings for a session.
+[Experimental(Diagnostics.Experimental)]
+public sealed class SessionSettingsRepoSnapshot
+{
+ /// Gets or sets the branch value.
+ [JsonPropertyName("branch")]
+ public string? Branch { get; set; }
+
+ /// Gets or sets the commit value.
+ [JsonPropertyName("commit")]
+ public string? Commit { get; set; }
+
+ /// Gets or sets the host value.
+ [JsonPropertyName("host")]
+ public string? Host { get; set; }
+
+ /// Gets or sets the hostProtocol value.
+ [JsonPropertyName("hostProtocol")]
+ public string? HostProtocol { get; set; }
+
+ /// Gets or sets the id value.
+ [JsonPropertyName("id")]
+ public double? Id { get; set; }
+
+ /// Gets or sets the name value.
+ [JsonPropertyName("name")]
+ public string? Name { get; set; }
+
+ /// Gets or sets the ownerId value.
+ [JsonPropertyName("ownerId")]
+ public double? OwnerId { get; set; }
+
+ /// Gets or sets the ownerName value.
+ [JsonPropertyName("ownerName")]
+ public string? OwnerName { get; set; }
+
+ /// Gets or sets the prCommitCount value.
+ [JsonPropertyName("prCommitCount")]
+ public double? PrCommitCount { get; set; }
+
+ /// Gets or sets the readWrite value.
+ [JsonPropertyName("readWrite")]
+ public bool? ReadWrite { get; set; }
+
+ /// Gets or sets the secretScanningUrl value.
+ [JsonPropertyName("secretScanningUrl")]
+ public string? SecretScanningUrl { get; set; }
+
+ /// Gets or sets the serverUrl value.
+ [JsonPropertyName("serverUrl")]
+ public string? ServerUrl { get; set; }
+}
+
+/// Redacted validation and memory-tool settings for a session.
+[Experimental(Diagnostics.Experimental)]
+public sealed class SessionSettingsValidationSnapshot
+{
+ /// Gets or sets the advisoryEnabled value.
+ [JsonPropertyName("advisoryEnabled")]
+ public bool? AdvisoryEnabled { get; set; }
+
+ /// Gets or sets the codeqlEnabled value.
+ [JsonPropertyName("codeqlEnabled")]
+ public bool? CodeqlEnabled { get; set; }
+
+ /// Gets or sets the codeReviewEnabled value.
+ [JsonPropertyName("codeReviewEnabled")]
+ public bool? CodeReviewEnabled { get; set; }
+
+ /// Gets or sets the codeReviewModel value.
+ [JsonPropertyName("codeReviewModel")]
+ public string? CodeReviewModel { get; set; }
+
+ /// Gets or sets the dependabotTimeout value.
+ [JsonPropertyName("dependabotTimeout")]
+ public double? DependabotTimeout { get; set; }
+
+ /// Gets or sets the memoryStoreEnabled value.
+ [JsonPropertyName("memoryStoreEnabled")]
+ public bool? MemoryStoreEnabled { get; set; }
+
+ /// Gets or sets the memoryVoteEnabled value.
+ [JsonPropertyName("memoryVoteEnabled")]
+ public bool? MemoryVoteEnabled { get; set; }
+
+ /// Gets or sets the secretScanningEnabled value.
+ [JsonPropertyName("secretScanningEnabled")]
+ public bool? SecretScanningEnabled { get; set; }
+
+ /// Gets or sets the timeout value.
+ [JsonPropertyName("timeout")]
+ public double? Timeout { get; set; }
+}
+
+/// Redacted, serializable view of session runtime settings for SDK boundary consumers. Secrets and raw feature flags are intentionally excluded.
+[Experimental(Diagnostics.Experimental)]
+internal sealed class SessionSettingsSnapshot
+{
+ /// Gets or sets the clientName value.
+ [JsonPropertyName("clientName")]
+ public string? ClientName { get; set; }
+
+ /// Gets or sets the job value.
+ [JsonPropertyName("job")]
+ public SessionSettingsJobSnapshot Job { get => field ??= new(); set; }
+
+ /// Gets or sets the model value.
+ [JsonPropertyName("model")]
+ public SessionSettingsModelSnapshot Model { get => field ??= new(); set; }
+
+ /// Gets or sets the onlineEvaluation value.
+ [JsonPropertyName("onlineEvaluation")]
+ public SessionSettingsOnlineEvaluationSnapshot OnlineEvaluation { get => field ??= new(); set; }
+
+ /// Gets or sets the repo value.
+ [JsonPropertyName("repo")]
+ public SessionSettingsRepoSnapshot Repo { get => field ??= new(); set; }
+
+ /// Gets or sets the startTimeMs value.
+ [JsonPropertyName("startTimeMs")]
+ public double? StartTimeMs { get; set; }
+
+ /// Gets or sets the timeoutMs value.
+ [JsonPropertyName("timeoutMs")]
+ public double? TimeoutMs { get; set; }
+
+ /// Gets or sets the validation value.
+ [JsonPropertyName("validation")]
+ public SessionSettingsValidationSnapshot Validation { get => field ??= new(); set; }
+
+ /// Gets or sets the version value.
+ [JsonPropertyName("version")]
+ public string? Version { get; set; }
+}
+
+/// Identifies the target session.
+[Experimental(Diagnostics.Experimental)]
+internal sealed class SessionSettingsSnapshotRequest
+{
+ /// Target session identifier.
+ [JsonPropertyName("sessionId")]
+ public string SessionId { get; set; } = string.Empty;
+}
+
+/// Result of evaluating a Rust-owned settings predicate.
+[Experimental(Diagnostics.Experimental)]
+internal sealed class SessionSettingsEvaluatePredicateResult
+{
+ /// Gets or sets the enabled value.
+ [JsonPropertyName("enabled")]
+ public bool Enabled { get; set; }
+}
+
+/// Named Rust-owned settings predicate to evaluate for this session.
+[Experimental(Diagnostics.Experimental)]
+internal sealed class SessionSettingsEvaluatePredicateRequest
+{
+ /// 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; }
+}
+
+/// Identifier of the spawned process, used to correlate streamed output and exit notifications.
+[Experimental(Diagnostics.Experimental)]
+public sealed class ShellExecResult
+{
+ /// Unique identifier for tracking streamed output.
+ [JsonPropertyName("processId")]
+ public string ProcessId { get; set; } = string.Empty;
+}
+
+/// Shell command to run, with optional working directory and timeout in milliseconds.
+[Experimental(Diagnostics.Experimental)]
+internal sealed class ShellExecRequest
+{
+ /// Shell command to execute.
+ [JsonPropertyName("command")]
+ public string Command { get; set; } = string.Empty;
+
+ /// Working directory (defaults to session working directory).
+ [JsonPropertyName("cwd")]
+ public string? Cwd { get; set; }
+
+ /// Target session identifier.
+ [JsonPropertyName("sessionId")]
+ public string SessionId { get; set; } = string.Empty;
+
+ /// Timeout in milliseconds (default: 30000).
+ [JsonConverter(typeof(MillisecondsTimeSpanConverter))]
+ [JsonPropertyName("timeout")]
+ public TimeSpan? Timeout { get; set; }
+}
+
+/// Indicates whether the signal was delivered; false if the process was unknown or already exited.
+[Experimental(Diagnostics.Experimental)]
+public sealed class ShellKillResult
{
/// Whether the signal was sent successfully.
[JsonPropertyName("killed")]
@@ -10474,7 +10997,7 @@ internal sealed class SessionHistorySummarizeForHandoffRequest
public string SessionId { get; set; } = string.Empty;
}
-/// Schema for the `QueuePendingItems` type.
+/// User-facing pending queue entry, with kind and display text for a queued message, slash command, or model change.
[Experimental(Diagnostics.Experimental)]
public sealed class QueuePendingItems
{
@@ -10618,7 +11141,7 @@ public sealed class RegisterEventInterestResult
[Experimental(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 the full interactive OAuth flow to the consumer; when no interest is registered the runtime installs a browserless fallback that silently reuses cached tokens). 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`.
+ /// 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 OAuth token acquisition to the consumer; when no interest is registered OAuth-required servers become needs-auth). 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;
@@ -10683,7 +11206,7 @@ public sealed class UsageMetricsModelMetricRequests
public long Count { get; set; }
}
-/// Schema for the `UsageMetricsModelMetricTokenDetail` type.
+/// Per-model token-detail entry containing the accumulated token count for one token type.
[Experimental(Diagnostics.Experimental)]
public sealed class UsageMetricsModelMetricTokenDetail
{
@@ -10717,7 +11240,7 @@ public sealed class UsageMetricsModelMetricUsage
public long? ReasoningTokens { get; set; }
}
-/// Schema for the `UsageMetricsModelMetric` type.
+/// Per-model usage metrics, including request counts/costs, token usage, nano-AI units, and per-token-type details.
[Experimental(Diagnostics.Experimental)]
public sealed class UsageMetricsModelMetric
{
@@ -10738,7 +11261,7 @@ public sealed class UsageMetricsModelMetric
public UsageMetricsModelMetricUsage Usage { get => field ??= new(); set; }
}
-/// Schema for the `UsageMetricsTokenDetail` type.
+/// Session-wide token-detail entry containing the accumulated token count for one token type.
[Experimental(Diagnostics.Experimental)]
public sealed class UsageMetricsTokenDetail
{
@@ -10922,7 +11445,7 @@ internal sealed class VisibilitySetRequest
public SessionVisibilityStatus Status { get; set; }
}
-/// Schema for the `ScheduleEntry` type.
+/// Scheduled prompt entry with ID, timing (`intervalMs`, `cron`, or `at`), prompt text, recurrence, and next run time.
[Experimental(Diagnostics.Experimental)]
public sealed class ScheduleEntry
{
@@ -11222,7 +11745,7 @@ public sealed class SessionFsReaddirRequest
public string SessionId { get; set; } = string.Empty;
}
-/// Schema for the `SessionFsReaddirWithTypesEntry` type.
+/// Directory entry returned by session filesystem `readdirWithTypes`, with name and entry type.
[Experimental(Diagnostics.Experimental)]
public sealed class SessionFsReaddirWithTypesEntry
{
@@ -11515,14 +12038,26 @@ public sealed class LlmInferenceHttpRequestStartResult
[Experimental(Diagnostics.Experimental)]
public sealed class LlmInferenceHttpRequestStartRequest
{
+ /// Stable per-agent-instance id attributing this request to a specific agent trajectory. Present when the request originates from an agent turn; absent for requests issued outside any agent context (e.g. some SDK callers). A request with an `agentId` but no `parentAgentId` is a root-agent request; one carrying both is a subagent request. Sourced from the runtime's per-request agent context and surfaced on the envelope independently of transport, so it is available for both first-party (CAPI) and BYOK/custom-provider requests; on the CAPI transport the runtime derives the upstream `X-Agent-Task-Id` header from this same context. Consumers routing each provider call to a training trajectory should key on this rather than on lifecycle events, since it is available on the request path before sampling.
+ [JsonPropertyName("agentId")]
+ public string? AgentId { get; set; }
+
/// Gets or sets the headers value.
[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;
+ /// Id of the parent agent that spawned the agent issuing this request. Present only for subagent requests; absent for root-agent requests and non-agent requests. Combined with `agentId`, this lets consumers attribute a call to a child trajectory versus the root. Like `agentId`, it comes from the runtime's per-request agent context independently of transport; on the CAPI transport the runtime derives the upstream `X-Parent-Agent-Id` header from this same context.
+ [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;
@@ -11665,7 +12200,7 @@ public sealed class GitHubTelemetryEvent
public string? SessionId { get; set; }
}
-/// Payload for a `gitHubTelemetry.event` notification: a single GitHub telemetry event the runtime forwards to a host connection that opted into telemetry forwarding for the 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(Diagnostics.Experimental)]
public sealed class GitHubTelemetryNotification
{
@@ -11677,9 +12212,9 @@ public sealed class GitHubTelemetryNotification
[JsonPropertyName("restricted")]
public bool Restricted { get; set; }
- /// Session the telemetry event belongs to.
+ /// 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; } = string.Empty;
+ public string? SessionId { get; set; }
}
/// Resolved Anthropic adaptive-thinking capability for a model.
@@ -13851,6 +14386,264 @@ public override void Write(Utf8JsonWriter writer, AuthInfoType value, JsonSerial
}
+/// Source category for a collected debug bundle entry.
+[Experimental(Diagnostics.Experimental)]
+[JsonConverter(typeof(Converter))]
+[DebuggerDisplay("{Value,nq}")]
+public readonly struct DebugCollectLogsSource : IEquatable
+{
+ private readonly string? _value;
+
+ /// Initializes a new instance of the struct.
+ /// The value to associate with this .
+ [JsonConstructor]
+ public DebugCollectLogsSource(string value)
+ {
+ ArgumentException.ThrowIfNullOrWhiteSpace(value);
+ _value = value;
+ }
+
+ /// Gets the value associated with this .
+ public string Value => _value ?? string.Empty;
+
+ /// Session event log.
+ public static DebugCollectLogsSource Events { get; } = new("events");
+
+ /// Process log for the session.
+ public static DebugCollectLogsSource ProcessLog { get; } = new("process-log");
+
+ /// Interactive shell log for the session.
+ public static DebugCollectLogsSource ShellLog { get; } = new("shell-log");
+
+ /// Caller-provided diagnostic entry.
+ public static DebugCollectLogsSource Additional { get; } = new("additional");
+
+ /// Returns a value indicating whether two instances are equivalent.
+ public static bool operator ==(DebugCollectLogsSource left, DebugCollectLogsSource right) => left.Equals(right);
+
+ /// Returns a value indicating whether two instances are not equivalent.
+ public static bool operator !=(DebugCollectLogsSource left, DebugCollectLogsSource right) => !(left == right);
+
+ ///
+ public override bool Equals(object? obj) => obj is DebugCollectLogsSource other && Equals(other);
+
+ ///
+ public bool Equals(DebugCollectLogsSource 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 DebugCollectLogsSource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert));
+ }
+
+ ///
+ public override void Write(Utf8JsonWriter writer, DebugCollectLogsSource value, JsonSerializerOptions options)
+ {
+ GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(DebugCollectLogsSource));
+ }
+ }
+}
+
+
+/// Destination kind that was written.
+[Experimental(Diagnostics.Experimental)]
+[JsonConverter(typeof(Converter))]
+[DebuggerDisplay("{Value,nq}")]
+public readonly struct DebugCollectLogsResultKind : IEquatable
+{
+ private readonly string? _value;
+
+ /// Initializes a new instance of the struct.
+ /// The value to associate with this .
+ [JsonConstructor]
+ public DebugCollectLogsResultKind(string value)
+ {
+ ArgumentException.ThrowIfNullOrWhiteSpace(value);
+ _value = value;
+ }
+
+ /// Gets the value associated with this .
+ public string Value => _value ?? string.Empty;
+
+ /// A .tgz archive was written.
+ public static DebugCollectLogsResultKind Archive { get; } = new("archive");
+
+ /// A directory containing redacted files was written.
+ public static DebugCollectLogsResultKind Directory { get; } = new("directory");
+
+ /// Returns a value indicating whether two instances are equivalent.
+ public static bool operator ==(DebugCollectLogsResultKind left, DebugCollectLogsResultKind right) => left.Equals(right);
+
+ /// Returns a value indicating whether two instances are not equivalent.
+ public static bool operator !=(DebugCollectLogsResultKind left, DebugCollectLogsResultKind right) => !(left == right);
+
+ ///
+ public override bool Equals(object? obj) => obj is DebugCollectLogsResultKind other && Equals(other);
+
+ ///
+ public bool Equals(DebugCollectLogsResultKind 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 DebugCollectLogsResultKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert));
+ }
+
+ ///
+ public override void Write(Utf8JsonWriter writer, DebugCollectLogsResultKind value, JsonSerializerOptions options)
+ {
+ GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(DebugCollectLogsResultKind));
+ }
+ }
+}
+
+
+/// Kind of caller-provided debug log entry.
+[Experimental(Diagnostics.Experimental)]
+[JsonConverter(typeof(Converter))]
+[DebuggerDisplay("{Value,nq}")]
+public readonly struct DebugCollectLogsEntryKind : IEquatable
+{
+ private readonly string? _value;
+
+ /// Initializes a new instance of the struct.
+ /// The value to associate with this .
+ [JsonConstructor]
+ public DebugCollectLogsEntryKind(string value)
+ {
+ ArgumentException.ThrowIfNullOrWhiteSpace(value);
+ _value = value;
+ }
+
+ /// Gets the value associated with this .
+ public string Value => _value ?? string.Empty;
+
+ /// Include a single server-local file.
+ public static DebugCollectLogsEntryKind File { get; } = new("file");
+
+ /// Include files from a server-local directory recursively.
+ public static DebugCollectLogsEntryKind Directory { get; } = new("directory");
+
+ /// Returns a value indicating whether two instances are equivalent.
+ public static bool operator ==(DebugCollectLogsEntryKind left, DebugCollectLogsEntryKind right) => left.Equals(right);
+
+ /// Returns a value indicating whether two instances are not equivalent.
+ public static bool operator !=(DebugCollectLogsEntryKind left, DebugCollectLogsEntryKind right) => !(left == right);
+
+ ///
+ public override bool Equals(object? obj) => obj is DebugCollectLogsEntryKind other && Equals(other);
+
+ ///
+ public bool Equals(DebugCollectLogsEntryKind 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 DebugCollectLogsEntryKind Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert));
+ }
+
+ ///
+ public override void Write(Utf8JsonWriter writer, DebugCollectLogsEntryKind value, JsonSerializerOptions options)
+ {
+ GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(DebugCollectLogsEntryKind));
+ }
+ }
+}
+
+
+/// How a collected debug entry should be redacted before being staged.
+[Experimental(Diagnostics.Experimental)]
+[JsonConverter(typeof(Converter))]
+[DebuggerDisplay("{Value,nq}")]
+public readonly struct DebugCollectLogsRedaction : IEquatable
+{
+ private readonly string? _value;
+
+ /// Initializes a new instance of the struct.
+ /// The value to associate with this .
+ [JsonConstructor]
+ public DebugCollectLogsRedaction(string value)
+ {
+ ArgumentException.ThrowIfNullOrWhiteSpace(value);
+ _value = value;
+ }
+
+ /// Gets the value associated with this .
+ public string Value => _value ?? string.Empty;
+
+ /// Redact the file as plain UTF-8 log text.
+ public static DebugCollectLogsRedaction PlainText { get; } = new("plain-text");
+
+ /// Redact each non-empty line as a session event JSON object, falling back to plain-text redaction for malformed lines.
+ public static DebugCollectLogsRedaction EventsJsonl { get; } = new("events-jsonl");
+
+ /// Returns a value indicating whether two instances are equivalent.
+ public static bool operator ==(DebugCollectLogsRedaction left, DebugCollectLogsRedaction right) => left.Equals(right);
+
+ /// Returns a value indicating whether two instances are not equivalent.
+ public static bool operator !=(DebugCollectLogsRedaction left, DebugCollectLogsRedaction right) => !(left == right);
+
+ ///
+ public override bool Equals(object? obj) => obj is DebugCollectLogsRedaction other && Equals(other);
+
+ ///
+ public bool Equals(DebugCollectLogsRedaction 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 DebugCollectLogsRedaction Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert));
+ }
+
+ ///
+ public override void Write(Utf8JsonWriter writer, DebugCollectLogsRedaction value, JsonSerializerOptions options)
+ {
+ GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(DebugCollectLogsRedaction));
+ }
+ }
+}
+
+
/// Allowed values for the `WorkspacesWorkspaceDetailsHostType` enumeration.
[Experimental(Diagnostics.Experimental)]
[JsonConverter(typeof(Converter))]
@@ -16551,6 +17344,72 @@ public override void Write(Utf8JsonWriter writer, PermissionsSetApproveAllSource
}
+/// Current or requested allow-all mode.
+[Experimental(Diagnostics.Experimental)]
+[JsonConverter(typeof(Converter))]
+[DebuggerDisplay("{Value,nq}")]
+public readonly struct PermissionsAllowAllMode : IEquatable
+{
+ private readonly string? _value;
+
+ /// Initializes a new instance of the struct.
+ /// The value to associate with this .
+ [JsonConstructor]
+ public PermissionsAllowAllMode(string value)
+ {
+ ArgumentException.ThrowIfNullOrWhiteSpace(value);
+ _value = value;
+ }
+
+ /// Gets the value associated with this .
+ public string Value => _value ?? string.Empty;
+
+ /// Permission requests follow the normal approval flow.
+ public static PermissionsAllowAllMode Off { get; } = new("off");
+
+ /// Tool, path, and URL permission requests are automatically approved.
+ public static PermissionsAllowAllMode On { get; } = new("on");
+
+ /// Permission requests follow the normal approval flow with an LLM advisory recommendation attached; clients may choose to auto-approve requests the judge evaluated as acceptable.
+ public static PermissionsAllowAllMode Auto { get; } = new("auto");
+
+ /// Returns a value indicating whether two instances are equivalent.
+ public static bool operator ==(PermissionsAllowAllMode left, PermissionsAllowAllMode right) => left.Equals(right);
+
+ /// Returns a value indicating whether two instances are not equivalent.
+ public static bool operator !=(PermissionsAllowAllMode left, PermissionsAllowAllMode right) => !(left == right);
+
+ ///
+ public override bool Equals(object? obj) => obj is PermissionsAllowAllMode other && Equals(other);
+
+ ///
+ public bool Equals(PermissionsAllowAllMode 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 PermissionsAllowAllMode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert));
+ }
+
+ ///
+ public override void Write(Utf8JsonWriter writer, PermissionsAllowAllMode value, JsonSerializerOptions options)
+ {
+ GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(PermissionsAllowAllMode));
+ }
+ }
+}
+
+
/// Optional source for allow-all telemetry. Defaults to `rpc` when omitted for SDK callers.
[Experimental(Diagnostics.Experimental)]
[JsonConverter(typeof(Converter))]
@@ -17001,6 +17860,120 @@ public override void Write(Utf8JsonWriter writer, SessionWorkingDirectoryContext
}
+/// Rust-owned settings predicates exposed across the SDK boundary. Raw feature-flag names are intentionally not part of the contract.
+[Experimental(Diagnostics.Experimental)]
+[JsonConverter(typeof(Converter))]
+[DebuggerDisplay("{Value,nq}")]
+public readonly struct SessionSettingsPredicateName : IEquatable
+{
+ private readonly string? _value;
+
+ /// Initializes a new instance of the struct.
+ /// The value to associate with this .
+ [JsonConstructor]
+ public SessionSettingsPredicateName(string value)
+ {
+ ArgumentException.ThrowIfNullOrWhiteSpace(value);
+ _value = value;
+ }
+
+ /// Gets the value associated with this .
+ public string Value => _value ?? string.Empty;
+
+ /// Whether the security-tools feature flag enables security tool wiring.
+ public static SessionSettingsPredicateName SecurityToolsEnabled { get; } = new("securityToolsEnabled");
+
+ /// Whether third-party security tools should receive the security prompt.
+ public static SessionSettingsPredicateName ThirdPartySecurityPromptEnabled { get; } = new("thirdPartySecurityPromptEnabled");
+
+ /// Whether validation may run in parallel.
+ public static SessionSettingsPredicateName ParallelValidationEnabled { get; } = new("parallelValidationEnabled");
+
+ /// Whether runtime timing telemetry is enabled.
+ public static SessionSettingsPredicateName RuntimeTimingTelemetryEnabled { get; } = new("runtimeTimingTelemetryEnabled");
+
+ /// Whether the co-author hook is enabled.
+ public static SessionSettingsPredicateName CoAuthorHookEnabled { get; } = new("coAuthorHookEnabled");
+
+ /// Whether Chronicle integration is enabled.
+ public static SessionSettingsPredicateName ChronicleEnabled { get; } = new("chronicleEnabled");
+
+ /// Whether content-exclusion policy may self-fetch data.
+ public static SessionSettingsPredicateName ContentExclusionSelfFetchEnabled { get; } = new("contentExclusionSelfFetchEnabled");
+
+ /// Whether Claude Opus token-limit caps should be applied.
+ public static SessionSettingsPredicateName CapClaudeOpusTokenLimitsEnabled { get; } = new("capClaudeOpusTokenLimitsEnabled");
+
+ /// Whether code-review behavior is enabled.
+ public static SessionSettingsPredicateName CodeReviewFeatureEnabled { get; } = new("codeReviewFeatureEnabled");
+
+ /// Whether CCA should use the TypeScript autofind behavior.
+ public static SessionSettingsPredicateName CcaUseTsAutofindEnabled { get; } = new("ccaUseTsAutofindEnabled");
+
+ /// Whether the dependency checker is enabled.
+ public static SessionSettingsPredicateName DependencyCheckerEnabled { get; } = new("dependencyCheckerEnabled");
+
+ /// Whether the Dependabot checker is enabled.
+ public static SessionSettingsPredicateName DependabotCheckerEnabled { get; } = new("dependabotCheckerEnabled");
+
+ /// Whether the CodeQL checker is enabled.
+ public static SessionSettingsPredicateName CodeqlCheckerEnabled { get; } = new("codeqlCheckerEnabled");
+
+ /// Whether trivial-change handling is enabled.
+ public static SessionSettingsPredicateName TrivialChangeEnabled { get; } = new("trivialChangeEnabled");
+
+ /// Whether trivial-change skip behavior is enabled.
+ public static SessionSettingsPredicateName TrivialChangeSkipEnabled { get; } = new("trivialChangeSkipEnabled");
+
+ /// Whether trivial-change handling is enabled for code review.
+ public static SessionSettingsPredicateName TrivialChangeEnabledForCodeReview { get; } = new("trivialChangeEnabledForCodeReview");
+
+ /// Whether trivial-change skip behavior is enabled for code review.
+ public static SessionSettingsPredicateName TrivialChangeSkipEnabledForCodeReview { get; } = new("trivialChangeSkipEnabledForCodeReview");
+
+ /// Whether trivial-change handling is enabled for a specific tool.
+ public static SessionSettingsPredicateName TrivialChangeEnabledForTool { get; } = new("trivialChangeEnabledForTool");
+
+ /// Whether trivial-change skip behavior is enabled for a specific tool.
+ public static SessionSettingsPredicateName TrivialChangeSkipEnabledForTool { get; } = new("trivialChangeSkipEnabledForTool");
+
+ /// Returns a value indicating whether two instances are equivalent.
+ public static bool operator ==(SessionSettingsPredicateName left, SessionSettingsPredicateName right) => left.Equals(right);
+
+ /// Returns a value indicating whether two instances are not equivalent.
+ public static bool operator !=(SessionSettingsPredicateName left, SessionSettingsPredicateName right) => !(left == right);
+
+ ///
+ public override bool Equals(object? obj) => obj is SessionSettingsPredicateName other && Equals(other);
+
+ ///
+ public bool Equals(SessionSettingsPredicateName 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 SessionSettingsPredicateName Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert));
+ }
+
+ ///
+ public override void Write(Utf8JsonWriter writer, SessionSettingsPredicateName value, JsonSerializerOptions options)
+ {
+ GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionSettingsPredicateName));
+ }
+ }
+}
+
+
/// Signal to send (default: SIGTERM).
[Experimental(Diagnostics.Experimental)]
[JsonConverter(typeof(Converter))]
@@ -17663,12 +18636,13 @@ public async Task PingAsync(string? message = null, CancellationToke
/// 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.
/// Connection token; required when the server was started with COPILOT_CONNECTION_TOKEN.
+ /// Opt this connection in to GitHub telemetry forwarding for its lifetime. When set, the runtime forwards every internal telemetry event it emits — across all sessions, plus sessionless events — to this connection over the `gitHubTelemetry.event` notification, in addition to the runtime's normal GitHub/CTS emission (dual-write). 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.
/// The to monitor for cancellation requests. The default is .
/// Handshake result reporting the server's protocol version and package version on success.
[Experimental(Diagnostics.Experimental)]
- internal async Task ConnectAsync(string? token = null, CancellationToken cancellationToken = default)
+ internal async Task ConnectAsync(string? token = null, bool? enableGitHubTelemetryForwarding = null, CancellationToken cancellationToken = default)
{
- var request = new ConnectRequest { Token = token };
+ var request = new ConnectRequest { Token = token, EnableGitHubTelemetryForwarding = enableGitHubTelemetryForwarding };
return await CopilotClient.InvokeRpcAsync(_rpc, "connect", [request], cancellationToken);
}
@@ -18775,17 +19749,6 @@ public async Task GetRemoteControlStatusAsync(Cancell
return await CopilotClient.InvokeRpcAsync(_rpc, "sessions.getRemoteControlStatus", [], cancellationToken);
}
- /// Cursor-based long-poll for sessions spawned by the runtime (e.g. in response to a Mission Control `start_session` command). The cursor is an opaque token; pass it back to receive only spawn events that occurred AFTER the cursor was issued. Omit the cursor on the first call to receive any events buffered since the runtime started. Internal: this is a CLI background-daemon plumbing primitive. SDK consumers that need to react to runtime-spawned sessions should subscribe to a higher-level event stream rather than driving a long-poll loop.
- /// Opaque cursor returned by a previous poll. Omit on the first call to receive any spawn events buffered since the runtime started.
- /// Milliseconds to wait for new spawn events when the cursor is at the tail. 0 (default) returns immediately even if no events are buffered. Capped at 60000ms.
- /// The to monitor for cancellation requests. The default is .
- /// Batch of spawn events plus a cursor for follow-up polls.
- internal async Task PollSpawnedSessionsAsync(string? cursor = null, TimeSpan? waitMs = null, CancellationToken cancellationToken = default)
- {
- var request = new SessionsPollSpawnedSessionsRequest { Cursor = cursor, Wait = waitMs };
- return await CopilotClient.InvokeRpcAsync(_rpc, "sessions.pollSpawnedSessions", [request], cancellationToken);
- }
-
/// Registers extension-provided tools on the given session, gated by an optional `enabled` callback. Returns an opaque unsubscribe function the caller must invoke to deregister the tools when the extension is torn down. Marked internal because `loader`, `enabled`, and the returned `unsubscribe` are in-process handles that cannot cross the JSON-RPC boundary. Disappears once extension discovery / launch / tool registration are owned by the runtime: SDK consumers will pass pure config (search paths, disabled ids) via `SessionOptions` and the runtime will resolve, launch, register, and tear down extensions itself.
/// Session to register extension tools on.
/// In-process ExtensionLoader handle (CLI-only optimization). Marked internal: this field is excluded from the public SDK surface. When the CLI migrates to a process-separated SDK, extension discovery/launch moves entirely into the runtime — the CLI passes pure config (search paths, disabled ids) via SessionOptions instead.
@@ -18861,6 +19824,12 @@ internal SessionRpc(CopilotSession session)
Interlocked.CompareExchange(ref field, new(_session), null) ??
field;
+ /// Debug APIs.
+ public DebugApi Debug =>
+ field ??
+ Interlocked.CompareExchange(ref field, new(_session), null) ??
+ field;
+
/// Canvas APIs.
public CanvasApi Canvas =>
field ??
@@ -19005,6 +19974,12 @@ internal SessionRpc(CopilotSession session)
Interlocked.CompareExchange(ref field, new(_session), null) ??
field;
+ /// Settings APIs.
+ public SettingsApi Settings =>
+ field ??
+ Interlocked.CompareExchange(ref field, new(_session), null) ??
+ field;
+
/// Shell APIs.
public ShellApi Shell =>
field ??
@@ -19171,6 +20146,33 @@ public async Task SetCredentialsAsync(AuthInfo? cre
}
}
+/// Provides session-scoped Debug APIs.
+[Experimental(Diagnostics.Experimental)]
+public sealed class DebugApi
+{
+ private readonly CopilotSession _session;
+
+ internal DebugApi(CopilotSession session)
+ {
+ _session = session;
+ }
+
+ /// Collects a redacted session debug log bundle into a local archive or staging directory. The runtime includes session-owned logs by default and accepts caller-provided diagnostic entries so host applications can add their own files without changing this API shape.
+ /// Where the redacted bundle should be written. Use `archive` to produce a .tgz, or `directory` to stage redacted files for caller-managed upload/post-processing.
+ /// Which built-in session diagnostics to include. Omitted fields default to true.
+ /// 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.
+ /// The to monitor for cancellation requests. The default is .
+ /// Result of collecting a redacted debug bundle.
+ public async Task CollectLogsAsync(DebugCollectLogsDestination destination, DebugCollectLogsInclude? include = null, IList? additionalEntries = null, CancellationToken cancellationToken = default)
+ {
+ ArgumentNullException.ThrowIfNull(destination);
+ _session.ThrowIfDisposed();
+
+ var request = new DebugCollectLogsRequest { SessionId = _session.SessionId, Destination = destination, Include = include, AdditionalEntries = additionalEntries };
+ return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.debug.collectLogs", [request], cancellationToken);
+ }
+}
+
/// Provides session-scoped Canvas APIs.
[Experimental(Diagnostics.Experimental)]
public sealed class CanvasApi
@@ -19294,16 +20296,17 @@ public async Task GetCurrentAsync(CancellationToken cancellationTo
/// Model selection id to switch to, as returned by `list`. A bare id (e.g. `claude-sonnet-4.6`) names a Copilot (CAPI) model; a provider-qualified id (`provider/id`, e.g. `acme/claude-sonnet`) targets a registry BYOK model.
/// Reasoning effort level to use for the model. "none" disables reasoning.
/// Reasoning summary mode to request for supported model clients.
+ /// Output verbosity level to request for supported models.
/// Override individual model capabilities resolved by the runtime.
/// 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.
/// The to monitor for cancellation requests. The default is .
/// The model identifier active on the session after the switch.
- public async Task SwitchToAsync(string modelId, string? reasoningEffort = null, ReasoningSummary? reasoningSummary = null, ModelCapabilitiesOverride? modelCapabilities = null, ContextTier? contextTier = null, CancellationToken cancellationToken = default)
+ public async Task SwitchToAsync(string modelId, string? reasoningEffort = null, ReasoningSummary? reasoningSummary = null, Verbosity? verbosity = null, ModelCapabilitiesOverride? modelCapabilities = null, ContextTier? contextTier = null, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(modelId);
_session.ThrowIfDisposed();
- var request = new ModelSwitchToRequest { SessionId = _session.SessionId, ModelId = modelId, ReasoningEffort = reasoningEffort, ReasoningSummary = reasoningSummary, ModelCapabilities = modelCapabilities, ContextTier = contextTier };
+ var request = new ModelSwitchToRequest { SessionId = _session.SessionId, ModelId = modelId, ReasoningEffort = reasoningEffort, ReasoningSummary = reasoningSummary, Verbosity = verbosity, ModelCapabilities = modelCapabilities, ContextTier = contextTier };
return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.model.switchTo", [request], cancellationToken);
}
@@ -20240,20 +21243,6 @@ internal McpOauthApi(CopilotSession session)
_session = session;
}
- /// Responds to a pending MCP OAuth request with an in-process provider. This internal CLI-only API accepts a live OAuthClientProvider instance and cannot be used over the SDK JSON-RPC boundary. Use session.mcp.oauth.handlePendingRequest instead for the public SDK-safe response path.
- /// OAuth request identifier from mcp.oauth_required.
- /// In-process OAuthClientProvider instance, or omitted to deny. Marked internal: cannot be serialized across the JSON-RPC boundary.
- /// The to monitor for cancellation requests. The default is .
- /// Empty result after recording the MCP OAuth response.
- internal async Task RespondAsync(string requestId, object? provider = null, CancellationToken cancellationToken = default)
- {
- ArgumentNullException.ThrowIfNull(requestId);
- _session.ThrowIfDisposed();
-
- var request = new McpOauthRespondRequest { SessionId = _session.SessionId, RequestId = requestId, Provider = CopilotClient.ToJsonElementForWire(provider) };
- return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.mcp.oauth.respond", [request], cancellationToken);
- }
-
/// Resolves a pending MCP OAuth request with a host-provided token or cancellation. The pending request is emitted as mcp.oauth_required with the data necessary to authorize the request.
/// OAuth request identifier from the mcp.oauth_required event.
/// Host response to the pending OAuth request.
@@ -20442,7 +21431,7 @@ public async Task ReloadAsync(PluginsReloadRequest? request = null, Cancellation
{
_session.ThrowIfDisposed();
- var rpcRequest = new PluginsReloadRequestWithSession { SessionId = _session.SessionId, ReloadMcp = request?.ReloadMcp, ReloadCustomAgents = request?.ReloadCustomAgents, ReloadHooks = request?.ReloadHooks, DeferRepoHooks = request?.DeferRepoHooks };
+ var rpcRequest = new PluginsReloadRequestWithSession { SessionId = _session.SessionId, ReloadMcp = request?.ReloadMcp, ReloadCustomAgents = request?.ReloadCustomAgents, ReloadHooks = request?.ReloadHooks, ReloadExtensions = request?.ReloadExtensions, DeferRepoHooks = request?.DeferRepoHooks };
await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.plugins.reload", [rpcRequest], cancellationToken);
}
}
@@ -20500,6 +21489,7 @@ internal OptionsApi(CopilotSession session)
/// Per-property model capability overrides for the selected model.
/// Reasoning effort for the selected model (model-defined enum).
/// Reasoning summary mode for supported model clients.
+ /// Output verbosity level for supported models.
/// Identifier of the client driving the session.
/// Identifier sent to LSP-style integrations.
/// Stable integration identifier used for analytics and rate-limit attribution.
@@ -20551,11 +21541,11 @@ internal OptionsApi(CopilotSession session)
/// 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, 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? excludedBuiltinAgents = null, OptionsUpdateToolFilterPrecedence? toolFilterPrecedence = null, bool? enableScriptSafety = null, string? shellInitProfile = null, IList? shellProcessFlags = null, SandboxConfig? sandboxConfig = null, bool? logInteractiveShells = null, OptionsUpdateEnvValueMode? envValueMode = null, bool? allowAllMcpServerInstructions = null, IList? skillDirectories = 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, 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? excludedBuiltinAgents = null, OptionsUpdateToolFilterPrecedence? toolFilterPrecedence = null, bool? enableScriptSafety = null, string? shellInitProfile = null, IList? shellProcessFlags = null, SandboxConfig? sandboxConfig = null, bool? logInteractiveShells = null, OptionsUpdateEnvValueMode? envValueMode = null, bool? allowAllMcpServerInstructions = null, IList? skillDirectories = 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, 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, ClientName = clientName, LspClientName = lspClientName, IntegrationId = integrationId, FeatureFlags = featureFlags, IsExperimentalMode = isExperimentalMode, Provider = provider, Capi = capi, WorkingDirectory = workingDirectory, AvailableTools = availableTools, ExcludedTools = excludedTools, ExcludedBuiltinAgents = excludedBuiltinAgents, ToolFilterPrecedence = toolFilterPrecedence, EnableScriptSafety = enableScriptSafety, ShellInitProfile = shellInitProfile, ShellProcessFlags = shellProcessFlags, SandboxConfig = sandboxConfig, LogInteractiveShells = logInteractiveShells, EnvValueMode = envValueMode, AllowAllMcpServerInstructions = allowAllMcpServerInstructions, SkillDirectories = skillDirectories, 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, 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, ExcludedBuiltinAgents = excludedBuiltinAgents, ToolFilterPrecedence = toolFilterPrecedence, EnableScriptSafety = enableScriptSafety, ShellInitProfile = shellInitProfile, ShellProcessFlags = shellProcessFlags, SandboxConfig = sandboxConfig, LogInteractiveShells = logInteractiveShells, EnvValueMode = envValueMode, AllowAllMcpServerInstructions = allowAllMcpServerInstructions, SkillDirectories = skillDirectories, 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, 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);
}
}
@@ -20904,7 +21894,7 @@ public async Task HandlePendingElicitationAsync(string requ
/// Resolves a pending `user_input.requested` event with the user's response.
/// The unique request ID from the user_input.requested event.
- /// Schema for the `UIUserInputResponse` type.
+ /// User response for a pending user-input request, with answer text and whether it was typed freeform.
/// The to monitor for cancellation requests. The default is .
/// Indicates whether the pending UI request was resolved by this call.
public async Task HandlePendingUserInputAsync(string requestId, UIUserInputResponse response, CancellationToken cancellationToken = default)
@@ -20962,7 +21952,7 @@ public async Task HandlePendingSessionLimitsExhaustedAsyn
/// Resolves a pending `exit_plan_mode.requested` event with the user's response.
/// The unique request ID from the exit_plan_mode.requested event.
- /// Schema for the `UIExitPlanModeResponse` type.
+ /// User response for a pending exit-plan-mode request, with approval state, selected action, auto-approve flag, and feedback.
/// The to monitor for cancellation requests. The default is .
/// Indicates whether the pending UI request was resolved by this call.
public async Task HandlePendingExitPlanModeAsync(string requestId, UIExitPlanModeResponse response, CancellationToken cancellationToken = default)
@@ -21067,22 +22057,24 @@ public async Task SetApproveAllAsync(bool enable
return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.permissions.setApproveAll", [request], cancellationToken);
}
- /// Enables or disables full allow-all permissions (tools, paths, and URLs) for the session. Used by attach-mode clients (e.g. LocalRpcSession's `/allow-all` forwarder) to flip the target session's permission state. Unlike `setApproveAll`, this swaps in the unrestricted path and URL managers and emits `session.permissions_changed` on transition. The result returns the authoritative post-mutation state so callers can update their local mirrors without racing the `session.permissions_changed` notification on the same wire.
- /// Whether to enable full allow-all permissions.
+ /// Sets the allow-all permission mode for the session. Used by attach-mode clients (e.g. LocalRpcSession's `/allow-all` forwarder) to flip the target session's permission state. The `on` mode swaps in unrestricted path and URL managers and emits `session.permissions_changed` on transition; the `auto` mode keeps normal prompt paths active while attaching LLM safety recommendations. The result returns the authoritative post-mutation state so callers can update their local mirrors without racing the `session.permissions_changed` notification on the same wire.
+ /// Allow-all mode to apply. `on` enables full allow-all; `auto` enables advisory LLM auto-approval; `off` disables both.
+ /// Legacy full allow-all toggle. Prefer `mode`; when `mode` is omitted, `enabled: true` is treated as `mode: "on"` and any other value is treated as `mode: "off"`.
+ /// Optional model id for the `auto` mode auto-approval LLM judging. Only meaningful when `mode` is `auto`; ignored otherwise. When omitted, the session's active model is used.
/// Optional source for allow-all telemetry. Defaults to `rpc` when omitted for SDK callers.
/// The to monitor for cancellation requests. The default is .
/// Indicates whether the operation succeeded and reports the post-mutation state.
- public async Task SetAllowAllAsync(bool enabled, PermissionsSetAllowAllSource? source = null, CancellationToken cancellationToken = default)
+ public async Task SetAllowAllAsync(PermissionsAllowAllMode? mode = null, bool? enabled = null, string? model = null, PermissionsSetAllowAllSource? source = null, CancellationToken cancellationToken = default)
{
_session.ThrowIfDisposed();
- var request = new PermissionsSetAllowAllRequest { SessionId = _session.SessionId, Enabled = enabled, Source = source };
+ var request = new PermissionsSetAllowAllRequest { SessionId = _session.SessionId, Mode = mode, Enabled = enabled, Model = model, Source = source };
return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.permissions.setAllowAll", [request], cancellationToken);
}
- /// Returns whether full allow-all permissions are currently active for the session.
+ /// Returns the current allow-all permission mode for the session.
/// The to monitor for cancellation requests. The default is .
- /// Current full allow-all permission state.
+ /// Current allow-all permission mode.
public async Task GetAllowAllAsync(CancellationToken cancellationToken = default)
{
_session.ThrowIfDisposed();
@@ -21415,6 +22407,29 @@ public async Task ContextInfoAsync(long promptTokenLi
return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.metadata.contextInfo", [request], cancellationToken);
}
+ /// Returns the experimental per-source attribution breakdown of the session's current context window as a flat list of entries (skills, subagents, MCP servers, built-in tools, plugin rollups, system/tool-definition costs, with nesting via parentId), plus the successful compaction count. The heaviest individual messages are available separately via `metadata.getContextHeaviestMessages`. Returns null until the session has initialized its system prompt and tool metadata.
+ /// The to monitor for cancellation requests. The default is .
+ /// Per-source attribution breakdown for the session's current context window, or null if uninitialized.
+ public async Task GetContextAttributionAsync(CancellationToken cancellationToken = default)
+ {
+ _session.ThrowIfDisposed();
+
+ var request = new SessionMetadataGetContextAttributionRequest { SessionId = _session.SessionId };
+ return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.metadata.getContextAttribution", [request], cancellationToken);
+ }
+
+ /// Returns the largest individual messages currently in the session's context window, most-expensive first. Companion to `metadata.getContextAttribution`. Returns an empty list until the session has initialized.
+ /// Maximum number of messages to return, most-expensive first. Omit for the server default.
+ /// The to monitor for cancellation requests. The default is .
+ /// The heaviest individual messages in the session's context window, most-expensive first.
+ public async Task GetContextHeaviestMessagesAsync(long? limit = null, CancellationToken cancellationToken = default)
+ {
+ _session.ThrowIfDisposed();
+
+ var request = new MetadataContextHeaviestMessagesRequest { SessionId = _session.SessionId, Limit = limit };
+ return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.metadata.getContextHeaviestMessages", [request], cancellationToken);
+ }
+
/// Records a working-directory/git context change and emits a `session.context_changed` event.
/// Updated working directory and git context. Emitted as the new payload of `session.context_changed`.
/// The to monitor for cancellation requests. The default is .
@@ -21455,6 +22470,42 @@ public async Task RecomputeContextTokensAs
}
}
+/// Provides session-scoped Settings APIs.
+[Experimental(Diagnostics.Experimental)]
+public sealed class SettingsApi
+{
+ private readonly CopilotSession _session;
+
+ internal SettingsApi(CopilotSession session)
+ {
+ _session = session;
+ }
+
+ /// Returns a redacted snapshot of session runtime settings, with secrets and raw feature flags excluded. Internal: the runtime settings shape is a runtime-internal surface and is deliberately kept out of the public SDK, because consumers should not depend on the runtime's internal settings layout. It remains callable in-process and is expected to be reworked as the runtime internals are consolidated.
+ /// The to monitor for cancellation requests. The default is .
+ /// Redacted, serializable view of session runtime settings for SDK boundary consumers. Secrets and raw feature flags are intentionally excluded.
+ internal async Task SnapshotAsync(CancellationToken cancellationToken = default)
+ {
+ _session.ThrowIfDisposed();
+
+ var request = new SessionSettingsSnapshotRequest { SessionId = _session.SessionId };
+ return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.settings.snapshot", [request], cancellationToken);
+ }
+
+ /// Evaluates a named Rust-owned settings predicate without exposing raw feature flags. Internal: the raw feature-flag names and composition are runtime-internal, so this predicate-evaluation helper is kept out of the public SDK surface and is callable in-process only.
+ /// Predicate name. The runtime owns the raw feature-flag names and composition logic.
+ /// Tool name for tool-scoped predicates such as trivial-change handling.
+ /// The to monitor for cancellation requests. The default is .
+ /// Result of evaluating a Rust-owned settings predicate.
+ internal async Task EvaluatePredicateAsync(SessionSettingsPredicateName name, string? toolName = null, CancellationToken cancellationToken = default)
+ {
+ _session.ThrowIfDisposed();
+
+ var request = new SessionSettingsEvaluatePredicateRequest { SessionId = _session.SessionId, Name = name, ToolName = toolName };
+ return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.settings.evaluatePredicate", [request], cancellationToken);
+ }
+}
+
/// Provides session-scoped Shell APIs.
[Experimental(Diagnostics.Experimental)]
public sealed class ShellApi
@@ -21677,7 +22728,7 @@ public async Task TailAsync(CancellationToken cancellationTo
}
/// Registers consumer interest in an event type for runtime gating purposes.
- /// 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 the full interactive OAuth flow to the consumer; when no interest is registered the runtime installs a browserless fallback that silently reuses cached tokens). 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`.
+ /// 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 OAuth token acquisition to the consumer; when no interest is registered OAuth-required servers become needs-auth). 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`.
/// The to monitor for cancellation requests. The default is .
/// Opaque handle representing an event-type interest registration.
public async Task RegisterInterestAsync(string eventType, CancellationToken cancellationToken = default)
@@ -22081,8 +23132,8 @@ public interface ILlmInferenceHandler
[Experimental(Diagnostics.Experimental)]
public interface IGitHubTelemetryHandler
{
- /// Forwards a single GitHub telemetry event to a host connection that opted into telemetry forwarding for the session.
- /// Payload for a `gitHubTelemetry.event` notification: a single GitHub telemetry event the runtime forwards to a host connection that opted into telemetry forwarding for the session.
+ /// Forwards a single GitHub telemetry event to a host connection that opted into telemetry forwarding during the `server.connect` handshake. Opted-in connections receive every event the runtime emits after the handshake — across all sessions, plus sessionless events (for example, `server.sendTelemetry` calls with no session id).
+ /// 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.
/// The to monitor for cancellation requests. The default is .
Task EventAsync(GitHubTelemetryNotification request, CancellationToken cancellationToken = default);
}
@@ -22157,6 +23208,8 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH
[JsonSerializable(typeof(GitHub.Copilot.AssistantReasoningEvent), TypeInfoPropertyName = "SessionEventsAssistantReasoningEvent")]
[JsonSerializable(typeof(GitHub.Copilot.AssistantStreamingDeltaData), TypeInfoPropertyName = "SessionEventsAssistantStreamingDeltaData")]
[JsonSerializable(typeof(GitHub.Copilot.AssistantStreamingDeltaEvent), TypeInfoPropertyName = "SessionEventsAssistantStreamingDeltaEvent")]
+[JsonSerializable(typeof(GitHub.Copilot.AssistantToolCallDeltaData), TypeInfoPropertyName = "SessionEventsAssistantToolCallDeltaData")]
+[JsonSerializable(typeof(GitHub.Copilot.AssistantToolCallDeltaEvent), TypeInfoPropertyName = "SessionEventsAssistantToolCallDeltaEvent")]
[JsonSerializable(typeof(GitHub.Copilot.AssistantTurnEndData), TypeInfoPropertyName = "SessionEventsAssistantTurnEndData")]
[JsonSerializable(typeof(GitHub.Copilot.AssistantTurnEndEvent), TypeInfoPropertyName = "SessionEventsAssistantTurnEndEvent")]
[JsonSerializable(typeof(GitHub.Copilot.AssistantTurnStartData), TypeInfoPropertyName = "SessionEventsAssistantTurnStartData")]
@@ -22189,6 +23242,7 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH
[JsonSerializable(typeof(GitHub.Copilot.AttachmentSelectionDetails), TypeInfoPropertyName = "SessionEventsAttachmentSelectionDetails")]
[JsonSerializable(typeof(GitHub.Copilot.AttachmentSelectionDetailsEnd), TypeInfoPropertyName = "SessionEventsAttachmentSelectionDetailsEnd")]
[JsonSerializable(typeof(GitHub.Copilot.AttachmentSelectionDetailsStart), TypeInfoPropertyName = "SessionEventsAttachmentSelectionDetailsStart")]
+[JsonSerializable(typeof(GitHub.Copilot.AutoApprovalRecommendation), TypeInfoPropertyName = "SessionEventsAutoApprovalRecommendation")]
[JsonSerializable(typeof(GitHub.Copilot.AutoModeSwitchCompletedData), TypeInfoPropertyName = "SessionEventsAutoModeSwitchCompletedData")]
[JsonSerializable(typeof(GitHub.Copilot.AutoModeSwitchCompletedEvent), TypeInfoPropertyName = "SessionEventsAutoModeSwitchCompletedEvent")]
[JsonSerializable(typeof(GitHub.Copilot.AutoModeSwitchRequestedData), TypeInfoPropertyName = "SessionEventsAutoModeSwitchRequestedData")]
@@ -22291,6 +23345,8 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH
[JsonSerializable(typeof(GitHub.Copilot.OmittedBinaryType), TypeInfoPropertyName = "SessionEventsOmittedBinaryType")]
[JsonSerializable(typeof(GitHub.Copilot.PendingMessagesModifiedData), TypeInfoPropertyName = "SessionEventsPendingMessagesModifiedData")]
[JsonSerializable(typeof(GitHub.Copilot.PendingMessagesModifiedEvent), TypeInfoPropertyName = "SessionEventsPendingMessagesModifiedEvent")]
+[JsonSerializable(typeof(GitHub.Copilot.PermissionAllowAllMode), TypeInfoPropertyName = "SessionEventsPermissionAllowAllMode")]
+[JsonSerializable(typeof(GitHub.Copilot.PermissionAutoApproval), TypeInfoPropertyName = "SessionEventsPermissionAutoApproval")]
[JsonSerializable(typeof(GitHub.Copilot.PermissionCompletedData), TypeInfoPropertyName = "SessionEventsPermissionCompletedData")]
[JsonSerializable(typeof(GitHub.Copilot.PermissionCompletedEvent), TypeInfoPropertyName = "SessionEventsPermissionCompletedEvent")]
[JsonSerializable(typeof(GitHub.Copilot.PermissionPromptRequest), TypeInfoPropertyName = "SessionEventsPermissionPromptRequest")]
@@ -22436,6 +23492,7 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH
[JsonSerializable(typeof(GitHub.Copilot.UserToolSessionApprovalMemory), TypeInfoPropertyName = "SessionEventsUserToolSessionApprovalMemory")]
[JsonSerializable(typeof(GitHub.Copilot.UserToolSessionApprovalRead), TypeInfoPropertyName = "SessionEventsUserToolSessionApprovalRead")]
[JsonSerializable(typeof(GitHub.Copilot.UserToolSessionApprovalWrite), TypeInfoPropertyName = "SessionEventsUserToolSessionApprovalWrite")]
+[JsonSerializable(typeof(GitHub.Copilot.Verbosity), TypeInfoPropertyName = "SessionEventsVerbosity")]
[JsonSerializable(typeof(GitHub.Copilot.WorkingDirectoryContext), TypeInfoPropertyName = "SessionEventsWorkingDirectoryContext")]
[JsonSerializable(typeof(GitHub.Copilot.WorkingDirectoryContextHostType), TypeInfoPropertyName = "SessionEventsWorkingDirectoryContextHostType")]
[JsonSerializable(typeof(GitHub.Copilot.WorkspaceFileChangedOperation), TypeInfoPropertyName = "SessionEventsWorkspaceFileChangedOperation")]
@@ -22500,6 +23557,7 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH
[JsonSerializable(typeof(ConnectResult))]
[JsonSerializable(typeof(ConnectedRemoteSessionMetadata))]
[JsonSerializable(typeof(ConnectedRemoteSessionMetadataRepository))]
+[JsonSerializable(typeof(ContextHeaviestMessage))]
[JsonSerializable(typeof(CopilotUserResponse))]
[JsonSerializable(typeof(CopilotUserResponseEndpoints))]
[JsonSerializable(typeof(CopilotUserResponseOrganizationListItem))]
@@ -22509,6 +23567,13 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH
[JsonSerializable(typeof(CopilotUserResponseQuotaSnapshotsPremiumInteractions))]
[JsonSerializable(typeof(CurrentModel))]
[JsonSerializable(typeof(CurrentToolMetadata))]
+[JsonSerializable(typeof(DebugCollectLogsCollectedEntry))]
+[JsonSerializable(typeof(DebugCollectLogsDestination))]
+[JsonSerializable(typeof(DebugCollectLogsEntry))]
+[JsonSerializable(typeof(DebugCollectLogsInclude))]
+[JsonSerializable(typeof(DebugCollectLogsRequest))]
+[JsonSerializable(typeof(DebugCollectLogsResult))]
+[JsonSerializable(typeof(DebugCollectLogsSkippedEntry))]
[JsonSerializable(typeof(DiscoveredCanvas))]
[JsonSerializable(typeof(DiscoveredMcpServer))]
[JsonSerializable(typeof(EnqueueCommandParams))]
@@ -22542,6 +23607,8 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH
[JsonSerializable(typeof(HistorySummarizeForHandoffResult))]
[JsonSerializable(typeof(HistoryTruncateRequest))]
[JsonSerializable(typeof(HistoryTruncateResult))]
+[JsonSerializable(typeof(IDictionary))]
+[JsonSerializable(typeof(IList))]
[JsonSerializable(typeof(InstalledPlugin))]
[JsonSerializable(typeof(InstalledPluginInfo))]
[JsonSerializable(typeof(InstructionDiscoveryPath))]
@@ -22618,8 +23685,6 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH
[JsonSerializable(typeof(McpOauthLoginRequest))]
[JsonSerializable(typeof(McpOauthLoginResult))]
[JsonSerializable(typeof(McpOauthPendingRequestResponse))]
-[JsonSerializable(typeof(McpOauthRespondRequest))]
-[JsonSerializable(typeof(McpOauthRespondResult))]
[JsonSerializable(typeof(McpRegisterExternalClientRequest))]
[JsonSerializable(typeof(McpReloadWithConfigRequest))]
[JsonSerializable(typeof(McpRemoveGitHubResult))]
@@ -22636,6 +23701,12 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH
[JsonSerializable(typeof(McpStopServerRequest))]
[JsonSerializable(typeof(McpTools))]
[JsonSerializable(typeof(McpUnregisterExternalClientRequest))]
+[JsonSerializable(typeof(MetadataContextAttributionResult))]
+[JsonSerializable(typeof(MetadataContextAttributionResultContextAttribution))]
+[JsonSerializable(typeof(MetadataContextAttributionResultContextAttributionCompactions))]
+[JsonSerializable(typeof(MetadataContextAttributionResultContextAttributionEntry))]
+[JsonSerializable(typeof(MetadataContextHeaviestMessagesRequest))]
+[JsonSerializable(typeof(MetadataContextHeaviestMessagesResult))]
[JsonSerializable(typeof(MetadataContextInfoRequest))]
[JsonSerializable(typeof(MetadataContextInfoResult))]
[JsonSerializable(typeof(MetadataContextInfoResultContextInfo))]
@@ -22753,7 +23824,6 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH
[JsonSerializable(typeof(PluginsReloadRequestWithSession))]
[JsonSerializable(typeof(PluginsUninstallRequest))]
[JsonSerializable(typeof(PluginsUpdateRequest))]
-[JsonSerializable(typeof(PollSpawnedSessionsResult))]
[JsonSerializable(typeof(ProviderAddRequest))]
[JsonSerializable(typeof(ProviderAddResult))]
[JsonSerializable(typeof(ProviderConfig))]
@@ -22870,6 +23940,7 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH
[JsonSerializable(typeof(SessionMcpReloadRequest))]
[JsonSerializable(typeof(SessionMcpRemoveGitHubRequest))]
[JsonSerializable(typeof(SessionMetadataActivityRequest))]
+[JsonSerializable(typeof(SessionMetadataGetContextAttributionRequest))]
[JsonSerializable(typeof(SessionMetadataIsProcessingRequest))]
[JsonSerializable(typeof(SessionMetadataSnapshot))]
[JsonSerializable(typeof(SessionMetadataSnapshotRequest))]
@@ -22892,6 +23963,16 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH
[JsonSerializable(typeof(SessionScheduleListRequest))]
[JsonSerializable(typeof(SessionSetCredentialsParams))]
[JsonSerializable(typeof(SessionSetCredentialsResult))]
+[JsonSerializable(typeof(SessionSettingsBuiltInToolAvailabilitySnapshot))]
+[JsonSerializable(typeof(SessionSettingsEvaluatePredicateRequest))]
+[JsonSerializable(typeof(SessionSettingsEvaluatePredicateResult))]
+[JsonSerializable(typeof(SessionSettingsJobSnapshot))]
+[JsonSerializable(typeof(SessionSettingsModelSnapshot))]
+[JsonSerializable(typeof(SessionSettingsOnlineEvaluationSnapshot))]
+[JsonSerializable(typeof(SessionSettingsRepoSnapshot))]
+[JsonSerializable(typeof(SessionSettingsSnapshot))]
+[JsonSerializable(typeof(SessionSettingsSnapshotRequest))]
+[JsonSerializable(typeof(SessionSettingsValidationSnapshot))]
[JsonSerializable(typeof(SessionSizes))]
[JsonSerializable(typeof(SessionSkillsEnsureLoadedRequest))]
[JsonSerializable(typeof(SessionSkillsGetInvokedRequest))]
@@ -22939,8 +24020,6 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH
[JsonSerializable(typeof(SessionsListRequest))]
[JsonSerializable(typeof(SessionsLoadDeferredRepoHooksRequest))]
[JsonSerializable(typeof(SessionsOpenProgress))]
-[JsonSerializable(typeof(SessionsPollSpawnedSessionsEvent))]
-[JsonSerializable(typeof(SessionsPollSpawnedSessionsRequest))]
[JsonSerializable(typeof(SessionsPruneOldRequest))]
[JsonSerializable(typeof(SessionsRegisterExtensionToolsOnSessionOptions))]
[JsonSerializable(typeof(SessionsReleaseLockRequest))]
@@ -22976,6 +24055,7 @@ public static void RegisterClientGlobalApiHandlers(JsonRpc rpc, ClientGlobalApiH
[JsonSerializable(typeof(SkillsLoadDiagnostics))]
[JsonSerializable(typeof(SlashCommandInfo))]
[JsonSerializable(typeof(SlashCommandInput))]
+[JsonSerializable(typeof(SlashCommandInputChoice))]
[JsonSerializable(typeof(SlashCommandInvocationResult))]
[JsonSerializable(typeof(SlashCommandSelectSubcommandOption))]
[JsonSerializable(typeof(SubagentSettingsEntry))]
diff --git a/dotnet/src/Generated/SessionEvents.cs b/dotnet/src/Generated/SessionEvents.cs
index 1d9dfdcec..c3f827dec 100644
--- a/dotnet/src/Generated/SessionEvents.cs
+++ b/dotnet/src/Generated/SessionEvents.cs
@@ -33,6 +33,7 @@ namespace GitHub.Copilot;
[JsonDerivedType(typeof(AssistantReasoningEvent), "assistant.reasoning")]
[JsonDerivedType(typeof(AssistantReasoningDeltaEvent), "assistant.reasoning_delta")]
[JsonDerivedType(typeof(AssistantStreamingDeltaEvent), "assistant.streaming_delta")]
+[JsonDerivedType(typeof(AssistantToolCallDeltaEvent), "assistant.tool_call_delta")]
[JsonDerivedType(typeof(AssistantTurnEndEvent), "assistant.turn_end")]
[JsonDerivedType(typeof(AssistantTurnStartEvent), "assistant.turn_start")]
[JsonDerivedType(typeof(AssistantUsageEvent), "assistant.usage")]
@@ -363,7 +364,7 @@ public sealed partial class SessionSessionLimitsChangedEvent : SessionEvent
public required SessionSessionLimitsChangedData Data { get; set; }
}
-/// Permissions change details carrying the aggregate allow-all boolean transition.
+/// Permissions change details carrying the aggregate allow-all transition.
/// Represents the session.permissions_changed event.
public sealed partial class SessionPermissionsChangedEvent : SessionEvent
{
@@ -545,7 +546,7 @@ public sealed partial class SessionTaskCompleteEvent : SessionEvent
public required SessionTaskCompleteData Data { get; set; }
}
-/// Schema for the `UserMessageData` type.
+/// Payload of `user.message` with displayed and model-transformed content, attachments, source/delivery metadata, mode, and telemetry IDs.
/// Represents the user.message event.
public sealed partial class UserMessageEvent : SessionEvent
{
@@ -623,6 +624,19 @@ public sealed partial class AssistantReasoningDeltaEvent : SessionEvent
public required AssistantReasoningDeltaData Data { get; set; }
}
+/// Streaming tool-call input delta for incremental tool-call updates.
+/// Represents the assistant.tool_call_delta event.
+public sealed partial class AssistantToolCallDeltaEvent : SessionEvent
+{
+ ///
+ [JsonIgnore]
+ public override string Type => "assistant.tool_call_delta";
+
+ /// The assistant.tool_call_delta event payload.
+ [JsonPropertyName("data")]
+ public required AssistantToolCallDeltaData Data { get; set; }
+}
+
/// Streaming response progress with cumulative byte count.
/// Represents the assistant.streaming_delta event.
public sealed partial class AssistantStreamingDeltaEvent : SessionEvent
@@ -1300,7 +1314,7 @@ public sealed partial class ExitPlanModeCompletedEvent : SessionEvent
public required ExitPlanModeCompletedData Data { get; set; }
}
-/// Schema for the `ToolsUpdatedData` type.
+/// Payload of `session.tools_updated` identifying the model whose resolved tools were updated.
/// Represents the session.tools_updated event.
public sealed partial class SessionToolsUpdatedEvent : SessionEvent
{
@@ -1313,7 +1327,7 @@ public sealed partial class SessionToolsUpdatedEvent : SessionEvent
public required SessionToolsUpdatedData Data { get; set; }
}
-/// Schema for the `BackgroundTasksChangedData` type.
+/// Empty payload for `session.background_tasks_changed`, indicating background task state changed.
/// Represents the session.background_tasks_changed event.
public sealed partial class SessionBackgroundTasksChangedEvent : SessionEvent
{
@@ -1326,7 +1340,7 @@ public sealed partial class SessionBackgroundTasksChangedEvent : SessionEvent
public required SessionBackgroundTasksChangedData Data { get; set; }
}
-/// Schema for the `SkillsLoadedData` type.
+/// Payload of `session.skills_loaded` listing resolved skill metadata.
/// Represents the session.skills_loaded event.
public sealed partial class SessionSkillsLoadedEvent : SessionEvent
{
@@ -1339,7 +1353,7 @@ public sealed partial class SessionSkillsLoadedEvent : SessionEvent
public required SessionSkillsLoadedData Data { get; set; }
}
-/// Schema for the `CustomAgentsUpdatedData` type.
+/// Payload of `session.custom_agents_updated` with loaded custom agents plus non-fatal warnings and fatal errors.
/// Represents the session.custom_agents_updated event.
public sealed partial class SessionCustomAgentsUpdatedEvent : SessionEvent
{
@@ -1352,7 +1366,7 @@ public sealed partial class SessionCustomAgentsUpdatedEvent : SessionEvent
public required SessionCustomAgentsUpdatedData Data { get; set; }
}
-/// Schema for the `McpServersLoadedData` type.
+/// Payload of `session.mcp_servers_loaded` listing MCP server status summaries.
/// Represents the session.mcp_servers_loaded event.
public sealed partial class SessionMcpServersLoadedEvent : SessionEvent
{
@@ -1365,7 +1379,7 @@ public sealed partial class SessionMcpServersLoadedEvent : SessionEvent
public required SessionMcpServersLoadedData Data { get; set; }
}
-/// Schema for the `McpServerStatusChangedData` type.
+/// Payload of `session.mcp_server_status_changed` for one MCP server's status and optional failure error.
/// Represents the session.mcp_server_status_changed event.
public sealed partial class SessionMcpServerStatusChangedEvent : SessionEvent
{
@@ -1378,7 +1392,7 @@ public sealed partial class SessionMcpServerStatusChangedEvent : SessionEvent
public required SessionMcpServerStatusChangedData Data { get; set; }
}
-/// Schema for the `ExtensionsLoadedData` type.
+/// Payload of `session.extensions_loaded` listing discovered extensions and their statuses.
/// Represents the session.extensions_loaded event.
public sealed partial class SessionExtensionsLoadedEvent : SessionEvent
{
@@ -1391,7 +1405,7 @@ public sealed partial class SessionExtensionsLoadedEvent : SessionEvent
public required SessionExtensionsLoadedData Data { get; set; }
}
-/// Schema for the `CanvasOpenedData` type.
+/// Payload of `session.canvas.opened` with canvas instance and provider IDs plus optional title, status, URL, and input.
/// Represents the session.canvas.opened event.
[Experimental(Diagnostics.Experimental)]
public sealed partial class SessionCanvasOpenedEvent : SessionEvent
@@ -1405,7 +1419,7 @@ public sealed partial class SessionCanvasOpenedEvent : SessionEvent
public required SessionCanvasOpenedData Data { get; set; }
}
-/// Schema for the `CanvasRegistryChangedData` type.
+/// Payload of `session.canvas.registry_changed` listing the canvas declarations currently available.
/// Represents the session.canvas.registry_changed event.
[Experimental(Diagnostics.Experimental)]
public sealed partial class SessionCanvasRegistryChangedEvent : SessionEvent
@@ -1419,7 +1433,7 @@ public sealed partial class SessionCanvasRegistryChangedEvent : SessionEvent
public required SessionCanvasRegistryChangedData Data { get; set; }
}
-/// Schema for the `CanvasClosedData` type.
+/// Payload of `session.canvas.closed` with the closed canvas instance ID, provider ID, and canvas ID.
/// Represents the session.canvas.closed event.
[Experimental(Diagnostics.Experimental)]
public sealed partial class SessionCanvasClosedEvent : SessionEvent
@@ -1475,7 +1489,7 @@ public sealed partial class SessionCanvasRemovedEvent : SessionEvent
public required SessionCanvasRemovedData Data { get; set; }
}
-/// Schema for the `ExtensionsAttachmentsPushedData` type.
+/// Payload of `session.extensions.attachments_pushed` with extension-contributed attachments for the next send.
/// Represents the session.extensions.attachments_pushed event.
public sealed partial class SessionExtensionsAttachmentsPushedEvent : SessionEvent
{
@@ -1565,6 +1579,11 @@ public sealed partial class SessionStartData
[JsonPropertyName("startTime")]
public required DateTimeOffset StartTime { get; set; }
+ /// Output verbosity level used for model calls, if applicable (e.g. "low", "medium", "high").
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("verbosity")]
+ public Verbosity? Verbosity { get; set; }
+
/// Schema version number for the session event format.
[JsonPropertyName("version")]
public required long Version { get; set; }
@@ -1635,6 +1654,11 @@ public sealed partial class SessionResumeData
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("sessionWasActive")]
public bool? SessionWasActive { get; set; }
+
+ /// Output verbosity level used for model calls, if applicable (e.g. "low", "medium", "high").
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("verbosity")]
+ public Verbosity? Verbosity { get; set; }
}
/// Notifies that the session's remote steering capability has changed.
@@ -1866,6 +1890,11 @@ public sealed partial class SessionModelChangeData
[JsonPropertyName("previousReasoningSummary")]
public ReasoningSummary? PreviousReasoningSummary { get; set; }
+ /// Output verbosity level before the model change, if applicable.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("previousVerbosity")]
+ public Verbosity? PreviousVerbosity { get; set; }
+
/// Reasoning effort level after the model change, if applicable.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("reasoningEffort")]
@@ -1875,6 +1904,11 @@ public sealed partial class SessionModelChangeData
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("reasoningSummary")]
public ReasoningSummary? ReasoningSummary { get; set; }
+
+ /// Output verbosity level after the model change, if applicable.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("verbosity")]
+ public Verbosity? Verbosity { get; set; }
}
/// Agent mode change details including previous and new modes.
@@ -1897,13 +1931,25 @@ public sealed partial class SessionSessionLimitsChangedData
public SessionLimitsConfig? SessionLimits { get; set; }
}
-/// Permissions change details carrying the aggregate allow-all boolean transition.
+/// Permissions change details carrying the aggregate allow-all transition.
public sealed partial class SessionPermissionsChangedData
{
+ /// Allow-all mode after the change.
+ [Experimental(Diagnostics.Experimental)]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("allowAllPermissionMode")]
+ public PermissionAllowAllMode? AllowAllPermissionMode { get; set; }
+
/// Aggregate allow-all flag after the change.
[JsonPropertyName("allowAllPermissions")]
public required bool AllowAllPermissions { get; set; }
+ /// Allow-all mode before the change.
+ [Experimental(Diagnostics.Experimental)]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("previousAllowAllPermissionMode")]
+ public PermissionAllowAllMode? PreviousAllowAllPermissionMode { get; set; }
+
/// Aggregate allow-all flag before the change.
[JsonPropertyName("previousAllowAllPermissions")]
public required bool PreviousAllowAllPermissions { get; set; }
@@ -2197,6 +2243,11 @@ public sealed partial class SessionCompactionStartData
[JsonPropertyName("conversationTokens")]
public long? ConversationTokens { get; set; }
+ /// Model identifier used for compaction, when known.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("model")]
+ public string? Model { get; set; }
+
/// Token count from system message(s) at compaction start.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("systemTokens")]
@@ -2315,7 +2366,7 @@ public sealed partial class SessionTaskCompleteData
public string? Summary { get; set; }
}
-/// Schema for the `UserMessageData` type.
+/// Payload of `user.message` with displayed and model-transformed content, attachments, source/delivery metadata, mode, and telemetry IDs.
public sealed partial class UserMessageData
{
/// The agent mode that was active when this message was sent.
@@ -2386,6 +2437,11 @@ public sealed partial class AssistantTurnStartData
[JsonPropertyName("interactionId")]
public string? InteractionId { get; set; }
+ /// Model identifier used for this turn, when known.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("model")]
+ public string? Model { get; set; }
+
/// Identifier for this turn within the agentic loop, typically a stringified turn number.
[JsonPropertyName("turnId")]
public required string TurnId { get; set; }
@@ -2423,6 +2479,28 @@ public sealed partial class AssistantReasoningDeltaData
public required string ReasoningId { get; set; }
}
+/// Streaming tool-call input delta for incremental tool-call updates.
+public sealed partial class AssistantToolCallDeltaData
+{
+ /// Raw provider tool input fragment to append for this tool call. Function/tool-use providers stream serialized JSON argument text (so newlines inside JSON string values may appear as escaped `\n` until the accumulated JSON is parsed); custom tool calls stream raw custom input.
+ [JsonPropertyName("inputDelta")]
+ public required string InputDelta { get; set; }
+
+ /// Tool call ID this delta belongs to, matching the corresponding assistant.message tool request.
+ [JsonPropertyName("toolCallId")]
+ public required string ToolCallId { get; set; }
+
+ /// Name of the tool being invoked, when known from the stream.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("toolName")]
+ public string? ToolName { get; set; }
+
+ /// Tool call type, when known from the stream.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("toolType")]
+ public AssistantMessageToolRequestType? ToolType { get; set; }
+}
+
/// Streaming response progress with cumulative byte count.
public sealed partial class AssistantStreamingDeltaData
{
@@ -2565,6 +2643,11 @@ public sealed partial class AssistantMessageDeltaData
/// Turn completion metadata including the turn identifier.
public sealed partial class AssistantTurnEndData
{
+ /// Model identifier used for this turn, when known.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("model")]
+ public string? Model { get; set; }
+
/// Identifier of the turn that has ended, matching the corresponding assistant.turn_start event.
[JsonPropertyName("turnId")]
public required string TurnId { get; set; }
@@ -2964,6 +3047,11 @@ public sealed partial class SkillInvokedData
[JsonPropertyName("description")]
public string? Description { get; set; }
+ /// Model identifier active when the skill was invoked, when known.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("model")]
+ public string? Model { get; set; }
+
/// Name of the invoked skill.
[JsonPropertyName("name")]
public required string Name { get; set; }
@@ -3729,7 +3817,7 @@ public sealed partial class ExitPlanModeCompletedData
public ExitPlanModeAction? SelectedAction { get; set; }
}
-/// Schema for the `ToolsUpdatedData` type.
+/// Payload of `session.tools_updated` identifying the model whose resolved tools were updated.
public sealed partial class SessionToolsUpdatedData
{
/// Identifier of the model the resolved tools apply to.
@@ -3737,12 +3825,12 @@ public sealed partial class SessionToolsUpdatedData
public required string Model { get; set; }
}
-/// Schema for the `BackgroundTasksChangedData` type.
+/// Empty payload for `session.background_tasks_changed`, indicating background task state changed.
public sealed partial class SessionBackgroundTasksChangedData
{
}
-/// Schema for the `SkillsLoadedData` type.
+/// Payload of `session.skills_loaded` listing resolved skill metadata.
public sealed partial class SessionSkillsLoadedData
{
/// Array of resolved skill metadata.
@@ -3750,7 +3838,7 @@ public sealed partial class SessionSkillsLoadedData
public required SkillsLoadedSkill[] Skills { get; set; }
}
-/// Schema for the `CustomAgentsUpdatedData` type.
+/// Payload of `session.custom_agents_updated` with loaded custom agents plus non-fatal warnings and fatal errors.
public sealed partial class SessionCustomAgentsUpdatedData
{
/// Array of loaded custom agent metadata.
@@ -3766,7 +3854,7 @@ public sealed partial class SessionCustomAgentsUpdatedData
public required string[] Warnings { get; set; }
}
-/// Schema for the `McpServersLoadedData` type.
+/// Payload of `session.mcp_servers_loaded` listing MCP server status summaries.
public sealed partial class SessionMcpServersLoadedData
{
/// Array of MCP server status summaries.
@@ -3774,7 +3862,7 @@ public sealed partial class SessionMcpServersLoadedData
public required McpServersLoadedServer[] Servers { get; set; }
}
-/// Schema for the `McpServerStatusChangedData` type.
+/// Payload of `session.mcp_server_status_changed` for one MCP server's status and optional failure error.
public sealed partial class SessionMcpServerStatusChangedData
{
/// Error message if the server entered a failed state.
@@ -3791,7 +3879,7 @@ public sealed partial class SessionMcpServerStatusChangedData
public required McpServerStatus Status { get; set; }
}
-/// Schema for the `ExtensionsLoadedData` type.
+/// Payload of `session.extensions_loaded` listing discovered extensions and their statuses.
public sealed partial class SessionExtensionsLoadedData
{
/// Array of discovered extensions and their status.
@@ -3799,7 +3887,7 @@ public sealed partial class SessionExtensionsLoadedData
public required ExtensionsLoadedExtension[] Extensions { get; set; }
}
-/// Schema for the `CanvasOpenedData` type.
+/// Payload of `session.canvas.opened` with canvas instance and provider IDs plus optional title, status, URL, and input.
[Experimental(Diagnostics.Experimental)]
public sealed partial class SessionCanvasOpenedData
{
@@ -3841,7 +3929,7 @@ public sealed partial class SessionCanvasOpenedData
public string? Url { get; set; }
}
-/// Schema for the `CanvasRegistryChangedData` type.
+/// Payload of `session.canvas.registry_changed` listing the canvas declarations currently available.
[Experimental(Diagnostics.Experimental)]
public sealed partial class SessionCanvasRegistryChangedData
{
@@ -3850,7 +3938,7 @@ public sealed partial class SessionCanvasRegistryChangedData
public required CanvasRegistryChangedCanvas[] Canvases { get; set; }
}
-/// Schema for the `CanvasClosedData` type.
+/// Payload of `session.canvas.closed` with the closed canvas instance ID, provider ID, and canvas ID.
[Experimental(Diagnostics.Experimental)]
public sealed partial class SessionCanvasClosedData
{
@@ -3936,7 +4024,7 @@ public sealed partial class SessionCanvasRemovedData
public required string InstanceId { get; set; }
}
-/// Schema for the `ExtensionsAttachmentsPushedData` type.
+/// Payload of `session.extensions.attachments_pushed` with extension-contributed attachments for the next send.
public sealed partial class SessionExtensionsAttachmentsPushedData
{
/// Attachments contributed by an extension; the host should surface these as composer pills and forward them via the next session.send call.
@@ -4090,7 +4178,7 @@ public sealed partial class ShutdownModelMetricRequests
public long? Count { get; set; }
}
-/// Schema for the `ShutdownModelMetricTokenDetail` type.
+/// A token-type entry in a shutdown model metric, storing the accumulated token count.
/// Nested data type for ShutdownModelMetricTokenDetail.
public sealed partial class ShutdownModelMetricTokenDetail
{
@@ -4125,7 +4213,7 @@ public sealed partial class ShutdownModelMetricUsage
public long? ReasoningTokens { get; set; }
}
-/// Schema for the `ShutdownModelMetric` type.
+/// Per-model shutdown metrics with request counts, token usage, nano-AI units, and token details.
/// Nested data type for ShutdownModelMetric.
public sealed partial class ShutdownModelMetric
{
@@ -4149,7 +4237,7 @@ public sealed partial class ShutdownModelMetric
public required ShutdownModelMetricUsage Usage { get; set; }
}
-/// Schema for the `ShutdownTokenDetail` type.
+/// A session-wide shutdown token-type entry storing the accumulated token count.
/// Nested data type for ShutdownTokenDetail.
public sealed partial class ShutdownTokenDetail
{
@@ -5052,7 +5140,7 @@ public sealed partial class AssistantUsageCopilotUsage
public required double TotalNanoAiu { get; set; }
}
-/// Schema for the `AssistantUsageQuotaSnapshot` type.
+/// Internal per-quota snapshot for assistant usage, including entitlement, consumed requests, overage, reset date, and remaining quota.
/// Nested data type for AssistantUsageQuotaSnapshot.
internal sealed partial class AssistantUsageQuotaSnapshot
{
@@ -5163,7 +5251,7 @@ public sealed partial class ToolExecutionStartShellToolInfo
public required string[] PossiblePaths { get; set; }
}
-/// Schema for the `ToolExecutionStartToolDescriptionMetaUI` type.
+/// MCP Apps tool `_meta.ui` resource URI and visibility captured on `tool.execution_start`.
/// Nested data type for ToolExecutionStartToolDescriptionMetaUI.
public sealed partial class ToolExecutionStartToolDescriptionMetaUI
{
@@ -5182,7 +5270,7 @@ public sealed partial class ToolExecutionStartToolDescriptionMetaUI
/// Nested data type for ToolExecutionStartToolDescriptionMeta.
public sealed partial class ToolExecutionStartToolDescriptionMeta
{
- /// Schema for the `ToolExecutionStartToolDescriptionMetaUI` type.
+ /// MCP Apps tool `_meta.ui` resource URI and visibility captured on `tool.execution_start`.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("ui")]
public ToolExecutionStartToolDescriptionMetaUI? Ui { get; set; }
@@ -5617,7 +5705,7 @@ public sealed partial class ToolExecutionCompleteContentResourceLink : ToolExecu
public required string Uri { get; set; }
}
-/// Schema for the `EmbeddedTextResourceContents` type.
+/// Embedded text resource contents identified by a URI, with an optional MIME type and a text payload.
/// Nested data type for EmbeddedTextResourceContents.
public sealed partial class EmbeddedTextResourceContents
{
@@ -5635,7 +5723,7 @@ public sealed partial class EmbeddedTextResourceContents
public required string Uri { get; set; }
}
-/// Schema for the `EmbeddedBlobResourceContents` type.
+/// Embedded binary resource contents identified by a URI, with an optional MIME type and a base64-encoded blob.
/// Nested data type for EmbeddedBlobResourceContents.
public sealed partial class EmbeddedBlobResourceContents
{
@@ -5765,7 +5853,7 @@ public partial class ToolExecutionCompleteContent
}
-/// Schema for the `ToolExecutionCompleteUIResourceMetaUICsp` type.
+/// CSP domain allowlists for an MCP Apps UI resource, including connect, resource, frame, and base URI domains.
/// Nested data type for ToolExecutionCompleteUIResourceMetaUICsp.
public sealed partial class ToolExecutionCompleteUIResourceMetaUICsp
{
@@ -5790,60 +5878,60 @@ public sealed partial class ToolExecutionCompleteUIResourceMetaUICsp
public string[]? ResourceDomains { get; set; }
}
-/// Schema for the `ToolExecutionCompleteUIResourceMetaUIPermissionsCamera` type.
+/// Marker object for camera permission on an MCP Apps UI resource.
/// Nested data type for ToolExecutionCompleteUIResourceMetaUIPermissionsCamera.
public sealed partial class ToolExecutionCompleteUIResourceMetaUIPermissionsCamera
{
}
-/// Schema for the `ToolExecutionCompleteUIResourceMetaUIPermissionsClipboardWrite` type.
+/// Marker object for clipboard-write permission on an MCP Apps UI resource.
/// Nested data type for ToolExecutionCompleteUIResourceMetaUIPermissionsClipboardWrite.
public sealed partial class ToolExecutionCompleteUIResourceMetaUIPermissionsClipboardWrite
{
}
-/// Schema for the `ToolExecutionCompleteUIResourceMetaUIPermissionsGeolocation` type.
+/// Marker object for geolocation permission on an MCP Apps UI resource.
/// Nested data type for ToolExecutionCompleteUIResourceMetaUIPermissionsGeolocation.
public sealed partial class ToolExecutionCompleteUIResourceMetaUIPermissionsGeolocation
{
}
-/// Schema for the `ToolExecutionCompleteUIResourceMetaUIPermissionsMicrophone` type.
+/// Marker object for microphone permission on an MCP Apps UI resource.
/// Nested data type for ToolExecutionCompleteUIResourceMetaUIPermissionsMicrophone.
public sealed partial class ToolExecutionCompleteUIResourceMetaUIPermissionsMicrophone
{
}
-/// Schema for the `ToolExecutionCompleteUIResourceMetaUIPermissions` type.
+/// Browser permission metadata for an MCP Apps UI resource, including camera, microphone, geolocation, and clipboard-write.
/// Nested data type for ToolExecutionCompleteUIResourceMetaUIPermissions.
public sealed partial class ToolExecutionCompleteUIResourceMetaUIPermissions
{
- /// Schema for the `ToolExecutionCompleteUIResourceMetaUIPermissionsCamera` type.
+ /// Marker object for camera permission on an MCP Apps UI resource.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("camera")]
public ToolExecutionCompleteUIResourceMetaUIPermissionsCamera? Camera { get; set; }
- /// Schema for the `ToolExecutionCompleteUIResourceMetaUIPermissionsClipboardWrite` type.
+ /// Marker object for clipboard-write permission on an MCP Apps UI resource.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("clipboardWrite")]
public ToolExecutionCompleteUIResourceMetaUIPermissionsClipboardWrite? ClipboardWrite { get; set; }
- /// Schema for the `ToolExecutionCompleteUIResourceMetaUIPermissionsGeolocation` type.
+ /// Marker object for geolocation permission on an MCP Apps UI resource.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("geolocation")]
public ToolExecutionCompleteUIResourceMetaUIPermissionsGeolocation? Geolocation { get; set; }
- /// Schema for the `ToolExecutionCompleteUIResourceMetaUIPermissionsMicrophone` type.
+ /// Marker object for microphone permission on an MCP Apps UI resource.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("microphone")]
public ToolExecutionCompleteUIResourceMetaUIPermissionsMicrophone? Microphone { get; set; }
}
-/// Schema for the `ToolExecutionCompleteUIResourceMetaUI` type.
+/// MCP Apps UI resource metadata for a completed tool result, including CSP, permissions, domain, and border preference.
/// Nested data type for ToolExecutionCompleteUIResourceMetaUI.
public sealed partial class ToolExecutionCompleteUIResourceMetaUI
{
- /// Schema for the `ToolExecutionCompleteUIResourceMetaUICsp` type.
+ /// CSP domain allowlists for an MCP Apps UI resource, including connect, resource, frame, and base URI domains.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("csp")]
public ToolExecutionCompleteUIResourceMetaUICsp? Csp { get; set; }
@@ -5853,7 +5941,7 @@ public sealed partial class ToolExecutionCompleteUIResourceMetaUI
[JsonPropertyName("domain")]
public string? Domain { get; set; }
- /// Schema for the `ToolExecutionCompleteUIResourceMetaUIPermissions` type.
+ /// Browser permission metadata for an MCP Apps UI resource, including camera, microphone, geolocation, and clipboard-write.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("permissions")]
public ToolExecutionCompleteUIResourceMetaUIPermissions? Permissions { get; set; }
@@ -5868,7 +5956,7 @@ public sealed partial class ToolExecutionCompleteUIResourceMetaUI
/// Nested data type for ToolExecutionCompleteUIResourceMeta.
public sealed partial class ToolExecutionCompleteUIResourceMeta
{
- /// Schema for the `ToolExecutionCompleteUIResourceMetaUI` type.
+ /// MCP Apps UI resource metadata for a completed tool result, including CSP, permissions, domain, and border preference.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("ui")]
public ToolExecutionCompleteUIResourceMetaUI? Ui { get; set; }
@@ -5943,7 +6031,7 @@ public sealed partial class ToolExecutionCompleteResult
public ToolExecutionCompleteUIResource? UiResource { get; set; }
}
-/// Schema for the `ToolExecutionCompleteToolDescriptionMetaUI` type.
+/// MCP Apps tool `_meta.ui` resource URI and visibility captured on `tool.execution_complete`.
/// Nested data type for ToolExecutionCompleteToolDescriptionMetaUI.
public sealed partial class ToolExecutionCompleteToolDescriptionMetaUI
{
@@ -5962,7 +6050,7 @@ public sealed partial class ToolExecutionCompleteToolDescriptionMetaUI
/// Nested data type for ToolExecutionCompleteToolDescriptionMeta.
public sealed partial class ToolExecutionCompleteToolDescriptionMeta
{
- /// Schema for the `ToolExecutionCompleteToolDescriptionMetaUI` type.
+ /// MCP Apps tool `_meta.ui` resource URI and visibility captured on `tool.execution_complete`.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("ui")]
public ToolExecutionCompleteToolDescriptionMetaUI? Ui { get; set; }
@@ -6021,7 +6109,7 @@ public sealed partial class SystemMessageMetadata
public IDictionary? Variables { get; set; }
}
-/// Schema for the `SystemNotificationAgentCompleted` type.
+/// System notification metadata for a background agent that completed or failed, including agent ID, type, status, description, and prompt.
/// The agent_completed variant of .
public sealed partial class SystemNotificationAgentCompleted : SystemNotification
{
@@ -6052,7 +6140,7 @@ public sealed partial class SystemNotificationAgentCompleted : SystemNotificatio
public required SystemNotificationAgentCompletedStatus Status { get; set; }
}
-/// Schema for the `SystemNotificationAgentIdle` type.
+/// System notification metadata for a background agent that became idle, including agent ID, type, and description.
/// The agent_idle variant of .
public sealed partial class SystemNotificationAgentIdle : SystemNotification
{
@@ -6074,7 +6162,7 @@ public sealed partial class SystemNotificationAgentIdle : SystemNotification
public string? Description { get; set; }
}
-/// Schema for the `SystemNotificationNewInboxMessage` type.
+/// System notification metadata for a new inbox message, including entry ID, sender details, and summary.
/// The new_inbox_message variant of .
public sealed partial class SystemNotificationNewInboxMessage : SystemNotification
{
@@ -6099,7 +6187,7 @@ public sealed partial class SystemNotificationNewInboxMessage : SystemNotificati
public required string Summary { get; set; }
}
-/// Schema for the `SystemNotificationShellCompleted` type.
+/// System notification metadata for a shell session that completed, including shell ID, optional exit code, and description.
/// The shell_completed variant of .
public sealed partial class SystemNotificationShellCompleted : SystemNotification
{
@@ -6122,7 +6210,7 @@ public sealed partial class SystemNotificationShellCompleted : SystemNotificatio
public required string ShellId { get; set; }
}
-/// Schema for the `SystemNotificationShellDetachedCompleted` type.
+/// System notification metadata for a detached shell session that completed, including shell ID and description.
/// The shell_detached_completed variant of .
public sealed partial class SystemNotificationShellDetachedCompleted : SystemNotification
{
@@ -6140,7 +6228,7 @@ public sealed partial class SystemNotificationShellDetachedCompleted : SystemNot
public required string ShellId { get; set; }
}
-/// Schema for the `SystemNotificationInstructionDiscovered` type.
+/// System notification metadata for an instruction file discovered during tool access, including source, trigger file, and tool.
/// The instruction_discovered variant of .
public sealed partial class SystemNotificationInstructionDiscovered : SystemNotification
{
@@ -6185,7 +6273,7 @@ public partial class SystemNotification
}
-/// Schema for the `PermissionRequestShellCommand` type.
+/// A parsed command identifier in a shell permission request, including whether it is read-only.
/// Nested data type for PermissionRequestShellCommand.
public sealed partial class PermissionRequestShellCommand
{
@@ -6198,7 +6286,7 @@ public sealed partial class PermissionRequestShellCommand
public required bool ReadOnly { get; set; }
}
-/// Schema for the `PermissionRequestShellPossibleUrl` type.
+/// A URL that may be accessed by a command in a shell permission request.
/// Nested data type for PermissionRequestShellPossibleUrl.
public sealed partial class PermissionRequestShellPossibleUrl
{
@@ -6293,6 +6381,16 @@ public sealed partial class PermissionRequestWrite : PermissionRequest
[JsonPropertyName("newFileContents")]
public string? NewFileContents { get; set; }
+ /// True when a built-in file tool (apply_patch / str_replace_editor) asked to write a path the sandbox filesystem policy would block, and the host opted in via sandbox.allowBypass. This is a request, not a grant: the write happens unsandboxed only if the user approves this permission request. Hosts should highlight the elevated risk in the approval UI.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("requestSandboxBypass")]
+ public bool? RequestSandboxBypass { get; set; }
+
+ /// Justification for the sandbox-bypass request. Only meaningful when requestSandboxBypass is true.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("requestSandboxBypassReason")]
+ public string? RequestSandboxBypassReason { get; set; }
+
/// Tool call ID that triggered this permission request.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("toolCallId")]
@@ -6378,6 +6476,16 @@ public sealed partial class PermissionRequestUrl : PermissionRequest
[JsonPropertyName("intention")]
public required string Intention { get; set; }
+ /// True when this URL fetch is requesting to bypass the sandbox network policy: either the model set requestSandboxBypass: true, or the tool re-issued the request as an interactive bypass after the network policy denied the approved URL (host opted in via sandbox.allowBypass). This is a request, not a grant: the fetch runs only if the user approves this permission request. Hosts should highlight the elevated risk in the approval UI.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("requestSandboxBypass")]
+ public bool? RequestSandboxBypass { get; set; }
+
+ /// Model-provided justification for the sandbox-bypass request. Only meaningful when requestSandboxBypass is true.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("requestSandboxBypassReason")]
+ public string? RequestSandboxBypassReason { get; set; }
+
/// Tool call ID that triggered this permission request.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("toolCallId")]
@@ -6554,6 +6662,21 @@ public partial class PermissionRequest
}
+/// Auto-approval judge information attached to a permission request. Present (non-null) only when the session's allow-all mode is "auto"; its absence means auto mode was off and the judge did not evaluate the request. The `recommendation` conveys the judge's disposition for this request.
+/// Nested data type for PermissionAutoApproval.
+[Experimental(Diagnostics.Experimental)]
+public sealed partial class PermissionAutoApproval
+{
+ /// Human-readable reason for the judge's recommendation, when available.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("reason")]
+ public string? Reason { get; set; }
+
+ /// The auto-approval safety judge's outcome for this request.
+ [JsonPropertyName("recommendation")]
+ public required AutoApprovalRecommendation Recommendation { get; set; }
+}
+
/// Shell command permission prompt.
/// The commands variant of .
public sealed partial class PermissionPromptRequestCommands : PermissionPromptRequest
@@ -6562,6 +6685,12 @@ public sealed partial class PermissionPromptRequestCommands : PermissionPromptRe
[JsonIgnore]
public override string Kind => "commands";
+ /// Auto-approval judge information for this request; present only when auto mode is enabled.
+ [Experimental(Diagnostics.Experimental)]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("autoApproval")]
+ public PermissionAutoApproval? AutoApproval { get; set; }
+
/// Whether the UI can offer session-wide approval for this command pattern.
[JsonPropertyName("canOfferSessionApproval")]
public required bool CanOfferSessionApproval { get; set; }
@@ -6597,6 +6726,12 @@ public sealed partial class PermissionPromptRequestWrite : PermissionPromptReque
[JsonIgnore]
public override string Kind => "write";
+ /// Auto-approval judge information for this request; present only when auto mode is enabled.
+ [Experimental(Diagnostics.Experimental)]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("autoApproval")]
+ public PermissionAutoApproval? AutoApproval { get; set; }
+
/// Whether the UI can offer session-wide approval for file write operations.
[JsonPropertyName("canOfferSessionApproval")]
public required bool CanOfferSessionApproval { get; set; }
@@ -6632,6 +6767,12 @@ public sealed partial class PermissionPromptRequestRead : PermissionPromptReques
[JsonIgnore]
public override string Kind => "read";
+ /// Auto-approval judge information for this request; present only when auto mode is enabled.
+ [Experimental(Diagnostics.Experimental)]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("autoApproval")]
+ public PermissionAutoApproval? AutoApproval { get; set; }
+
/// Human-readable description of why the file is being read.
[JsonPropertyName("intention")]
public required string Intention { get; set; }
@@ -6659,6 +6800,12 @@ public sealed partial class PermissionPromptRequestMcp : PermissionPromptRequest
[JsonPropertyName("args")]
public JsonElement? Args { get; set; }
+ /// Auto-approval judge information for this request; present only when auto mode is enabled.
+ [Experimental(Diagnostics.Experimental)]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("autoApproval")]
+ public PermissionAutoApproval? AutoApproval { get; set; }
+
/// Name of the MCP server providing the tool.
[JsonPropertyName("serverName")]
public required string ServerName { get; set; }
@@ -6685,10 +6832,26 @@ public sealed partial class PermissionPromptRequestUrl : PermissionPromptRequest
[JsonIgnore]
public override string Kind => "url";
+ /// Auto-approval judge information for this request; present only when auto mode is enabled.
+ [Experimental(Diagnostics.Experimental)]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("autoApproval")]
+ public PermissionAutoApproval? AutoApproval { get; set; }
+
/// Human-readable description of why the URL is being accessed.
[JsonPropertyName("intention")]
public required string Intention { get; set; }
+ /// True when this URL fetch is requesting to bypass the sandbox network policy: either the model set requestSandboxBypass: true, or the tool re-issued the request as an interactive bypass after the network policy denied the approved URL (host opted in via sandbox.allowBypass). This is a request, not a grant: the fetch runs only if the user approves this permission request. Hosts should highlight the elevated risk in the approval UI.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("requestSandboxBypass")]
+ public bool? RequestSandboxBypass { get; set; }
+
+ /// Model-provided justification for the sandbox-bypass request. Only meaningful when requestSandboxBypass is true.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("requestSandboxBypassReason")]
+ public string? RequestSandboxBypassReason { get; set; }
+
/// Tool call ID that triggered this permission request.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("toolCallId")]
@@ -6712,6 +6875,12 @@ public sealed partial class PermissionPromptRequestMemory : PermissionPromptRequ
[JsonPropertyName("action")]
public PermissionRequestMemoryAction? Action { get; set; }
+ /// Auto-approval judge information for this request; present only when auto mode is enabled.
+ [Experimental(Diagnostics.Experimental)]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("autoApproval")]
+ public PermissionAutoApproval? AutoApproval { get; set; }
+
/// Source references for the stored fact (store only).
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("citations")]
@@ -6755,6 +6924,12 @@ public sealed partial class PermissionPromptRequestCustomTool : PermissionPrompt
[JsonPropertyName("args")]
public JsonElement? Args { get; set; }
+ /// Auto-approval judge information for this request; present only when auto mode is enabled.
+ [Experimental(Diagnostics.Experimental)]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("autoApproval")]
+ public PermissionAutoApproval? AutoApproval { get; set; }
+
/// Tool call ID that triggered this permission request.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("toolCallId")]
@@ -6781,6 +6956,12 @@ public sealed partial class PermissionPromptRequestPath : PermissionPromptReques
[JsonPropertyName("accessKind")]
public required PermissionPromptRequestPathAccessKind AccessKind { get; set; }
+ /// Auto-approval judge information for this request; present only when auto mode is enabled.
+ [Experimental(Diagnostics.Experimental)]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("autoApproval")]
+ public PermissionAutoApproval? AutoApproval { get; set; }
+
/// File paths that require explicit approval.
[JsonPropertyName("paths")]
public required string[] Paths { get; set; }
@@ -6799,6 +6980,12 @@ public sealed partial class PermissionPromptRequestHook : PermissionPromptReques
[JsonIgnore]
public override string Kind => "hook";
+ /// Auto-approval judge information for this request; present only when auto mode is enabled.
+ [Experimental(Diagnostics.Experimental)]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("autoApproval")]
+ public PermissionAutoApproval? AutoApproval { get; set; }
+
/// Optional message from the hook explaining why confirmation is needed.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("hookMessage")]
@@ -6827,6 +7014,12 @@ public sealed partial class PermissionPromptRequestExtensionManagement : Permiss
[JsonIgnore]
public override string Kind => "extension-management";
+ /// Auto-approval judge information for this request; present only when auto mode is enabled.
+ [Experimental(Diagnostics.Experimental)]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("autoApproval")]
+ public PermissionAutoApproval? AutoApproval { get; set; }
+
/// Name of the extension being managed.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("extensionName")]
@@ -6850,6 +7043,12 @@ public sealed partial class PermissionPromptRequestExtensionPermissionAccess : P
[JsonIgnore]
public override string Kind => "extension-permission-access";
+ /// Auto-approval judge information for this request; present only when auto mode is enabled.
+ [Experimental(Diagnostics.Experimental)]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("autoApproval")]
+ public PermissionAutoApproval? AutoApproval { get; set; }
+
/// Capabilities the extension is requesting.
[JsonPropertyName("capabilities")]
public required string[] Capabilities { get; set; }
@@ -6888,7 +7087,7 @@ public partial class PermissionPromptRequest
}
-/// Schema for the `PermissionApproved` type.
+/// Permission response variant indicating the request was approved without persisting an approval rule.
/// The approved variant of .
public sealed partial class PermissionResultApproved : PermissionResult
{
@@ -6897,7 +7096,7 @@ public sealed partial class PermissionResultApproved : PermissionResult
public override string Kind => "approved";
}
-/// Schema for the `UserToolSessionApprovalCommands` type.
+/// Session-scoped tool-approval rule for specific shell command identifiers.
/// The commands variant of .
public sealed partial class UserToolSessionApprovalCommands : UserToolSessionApproval
{
@@ -6910,7 +7109,7 @@ public sealed partial class UserToolSessionApprovalCommands : UserToolSessionApp
public required string[] CommandIdentifiers { get; set; }
}
-/// Schema for the `UserToolSessionApprovalRead` type.
+/// Session-scoped tool-approval rule for read-only filesystem operations.
/// The read variant of .
public sealed partial class UserToolSessionApprovalRead : UserToolSessionApproval
{
@@ -6919,7 +7118,7 @@ public sealed partial class UserToolSessionApprovalRead : UserToolSessionApprova
public override string Kind => "read";
}
-/// Schema for the `UserToolSessionApprovalWrite` type.
+/// Session-scoped tool-approval rule for filesystem write operations.
/// The write variant of .
public sealed partial class UserToolSessionApprovalWrite : UserToolSessionApproval
{
@@ -6928,7 +7127,7 @@ public sealed partial class UserToolSessionApprovalWrite : UserToolSessionApprov
public override string Kind => "write";
}
-/// Schema for the `UserToolSessionApprovalMcp` type.
+/// Session-scoped tool-approval rule for an MCP server tool, or all tools on the server when `toolName` is null.
/// The mcp variant of .
public sealed partial class UserToolSessionApprovalMcp : UserToolSessionApproval
{
@@ -6945,7 +7144,7 @@ public sealed partial class UserToolSessionApprovalMcp : UserToolSessionApproval
public string? ToolName { get; set; }
}
-/// Schema for the `UserToolSessionApprovalMemory` type.
+/// Session-scoped tool-approval rule for writes to long-term memory.
/// The memory variant of .
public sealed partial class UserToolSessionApprovalMemory : UserToolSessionApproval
{
@@ -6954,7 +7153,7 @@ public sealed partial class UserToolSessionApprovalMemory : UserToolSessionAppro
public override string Kind => "memory";
}
-/// Schema for the `UserToolSessionApprovalCustomTool` type.
+/// Session-scoped tool-approval rule for a custom tool, keyed by tool name.
/// The custom-tool variant of .
public sealed partial class UserToolSessionApprovalCustomTool : UserToolSessionApproval
{
@@ -6967,7 +7166,7 @@ public sealed partial class UserToolSessionApprovalCustomTool : UserToolSessionA
public required string ToolName { get; set; }
}
-/// Schema for the `UserToolSessionApprovalExtensionManagement` type.
+/// Session-scoped tool-approval rule for extension-management operations, optionally narrowed by operation.
/// The extension-management variant of .
public sealed partial class UserToolSessionApprovalExtensionManagement : UserToolSessionApproval
{
@@ -6981,7 +7180,7 @@ public sealed partial class UserToolSessionApprovalExtensionManagement : UserToo
public string? Operation { get; set; }
}
-/// Schema for the `UserToolSessionApprovalExtensionPermissionAccess` type.
+/// Session-scoped tool-approval rule for an extension's permission-gated capability access, keyed by extension name.
/// The extension-permission-access variant of .
public sealed partial class UserToolSessionApprovalExtensionPermissionAccess : UserToolSessionApproval
{
@@ -7015,7 +7214,7 @@ public partial class UserToolSessionApproval
}
-/// Schema for the `PermissionApprovedForSession` type.
+/// Permission response variant that approves a request and remembers the provided approval for the rest of the session.
/// The approved-for-session variant of .
public sealed partial class PermissionResultApprovedForSession : PermissionResult
{
@@ -7028,7 +7227,7 @@ public sealed partial class PermissionResultApprovedForSession : PermissionResul
public required UserToolSessionApproval Approval { get; set; }
}
-/// Schema for the `PermissionApprovedForLocation` type.
+/// Permission response variant that approves a request and persists the provided approval to a project location key.
/// The approved-for-location variant of .
public sealed partial class PermissionResultApprovedForLocation : PermissionResult
{
@@ -7045,7 +7244,7 @@ public sealed partial class PermissionResultApprovedForLocation : PermissionResu
public required string LocationKey { get; set; }
}
-/// Schema for the `PermissionCancelled` type.
+/// Permission response variant indicating the request was cancelled before use, with an optional reason.
/// The cancelled variant of .
public sealed partial class PermissionResultCancelled : PermissionResult
{
@@ -7059,7 +7258,7 @@ public sealed partial class PermissionResultCancelled : PermissionResult
public string? Reason { get; set; }
}
-/// Schema for the `PermissionRule` type.
+/// A permission approval or denial rule matched against a tool request, identified by a rule kind with an optional argument value.
/// Nested data type for PermissionRule.
public sealed partial class PermissionRule
{
@@ -7072,7 +7271,7 @@ public sealed partial class PermissionRule
public required string Kind { get; set; }
}
-/// Schema for the `PermissionDeniedByRules` type.
+/// Permission response variant denied because matching approval rules explicitly blocked the request.
/// The denied-by-rules variant of .
public sealed partial class PermissionResultDeniedByRules : PermissionResult
{
@@ -7085,7 +7284,7 @@ public sealed partial class PermissionResultDeniedByRules : PermissionResult
public required PermissionRule[] Rules { get; set; }
}
-/// Schema for the `PermissionDeniedNoApprovalRuleAndCouldNotRequestFromUser` type.
+/// Permission response variant denied because no approval rule matched and user confirmation was unavailable.
/// The denied-no-approval-rule-and-could-not-request-from-user variant of .
public sealed partial class PermissionResultDeniedNoApprovalRuleAndCouldNotRequestFromUser : PermissionResult
{
@@ -7094,7 +7293,7 @@ public sealed partial class PermissionResultDeniedNoApprovalRuleAndCouldNotReque
public override string Kind => "denied-no-approval-rule-and-could-not-request-from-user";
}
-/// Schema for the `PermissionDeniedInteractivelyByUser` type.
+/// Permission response variant denied in an interactive user prompt, with optional feedback and force-reject flag.
/// The denied-interactively-by-user variant of .
public sealed partial class PermissionResultDeniedInteractivelyByUser : PermissionResult
{
@@ -7113,7 +7312,7 @@ public sealed partial class PermissionResultDeniedInteractivelyByUser : Permissi
public bool? ForceReject { get; set; }
}
-/// Schema for the `PermissionDeniedByContentExclusionPolicy` type.
+/// Permission response variant denying a path under content exclusion policy, with the path and message.
/// The denied-by-content-exclusion-policy variant of .
public sealed partial class PermissionResultDeniedByContentExclusionPolicy : PermissionResult
{
@@ -7130,7 +7329,7 @@ public sealed partial class PermissionResultDeniedByContentExclusionPolicy : Per
public required string Path { get; set; }
}
-/// Schema for the `PermissionDeniedByPermissionRequestHook` type.
+/// Permission response variant denied by a permission-request hook, with optional message and interrupt flag.
/// The denied-by-permission-request-hook variant of .
public sealed partial class PermissionResultDeniedByPermissionRequestHook : PermissionResult
{
@@ -7252,7 +7451,7 @@ public sealed partial class SessionLimitsExhaustedResponse
public double? MaxAiCredits { get; set; }
}
-/// Schema for the `CommandsChangedCommand` type.
+/// 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
{
@@ -7286,7 +7485,7 @@ public sealed partial class CapabilitiesChangedUI
public bool? McpApps { get; set; }
}
-/// Schema for the `SkillsLoadedSkill` type.
+/// A single resolved skill in `session.skills_loaded`, including source, invocability, enabled state, path, and argument hint.
/// Nested data type for SkillsLoadedSkill.
public sealed partial class SkillsLoadedSkill
{
@@ -7321,7 +7520,7 @@ public sealed partial class SkillsLoadedSkill
public required bool UserInvocable { get; set; }
}
-/// Schema for the `CustomAgentsUpdatedAgent` type.
+/// A single loaded custom agent in `session.custom_agents_updated`, with identity, source, tools, invocability, and model override.
/// Nested data type for CustomAgentsUpdatedAgent.
public sealed partial class CustomAgentsUpdatedAgent
{
@@ -7359,7 +7558,7 @@ public sealed partial class CustomAgentsUpdatedAgent
public required bool UserInvocable { get; set; }
}
-/// Schema for the `McpServersLoadedServer` type.
+/// A single MCP server status summary in `session.mcp_servers_loaded`, including name, status, source, transport, and plugin metadata.
/// Nested data type for McpServersLoadedServer.
public sealed partial class McpServersLoadedServer
{
@@ -7397,7 +7596,7 @@ public sealed partial class McpServersLoadedServer
public McpServerTransport? Transport { get; set; }
}
-/// Schema for the `ExtensionsLoadedExtension` type.
+/// A single extension discovered by `session.extensions_loaded`, including qualified ID, source, and current status.
/// Nested data type for ExtensionsLoadedExtension.
public sealed partial class ExtensionsLoadedExtension
{
@@ -7418,7 +7617,7 @@ public sealed partial class ExtensionsLoadedExtension
public required ExtensionsLoadedExtensionStatus Status { get; set; }
}
-/// Schema for the `CanvasRegistryChangedCanvasAction` type.
+/// A single action within a canvas declaration, with its name, optional description, and optional input schema.
/// Nested data type for CanvasRegistryChangedCanvasAction.
[Experimental(Diagnostics.Experimental)]
public sealed partial class CanvasRegistryChangedCanvasAction
@@ -7438,7 +7637,7 @@ public sealed partial class CanvasRegistryChangedCanvasAction
public required string Name { get; set; }
}
-/// Schema for the `CanvasRegistryChangedCanvas` type.
+/// A single canvas declaration in `session.canvas.registry_changed`, including provider IDs, display metadata, input schema, and actions.
/// Nested data type for CanvasRegistryChangedCanvas.
[Experimental(Diagnostics.Experimental)]
public sealed partial class CanvasRegistryChangedCanvas
@@ -7486,7 +7685,7 @@ public sealed partial class McpAppToolCallCompleteError
public required string Message { get; set; }
}
-/// Schema for the `McpAppToolCallCompleteToolMetaUI` type.
+/// MCP App tool `_meta.ui` resource URI and SEP-1865 visibility captured with an `mcp_app.tool_call_complete` result.
/// Nested data type for McpAppToolCallCompleteToolMetaUI.
public sealed partial class McpAppToolCallCompleteToolMetaUI
{
@@ -7505,7 +7704,7 @@ public sealed partial class McpAppToolCallCompleteToolMetaUI
/// Nested data type for McpAppToolCallCompleteToolMeta.
public sealed partial class McpAppToolCallCompleteToolMeta
{
- /// Schema for the `McpAppToolCallCompleteToolMetaUI` type.
+ /// MCP App tool `_meta.ui` resource URI and SEP-1865 visibility captured with an `mcp_app.tool_call_complete` result.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("ui")]
public McpAppToolCallCompleteToolMetaUI? Ui { get; set; }
@@ -7697,6 +7896,70 @@ public override void Write(Utf8JsonWriter writer, ReasoningSummary value, JsonSe
}
}
+/// Output verbosity level used for supported model calls (e.g. "low", "medium", "high").
+[JsonConverter(typeof(Converter))]
+[DebuggerDisplay("{Value,nq}")]
+public readonly struct Verbosity : IEquatable
+{
+ private readonly string? _value;
+
+ /// Initializes a new instance of the struct.
+ /// The value to associate with this .
+ [JsonConstructor]
+ public Verbosity(string value)
+ {
+ ArgumentException.ThrowIfNullOrWhiteSpace(value);
+ _value = value;
+ }
+
+ /// Gets the value associated with this .
+ public string Value => _value ?? string.Empty;
+
+ /// A terse response was requested.
+ public static Verbosity Low { get; } = new("low");
+
+ /// A medium amount of response detail was requested.
+ public static Verbosity Medium { get; } = new("medium");
+
+ /// A more detailed response was requested.
+ public static Verbosity High { get; } = new("high");
+
+ /// Returns a value indicating whether two instances are equivalent.
+ public static bool operator ==(Verbosity left, Verbosity right) => left.Equals(right);
+
+ /// Returns a value indicating whether two instances are not equivalent.
+ public static bool operator !=(Verbosity left, Verbosity right) => !(left == right);
+
+ ///
+ public override bool Equals(object? obj) => obj is Verbosity other && Equals(other);
+
+ ///
+ public bool Equals(Verbosity 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 Verbosity Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert));
+ }
+
+ ///
+ public override void Write(Utf8JsonWriter writer, Verbosity value, JsonSerializerOptions options)
+ {
+ GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(Verbosity));
+ }
+ }
+}
+
/// The type of operation performed on the autopilot objective state file.
[JsonConverter(typeof(Converter))]
[DebuggerDisplay("{Value,nq}")]
@@ -7892,6 +8155,71 @@ public override void Write(Utf8JsonWriter writer, SessionMode value, JsonSeriali
}
}
+/// Allow-all mode for the session.
+[Experimental(Diagnostics.Experimental)]
+[JsonConverter(typeof(Converter))]
+[DebuggerDisplay("{Value,nq}")]
+public readonly struct PermissionAllowAllMode : IEquatable
+{
+ private readonly string? _value;
+
+ /// Initializes a new instance of the struct.
+ /// The value to associate with this .
+ [JsonConstructor]
+ public PermissionAllowAllMode(string value)
+ {
+ ArgumentException.ThrowIfNullOrWhiteSpace(value);
+ _value = value;
+ }
+
+ /// Gets the value associated with this .
+ public string Value => _value ?? string.Empty;
+
+ /// Permission requests follow the normal approval flow.
+ public static PermissionAllowAllMode Off { get; } = new("off");
+
+ /// Tool, path, and URL permission requests are automatically approved.
+ public static PermissionAllowAllMode On { get; } = new("on");
+
+ /// Permission requests follow the normal approval flow with an LLM advisory recommendation attached; clients may choose to auto-approve requests the judge evaluated as acceptable.
+ public static PermissionAllowAllMode Auto { get; } = new("auto");
+
+ /// Returns a value indicating whether two instances are equivalent.
+ public static bool operator ==(PermissionAllowAllMode left, PermissionAllowAllMode right) => left.Equals(right);
+
+ /// Returns a value indicating whether two instances are not equivalent.
+ public static bool operator !=(PermissionAllowAllMode left, PermissionAllowAllMode right) => !(left == right);
+
+ ///
+ public override bool Equals(object? obj) => obj is PermissionAllowAllMode other && Equals(other);
+
+ ///
+ public bool Equals(PermissionAllowAllMode 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 PermissionAllowAllMode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert));
+ }
+
+ ///
+ public override void Write(Utf8JsonWriter writer, PermissionAllowAllMode value, JsonSerializerOptions options)
+ {
+ GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(PermissionAllowAllMode));
+ }
+ }
+}
+
/// The type of operation performed on the plan file.
[JsonConverter(typeof(Converter))]
[DebuggerDisplay("{Value,nq}")]
@@ -8395,46 +8723,42 @@ public override void Write(Utf8JsonWriter writer, UserMessageDelivery value, Jso
}
}
-/// The system that produced a citation.
-[Experimental(Diagnostics.Experimental)]
+/// Tool call type: "function" for standard tool calls, "custom" for grammar-based tool calls. Defaults to "function" when absent.
[JsonConverter(typeof(Converter))]
[DebuggerDisplay("{Value,nq}")]
-public readonly struct CitationProvider : IEquatable
+public readonly struct AssistantMessageToolRequestType : 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 CitationProvider(string value)
+ public AssistantMessageToolRequestType(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;
- /// Citation produced by an Anthropic (Claude) model response.
- public static CitationProvider Anthropic { get; } = new("anthropic");
-
- /// Citation produced by an OpenAI model response.
- public static CitationProvider Openai { get; } = new("openai");
+ /// Standard function-style tool call.
+ public static AssistantMessageToolRequestType Function { get; } = new("function");
- /// Citation synthesized client-side by the runtime from tool output.
- public static CitationProvider Client { get; } = new("client");
+ /// Custom grammar-based tool call.
+ public static AssistantMessageToolRequestType Custom { get; } = new("custom");
- /// Returns a value indicating whether two instances are equivalent.
- public static bool operator ==(CitationProvider left, CitationProvider right) => left.Equals(right);
+ /// Returns a value indicating whether two instances are equivalent.
+ public static bool operator ==(AssistantMessageToolRequestType left, AssistantMessageToolRequestType right) => left.Equals(right);
- /// Returns a value indicating whether two instances are not equivalent.
- public static bool operator !=(CitationProvider left, CitationProvider right) => !(left == right);
+ /// Returns a value indicating whether two instances are not equivalent.
+ public static bool operator !=(AssistantMessageToolRequestType left, AssistantMessageToolRequestType right) => !(left == right);
///
- public override bool Equals(object? obj) => obj is CitationProvider other && Equals(other);
+ public override bool Equals(object? obj) => obj is AssistantMessageToolRequestType other && Equals(other);
///
- public bool Equals(CitationProvider other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase);
+ public bool Equals(AssistantMessageToolRequestType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase);
///
public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value);
@@ -8442,60 +8766,64 @@ public CitationProvider(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 CitationProvider Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ public override AssistantMessageToolRequestType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert));
}
///
- public override void Write(Utf8JsonWriter writer, CitationProvider value, JsonSerializerOptions options)
+ public override void Write(Utf8JsonWriter writer, AssistantMessageToolRequestType value, JsonSerializerOptions options)
{
- GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(CitationProvider));
+ GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(AssistantMessageToolRequestType));
}
}
}
-/// Tool call type: "function" for standard tool calls, "custom" for grammar-based tool calls. Defaults to "function" when absent.
+/// The system that produced a citation.
+[Experimental(Diagnostics.Experimental)]
[JsonConverter(typeof(Converter))]
[DebuggerDisplay("{Value,nq}")]
-public readonly struct AssistantMessageToolRequestType : IEquatable
+public readonly struct CitationProvider : 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 AssistantMessageToolRequestType(string value)
+ public CitationProvider(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;
- /// Standard function-style tool call.
- public static AssistantMessageToolRequestType Function { get; } = new("function");
+ /// Citation produced by an Anthropic (Claude) model response.
+ public static CitationProvider Anthropic { get; } = new("anthropic");
- /// Custom grammar-based tool call.
- public static AssistantMessageToolRequestType Custom { get; } = new("custom");
+ /// Citation produced by an OpenAI model response.
+ public static CitationProvider Openai { get; } = new("openai");
- /// Returns a value indicating whether two instances are equivalent.
- public static bool operator ==(AssistantMessageToolRequestType left, AssistantMessageToolRequestType right) => left.Equals(right);
+ /// Citation synthesized client-side by the runtime from tool output.
+ public static CitationProvider Client { get; } = new("client");
- /// Returns a value indicating whether two instances are not equivalent.
- public static bool operator !=(AssistantMessageToolRequestType left, AssistantMessageToolRequestType right) => !(left == right);
+ /// Returns a value indicating whether two instances are equivalent.
+ public static bool operator ==(CitationProvider left, CitationProvider right) => left.Equals(right);
+
+ /// Returns a value indicating whether two instances are not equivalent.
+ public static bool operator !=(CitationProvider left, CitationProvider right) => !(left == right);
///
- public override bool Equals(object? obj) => obj is AssistantMessageToolRequestType other && Equals(other);
+ public override bool Equals(object? obj) => obj is CitationProvider other && Equals(other);
///
- public bool Equals(AssistantMessageToolRequestType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase);
+ public bool Equals(CitationProvider other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase);
///
public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value);
@@ -8503,20 +8831,20 @@ public AssistantMessageToolRequestType(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 AssistantMessageToolRequestType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ public override CitationProvider Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert));
}
///
- public override void Write(Utf8JsonWriter writer, AssistantMessageToolRequestType value, JsonSerializerOptions options)
+ public override void Write(Utf8JsonWriter writer, CitationProvider value, JsonSerializerOptions options)
{
- GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(AssistantMessageToolRequestType));
+ GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(CitationProvider));
}
}
}
@@ -9512,6 +9840,74 @@ public override void Write(Utf8JsonWriter writer, PermissionRequestMemoryDirecti
}
}
+/// Outcome of the auto-approval safety judge for a permission request. Present only when auto mode is enabled; its absence means the judge did not evaluate the request (auto mode was off).
+[Experimental(Diagnostics.Experimental)]
+[JsonConverter(typeof(Converter))]
+[DebuggerDisplay("{Value,nq}")]
+public readonly struct AutoApprovalRecommendation : IEquatable
+{
+ private readonly string? _value;
+
+ /// Initializes a new instance of the struct.
+ /// The value to associate with this .
+ [JsonConstructor]
+ public AutoApprovalRecommendation(string value)
+ {
+ ArgumentException.ThrowIfNullOrWhiteSpace(value);
+ _value = value;
+ }
+
+ /// Gets the value associated with this .
+ public string Value => _value ?? string.Empty;
+
+ /// The judge evaluated the request and recommends automatically approving it.
+ public static AutoApprovalRecommendation Approve { get; } = new("approve");
+
+ /// The judge evaluated the request and does not recommend auto-approving it; explicit approval is required. Whether that means prompting, denying, or something else is the consumer's decision.
+ public static AutoApprovalRecommendation RequireApproval { get; } = new("requireApproval");
+
+ /// Auto mode is enabled, but this request category is never auto-approvable (for example, sandbox-bypass requests), so the judge was not consulted.
+ public static AutoApprovalRecommendation Excluded { get; } = new("excluded");
+
+ /// The judge was consulted but did not return a usable recommendation, so the request requires explicit approval.
+ public static AutoApprovalRecommendation Error { get; } = new("error");
+
+ /// Returns a value indicating whether two instances are equivalent.
+ public static bool operator ==(AutoApprovalRecommendation left, AutoApprovalRecommendation right) => left.Equals(right);
+
+ /// Returns a value indicating whether two instances are not equivalent.
+ public static bool operator !=(AutoApprovalRecommendation left, AutoApprovalRecommendation right) => !(left == right);
+
+ ///
+ public override bool Equals(object? obj) => obj is AutoApprovalRecommendation other && Equals(other);
+
+ ///
+ public bool Equals(AutoApprovalRecommendation 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 AutoApprovalRecommendation Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert));
+ }
+
+ ///
+ public override void Write(Utf8JsonWriter writer, AutoApprovalRecommendation value, JsonSerializerOptions options)
+ {
+ GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(AutoApprovalRecommendation));
+ }
+ }
+}
+
/// Underlying permission kind that needs path approval.
[JsonConverter(typeof(Converter))]
[DebuggerDisplay("{Value,nq}")]
@@ -10597,6 +10993,8 @@ public override void Write(Utf8JsonWriter writer, ExtensionsLoadedExtensionStatu
[JsonSerializable(typeof(AssistantReasoningEvent))]
[JsonSerializable(typeof(AssistantStreamingDeltaData))]
[JsonSerializable(typeof(AssistantStreamingDeltaEvent))]
+[JsonSerializable(typeof(AssistantToolCallDeltaData))]
+[JsonSerializable(typeof(AssistantToolCallDeltaEvent))]
[JsonSerializable(typeof(AssistantTurnEndData))]
[JsonSerializable(typeof(AssistantTurnEndEvent))]
[JsonSerializable(typeof(AssistantTurnStartData))]
@@ -10707,6 +11105,7 @@ public override void Write(Utf8JsonWriter writer, ExtensionsLoadedExtensionStatu
[JsonSerializable(typeof(OmittedBinaryResult))]
[JsonSerializable(typeof(PendingMessagesModifiedData))]
[JsonSerializable(typeof(PendingMessagesModifiedEvent))]
+[JsonSerializable(typeof(PermissionAutoApproval))]
[JsonSerializable(typeof(PermissionCompletedData))]
[JsonSerializable(typeof(PermissionCompletedEvent))]
[JsonSerializable(typeof(PermissionPromptRequest))]
diff --git a/dotnet/src/GitHub.Copilot.SDK.csproj b/dotnet/src/GitHub.Copilot.SDK.csproj
index 7a9fa2bdc..f48fb802d 100644
--- a/dotnet/src/GitHub.Copilot.SDK.csproj
+++ b/dotnet/src/GitHub.Copilot.SDK.csproj
@@ -16,6 +16,7 @@
copilot.pnggithub;copilot;sdk;jsonrpc;agenttrue
+ truetruesnupkgtrue
diff --git a/dotnet/src/JsonRpc.cs b/dotnet/src/JsonRpc.cs
index edd0534ab..bf1684f17 100644
--- a/dotnet/src/JsonRpc.cs
+++ b/dotnet/src/JsonRpc.cs
@@ -206,14 +206,12 @@ public void Dispose()
private async Task SendMessageAsync(T message, JsonTypeInfo typeInfo, CancellationToken cancellationToken)
{
- // "Content-Length: " (16) + max int digits (10) + "\r\n\r\n" (4)
- const int MaxHeaderLength = 30;
-
var json = JsonSerializer.SerializeToUtf8Bytes(message, typeInfo);
- var headerBuf = ArrayPool.Shared.Rent(MaxHeaderLength);
- bool wrote = Utf8.TryWrite(headerBuf, $"Content-Length: {json.Length}\r\n\r\n", out int headerLen);
- Debug.Assert(wrote && headerLen > 0);
+ // Format the LSP header and body into a single pooled buffer so the framed
+ // message is written in one call — over the FFI transport that is one native
+ // boundary crossing per message instead of two.
+ var frame = BuildFrame(json, out int frameLen);
// Cancellation only applies to *waiting* for the write lock. Once we hold the lock
// and start writing a framed message, we must finish it — cancelling between the
@@ -223,15 +221,40 @@ private async Task SendMessageAsync(T message, JsonTypeInfo typeInfo, Canc
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
- await _sendStream.WriteAsync(headerBuf.AsMemory(0, headerLen), CancellationToken.None).ConfigureAwait(false);
- await _sendStream.WriteAsync(json, CancellationToken.None).ConfigureAwait(false);
+ await _sendStream.WriteAsync(frame.AsMemory(0, frameLen), CancellationToken.None).ConfigureAwait(false);
await _sendStream.FlushAsync(CancellationToken.None).ConfigureAwait(false);
}
finally
{
_writeLock.Release();
- ArrayPool.Shared.Return(headerBuf);
+ ArrayPool.Shared.Return(frame);
+ }
+ }
+
+ ///
+ /// Writes Content-Length: N\r\n\r\n followed by into a
+ /// single buffer rented from . The caller owns the returned
+ /// buffer and must return it to the shared pool.
+ ///
+ private static byte[] BuildFrame(ReadOnlySpan json, out int frameLen)
+ {
+ // "Content-Length: " (16) + max int digits (10) + "\r\n\r\n" (4)
+ const int MaxHeaderLength = 30;
+
+ // Over-rent by the (fixed, tiny) header bound so the header can be written
+ // straight into the frame — no scratch buffer or header copy. The JSON is
+ // already UTF-8, so the only copy is placing it after the header, which is
+ // unavoidable since Content-Length needs its length up front.
+ var frame = ArrayPool.Shared.Rent(MaxHeaderLength + json.Length);
+ if (!Utf8.TryWrite(frame, $"Content-Length: {json.Length}\r\n\r\n", out int headerLen))
+ {
+ ArrayPool.Shared.Return(frame);
+ throw new InvalidOperationException("Failed to write JSON-RPC frame header.");
}
+
+ json.CopyTo(frame.AsSpan(headerLen));
+ frameLen = headerLen + json.Length;
+ return frame;
}
private async Task ReadLoopAsync(CancellationToken cancellationToken)
diff --git a/dotnet/src/Session.cs b/dotnet/src/Session.cs
index f009faa0b..ae010a97f 100644
--- a/dotnet/src/Session.cs
+++ b/dotnet/src/Session.cs
@@ -1787,6 +1787,7 @@ await Rpc.Model.SwitchToAsync(
model,
options.ReasoningEffort,
options.ReasoningSummary,
+ null,
options.ModelCapabilities,
options.ContextTier,
cancellationToken);
diff --git a/dotnet/src/Types.cs b/dotnet/src/Types.cs
index 172d9305f..65295d3d2 100644
--- a/dotnet/src/Types.cs
+++ b/dotnet/src/Types.cs
@@ -145,6 +145,20 @@ public static TcpRuntimeConnection ForTcp(int port = 0, string? connectionToken
/// Optional shared secret to authenticate the connection.
public static UriRuntimeConnection ForUri(string url, string? connectionToken = null)
=> new() { Url = url, ConnectionToken = connectionToken };
+
+ ///
+ /// Host the runtime in-process by loading its native library and communicating
+ /// over the C ABI (FFI) — no child process is spawned by the SDK for JSON-RPC
+ /// transport. The bundled runtime is used; to point at a non-default runtime
+ /// entrypoint, set the COPILOT_CLI_PATH environment variable.
+ ///
+ ///
+ /// Works across the SDK's target frameworks: modern .NET uses NativeLibrary,
+ /// while netstandard2.0 consumers use a built-in fallback native loader.
+ ///
+ [Experimental(Diagnostics.Experimental)]
+ public static InProcessRuntimeConnection ForInProcess()
+ => new();
}
///
@@ -159,6 +173,16 @@ internal ChildProcessRuntimeConnection() { }
/// Extra command-line arguments to pass to the runtime process.
public IList? Args { get; set; }
+
+ ///
+ /// Gets or sets the environment variables passed to the spawned runtime process,
+ /// replacing the inherited environment.
+ ///
+ ///
+ /// Cannot be combined with ; setting both throws
+ /// an when the client is constructed.
+ ///
+ public IReadOnlyDictionary? Environment { get; set; }
}
///
@@ -170,6 +194,19 @@ public sealed class StdioRuntimeConnection : ChildProcessRuntimeConnection
internal StdioRuntimeConnection() { }
}
+///
+/// Hosts the runtime in-process by loading its native library and communicating
+/// over the C ABI (FFI). Construct via .
+/// Works across the SDK's target frameworks (modern .NET and netstandard2.0).
+/// To point at a non-default runtime entrypoint, set the COPILOT_CLI_PATH
+/// environment variable.
+///
+[Experimental(Diagnostics.Experimental)]
+public sealed class InProcessRuntimeConnection : RuntimeConnection
+{
+ internal InProcessRuntimeConnection() { }
+}
+
///
/// Spawns a runtime child process listening on a TCP socket. Construct via
/// .
@@ -281,6 +318,7 @@ private CopilotClientOptions(CopilotClientOptions? other)
OnListModels = other.OnListModels;
SessionFs = other.SessionFs;
RequestHandler = other.RequestHandler;
+ OnGitHubTelemetry = other.OnGitHubTelemetry;
SessionIdleTimeoutSeconds = other.SessionIdleTimeoutSeconds;
EnableRemoteSessions = other.EnableRemoteSessions;
Mode = other.Mode;
@@ -330,7 +368,15 @@ private CopilotClientOptions(CopilotClientOptions? other)
///
public CopilotLogLevel? LogLevel { get; set; }
- /// Environment variables to pass to the runtime process.
+ ///
+ /// Gets or sets environment variables passed to the runtime process.
+ ///
+ ///
+ /// Not supported with the in-process transport (),
+ /// which runs the runtime in the host process; setting this option there throws an
+ /// . For child-process transports, prefer
+ /// ; setting both throws.
+ ///
public IReadOnlyDictionary? Environment { get; set; }
/// Logger instance for SDK diagnostic output.
@@ -378,6 +424,15 @@ private CopilotClientOptions(CopilotClientOptions? other)
[Experimental(Diagnostics.Experimental)]
public CopilotRequestHandler? RequestHandler { get; set; }
+ ///
+ /// Experimental. Receives GitHub telemetry events the runtime forwards to this
+ /// connection; setting a handler opts created/resumed sessions into forwarding.
+ /// The SDK awaits the handler task so it may perform asynchronous work.
+ ///
+ [Experimental(Diagnostics.Experimental)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Func? OnGitHubTelemetry { get; set; }
+
///
/// OpenTelemetry configuration for the runtime.
/// When set to a non- instance, the runtime is started with OpenTelemetry instrumentation enabled.
diff --git a/dotnet/src/build/GitHub.Copilot.SDK.targets b/dotnet/src/build/GitHub.Copilot.SDK.targets
index 94b6515ea..5a5e51181 100644
--- a/dotnet/src/build/GitHub.Copilot.SDK.targets
+++ b/dotnet/src/build/GitHub.Copilot.SDK.targets
@@ -35,6 +35,13 @@
<_CopilotPlatform Condition="'$(_CopilotRid)' == 'osx-arm64'">darwin-arm64
<_CopilotBinary Condition="$(_CopilotRid.StartsWith('win-'))">copilot.exe
<_CopilotBinary Condition="'$(_CopilotBinary)' == ''">copilot
+
+ <_CopilotRuntimeLib Condition="$(_CopilotRid.StartsWith('win-'))">copilot_runtime.dll
+ <_CopilotRuntimeLib Condition="$(_CopilotRid.StartsWith('osx-'))">libcopilot_runtime.dylib
+ <_CopilotRuntimeLib Condition="'$(_CopilotRuntimeLib)' == ''">libcopilot_runtime.so
+ <_CopilotRuntimeNodePath>$(_CopilotCacheDir)\prebuilds\$(_CopilotPlatform)\runtime.node
+
+
diff --git a/dotnet/test/AssemblyInfo.cs b/dotnet/test/AssemblyInfo.cs
index e34f0e255..9380ca48c 100644
--- a/dotnet/test/AssemblyInfo.cs
+++ b/dotnet/test/AssemblyInfo.cs
@@ -3,6 +3,7 @@
*--------------------------------------------------------------------------------------------*/
using Xunit;
+using GitHub.Copilot.Test.Harness;
// Each E2E test class fixture spins up its own Copilot CLI subprocess plus a CapiProxy
// (replaying HTTP proxy) Node.js subprocess. With ~25 test classes, running them in parallel
@@ -13,3 +14,5 @@
// (a) sharing a single CLI subprocess across classes, or (b) gating concurrency with a
// semaphore that limits concurrent fixtures to a small number (e.g. 2-3).
[assembly: CollectionBehavior(DisableTestParallelization = true)]
+
+[assembly: InProcessEnvIsolation]
diff --git a/dotnet/test/ConnectionTokenTests.cs b/dotnet/test/ConnectionTokenTests.cs
index 524ff2586..3192bada6 100644
--- a/dotnet/test/ConnectionTokenTests.cs
+++ b/dotnet/test/ConnectionTokenTests.cs
@@ -113,7 +113,7 @@ public class ConnectionTokenAutoGeneratedTests : IAsyncLifetime
public async Task InitializeAsync()
{
_ctx = await E2ETestContext.CreateAsync();
- _client = _ctx.CreateClient(useStdio: false);
+ _client = _ctx.CreateClient(options: new CopilotClientOptions { Connection = RuntimeConnection.ForTcp() });
}
public async Task DisposeAsync()
diff --git a/dotnet/test/E2E/ClientE2ETests.cs b/dotnet/test/E2E/ClientE2ETests.cs
index 9972e3b33..5de6ce159 100644
--- a/dotnet/test/E2E/ClientE2ETests.cs
+++ b/dotnet/test/E2E/ClientE2ETests.cs
@@ -33,6 +33,32 @@ public async Task Should_Start_And_Connect_To_Server(bool useStdio)
}
}
+ [Fact]
+ public async Task Should_Start_And_Connect_Over_InProcess_Ffi()
+ {
+ // In-process FFI hosting resolves the CLI entrypoint (COPILOT_CLI_PATH or the
+ // bundled CLI binary) and its sibling native runtime library itself; if neither
+ // is available, StartAsync throws and the test fails hard.
+ using var client = new CopilotClient(new CopilotClientOptions
+ {
+ Connection = RuntimeConnection.ForInProcess(),
+ });
+
+ try
+ {
+ await client.StartAsync();
+ var pong = await client.PingAsync("ffi message");
+ Assert.Equal("pong: ffi message", pong.Message);
+ Assert.NotEqual(default, pong.Timestamp);
+
+ await client.StopAsync();
+ }
+ finally
+ {
+ await client.ForceStopAsync();
+ }
+ }
+
[Theory]
[InlineData(true)] // stdio transport
[InlineData(false)] // TCP transport
diff --git a/dotnet/test/E2E/ClientOptionsE2ETests.cs b/dotnet/test/E2E/ClientOptionsE2ETests.cs
index c2f16a042..a8ceda5b0 100644
--- a/dotnet/test/E2E/ClientOptionsE2ETests.cs
+++ b/dotnet/test/E2E/ClientOptionsE2ETests.cs
@@ -71,7 +71,6 @@ public async Task Should_Propagate_Process_Options_To_Spawned_Cli()
{
Connection = RuntimeConnection.ForStdio(path: cliPath, args: ["--capture-file", capturePath]),
BaseDirectory = copilotHomeFromOption,
- Environment = clientEnv,
GitHubToken = "process-option-token",
LogLevel = CopilotLogLevel.Debug,
SessionIdleTimeoutSeconds = 17,
@@ -85,7 +84,7 @@ public async Task Should_Propagate_Process_Options_To_Spawned_Cli()
CaptureContent = true,
},
UseLoggedInUser = false,
- });
+ }, environment: clientEnv);
await client.StartAsync();
@@ -219,6 +218,205 @@ public async Task Should_Forward_Granular_Multitenancy_Fields_In_Create_Wire_Req
await session.DisposeAsync();
}
+ [Fact]
+ public async Task Should_Forward_Advanced_Session_Options_In_Create_Wire_Request()
+ {
+ var (cliPath, capturePath) = await CreateFakeCliCaptureAsync();
+ var outputDirectory = Path.Join(Ctx.WorkDir, "large-output-create");
+
+ await using var client = Ctx.CreateClient(options: new CopilotClientOptions
+ {
+ Connection = RuntimeConnection.ForStdio(path: cliPath, args: ["--capture-file", capturePath]),
+ UseLoggedInUser = false,
+ });
+
+ await client.StartAsync();
+
+ var session = await client.CreateSessionAsync(new SessionConfig
+ {
+ ClientName = "advanced-create-client",
+ Model = "claude-sonnet-4.5",
+ ReasoningEffort = "medium",
+ ReasoningSummary = ReasoningSummary.Detailed,
+ ContextTier = ContextTier.LongContext,
+ EnableCitations = true,
+ Capi = new CapiSessionOptions { EnableWebSocketResponses = false },
+ McpOAuthTokenStorage = McpOAuthTokenStorageMode.Persistent,
+ CustomAgents =
+ [
+ new CustomAgentConfig
+ {
+ Name = "agent-one",
+ DisplayName = "Agent One",
+ Description = "Handles agent-one tasks.",
+ Prompt = "Be agent one.",
+ Tools = ["view"],
+ Infer = true,
+ Skills = ["create-skill"],
+ Model = "claude-haiku-4.5",
+ },
+ ],
+ DefaultAgent = new DefaultAgentConfig { ExcludedTools = ["edit"] },
+ Agent = "agent-one",
+ SkillDirectories = ["skills-create"],
+ DisabledSkills = ["disabled-create-skill"],
+ PluginDirectories = ["plugins-create"],
+ InfiniteSessions = new InfiniteSessionConfig
+ {
+ Enabled = false,
+ BackgroundCompactionThreshold = 0.5,
+ BufferExhaustionThreshold = 0.9,
+ },
+ LargeOutput = new LargeToolOutputConfig
+ {
+ Enabled = true,
+ MaxSizeBytes = 4096,
+ OutputDirectory = outputDirectory,
+ },
+ Memory = new MemoryConfiguration { Enabled = true },
+ GitHubToken = "session-create-token",
+ RemoteSession = GitHub.Copilot.Rpc.RemoteSessionMode.Export,
+ Cloud = new CloudSessionOptions
+ {
+ Repository = new CloudSessionRepository
+ {
+ Owner = "github",
+ Name = "copilot-sdk",
+ Branch = "main",
+ },
+ },
+ EnableMcpApps = true,
+ RequestCanvasRenderer = true,
+ RequestExtensions = true,
+ ExtensionSdkPath = "custom-extension-sdk",
+ ExtensionInfo = new ExtensionInfo { Source = "dotnet-sdk-tests", Name = "advanced-create-extension" },
+ Canvases =
+ [
+ new CanvasDeclaration
+ {
+ Id = "advanced-create-canvas",
+ DisplayName = "Advanced Create Canvas",
+ Description = "Covers create-time canvas options.",
+ },
+ ],
+ Providers =
+ [
+ new NamedProviderConfig
+ {
+ Name = "create-provider",
+ Type = "openai",
+ WireApi = "responses",
+ BaseUrl = "https://create-provider.example.test/v1",
+ ApiKey = "create-provider-key",
+ Headers = new Dictionary { ["X-Create-Provider"] = "yes" },
+ },
+ ],
+ Models =
+ [
+ new ProviderModelConfig
+ {
+ Provider = "create-provider",
+ Id = "create-model",
+ Name = "Create Model",
+ ModelId = "claude-sonnet-4.5",
+ WireModel = "create-wire-model",
+ MaxContextWindowTokens = 12_000,
+ MaxPromptTokens = 10_000,
+ MaxOutputTokens = 2_000,
+ },
+ ],
+ OnPermissionRequest = PermissionHandler.ApproveAll,
+ });
+
+ using var capture = JsonDocument.Parse(await File.ReadAllTextAsync(capturePath));
+ var createRequest = GetCapturedRequestParams(capture.RootElement, "session.create");
+ Assert.Equal("advanced-create-client", createRequest.GetProperty("clientName").GetString());
+ Assert.Equal("claude-sonnet-4.5", createRequest.GetProperty("model").GetString());
+ Assert.Equal("medium", createRequest.GetProperty("reasoningEffort").GetString());
+ Assert.Equal("detailed", createRequest.GetProperty("reasoningSummary").GetString());
+ Assert.Equal("long_context", createRequest.GetProperty("contextTier").GetString());
+ Assert.True(createRequest.GetProperty("enableCitations").GetBoolean());
+ Assert.False(createRequest.GetProperty("capi").GetProperty("enableWebSocketResponses").GetBoolean());
+ Assert.Equal("persistent", createRequest.GetProperty("mcpOAuthTokenStorage").GetString());
+ Assert.Equal("agent-one", createRequest.GetProperty("agent").GetString());
+ Assert.Equal("edit", createRequest.GetProperty("defaultAgent").GetProperty("excludedTools")[0].GetString());
+ Assert.Equal("agent-one", createRequest.GetProperty("customAgents")[0].GetProperty("name").GetString());
+ Assert.Equal("plugins-create", createRequest.GetProperty("pluginDirectories")[0].GetString());
+ Assert.Equal("disabled-create-skill", createRequest.GetProperty("disabledSkills")[0].GetString());
+ Assert.False(createRequest.GetProperty("infiniteSessions").GetProperty("enabled").GetBoolean());
+ Assert.True(createRequest.GetProperty("largeOutput").GetProperty("enabled").GetBoolean());
+ Assert.Equal(4096, createRequest.GetProperty("largeOutput").GetProperty("maxSizeBytes").GetInt64());
+ Assert.Equal(outputDirectory, createRequest.GetProperty("largeOutput").GetProperty("outputDir").GetString());
+ Assert.True(createRequest.GetProperty("memory").GetProperty("enabled").GetBoolean());
+ Assert.Equal("session-create-token", createRequest.GetProperty("gitHubToken").GetString());
+ Assert.Equal("export", createRequest.GetProperty("remoteSession").GetString());
+ Assert.Equal("github", createRequest.GetProperty("cloud").GetProperty("repository").GetProperty("owner").GetString());
+ Assert.True(createRequest.GetProperty("requestMcpApps").GetBoolean());
+ Assert.True(createRequest.GetProperty("requestCanvasRenderer").GetBoolean());
+ Assert.True(createRequest.GetProperty("requestExtensions").GetBoolean());
+ Assert.Equal("custom-extension-sdk", createRequest.GetProperty("extensionSdkPath").GetString());
+ Assert.Equal("advanced-create-extension", createRequest.GetProperty("extensionInfo").GetProperty("name").GetString());
+ Assert.Equal("advanced-create-canvas", createRequest.GetProperty("canvases")[0].GetProperty("id").GetString());
+ Assert.Equal("create-provider", createRequest.GetProperty("providers")[0].GetProperty("name").GetString());
+ Assert.Equal("responses", createRequest.GetProperty("providers")[0].GetProperty("wireApi").GetString());
+ Assert.Equal("create-model", createRequest.GetProperty("models")[0].GetProperty("id").GetString());
+ Assert.Equal(12000, createRequest.GetProperty("models")[0].GetProperty("maxContextWindowTokens").GetInt32());
+
+ await session.DisposeAsync();
+ }
+
+ [Fact]
+ public async Task Should_Forward_Singular_Provider_Options_In_Create_Wire_Request()
+ {
+ var (cliPath, capturePath) = await CreateFakeCliCaptureAsync();
+
+ await using var client = Ctx.CreateClient(options: new CopilotClientOptions
+ {
+ Connection = RuntimeConnection.ForStdio(path: cliPath, args: ["--capture-file", capturePath]),
+ UseLoggedInUser = false,
+ });
+
+ await client.StartAsync();
+
+ var session = await client.CreateSessionAsync(new SessionConfig
+ {
+ Model = "claude-sonnet-4.5",
+ Provider = new ProviderConfig
+ {
+ Type = "azure",
+ WireApi = "responses",
+ Transport = "http",
+ BaseUrl = "https://azure-provider.example.test/openai",
+ ApiKey = "provider-api-key",
+ BearerToken = "provider-bearer-token",
+ Azure = new AzureOptions { ApiVersion = "2024-02-15-preview" },
+ Headers = new Dictionary { ["X-Provider-Wire"] = "yes" },
+ ModelId = "claude-sonnet-4.5",
+ WireModel = "azure-deployment",
+ MaxPromptTokens = 8192,
+ MaxOutputTokens = 1024,
+ },
+ OnPermissionRequest = PermissionHandler.ApproveAll,
+ });
+
+ using var capture = JsonDocument.Parse(await File.ReadAllTextAsync(capturePath));
+ var provider = GetCapturedRequestParams(capture.RootElement, "session.create").GetProperty("provider");
+ Assert.Equal("azure", provider.GetProperty("type").GetString());
+ Assert.Equal("responses", provider.GetProperty("wireApi").GetString());
+ Assert.Equal("http", provider.GetProperty("transport").GetString());
+ Assert.Equal("https://azure-provider.example.test/openai", provider.GetProperty("baseUrl").GetString());
+ Assert.Equal("provider-api-key", provider.GetProperty("apiKey").GetString());
+ Assert.Equal("provider-bearer-token", provider.GetProperty("bearerToken").GetString());
+ Assert.Equal("2024-02-15-preview", provider.GetProperty("azure").GetProperty("apiVersion").GetString());
+ Assert.Equal("yes", provider.GetProperty("headers").GetProperty("X-Provider-Wire").GetString());
+ Assert.Equal("claude-sonnet-4.5", provider.GetProperty("modelId").GetString());
+ Assert.Equal("azure-deployment", provider.GetProperty("wireModel").GetString());
+ Assert.Equal(8192, provider.GetProperty("maxPromptTokens").GetInt32());
+ Assert.Equal(1024, provider.GetProperty("maxOutputTokens").GetInt32());
+
+ await session.DisposeAsync();
+ }
+
[Fact]
public async Task Should_Apply_Empty_Mode_Defaults_To_CreateSession_Wire_Request()
{
@@ -411,6 +609,88 @@ public async Task Should_Forward_Granular_Multitenancy_Fields_In_Resume_Wire_Req
await session.DisposeAsync();
}
+ [Fact]
+ public async Task Should_Forward_Advanced_Session_Options_In_Resume_Wire_Request()
+ {
+ var (cliPath, capturePath) = await CreateFakeCliCaptureAsync();
+ var outputDirectory = Path.Join(Ctx.WorkDir, "large-output-resume");
+ using var canvasInput = JsonDocument.Parse("{\"start\":41}");
+
+ await using var client = Ctx.CreateClient(options: new CopilotClientOptions
+ {
+ Connection = RuntimeConnection.ForStdio(path: cliPath, args: ["--capture-file", capturePath]),
+ UseLoggedInUser = false,
+ });
+
+ await client.StartAsync();
+
+ var session = await client.ResumeSessionAsync("advanced-resume-session", new ResumeSessionConfig
+ {
+ ClientName = "advanced-resume-client",
+ Model = "claude-haiku-4.5",
+ ReasoningEffort = "low",
+ ReasoningSummary = ReasoningSummary.None,
+ ContextTier = ContextTier.Default,
+ SuppressResumeEvent = true,
+ ContinuePendingWork = true,
+ McpOAuthTokenStorage = McpOAuthTokenStorageMode.Persistent,
+ PluginDirectories = ["plugins-resume"],
+ LargeOutput = new LargeToolOutputConfig
+ {
+ Enabled = false,
+ MaxSizeBytes = 2048,
+ OutputDirectory = outputDirectory,
+ },
+ Memory = new MemoryConfiguration { Enabled = false },
+ RemoteSession = GitHub.Copilot.Rpc.RemoteSessionMode.On,
+ OpenCanvases =
+ [
+ new GitHub.Copilot.Rpc.OpenCanvasInstance
+ {
+ CanvasId = "resume-canvas",
+ ExtensionId = "dotnet-sdk-tests/resume-extension",
+ ExtensionName = "Resume Extension",
+ InstanceId = "resume-canvas-1",
+ Input = canvasInput.RootElement.Clone(),
+ Status = "ready",
+ Title = "Resume Canvas",
+ Url = "https://example.com/resume-canvas",
+ },
+ ],
+ OnPermissionRequest = PermissionHandler.ApproveAll,
+ });
+
+ using var capture = JsonDocument.Parse(await File.ReadAllTextAsync(capturePath));
+ var resumeRequest = GetCapturedRequestParams(capture.RootElement, "session.resume");
+ Assert.Equal("advanced-resume-session", resumeRequest.GetProperty("sessionId").GetString());
+ Assert.Equal("advanced-resume-client", resumeRequest.GetProperty("clientName").GetString());
+ Assert.Equal("claude-haiku-4.5", resumeRequest.GetProperty("model").GetString());
+ Assert.Equal("low", resumeRequest.GetProperty("reasoningEffort").GetString());
+ Assert.Equal("none", resumeRequest.GetProperty("reasoningSummary").GetString());
+ Assert.Equal("default", resumeRequest.GetProperty("contextTier").GetString());
+ Assert.True(resumeRequest.GetProperty("disableResume").GetBoolean());
+ Assert.True(resumeRequest.GetProperty("continuePendingWork").GetBoolean());
+ Assert.Equal("persistent", resumeRequest.GetProperty("mcpOAuthTokenStorage").GetString());
+ Assert.Equal("plugins-resume", resumeRequest.GetProperty("pluginDirectories")[0].GetString());
+ Assert.False(resumeRequest.GetProperty("largeOutput").GetProperty("enabled").GetBoolean());
+ Assert.Equal(2048, resumeRequest.GetProperty("largeOutput").GetProperty("maxSizeBytes").GetInt64());
+ Assert.Equal(outputDirectory, resumeRequest.GetProperty("largeOutput").GetProperty("outputDir").GetString());
+ Assert.False(resumeRequest.GetProperty("memory").GetProperty("enabled").GetBoolean());
+ Assert.Equal("on", resumeRequest.GetProperty("remoteSession").GetString());
+
+ var openCanvas = resumeRequest.GetProperty("openCanvases")[0];
+ Assert.Equal("resume-canvas", openCanvas.GetProperty("canvasId").GetString());
+ Assert.Equal("dotnet-sdk-tests/resume-extension", openCanvas.GetProperty("extensionId").GetString());
+ Assert.Equal("Resume Extension", openCanvas.GetProperty("extensionName").GetString());
+ Assert.Equal("resume-canvas-1", openCanvas.GetProperty("instanceId").GetString());
+ Assert.Equal(41, openCanvas.GetProperty("input").GetProperty("start").GetInt32());
+ Assert.Equal("ready", openCanvas.GetProperty("status").GetString());
+ Assert.Equal("Resume Canvas", openCanvas.GetProperty("title").GetString());
+ Assert.Equal("https://example.com/resume-canvas", openCanvas.GetProperty("url").GetString());
+
+ await session.DisposeAsync();
+ }
+
[Fact]
public async Task Should_Apply_Empty_Mode_Defaults_To_ResumeSession_Wire_Request()
{
diff --git a/dotnet/test/E2E/CopilotRequestE2EProvider.cs b/dotnet/test/E2E/CopilotRequestE2EProvider.cs
index e8e483556..bade5c6e5 100644
--- a/dotnet/test/E2E/CopilotRequestE2EProvider.cs
+++ b/dotnet/test/E2E/CopilotRequestE2EProvider.cs
@@ -96,7 +96,9 @@ private static HttpResponseMessage BuildInferenceResponse(string url, string bod
if (u.EndsWith("/messages", StringComparison.Ordinal))
{
- return Json(BufferedAnthropicMessageJson);
+ return wantsStream
+ ? Sse(string.Concat(AnthropicStreamEvents))
+ : Json(BufferedAnthropicMessageJson);
}
// /chat/completions non-streaming (and any other inference url) — buffered JSON.
@@ -158,6 +160,20 @@ internal static HttpResponseMessage BuildNonInferenceResponse(string url)
"data: [DONE]\n\n",
];
+ // Anthropic Messages streaming (SSE) sequence. Emitted when the runtime issues a
+ // streaming /messages request (stream: true); the buffered JSON below is only valid
+ // for non-streaming requests, and returning it for a streaming request makes the
+ // runtime's Anthropic client fail with "stream ended without producing a Message".
+ private static readonly string[] AnthropicStreamEvents =
+ [
+ "event: message_start\ndata: {\"type\":\"message_start\",\"message\":{\"id\":\"msg_stub_1\",\"type\":\"message\",\"role\":\"assistant\",\"model\":\"claude-sonnet-4.5\",\"content\":[],\"stop_reason\":null,\"stop_sequence\":null,\"usage\":{\"input_tokens\":5,\"output_tokens\":1}}}\n\n",
+ "event: content_block_start\ndata: {\"type\":\"content_block_start\",\"index\":0,\"content_block\":{\"type\":\"text\",\"text\":\"\"}}\n\n",
+ "event: content_block_delta\ndata: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"" + SyntheticText + "\"}}\n\n",
+ "event: content_block_stop\ndata: {\"type\":\"content_block_stop\",\"index\":0}\n\n",
+ "event: message_delta\ndata: {\"type\":\"message_delta\",\"delta\":{\"stop_reason\":\"end_turn\",\"stop_sequence\":null},\"usage\":{\"output_tokens\":7}}\n\n",
+ "event: message_stop\ndata: {\"type\":\"message_stop\"}\n\n",
+ ];
+
private static readonly string BufferedResponseJson =
"{\"id\":\"resp_stub_1\",\"object\":\"response\",\"status\":\"completed\",\"output\":[{\"id\":\"msg_1\",\"type\":\"message\",\"role\":\"assistant\",\"content\":[{\"type\":\"output_text\",\"text\":\"" + SyntheticText + "\"}]}],\"usage\":{\"input_tokens\":5,\"output_tokens\":7,\"total_tokens\":12}}";
diff --git a/dotnet/test/E2E/CopilotRequestWebSocketE2ETests.cs b/dotnet/test/E2E/CopilotRequestWebSocketE2ETests.cs
index 464aadb66..9bb19df7d 100644
--- a/dotnet/test/E2E/CopilotRequestWebSocketE2ETests.cs
+++ b/dotnet/test/E2E/CopilotRequestWebSocketE2ETests.cs
@@ -51,8 +51,7 @@ public async Task Services_A_WebSocket_Turn_End_To_End_Via_The_Request_Handler()
{
Connection = RuntimeConnection.ForStdio(),
RequestHandler = handler,
- Environment = env,
- });
+ }, environment: env);
await client.StartAsync();
var session = await client.CreateSessionAsync(new SessionConfig
diff --git a/dotnet/test/E2E/GitHubTelemetryForwardingE2ETests.cs b/dotnet/test/E2E/GitHubTelemetryForwardingE2ETests.cs
new file mode 100644
index 000000000..343c4815b
--- /dev/null
+++ b/dotnet/test/E2E/GitHubTelemetryForwardingE2ETests.cs
@@ -0,0 +1,63 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ *--------------------------------------------------------------------------------------------*/
+
+using System.Collections.Concurrent;
+using GitHub.Copilot.Rpc;
+using GitHub.Copilot.Test.Harness;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace GitHub.Copilot.Test.E2E;
+
+#pragma warning disable GHCP001 // GitHub telemetry forwarding is experimental.
+
+public class GitHubTelemetryForwardingE2ETests(E2ETestFixture fixture, ITestOutputHelper output)
+ : E2ETestBase(fixture, "github_telemetry", output)
+{
+ [Fact]
+ public async Task Should_Forward_GitHub_Telemetry_For_A_Live_Session()
+ {
+ var notifications = new ConcurrentQueue();
+
+ await using var client = Ctx.CreateClient(options: new CopilotClientOptions
+ {
+ OnGitHubTelemetry = notification =>
+ {
+ notifications.Enqueue(notification);
+ return Task.CompletedTask;
+ },
+ });
+
+ CopilotSession? session = null;
+ try
+ {
+ session = await client.CreateSessionAsync(new SessionConfig
+ {
+ OnPermissionRequest = PermissionHandler.ApproveAll,
+ });
+
+ await TestHelper.WaitForConditionAsync(
+ () => !notifications.IsEmpty,
+ timeout: TimeSpan.FromSeconds(30),
+ timeoutMessage: "Timed out waiting for GitHub telemetry notification.");
+
+ Assert.True(notifications.TryPeek(out var notification));
+ Assert.False(string.IsNullOrEmpty(notification.SessionId));
+ Assert.NotNull(notification.Event);
+ Assert.NotEmpty(notification.Event.Kind);
+ Assert.IsType(notification.Restricted);
+ }
+ finally
+ {
+ if (session is not null)
+ {
+ await session.DisposeAsync();
+ }
+
+ await client.StopAsync();
+ }
+ }
+}
+
+#pragma warning restore GHCP001
diff --git a/dotnet/test/E2E/McpOAuthE2ETests.cs b/dotnet/test/E2E/McpOAuthE2ETests.cs
index 417b7ad1b..f101bbc31 100644
--- a/dotnet/test/E2E/McpOAuthE2ETests.cs
+++ b/dotnet/test/E2E/McpOAuthE2ETests.cs
@@ -70,6 +70,57 @@ public async Task Should_Satisfy_MCP_OAuth_Using_Host_Provided_Token()
Assert.Contains(requests, request => request.Authorization == $"Bearer {ExpectedToken}");
}
+ [Fact]
+ public async Task Should_Resolve_Pending_MCP_OAuth_Request_With_Direct_Rpc()
+ {
+ await using var oauthServer = await OAuthMcpServer.StartAsync(ExpectedToken);
+ var serverName = "oauth-direct-rpc-mcp";
+ var authRequest = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
+ var releaseHandler = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
+
+ await using var session = await CreateSessionAsync(new SessionConfig
+ {
+ OnMcpAuthRequest = request =>
+ {
+ authRequest.TrySetResult(request);
+ return releaseHandler.Task;
+ },
+ McpServers = new Dictionary
+ {
+ [serverName] = new McpHttpServerConfig
+ {
+ Url = $"{oauthServer.Url}/mcp",
+ Tools = ["*"],
+ },
+ },
+ });
+
+ var connected = WaitForMcpServerStatusAsync(session, serverName, McpServerStatus.Connected);
+ var request = await authRequest.Task.WaitAsync(TimeSpan.FromSeconds(30));
+ Assert.NotEmpty(request.RequestId);
+ Assert.Equal(serverName, request.ServerName);
+ Assert.Equal($"{oauthServer.Url}/mcp", request.ServerUrl);
+ Assert.Equal(McpOauthRequestReason.Initial, request.Reason);
+ Assert.NotNull(request.WwwAuthenticateParams);
+ Assert.Equal("mcp.read", request.WwwAuthenticateParams!.Scope);
+
+ var handled = await session.Rpc.Mcp.Oauth.HandlePendingRequestAsync(
+ request.RequestId,
+ new McpOauthPendingRequestResponseToken
+ {
+ AccessToken = ExpectedToken,
+ TokenType = "Bearer",
+ ExpiresIn = 3600,
+ });
+ Assert.True(handled.Success);
+
+ await connected;
+ var tools = await session.Rpc.Mcp.ListToolsAsync(serverName);
+ Assert.Contains(tools.Tools, tool => tool.Name == "whoami");
+
+ releaseHandler.SetResult(McpAuthResult.FromToken(new McpAuthToken { AccessToken = ExpectedToken }));
+ }
+
[Fact]
public async Task Should_Request_Replacement_Tokens_Across_MCP_OAuth_Lifecycle()
{
@@ -172,7 +223,7 @@ public async Task Should_Cancel_Pending_MCP_OAuth_Request()
}
});
- await WaitForMcpServerStatusAsync(session, serverName, McpServerStatus.Failed);
+ await WaitForMcpServerStatusAsync(session, serverName, McpServerStatus.NeedsAuth);
Assert.NotNull(observedRequest);
Assert.NotEmpty(observedRequest!.RequestId);
diff --git a/dotnet/test/E2E/ModeHandlersE2ETests.cs b/dotnet/test/E2E/ModeHandlersE2ETests.cs
index 40552fa9f..a397999f7 100644
--- a/dotnet/test/E2E/ModeHandlersE2ETests.cs
+++ b/dotnet/test/E2E/ModeHandlersE2ETests.cs
@@ -155,7 +155,7 @@ private CopilotClient CreateAuthenticatedClient()
["COPILOT_DEBUG_GITHUB_API_URL"] = Ctx.ProxyUrl,
};
- return Ctx.CreateClient(options: new CopilotClientOptions { Environment = env });
+ return Ctx.CreateClient(environment: env);
}
private Task ConfigureAuthenticatedUserAsync()
diff --git a/dotnet/test/E2E/PerSessionAuthE2ETests.cs b/dotnet/test/E2E/PerSessionAuthE2ETests.cs
index 7e104b33d..d1226f373 100644
--- a/dotnet/test/E2E/PerSessionAuthE2ETests.cs
+++ b/dotnet/test/E2E/PerSessionAuthE2ETests.cs
@@ -22,7 +22,7 @@ private CopilotClient CreateAuthTestClient()
};
// Disable the harness's auto-injected client token so the per-session
// auth tests validate only session-scoped tokens.
- return Ctx.CreateClient(options: new CopilotClientOptions { Environment = env }, autoInjectGitHubToken: false);
+ return Ctx.CreateClient(environment: env, autoInjectGitHubToken: false);
}
private CopilotClient CreateNoAuthTestClient()
@@ -32,9 +32,8 @@ private CopilotClient CreateNoAuthTestClient()
return Ctx.CreateClient(options: new CopilotClientOptions
{
- Environment = env,
UseLoggedInUser = false,
- }, autoInjectGitHubToken: false);
+ }, autoInjectGitHubToken: false, environment: env);
}
private static Dictionary WithoutAuthEnv(Dictionary env)
diff --git a/dotnet/test/E2E/ProviderEndpointE2ETests.cs b/dotnet/test/E2E/ProviderEndpointE2ETests.cs
index f7e9a7885..7ea4eecf3 100644
--- a/dotnet/test/E2E/ProviderEndpointE2ETests.cs
+++ b/dotnet/test/E2E/ProviderEndpointE2ETests.cs
@@ -23,7 +23,7 @@ private CopilotClient CreateProviderEndpointClient()
{
["COPILOT_ALLOW_GET_PROVIDER_ENDPOINT"] = "true",
};
- return Ctx.CreateClient(options: new CopilotClientOptions { Environment = env });
+ return Ctx.CreateClient(environment: env);
}
[Fact]
diff --git a/dotnet/test/E2E/RpcExtensionsLoadedE2ETests.cs b/dotnet/test/E2E/RpcExtensionsLoadedE2ETests.cs
index c1e43b09e..af959bd7e 100644
--- a/dotnet/test/E2E/RpcExtensionsLoadedE2ETests.cs
+++ b/dotnet/test/E2E/RpcExtensionsLoadedE2ETests.cs
@@ -58,8 +58,7 @@ private CopilotClient CreateExtensionsClient()
return Ctx.CreateClient(options: new CopilotClientOptions
{
Connection = RuntimeConnection.ForStdio(args: ["--yolo"]),
- Environment = ExtensionsEnabledEnvironment(),
- });
+ }, environment: ExtensionsEnabledEnvironment());
}
///
diff --git a/dotnet/test/E2E/RpcMcpAndSkillsE2ETests.cs b/dotnet/test/E2E/RpcMcpAndSkillsE2ETests.cs
index d53f93c9a..350aac427 100644
--- a/dotnet/test/E2E/RpcMcpAndSkillsE2ETests.cs
+++ b/dotnet/test/E2E/RpcMcpAndSkillsE2ETests.cs
@@ -398,10 +398,7 @@ private CopilotClient CreateMcpAppsClient()
environment["COPILOT_MCP_APPS"] = "true";
environment["MCP_APPS"] = "true";
- return Ctx.CreateClient(options: new CopilotClientOptions
- {
- Environment = environment,
- });
+ return Ctx.CreateClient(environment: environment);
}
private static void CreateSkill(string skillsDir, string skillName, string description)
diff --git a/dotnet/test/E2E/RpcServerE2ETests.cs b/dotnet/test/E2E/RpcServerE2ETests.cs
index da4a360dd..47df25615 100644
--- a/dotnet/test/E2E/RpcServerE2ETests.cs
+++ b/dotnet/test/E2E/RpcServerE2ETests.cs
@@ -37,9 +37,8 @@ private CopilotClient CreateAuthenticatedClient(string token)
return Ctx.CreateClient(options: new CopilotClientOptions
{
- Environment = env,
GitHubToken = token,
- });
+ }, environment: env);
}
private async Task ConfigureAuthenticatedUserAsync(
@@ -126,6 +125,40 @@ public async Task Should_Call_Rpc_Ping_With_Typed_Params_And_Result()
Assert.NotEqual(default, result.Timestamp);
}
+ [Fact]
+ public async Task Should_Reject_Llm_Inference_Response_Frames_For_Missing_Request()
+ {
+ await Client.StartAsync();
+
+ var start = await Client.Rpc.LlmInference.HttpResponseStartAsync(
+ requestId: "missing-llm-inference-request",
+ status: 200,
+ headers: new Dictionary>
+ {
+ ["content-type"] = ["text/event-stream"],
+ },
+ statusText: "OK");
+ Assert.False(start.Accepted);
+
+ var chunk = await Client.Rpc.LlmInference.HttpResponseChunkAsync(
+ requestId: "missing-llm-inference-request",
+ data: "data: {}\n\n",
+ binary: false,
+ end: false);
+ Assert.False(chunk.Accepted);
+
+ var error = await Client.Rpc.LlmInference.HttpResponseChunkAsync(
+ requestId: "missing-llm-inference-request",
+ data: string.Empty,
+ end: true,
+ error: new GitHub.Copilot.Rpc.LlmInferenceHttpResponseChunkError
+ {
+ Code = "missing_request",
+ Message = "No pending LLM inference request.",
+ });
+ Assert.False(error.Accepted);
+ }
+
[Fact]
public async Task Should_Call_Rpc_Models_List_With_Typed_Result()
{
@@ -203,10 +236,7 @@ public async Task Should_Add_Secret_Filter_Values()
{
var environment = Ctx.GetEnvironment();
environment["COPILOT_ENABLE_SECRET_FILTERING"] = "true";
- await using var client = Ctx.CreateClient(options: new CopilotClientOptions
- {
- Environment = environment,
- });
+ await using var client = Ctx.CreateClient(environment: environment);
await client.StartAsync();
var secret = $"rpc-secret-{Guid.NewGuid():N}";
@@ -347,7 +377,7 @@ public async Task Should_Check_In_Use_Session_From_Another_Runtime_And_Release_L
{
var sessionId = Guid.NewGuid().ToString();
var workingDirectory = CreateUniqueWorkDirectory("server-rpc-in-use");
- await using var otherClient = Ctx.CreateClient(useStdio: true);
+ await using var otherClient = Ctx.CreateClient(options: new CopilotClientOptions { Connection = RuntimeConnection.ForStdio() });
await using var otherSession = await otherClient.CreateSessionAsync(new SessionConfig
{
SessionId = sessionId,
@@ -493,6 +523,44 @@ public async Task Should_Discover_Server_Mcp_And_Skills()
Assert.True(discoveredSkill.Enabled);
Assert.EndsWith(Path.Join(skillName, "SKILL.md"), discoveredSkill.Path);
+ var skillPaths = await Client.Rpc.Skills.GetDiscoveryPathsAsync(
+ projectPaths: [Ctx.WorkDir],
+ excludeHostSkills: true);
+ var projectSkillPath = Assert.Single(skillPaths.Paths, path =>
+ PathEquals(Ctx.WorkDir, path.ProjectPath) && path.PreferredForCreation);
+ Assert.False(string.IsNullOrWhiteSpace(projectSkillPath.Path));
+
+ var agents = await Client.Rpc.Agents.DiscoverAsync(
+ projectPaths: [Ctx.WorkDir],
+ excludeHostAgents: true);
+ Assert.NotNull(agents.Agents);
+ Assert.All(agents.Agents, agent => Assert.False(string.IsNullOrWhiteSpace(agent.Name)));
+
+ var agentPaths = await Client.Rpc.Agents.GetDiscoveryPathsAsync(
+ projectPaths: [Ctx.WorkDir],
+ excludeHostAgents: true);
+ var projectAgentPath = Assert.Single(agentPaths.Paths, path =>
+ PathEquals(Ctx.WorkDir, path.ProjectPath) && path.PreferredForCreation);
+ Assert.False(string.IsNullOrWhiteSpace(projectAgentPath.Path));
+
+ var instructions = await Client.Rpc.Instructions.DiscoverAsync(
+ projectPaths: [Ctx.WorkDir],
+ excludeHostInstructions: true);
+ Assert.NotNull(instructions.Sources);
+ Assert.All(instructions.Sources, source =>
+ {
+ Assert.False(string.IsNullOrWhiteSpace(source.Id));
+ Assert.False(string.IsNullOrWhiteSpace(source.Label));
+ Assert.False(string.IsNullOrWhiteSpace(source.SourcePath));
+ });
+
+ var instructionPaths = await Client.Rpc.Instructions.GetDiscoveryPathsAsync(
+ projectPaths: [Ctx.WorkDir],
+ excludeHostInstructions: true);
+ Assert.NotEmpty(instructionPaths.Paths);
+ Assert.Contains(instructionPaths.Paths, path => PathEquals(Ctx.WorkDir, path.ProjectPath));
+ Assert.All(instructionPaths.Paths, path => Assert.False(string.IsNullOrWhiteSpace(path.Path)));
+
try
{
await Client.Rpc.Skills.Config.SetDisabledSkillsAsync([skillName]);
diff --git a/dotnet/test/E2E/RpcServerMiscE2ETests.cs b/dotnet/test/E2E/RpcServerMiscE2ETests.cs
index 6d04a35f8..29e560100 100644
--- a/dotnet/test/E2E/RpcServerMiscE2ETests.cs
+++ b/dotnet/test/E2E/RpcServerMiscE2ETests.cs
@@ -4,14 +4,15 @@
using GitHub.Copilot;
using GitHub.Copilot.Rpc;
+using GitHub.Copilot.Test.Harness;
using Xunit;
using Xunit.Abstractions;
namespace GitHub.Copilot.Test.E2E;
///
-/// E2E coverage for the remaining miscellaneous server-scoped RPC methods that were previously
-/// untested: user.settings.reload, agentRegistry.spawn, runtime.shutdown, sessions.open, and the
+/// E2E coverage for miscellaneous server-scoped RPC methods, including account auth state,
+/// user.settings get/set/reload, agentRegistry.spawn, runtime.shutdown, sessions.open, and the
/// session-scoped session.extensions.sendAttachmentsToMessage.
///
/// Several of these are intentionally exercised at the wiring/guard boundary because the meaningful
@@ -32,6 +33,97 @@ public async Task Should_Reload_User_Settings()
await Client.Rpc.User.Settings.ReloadAsync();
}
+ [Fact]
+ public async Task Should_Get_Set_And_Clear_User_Settings()
+ {
+ await Client.StartAsync();
+
+ var before = await Client.Rpc.User.Settings.GetAsync();
+ Assert.NotNull(before.Settings);
+ Assert.NotEmpty(before.Settings);
+ Assert.All(before.Settings, setting =>
+ {
+ Assert.False(string.IsNullOrWhiteSpace(setting.Key));
+ Assert.True(
+ setting.Value.Value.ValueKind != System.Text.Json.JsonValueKind.Undefined
+ || setting.Value.Default.ValueKind != System.Text.Json.JsonValueKind.Undefined,
+ $"Setting '{setting.Key}' should expose either a value or a default.");
+ });
+
+ var settingToToggle = before.Settings.First(setting =>
+ setting.Value.Value.ValueKind is System.Text.Json.JsonValueKind.True or System.Text.Json.JsonValueKind.False);
+ var settingKey = settingToToggle.Key;
+ var toggledValue = settingToToggle.Value.Value.ValueKind != System.Text.Json.JsonValueKind.True;
+
+ var set = await Client.Rpc.User.Settings.SetAsync(ParseSettingJson(settingKey, toggledValue ? "true" : "false"));
+ Assert.NotNull(set.ShadowedKeys);
+ Assert.DoesNotContain(settingKey, set.ShadowedKeys);
+
+ await Client.Rpc.User.Settings.ReloadAsync();
+ var afterSet = await Client.Rpc.User.Settings.GetAsync();
+ var updatedSetting = Assert.Contains(settingKey, afterSet.Settings);
+ Assert.False(updatedSetting.IsDefault);
+ Assert.Equal(toggledValue, updatedSetting.Value.GetBoolean());
+
+ var clear = await Client.Rpc.User.Settings.SetAsync(ParseSettingJson(settingKey, "null"));
+ Assert.NotNull(clear.ShadowedKeys);
+
+ await Client.Rpc.User.Settings.ReloadAsync();
+ var afterClear = await Client.Rpc.User.Settings.GetAsync();
+ var clearedSetting = Assert.Contains(settingKey, afterClear.Settings);
+ Assert.True(clearedSetting.IsDefault);
+ }
+
+ [Fact]
+ public async Task Should_Login_List_GetCurrentAuth_And_Logout_Account()
+ {
+ var (client, home) = await CreateIsolatedClientAsync(autoInjectGitHubToken: false);
+ var login = $"rpc-account-{Guid.NewGuid():N}";
+ var token = $"rpc-account-token-{Guid.NewGuid():N}";
+
+ try
+ {
+ await Ctx.SetCopilotUserByTokenAsync(token, new CopilotUserConfig(
+ Login: login,
+ CopilotPlan: "individual_pro",
+ Endpoints: new CopilotUserEndpoints(Api: Ctx.ProxyUrl, Telemetry: "https://localhost:1/telemetry"),
+ AnalyticsTrackingId: "rpc-account-tracking-id"));
+
+ var initial = await client.Rpc.Account.GetCurrentAuthAsync();
+ Assert.Null(initial.AuthInfo);
+
+ var loginResult = await client.Rpc.Account.LoginAsync("https://github.com", login, token);
+ Assert.NotNull(loginResult);
+
+ var current = await client.Rpc.Account.GetCurrentAuthAsync();
+ Assert.Null(current.AuthErrors);
+ var authInfo = Assert.IsType(current.AuthInfo);
+ Assert.Equal("https://github.com", authInfo.Host);
+ Assert.Equal(login, authInfo.Login);
+
+ var users = await client.Rpc.Account.GetAllUsersAsync();
+ Assert.All(users, user => Assert.False(string.IsNullOrWhiteSpace(user.AuthInfo.Type)));
+ var account = users.FirstOrDefault(user =>
+ user.AuthInfo is AuthInfoUser userAuth
+ && string.Equals(userAuth.Login, login, StringComparison.Ordinal));
+ if (account is not null)
+ {
+ Assert.Equal(token, account.Token);
+ }
+
+ var logout = await client.Rpc.Account.LogoutAsync(authInfo);
+ Assert.False(logout.HasMoreUsers);
+
+ var afterLogout = await client.Rpc.Account.GetCurrentAuthAsync();
+ Assert.Null(afterLogout.AuthInfo);
+ }
+ finally
+ {
+ await client.DisposeAsync();
+ TryDeleteDirectory(home);
+ }
+ }
+
[Fact]
public async Task Should_Report_Agent_Registry_Spawn_Gate_Closed()
{
@@ -74,7 +166,7 @@ await Harness.TestHelper.WaitForConditionAsync(
async () =>
{
try { await client.Rpc.User.Settings.ReloadAsync(); return false; }
- catch { return true; }
+ catch (Exception ex) when (IsExpectedShutdownException(ex)) { return true; }
},
timeout: TimeSpan.FromSeconds(15),
pollInterval: TimeSpan.FromMilliseconds(100),
@@ -82,8 +174,7 @@ await Harness.TestHelper.WaitForConditionAsync(
}
finally
{
- try { await client.DisposeAsync(); }
- catch { /* process is already gone after shutdown */ }
+ await DisposeStoppedRuntimeClientAsync(client);
}
}
@@ -103,7 +194,7 @@ public async Task Should_Report_Not_Found_When_Opening_Session_Without_Context()
}
finally
{
- try { await client.DisposeAsync(); } catch { /* best-effort */ }
+ await client.DisposeAsync();
TryDeleteDirectory(home);
}
}
@@ -127,7 +218,8 @@ public async Task Should_Reject_Send_Attachments_From_Non_Extension_Connection()
/// Creates a started client backed by a throwaway COPILOT_HOME so its session store is empty and
/// independent of every other test and of the shared fixture client.
///
- private async Task<(CopilotClient Client, string Home)> CreateIsolatedClientAsync()
+ private async Task<(CopilotClient Client, string Home)> CreateIsolatedClientAsync(
+ bool autoInjectGitHubToken = true)
{
var home = Path.Combine(Path.GetTempPath(), "copilot-e2e-misc-home-" + Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(home);
@@ -137,8 +229,22 @@ public async Task Should_Reject_Send_Attachments_From_Non_Extension_Connection()
env["GH_CONFIG_DIR"] = home;
env["XDG_CONFIG_HOME"] = home;
env["XDG_STATE_HOME"] = home;
+ if (!autoInjectGitHubToken)
+ {
+ env["GH_TOKEN"] = "";
+ env["GITHUB_TOKEN"] = "";
+ }
+
+ var options = new CopilotClientOptions();
+ if (!autoInjectGitHubToken)
+ {
+ options.UseLoggedInUser = false;
+ }
- var client = Ctx.CreateClient(options: new CopilotClientOptions { Environment = env });
+ var client = Ctx.CreateClient(
+ options: options,
+ autoInjectGitHubToken: autoInjectGitHubToken,
+ environment: env);
await client.StartAsync();
return (client, home);
}
@@ -152,9 +258,36 @@ private static void TryDeleteDirectory(string path)
Directory.Delete(path, recursive: true);
}
}
- catch
+ catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
{
// Temp directories are reclaimed by the OS; ignore transient locks on cleanup.
}
}
+
+ private static async Task DisposeStoppedRuntimeClientAsync(CopilotClient client)
+ {
+ try
+ {
+ await client.DisposeAsync();
+ }
+ catch (Exception ex) when (IsExpectedShutdownException(ex))
+ {
+ // The runtime.shutdown test intentionally stops the process before disposal.
+ }
+ }
+
+ private static bool IsExpectedShutdownException(Exception ex) =>
+ ex is OperationCanceledException
+ or InvalidOperationException
+ or ObjectDisposedException
+ or IOException;
+
+ private static System.Text.Json.JsonElement ParseJsonElement(string json)
+ {
+ using var document = System.Text.Json.JsonDocument.Parse(json);
+ return document.RootElement.Clone();
+ }
+
+ private static System.Text.Json.JsonElement ParseSettingJson(string key, string valueLiteral)
+ => ParseJsonElement("{\"" + System.Text.Json.JsonEncodedText.Encode(key) + "\":" + valueLiteral + "}");
}
diff --git a/dotnet/test/E2E/RpcServerPluginsE2ETests.cs b/dotnet/test/E2E/RpcServerPluginsE2ETests.cs
index eea409593..64a0f1c26 100644
--- a/dotnet/test/E2E/RpcServerPluginsE2ETests.cs
+++ b/dotnet/test/E2E/RpcServerPluginsE2ETests.cs
@@ -302,7 +302,7 @@ This skill exists so the plugin reports at least one installed skill.
env["XDG_CONFIG_HOME"] = home;
env["XDG_STATE_HOME"] = home;
- var client = Ctx.CreateClient(options: new CopilotClientOptions { Environment = env });
+ var client = Ctx.CreateClient(environment: env);
await client.StartAsync();
return (client, home);
}
diff --git a/dotnet/test/E2E/RpcSessionStateExtrasE2ETests.cs b/dotnet/test/E2E/RpcSessionStateExtrasE2ETests.cs
index 5b1ce1484..f3f3d5d5d 100644
--- a/dotnet/test/E2E/RpcSessionStateExtrasE2ETests.cs
+++ b/dotnet/test/E2E/RpcSessionStateExtrasE2ETests.cs
@@ -11,8 +11,10 @@ namespace GitHub.Copilot.Test.E2E;
///
/// E2E coverage for session-scoped RPC methods that were previously untested:
-/// model.list, metadata.activity, permissions.getAllowAll/setAllowAll, plan.readSqlTodos,
-/// telemetry.getEngagementId, tools.getCurrentMetadata, and the session-scoped plugins.reload.
+/// completions, model.list, metadata.activity/context attribution/heaviest messages,
+/// permissions.getAllowAll/setAllowAll, plan.readSqlTodos, provider.add,
+/// telemetry.getEngagementId, tools.getCurrentMetadata/updateSubagentSettings,
+/// session visibility, and the session-scoped plugins.reload.
///
public class RpcSessionStateExtrasE2ETests(E2ETestFixture fixture, ITestOutputHelper output)
: E2ETestBase(fixture, "rpc_session_state_extras", output)
@@ -41,6 +43,69 @@ public async Task Should_List_Models_For_Session()
Assert.Contains(result.List, model => model.GetRawText().Contains("claude-sonnet-4.5", StringComparison.Ordinal));
}
+ [Fact]
+ public async Task Should_Add_Byok_Provider_And_Model_At_Runtime()
+ {
+ await using var session = await CreateSessionAsync();
+ var providerName = $"sdk-runtime-provider-{Guid.NewGuid():N}";
+ var modelId = "sdk-runtime-model";
+ var selectionId = $"{providerName}/{modelId}";
+
+ var added = await session.Rpc.Provider.AddAsync(
+ providers:
+ [
+ new GitHub.Copilot.Rpc.NamedProviderConfig
+ {
+ Name = providerName,
+ Type = ProviderConfigType.Openai,
+ WireApi = ProviderConfigWireApi.Completions,
+ BaseUrl = "https://api.example.test/v1",
+ ApiKey = "runtime-provider-secret",
+ Headers = new Dictionary { ["X-SDK-Provider"] = "runtime" },
+ },
+ ],
+ models:
+ [
+ new GitHub.Copilot.Rpc.ProviderModelConfig
+ {
+ Provider = providerName,
+ Id = modelId,
+ Name = "SDK Runtime Model",
+ ModelId = "claude-sonnet-4.5",
+ WireModel = "wire-sdk-runtime-model",
+ MaxContextWindowTokens = 4_096,
+ MaxPromptTokens = 3_072,
+ MaxOutputTokens = 1_024,
+ Capabilities = new GitHub.Copilot.Rpc.ModelCapabilitiesOverride
+ {
+ Limits = new GitHub.Copilot.Rpc.ModelCapabilitiesOverrideLimits
+ {
+ MaxContextWindowTokens = 4_096,
+ MaxPromptTokens = 3_072,
+ MaxOutputTokens = 1_024,
+ },
+ Supports = new GitHub.Copilot.Rpc.ModelCapabilitiesOverrideSupports
+ {
+ ReasoningEffort = false,
+ Vision = false,
+ },
+ },
+ },
+ ]);
+
+ var addedModel = Assert.Single(added.Models);
+ var addedModelJson = addedModel.GetRawText();
+ Assert.Contains(selectionId, addedModelJson, StringComparison.Ordinal);
+ Assert.Contains("SDK Runtime Model", addedModelJson, StringComparison.Ordinal);
+
+ var listed = await session.Rpc.Model.ListAsync();
+ Assert.Contains(listed.List, model => model.GetRawText().Contains(selectionId, StringComparison.Ordinal));
+
+ var switched = await session.Rpc.Model.SwitchToAsync(selectionId);
+ Assert.Equal(selectionId, switched.ModelId);
+ Assert.Equal(selectionId, (await session.Rpc.Model.GetCurrentAsync()).ModelId);
+ }
+
[Fact]
public async Task Should_Report_Session_Activity_When_Idle()
{
@@ -54,6 +119,36 @@ public async Task Should_Report_Session_Activity_When_Idle()
Assert.False(activity.Abortable, "Expected a freshly created session to have nothing abortable.");
}
+ [Fact]
+ public async Task Should_Return_Empty_Completions_When_Host_Does_Not_Provide_Them()
+ {
+ await using var session = await CreateSessionAsync();
+
+ var triggers = await session.Rpc.Completions.GetTriggerCharactersAsync();
+ Assert.NotNull(triggers.TriggerCharacters);
+ Assert.Empty(triggers.TriggerCharacters);
+
+ var completions = await session.Rpc.Completions.RequestAsync("Use @", offset: 5);
+ Assert.NotNull(completions.Items);
+ Assert.Empty(completions.Items);
+ }
+
+ [Fact]
+ public async Task Should_Report_Visibility_As_Unsynced_For_Local_Session()
+ {
+ await using var session = await CreateSessionAsync();
+
+ var initial = await session.Rpc.Visibility.GetAsync();
+ Assert.False(initial.Synced);
+ Assert.Null(initial.Status);
+ Assert.Null(initial.ShareUrl);
+
+ var set = await session.Rpc.Visibility.SetAsync(SessionVisibilityStatus.Repo);
+ Assert.False(set.Synced);
+ Assert.Null(set.Status);
+ Assert.Null(set.ShareUrl);
+ }
+
[Fact]
public async Task Should_Get_And_Set_AllowAll_Permissions()
{
@@ -64,19 +159,19 @@ public async Task Should_Get_And_Set_AllowAll_Permissions()
var initial = await session.Rpc.Permissions.GetAllowAllAsync();
Assert.False(initial.Enabled, "Allow-all should be disabled on a fresh session.");
- var enable = await session.Rpc.Permissions.SetAllowAllAsync(true);
+ var enable = await session.Rpc.Permissions.SetAllowAllAsync(enabled: true);
Assert.True(enable.Success);
Assert.True(enable.Enabled);
Assert.True((await session.Rpc.Permissions.GetAllowAllAsync()).Enabled);
- var disable = await session.Rpc.Permissions.SetAllowAllAsync(false);
+ var disable = await session.Rpc.Permissions.SetAllowAllAsync(enabled: false);
Assert.True(disable.Success);
Assert.False(disable.Enabled);
Assert.False((await session.Rpc.Permissions.GetAllowAllAsync()).Enabled);
}
finally
{
- await session.Rpc.Permissions.SetAllowAllAsync(false);
+ await session.Rpc.Permissions.SetAllowAllAsync(enabled: false);
}
}
@@ -127,6 +222,74 @@ public async Task Should_Get_Current_Tool_Metadata_After_Initialization()
});
}
+ [Fact]
+ public async Task Should_Get_Context_Attribution_And_Heaviest_Messages_After_Turn()
+ {
+ await using var session = await CreateSessionAsync();
+
+ var answer = await session.SendAndWaitAsync(new MessageOptions
+ {
+ Prompt = "Say CONTEXT_METADATA_OK exactly.",
+ });
+ Assert.Contains("CONTEXT_METADATA_OK", answer?.Data.Content ?? string.Empty, StringComparison.Ordinal);
+
+ var attribution = await session.Rpc.Metadata.GetContextAttributionAsync();
+ var contextAttribution = Assert.IsType(
+ attribution.ContextAttribution);
+ Assert.True(contextAttribution.TotalTokens > 0);
+ Assert.True(contextAttribution.Compactions.Count >= 0);
+ Assert.NotEmpty(contextAttribution.Entries);
+ Assert.All(contextAttribution.Entries, entry =>
+ {
+ Assert.False(string.IsNullOrWhiteSpace(entry.Id));
+ Assert.False(string.IsNullOrWhiteSpace(entry.Kind));
+ Assert.False(string.IsNullOrWhiteSpace(entry.Label));
+ Assert.True(entry.Tokens >= 0);
+ if (entry.Attributes is not null)
+ {
+ Assert.All(entry.Attributes, attribute => Assert.False(string.IsNullOrWhiteSpace(attribute.Key)));
+ }
+ });
+
+ var heaviest = await session.Rpc.Metadata.GetContextHeaviestMessagesAsync(limit: 2);
+ Assert.True(heaviest.TotalTokens > 0);
+ Assert.NotNull(heaviest.Messages);
+ Assert.True(heaviest.Messages.Count <= 2);
+ Assert.All(heaviest.Messages, message =>
+ {
+ Assert.False(string.IsNullOrWhiteSpace(message.Id));
+ Assert.False(string.IsNullOrWhiteSpace(message.Label));
+ Assert.False(string.IsNullOrWhiteSpace(message.Role));
+ Assert.True(message.Tokens > 0);
+ });
+ }
+
+ [Fact]
+ public async Task Should_Update_And_Clear_Live_Subagent_Settings()
+ {
+ await using var session = await CreateSessionAsync();
+
+ var update = await session.Rpc.Tools.UpdateSubagentSettingsAsync(new UpdateSubagentSettingsRequestSubagents
+ {
+ Agents = new Dictionary
+ {
+ ["general-purpose"] = new()
+ {
+ Model = "claude-sonnet-4.5",
+ EffortLevel = "high",
+ ContextTier = SubagentSettingsEntryContextTier.Default,
+ },
+ },
+ DisabledSubagents = ["explore"],
+ MaxConcurrency = 2,
+ MaxDepth = 1,
+ });
+ Assert.NotNull(update);
+
+ var clear = await session.Rpc.Tools.UpdateSubagentSettingsAsync();
+ Assert.NotNull(clear);
+ }
+
[Fact]
public async Task Should_Reload_Session_Plugins()
{
@@ -150,9 +313,8 @@ private CopilotClient CreateAuthenticatedClient(string token)
return Ctx.CreateClient(options: new CopilotClientOptions
{
- Environment = env,
GitHubToken = token,
- });
+ }, environment: env);
}
private async Task ConfigureAuthenticatedUserAsync(string token)
diff --git a/dotnet/test/E2E/RpcTasksAndHandlersE2ETests.cs b/dotnet/test/E2E/RpcTasksAndHandlersE2ETests.cs
index fbb289297..9b9738a2e 100644
--- a/dotnet/test/E2E/RpcTasksAndHandlersE2ETests.cs
+++ b/dotnet/test/E2E/RpcTasksAndHandlersE2ETests.cs
@@ -209,6 +209,14 @@ public async Task Should_Return_Expected_Results_For_Missing_Pending_Handler_Req
response: UIAutoModeSwitchResponse.No);
Assert.False(autoModeSwitch.Success);
+ var sessionLimits = await session.Rpc.Ui.HandlePendingSessionLimitsExhaustedAsync(
+ requestId: "missing-session-limits-exhausted-request",
+ response: new UISessionLimitsExhaustedResponse
+ {
+ Action = UISessionLimitsExhaustedResponseAction.Cancel,
+ });
+ Assert.False(sessionLimits.Success);
+
var exitPlanMode = await session.Rpc.Ui.HandlePendingExitPlanModeAsync(
requestId: "missing-exit-plan-mode-request",
response: new UIExitPlanModeResponse
@@ -251,6 +259,19 @@ public async Task Should_Return_Expected_Results_For_Missing_Pending_Handler_Req
LocationKey = "missing-location",
});
Assert.False(locationApproval.Success);
+
+ var missingHeaders = await session.Rpc.Mcp.Headers.HandlePendingHeadersRefreshRequestAsync(
+ requestId: "missing-headers-refresh-request",
+ result: new McpHeadersHandlePendingHeadersRefreshRequestHeaders
+ {
+ Headers = new Dictionary { ["X-SDK-Test"] = "missing" },
+ });
+ Assert.False(missingHeaders.Success);
+
+ var missingNoHeaders = await session.Rpc.Mcp.Headers.HandlePendingHeadersRefreshRequestAsync(
+ requestId: "missing-headers-refresh-none-request",
+ result: new McpHeadersHandlePendingHeadersRefreshRequestNone());
+ Assert.False(missingNoHeaders.Success);
}
[Fact]
diff --git a/dotnet/test/E2E/SessionFsSqliteE2ETests.cs b/dotnet/test/E2E/SessionFsSqliteE2ETests.cs
index 1e6175f9c..bf7bdf3b5 100644
--- a/dotnet/test/E2E/SessionFsSqliteE2ETests.cs
+++ b/dotnet/test/E2E/SessionFsSqliteE2ETests.cs
@@ -117,9 +117,9 @@ await TestHelper.WaitForConditionAsync(
private CopilotClient CreateSessionFsClient()
{
return Ctx.CreateClient(
- useStdio: true,
options: new CopilotClientOptions
{
+ Connection = RuntimeConnection.ForStdio(),
SessionFs = SessionFsConfig,
});
}
diff --git a/dotnet/test/E2E/SubagentHooksE2ETests.cs b/dotnet/test/E2E/SubagentHooksE2ETests.cs
index 23ba8ed3a..4723c19b7 100644
--- a/dotnet/test/E2E/SubagentHooksE2ETests.cs
+++ b/dotnet/test/E2E/SubagentHooksE2ETests.cs
@@ -20,7 +20,7 @@ public async Task Should_Invoke_PreToolUse_And_PostToolUse_Hooks_For_Sub_Agent_T
// Create a client with the session-based subagents feature flag
var env = new Dictionary(Ctx.GetEnvironment());
env["COPILOT_EXP_COPILOT_CLI_SESSION_BASED_SUBAGENTS"] = "true";
- var client = Ctx.CreateClient(options: new CopilotClientOptions { Environment = env });
+ var client = Ctx.CreateClient(environment: env);
var session = await client.CreateSessionAsync(new SessionConfig
{
diff --git a/dotnet/test/E2E/TelemetryExportE2ETests.cs b/dotnet/test/E2E/TelemetryExportE2ETests.cs
index 22ed5663d..2dd9d591a 100644
--- a/dotnet/test/E2E/TelemetryExportE2ETests.cs
+++ b/dotnet/test/E2E/TelemetryExportE2ETests.cs
@@ -24,6 +24,7 @@ public async Task Should_Export_File_Telemetry_For_Sdk_Interactions()
await using var client = Ctx.CreateClient(options: new CopilotClientOptions
{
+ Connection = RuntimeConnection.ForStdio(),
Telemetry = new TelemetryConfig
{
FilePath = telemetryPath,
diff --git a/dotnet/test/Harness/E2ETestContext.cs b/dotnet/test/Harness/E2ETestContext.cs
index 6e26299a4..f4df1749f 100644
--- a/dotnet/test/Harness/E2ETestContext.cs
+++ b/dotnet/test/Harness/E2ETestContext.cs
@@ -216,6 +216,16 @@ public Dictionary GetEnvironment()
env["GITHUB_TOKEN"] = env["GH_TOKEN"] = DefaultGitHubToken;
+ // Disable HMAC auth for E2E runs. CI sets COPILOT_HMAC_KEY at the job
+ // level as an ambient credential, but the replay snapshots are captured
+ // against Bearer/OAuth (SDK-token) requests. In stdio the SDK token
+ // outranks HMAC so this is a no-op, but in-process auth resolution runs
+ // host-side in this process and would otherwise pick HMAC (which ranks
+ // above the GitHub token) and fail provider.getEndpoint. An empty value
+ // disables the method (runtime filters out empty HMAC keys).
+ env["COPILOT_HMAC_KEY"] = "";
+ env["CAPI_HMAC_KEY"] = "";
+
return env!;
}
@@ -227,41 +237,77 @@ public Dictionary GetEnvironment()
}
public CopilotClient CreateClient(
- bool? useStdio = null,
CopilotClientOptions? options = null,
bool autoInjectGitHubToken = true,
- bool persistent = false)
+ bool persistent = false,
+ IReadOnlyDictionary? environment = null)
{
options ??= new CopilotClientOptions();
options.WorkingDirectory ??= WorkDir;
- options.Environment ??= GetEnvironment();
options.Logger ??= Logger;
- // Build the connection. If the caller supplied one, just ensure the runtime path is set;
- // otherwise default to Stdio with the bundled runtime (matches CopilotClient's own default).
- // useStdio is a convenience shortcut for the no-Connection case; passing both is ambiguous.
- if (useStdio is not null && options.Connection is not null)
+ // Tests must supply environment via the 'environment' parameter, which the
+ // harness routes to the right place per transport (the connection for
+ // child-process transports, the host process for in-process). Setting
+ // options.Environment directly bypasses that routing and is unsupported
+ // in-process, so reject it here.
+ if (options.Environment is not null)
{
throw new ArgumentException(
- "Specify either useStdio or options.Connection, not both. " +
- "Use options.Connection (e.g. RuntimeConnection.ForStdio() / RuntimeConnection.ForTcp()) to control transport when supplying a Connection.",
- nameof(useStdio));
+ "Do not set options.Environment in E2E tests; pass the 'environment' parameter to CreateClient instead.",
+ nameof(options));
}
+ // The full environment the client runs with: harness defaults (proxy
+ // redirect, isolated home, cleared HMAC/tokens, etc.) unless the test
+ // supplied a complete replacement.
+ var env = environment is not null
+ ? environment.ToDictionary(kvp => kvp.Key, kvp => kvp.Value)
+ : GetEnvironment();
+
+ // When the test doesn't pin a transport, leave Connection null so
+ // CopilotClient honors COPILOT_SDK_DEFAULT_CONNECTION (stdio by default,
+ // or in-process); the CI matrix uses this to run the suite under both.
+ // Tests that need a specific transport set options.Connection directly.
var cliPath = GetCliPath(_repoRoot);
switch (options.Connection)
{
+ case null when !IsInProcess(null):
+ // No explicit connection and not the in-process default: the
+ // default resolves to stdio, so materialize it here so the
+ // environment can be attached to the connection below.
+ options.Connection = RuntimeConnection.ForStdio(path: cliPath);
+ break;
case null:
- options.Connection = useStdio == false
- ? RuntimeConnection.ForTcp(path: cliPath)
- : RuntimeConnection.ForStdio(path: cliPath);
+ // In-process default: leave Connection unset so CopilotClient's
+ // ResolveDefaultConnection honors COPILOT_SDK_DEFAULT_CONNECTION.
break;
case ChildProcessRuntimeConnection child when child.Path is null:
child.Path = cliPath;
break;
}
+ if (IsInProcess(options.Connection))
+ {
+ // In-process hosting: runtime code runs host-side in this process (the
+ // loaded cdylib) and reads the ambient process environment rather than
+ // the environment passed to copilot_runtime_host_start, so the per-test
+ // redirects, cleared tokens/HMAC, and isolated home must be mirrored
+ // onto this process's real environment. Restored after each test by
+ // InProcessEnvIsolationAttribute.
+ foreach (var (name, value) in env)
+ {
+ InProcessEnvIsolation.Apply(name, value);
+ }
+ }
+ else if (options.Connection is ChildProcessRuntimeConnection child)
+ {
+ // Child-process transport: hand the environment to the spawned child
+ // via the connection, where per-client environment is coherent.
+ child.Environment = env;
+ }
+
// Auto-inject auth token unless connecting to an existing runtime via URI.
var isExistingRuntime = options.Connection is UriRuntimeConnection;
if (autoInjectGitHubToken
@@ -312,7 +358,7 @@ public async Task CleanupAfterTestAsync()
{
try
{
- await client.ForceStopAsync();
+ await StopClientForCleanupAsync(client);
}
catch (Exception ex) when (IsTransientCleanupException(ex))
{
@@ -346,7 +392,7 @@ public async ValueTask DisposeAsync()
{
try
{
- await client.ForceStopAsync();
+ await StopClientForCleanupAsync(client);
}
catch (Exception ex) when (IsTransientCleanupException(ex))
{
@@ -408,6 +454,45 @@ private static async Task DeleteDirectoryAsync(string path)
}
}
+ ///
+ /// Determines whether the resolved transport is the in-process (FFI) host,
+ /// mirroring 's own default-connection resolution:
+ /// an explicit , or (when no connection
+ /// is given) the COPILOT_SDK_DEFAULT_CONNECTION=inprocess default.
+ ///
+ private static bool IsInProcess(RuntimeConnection? connection)
+ {
+ if (connection is InProcessRuntimeConnection)
+ {
+ return true;
+ }
+ if (connection is null)
+ {
+ return string.Equals(
+ Environment.GetEnvironmentVariable("COPILOT_SDK_DEFAULT_CONNECTION"),
+ "inprocess",
+ StringComparison.OrdinalIgnoreCase);
+ }
+ return false;
+ }
+
+ // Inproc holds the session-store SQLite handle in-process; graceful StopAsync releases it so the temp-dir delete succeeds on Windows.
+ private static async Task StopClientForCleanupAsync(CopilotClient client)
+ {
+ var isInProcess = string.Equals(
+ Environment.GetEnvironmentVariable("COPILOT_SDK_DEFAULT_CONNECTION"),
+ "inprocess",
+ StringComparison.OrdinalIgnoreCase);
+ if (isInProcess)
+ {
+ await client.StopAsync();
+ }
+ else
+ {
+ await client.ForceStopAsync();
+ }
+ }
+
private static bool IsTransientCleanupException(Exception exception)
=> exception is IOException or UnauthorizedAccessException;
}
diff --git a/dotnet/test/Harness/InProcessEnvIsolation.cs b/dotnet/test/Harness/InProcessEnvIsolation.cs
new file mode 100644
index 000000000..14b065204
--- /dev/null
+++ b/dotnet/test/Harness/InProcessEnvIsolation.cs
@@ -0,0 +1,93 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ *--------------------------------------------------------------------------------------------*/
+
+using System.Collections;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Xunit.Sdk;
+
+namespace GitHub.Copilot.Test.Harness;
+
+// Because many of the tests mutate global environment variables, we have to snapshot the original
+// state and restore it after each test. Otherwise tests influence each other depending on run order.
+// This is especially important for the in-process transport because the runtime is inside the test
+// host process and will be reading/writing its environment variables directly.
+internal static class InProcessEnvIsolation
+{
+ // Unset because CI sets them but the replay snapshots expect Bearer/OAuth.
+ private static readonly string[] SuppressEnvVars = ["COPILOT_HMAC_KEY", "CAPI_HMAC_KEY"];
+
+ // Captured at load, before any fixture/test mutates env.
+ private static readonly Dictionary s_ambient = CaptureEnvironment();
+
+ // Runs at assembly load so the ambient env is snapshotted before the shared
+ // fixture mirrors per-test env onto the process. Justifies suppressing CA2255.
+#pragma warning disable CA2255 // ModuleInitializer discouraged in libraries; intentional in this test harness.
+ [ModuleInitializer]
+ internal static void CaptureAtLoad() => _ = s_ambient;
+#pragma warning restore CA2255
+
+ [DllImport("libc", EntryPoint = "setenv", CharSet = CharSet.Ansi,
+ BestFitMapping = false, ThrowOnUnmappableChar = true)]
+ private static extern int NativeSetEnv(string name, string value, int overwrite);
+
+ [DllImport("libc", EntryPoint = "unsetenv", CharSet = CharSet.Ansi,
+ BestFitMapping = false, ThrowOnUnmappableChar = true)]
+ private static extern int NativeUnsetEnv(string name);
+
+ // Sets/unsets on the managed cache and, on Unix, the libc block so native
+ // readers in the loaded cdylib observe it.
+ public static void Apply(string name, string? value)
+ {
+ Environment.SetEnvironmentVariable(name, value);
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ _ = value is null ? NativeUnsetEnv(name) : NativeSetEnv(name, value, 1);
+ }
+ }
+
+ public static void NeutralizeAmbientCredentials()
+ {
+ foreach (var name in SuppressEnvVars)
+ {
+ Apply(name, null);
+ }
+ }
+
+ public static void RestoreAmbient()
+ {
+ foreach (DictionaryEntry entry in Environment.GetEnvironmentVariables())
+ {
+ var name = (string)entry.Key;
+ if (!s_ambient.ContainsKey(name))
+ {
+ Apply(name, null);
+ }
+ }
+
+ foreach (var (name, value) in s_ambient)
+ {
+ if (!string.Equals(Environment.GetEnvironmentVariable(name), value, StringComparison.Ordinal))
+ {
+ Apply(name, value);
+ }
+ }
+ }
+
+ private static Dictionary CaptureEnvironment() =>
+ Environment.GetEnvironmentVariables()
+ .Cast()
+ .ToDictionary(e => (string)e.Key, e => e.Value?.ToString(), StringComparer.Ordinal);
+}
+
+[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
+public sealed class InProcessEnvIsolationAttribute : BeforeAfterTestAttribute
+{
+ public override void Before(MethodInfo methodUnderTest) =>
+ InProcessEnvIsolation.NeutralizeAmbientCredentials();
+
+ public override void After(MethodInfo methodUnderTest) =>
+ InProcessEnvIsolation.RestoreAmbient();
+}
diff --git a/dotnet/test/Harness/ModuleInitializerAttribute.cs b/dotnet/test/Harness/ModuleInitializerAttribute.cs
new file mode 100644
index 000000000..fd9528733
--- /dev/null
+++ b/dotnet/test/Harness/ModuleInitializerAttribute.cs
@@ -0,0 +1,13 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ *--------------------------------------------------------------------------------------------*/
+
+#if !NET5_0_OR_GREATER
+namespace System.Runtime.CompilerServices;
+
+// Polyfill so [ModuleInitializer] compiles on net472; recognized by the compiler.
+[AttributeUsage(AttributeTargets.Method, Inherited = false)]
+internal sealed class ModuleInitializerAttribute : Attribute
+{
+}
+#endif
diff --git a/dotnet/test/Unit/ClientSessionLifetimeTests.cs b/dotnet/test/Unit/ClientSessionLifetimeTests.cs
index a028a6c7e..f736e8dee 100644
--- a/dotnet/test/Unit/ClientSessionLifetimeTests.cs
+++ b/dotnet/test/Unit/ClientSessionLifetimeTests.cs
@@ -32,6 +32,20 @@ public async Task StopAsync_Requests_Runtime_Shutdown_For_Owned_Process()
Assert.Equal(1, server.RuntimeShutdownCount);
}
+ [Fact]
+ public async Task DisposeAsync_Requests_Runtime_Shutdown_For_Owned_Process()
+ {
+ await using var server = await FakeCopilotServer.StartAsync();
+ var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url) });
+ await client.StartAsync();
+ using var process = StartExitedProcess();
+ await ReplaceConnectionCliProcessAsync(client, process);
+
+ await client.DisposeAsync();
+
+ Assert.Equal(1, server.RuntimeShutdownCount);
+ }
+
[Fact]
public async Task StopAsync_Does_Not_Throw_When_Runtime_Shutdown_Fails()
{
@@ -423,7 +437,7 @@ private static async Task ReplaceConnectionCliProcessAsync(CopilotClient client,
var rpc = connectionType.GetProperty("Rpc")!.GetValue(connection);
var networkStream = connectionType.GetProperty("NetworkStream")!.GetValue(connection);
var constructor = connectionType.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).Single();
- var updatedConnection = constructor.Invoke([rpc, process, networkStream, null]);
+ var updatedConnection = constructor.Invoke([rpc, process, networkStream, null, null]);
var fromResult = typeof(Task).GetMethod(nameof(Task.FromResult))!.MakeGenericMethod(connectionType);
field.SetValue(client, fromResult.Invoke(null, [updatedConnection]));
}
diff --git a/dotnet/test/Unit/GitHubTelemetryTests.cs b/dotnet/test/Unit/GitHubTelemetryTests.cs
new file mode 100644
index 000000000..f82e0db6e
--- /dev/null
+++ b/dotnet/test/Unit/GitHubTelemetryTests.cs
@@ -0,0 +1,482 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ *--------------------------------------------------------------------------------------------*/
+
+#if NET8_0_OR_GREATER
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Text.Json;
+using Xunit;
+
+using GitHub.Copilot.Rpc;
+
+namespace GitHub.Copilot.Test.Unit;
+
+#pragma warning disable GHCP001 // GitHub telemetry forwarding is experimental.
+
+public sealed class GitHubTelemetryTests
+{
+ [Fact]
+ public async Task CreateSession_Opts_Into_Forwarding_When_Handler_Provided()
+ {
+ await using var server = await FakeTelemetryServer.StartAsync();
+ await using var client = new CopilotClient(new CopilotClientOptions
+ {
+ Connection = RuntimeConnection.ForUri(server.Url),
+ OnGitHubTelemetry = _ => Task.CompletedTask,
+ });
+ await client.StartAsync();
+
+ await client.CreateSessionAsync(new SessionConfig { OnPermissionRequest = PermissionHandler.ApproveAll });
+
+ var createParams = server.LastCreateParams ?? throw new InvalidOperationException("session.create was not captured.");
+ Assert.True(createParams.TryGetProperty("enableGitHubTelemetryForwarding", out var flag));
+ Assert.True(flag.GetBoolean());
+ }
+
+ [Fact]
+ public async Task ResumeSession_Opts_Into_Forwarding_When_Handler_Provided()
+ {
+ await using var server = await FakeTelemetryServer.StartAsync();
+ await using var client = new CopilotClient(new CopilotClientOptions
+ {
+ Connection = RuntimeConnection.ForUri(server.Url),
+ OnGitHubTelemetry = _ => Task.CompletedTask,
+ });
+ await client.StartAsync();
+
+ await client.ResumeSessionAsync("session-1", new ResumeSessionConfig { OnPermissionRequest = PermissionHandler.ApproveAll });
+
+ var resumeParams = server.LastResumeParams ?? throw new InvalidOperationException("session.resume was not captured.");
+ Assert.True(resumeParams.TryGetProperty("enableGitHubTelemetryForwarding", out var flag));
+ Assert.True(flag.GetBoolean());
+ }
+
+ [Fact]
+ public async Task Connect_Opts_Into_Forwarding_When_Handler_Provided()
+ {
+ await using var server = await FakeTelemetryServer.StartAsync();
+ await using var client = new CopilotClient(new CopilotClientOptions
+ {
+ Connection = RuntimeConnection.ForUri(server.Url),
+ OnGitHubTelemetry = _ => Task.CompletedTask,
+ });
+ await client.StartAsync();
+
+ var connectParams = server.LastConnectParams ?? throw new InvalidOperationException("connect was not captured.");
+ Assert.True(connectParams.TryGetProperty("enableGitHubTelemetryForwarding", out var flag));
+ Assert.True(flag.GetBoolean());
+ }
+
+ [Fact]
+ public async Task Connect_Does_Not_Opt_In_Without_Handler()
+ {
+ await using var server = await FakeTelemetryServer.StartAsync();
+ await using var client = new CopilotClient(new CopilotClientOptions
+ {
+ Connection = RuntimeConnection.ForUri(server.Url),
+ });
+ await client.StartAsync();
+
+ var connectParams = server.LastConnectParams ?? throw new InvalidOperationException("connect was not captured.");
+ var present = connectParams.TryGetProperty("enableGitHubTelemetryForwarding", out var flag);
+ Assert.True(
+ !present || flag.ValueKind == JsonValueKind.Null,
+ "connect request should omit enableGitHubTelemetryForwarding (or send null) when no handler is registered");
+ }
+
+ [Fact]
+ public async Task CreateSession_Does_Not_Opt_In_Without_Handler()
+ {
+ await using var server = await FakeTelemetryServer.StartAsync();
+ await using var client = new CopilotClient(new CopilotClientOptions
+ {
+ Connection = RuntimeConnection.ForUri(server.Url),
+ });
+ await client.StartAsync();
+
+ await client.CreateSessionAsync(new SessionConfig { OnPermissionRequest = PermissionHandler.ApproveAll });
+
+ var createParams = server.LastCreateParams ?? throw new InvalidOperationException("session.create was not captured.");
+ var optedIn = createParams.TryGetProperty("enableGitHubTelemetryForwarding", out var flag)
+ && flag.ValueKind == JsonValueKind.True;
+ Assert.False(optedIn);
+ }
+
+ [Fact]
+ public async Task GitHubTelemetry_Event_Is_Forwarded_To_OnGitHubTelemetry()
+ {
+ var received = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
+
+ await using var server = await FakeTelemetryServer.StartAsync();
+ await using var client = new CopilotClient(new CopilotClientOptions
+ {
+ Connection = RuntimeConnection.ForUri(server.Url),
+ OnGitHubTelemetry = notification =>
+ {
+ received.TrySetResult(notification);
+ return Task.CompletedTask;
+ },
+ });
+ await client.StartAsync();
+
+ await server.SendGitHubTelemetryEventAsync(new Dictionary
+ {
+ ["sessionId"] = "session-1",
+ ["restricted"] = false,
+ ["event"] = new Dictionary
+ {
+ ["kind"] = "tool_call_executed",
+ ["properties"] = new Dictionary { ["tool"] = "shell" },
+ ["metrics"] = new Dictionary { ["duration_ms"] = 42 },
+ ["session_id"] = "session-1",
+ },
+ });
+
+ var notification = await received.Task.WaitAsync(TimeSpan.FromSeconds(10));
+ Assert.Equal("session-1", notification.SessionId);
+ Assert.False(notification.Restricted);
+ Assert.Equal("tool_call_executed", notification.Event.Kind);
+ Assert.Equal("shell", notification.Event.Properties["tool"]);
+ Assert.Equal(42, notification.Event.Metrics["duration_ms"]);
+ Assert.Equal("session-1", notification.Event.SessionId);
+ }
+
+ [Fact]
+ public async Task GitHubTelemetry_Event_Maps_Restricted_And_ClientInfo()
+ {
+ var received = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
+
+ await using var server = await FakeTelemetryServer.StartAsync();
+ await using var client = new CopilotClient(new CopilotClientOptions
+ {
+ Connection = RuntimeConnection.ForUri(server.Url),
+ OnGitHubTelemetry = notification =>
+ {
+ received.TrySetResult(notification);
+ return Task.CompletedTask;
+ },
+ });
+ await client.StartAsync();
+
+ await server.SendGitHubTelemetryEventAsync(new Dictionary
+ {
+ ["sessionId"] = "session-2",
+ ["restricted"] = true,
+ ["event"] = new Dictionary
+ {
+ ["kind"] = "model_call",
+ ["properties"] = new Dictionary { ["model"] = "gpt-5" },
+ ["metrics"] = new Dictionary { ["tokens"] = 128 },
+ ["session_id"] = "session-2",
+ ["client"] = new Dictionary
+ {
+ ["cli_version"] = "1.2.3",
+ ["os_platform"] = "win32",
+ ["os_arch"] = "x64",
+ ["node_version"] = "20.0.0",
+ ["is_staff"] = false,
+ },
+ },
+ });
+
+ var notification = await received.Task.WaitAsync(TimeSpan.FromSeconds(10));
+ Assert.True(notification.Restricted);
+
+ var clientInfo = notification.Event.Client;
+ Assert.NotNull(clientInfo);
+ Assert.Equal("1.2.3", clientInfo!.CliVersion);
+ Assert.Equal("win32", clientInfo.OsPlatform);
+ Assert.Equal("x64", clientInfo.OsArch);
+ Assert.Equal("20.0.0", clientInfo.NodeVersion);
+ Assert.Equal(false, clientInfo.IsStaff);
+ }
+
+ private sealed class FakeTelemetryServer : IAsyncDisposable
+ {
+ private readonly TcpListener _listener;
+ private readonly CancellationTokenSource _cts = new();
+ private readonly SemaphoreSlim _writeLock = new(1, 1);
+ private readonly TaskCompletionSource _connected = new(TaskCreationOptions.RunContinuationsAsynchronously);
+ private readonly Task _serverTask;
+
+ private FakeTelemetryServer(TcpListener listener)
+ {
+ _listener = listener;
+ _serverTask = RunAsync();
+ }
+
+ public string Url
+ {
+ get
+ {
+ var endpoint = (IPEndPoint)_listener.LocalEndpoint;
+ return $"http://127.0.0.1:{endpoint.Port}";
+ }
+ }
+
+ public JsonElement? LastCreateParams { get; private set; }
+
+ public JsonElement? LastResumeParams { get; private set; }
+
+ public JsonElement? LastConnectParams { get; private set; }
+
+ public static Task StartAsync()
+ {
+ var listener = new TcpListener(IPAddress.Loopback, 0);
+ listener.Start();
+ return Task.FromResult(new FakeTelemetryServer(listener));
+ }
+
+ public async Task SendGitHubTelemetryEventAsync(Dictionary notificationParams)
+ {
+ var stream = await _connected.Task.WaitAsync(_cts.Token);
+
+ // Send a genuine JSON-RPC notification (no "id"), exactly as the runtime
+ // does via sendNotification. This exercises the real notification dispatch
+ // path rather than masking it behind a request that carries an id.
+ await WriteMessageAsync(stream, new Dictionary
+ {
+ ["jsonrpc"] = "2.0",
+ ["method"] = "gitHubTelemetry.event",
+ ["params"] = notificationParams,
+ }, _cts.Token);
+ }
+
+ public async ValueTask DisposeAsync()
+ {
+ _cts.Cancel();
+ _listener.Stop();
+
+ try
+ {
+ await _serverTask;
+ }
+ catch (Exception ex) when (ex is OperationCanceledException or ObjectDisposedException or IOException or SocketException)
+ {
+ // Expected during teardown: the listener/socket is torn down while the
+ // server loop is still awaiting I/O. Observe the exception and move on.
+ _ = ex;
+ }
+
+ _cts.Dispose();
+ _writeLock.Dispose();
+ }
+
+ private async Task RunAsync()
+ {
+ using var tcpClient = await _listener.AcceptTcpClientAsync(_cts.Token);
+ using var stream = tcpClient.GetStream();
+ _connected.TrySetResult(stream);
+
+ while (!_cts.Token.IsCancellationRequested)
+ {
+ using var message = await ReadMessageAsync(stream, _cts.Token);
+ if (message is null)
+ {
+ return;
+ }
+
+ // Inbound messages without a "method" are responses to our own
+ // server-initiated requests (e.g. session.* the SDK answers); the
+ // SDK never replies to the gitHubTelemetry.event notification.
+ if (!message.RootElement.TryGetProperty("method", out _))
+ {
+ continue;
+ }
+
+ await HandleRequestAsync(stream, message.RootElement, _cts.Token);
+ }
+ }
+
+ private async Task HandleRequestAsync(Stream stream, JsonElement request, CancellationToken cancellationToken)
+ {
+ if (!request.TryGetProperty("id", out var idElement))
+ {
+ return;
+ }
+
+ var id = idElement.Clone();
+ var method = request.GetProperty("method").GetString();
+
+ object? result = method switch
+ {
+ "connect" => CaptureConnect(request),
+ "session.create" => CaptureCreate(request),
+ "session.resume" => CaptureResume(request),
+ "session.send" => new Dictionary { ["messageId"] = "message-1" },
+ "session.destroy" => new Dictionary(),
+ "runtime.shutdown" => new Dictionary(),
+ _ => throw new InvalidOperationException($"Unexpected RPC method '{method}'."),
+ };
+
+ await WriteMessageAsync(stream, new Dictionary
+ {
+ ["jsonrpc"] = "2.0",
+ ["id"] = id,
+ ["result"] = result,
+ }, cancellationToken);
+ }
+
+ private Dictionary CaptureConnect(JsonElement request)
+ {
+ LastConnectParams = request.TryGetProperty("params", out var p) ? p.Clone() : null;
+ return new Dictionary
+ {
+ ["ok"] = true,
+ ["protocolVersion"] = 3,
+ ["version"] = "test",
+ };
+ }
+
+ private Dictionary CaptureCreate(JsonElement request)
+ {
+ LastCreateParams = request.TryGetProperty("params", out var p) ? p.Clone() : null;
+ return SessionResult(LastCreateParams);
+ }
+
+ private Dictionary CaptureResume(JsonElement request)
+ {
+ LastResumeParams = request.TryGetProperty("params", out var p) ? p.Clone() : null;
+ return SessionResult(LastResumeParams);
+ }
+
+ private static Dictionary SessionResult(JsonElement? paramsElement)
+ {
+ string sessionId = "session-1";
+ if (paramsElement is { ValueKind: JsonValueKind.Object } p
+ && p.TryGetProperty("sessionId", out var sidProp)
+ && sidProp.ValueKind == JsonValueKind.String
+ && sidProp.GetString() is string sid
+ && !string.IsNullOrEmpty(sid))
+ {
+ sessionId = sid;
+ }
+
+ return new Dictionary
+ {
+ ["sessionId"] = sessionId,
+ ["workspacePath"] = null,
+ ["capabilities"] = null,
+ };
+ }
+
+ private async Task WriteMessageAsync(Stream stream, object payload, CancellationToken cancellationToken)
+ {
+ using var bodyStream = new MemoryStream();
+ using (var writer = new Utf8JsonWriter(bodyStream))
+ {
+ WriteJsonValue(writer, payload);
+ }
+
+ var body = bodyStream.ToArray();
+ var header = Encoding.ASCII.GetBytes($"Content-Length: {body.Length}\r\n\r\n");
+
+ await _writeLock.WaitAsync(cancellationToken);
+ try
+ {
+ await stream.WriteAsync(header, cancellationToken);
+ await stream.WriteAsync(body, cancellationToken);
+ await stream.FlushAsync(cancellationToken);
+ }
+ finally
+ {
+ _writeLock.Release();
+ }
+ }
+
+ private static void WriteJsonValue(Utf8JsonWriter writer, object? value)
+ {
+ switch (value)
+ {
+ case null:
+ writer.WriteNullValue();
+ break;
+ case string stringValue:
+ writer.WriteStringValue(stringValue);
+ break;
+ case bool boolValue:
+ writer.WriteBooleanValue(boolValue);
+ break;
+ case int intValue:
+ writer.WriteNumberValue(intValue);
+ break;
+ case long longValue:
+ writer.WriteNumberValue(longValue);
+ break;
+ case JsonElement jsonElement:
+ jsonElement.WriteTo(writer);
+ break;
+ case Dictionary dictionary:
+ writer.WriteStartObject();
+ foreach (var (propertyName, propertyValue) in dictionary)
+ {
+ writer.WritePropertyName(propertyName);
+ WriteJsonValue(writer, propertyValue);
+ }
+ writer.WriteEndObject();
+ break;
+ default:
+ throw new InvalidOperationException($"Unexpected JSON value type '{value.GetType().Name}'.");
+ }
+ }
+
+ private static async Task ReadMessageAsync(Stream stream, CancellationToken cancellationToken)
+ {
+ var headerBytes = new List();
+ while (true)
+ {
+ var value = await ReadByteAsync(stream, cancellationToken);
+ if (value < 0)
+ {
+ return null;
+ }
+
+ headerBytes.Add((byte)value);
+ var count = headerBytes.Count;
+ if (count >= 4 &&
+ headerBytes[count - 4] == '\r' &&
+ headerBytes[count - 3] == '\n' &&
+ headerBytes[count - 2] == '\r' &&
+ headerBytes[count - 1] == '\n')
+ {
+ break;
+ }
+ }
+
+ var header = Encoding.ASCII.GetString([.. headerBytes]);
+ var contentLength = header
+ .Split(["\r\n"], StringSplitOptions.RemoveEmptyEntries)
+ .Select(line => line.Split(':', 2))
+ .Where(parts => parts.Length == 2 && parts[0].Equals("Content-Length", StringComparison.OrdinalIgnoreCase))
+ .Select(parts => int.Parse(parts[1].Trim(), System.Globalization.CultureInfo.InvariantCulture))
+ .Single();
+
+ var body = new byte[contentLength];
+ var offset = 0;
+ while (offset < body.Length)
+ {
+ var read = await stream.ReadAsync(body.AsMemory(offset, body.Length - offset), cancellationToken);
+ if (read == 0)
+ {
+ return null;
+ }
+
+ offset += read;
+ }
+
+ return JsonDocument.Parse(body);
+ }
+
+ private static async Task ReadByteAsync(Stream stream, CancellationToken cancellationToken)
+ {
+ var buffer = new byte[1];
+ var read = await stream.ReadAsync(buffer, cancellationToken);
+ return read == 0 ? -1 : buffer[0];
+ }
+ }
+}
+
+#pragma warning restore GHCP001
+#endif
diff --git a/go/client.go b/go/client.go
index 4e7f1f549..5b8dabf8f 100644
--- a/go/client.go
+++ b/go/client.go
@@ -730,6 +730,7 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses
req.RequestCanvasRenderer = config.RequestCanvasRenderer
req.RequestExtensions = config.RequestExtensions
req.ExtensionSDKPath = config.ExtensionSDKPath
+ req.ExtensionInfo = config.ExtensionInfo
req.ExpAssignments = config.ExpAssignments
if len(config.Commands) > 0 {
@@ -760,6 +761,9 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses
} else {
req.IncludeSubAgentStreamingEvents = Bool(true)
}
+ if c.options.OnGitHubTelemetry != nil {
+ req.EnableGitHubTelemetryForwarding = Bool(true)
+ }
if config.OnUserInputRequest != nil {
req.RequestUserInput = Bool(true)
}
@@ -1038,6 +1042,9 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string,
} else {
req.IncludeSubAgentStreamingEvents = Bool(true)
}
+ if c.options.OnGitHubTelemetry != nil {
+ req.EnableGitHubTelemetryForwarding = Bool(true)
+ }
if config.OnUserInputRequest != nil {
req.RequestUserInput = Bool(true)
}
@@ -1086,6 +1093,7 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string,
req.RequestCanvasRenderer = config.RequestCanvasRenderer
req.RequestExtensions = config.RequestExtensions
req.ExtensionSDKPath = config.ExtensionSDKPath
+ req.ExtensionInfo = config.ExtensionInfo
req.ExpAssignments = config.ExpAssignments
if config.OnPermissionRequest != nil {
req.RequestPermission = Bool(true)
@@ -1679,7 +1687,15 @@ func (c *Client) verifyProtocolVersion(ctx context.Context) error {
t := c.effectiveConnectionToken
tokenPtr = &t
}
- connectResult, err := c.internalRPC.Connect(ctx, &rpc.ConnectRequest{Token: tokenPtr})
+ connectReq := &connectHandshakeRequest{Token: tokenPtr}
+ // Opt in to GitHub telemetry forwarding at the connection level when a handler is
+ // registered (mirrors the runtime, which reads this flag on the `connect` handshake
+ // so the first session's un-replayable `session.start` event is forwarded). Also
+ // sent on session.create/resume for older CLIs.
+ if c.options.OnGitHubTelemetry != nil {
+ connectReq.EnableGitHubTelemetryForwarding = Bool(true)
+ }
+ rawConnectResult, err := c.client.Request(ctx, "connect", connectReq)
if err != nil {
var rpcErr *jsonrpc2.Error
if errors.As(err, &rpcErr) && (rpcErr.Code == jsonrpc2.ErrMethodNotFound.Code || rpcErr.Message == "Unhandled method connect") {
@@ -1694,6 +1710,10 @@ func (c *Client) verifyProtocolVersion(ctx context.Context) error {
return err
}
} else {
+ var connectResult rpc.ConnectResult
+ if err := json.Unmarshal(rawConnectResult, &connectResult); err != nil {
+ return err
+ }
v := int(connectResult.ProtocolVersion)
serverVersion = &v
}
@@ -1710,6 +1730,11 @@ func (c *Client) verifyProtocolVersion(ctx context.Context) error {
return nil
}
+type connectHandshakeRequest struct {
+ Token *string `json:"token,omitempty"`
+ EnableGitHubTelemetryForwarding *bool `json:"enableGitHubTelemetryForwarding,omitempty"`
+}
+
// stderrBufferSize is the maximum number of bytes kept from the CLI process's
// stderr. Only the tail is retained so that memory stays bounded even when the
// process produces a large amount of diagnostic output.
@@ -2057,17 +2082,35 @@ func (c *Client) setupNotificationHandler() {
}
return session.clientSessionAPIs
})
- if c.options.RequestHandler != nil {
- adapter := newCopilotRequestAdapter(c.options.RequestHandler, func() *rpc.ServerLlmInferenceAPI {
- if c.RPC == nil {
- return nil
- }
- return c.RPC.LlmInference
- })
- rpc.RegisterClientGlobalAPIHandlers(c.client, &rpc.ClientGlobalAPIHandlers{LlmInference: adapter})
+ if c.options.RequestHandler != nil || c.options.OnGitHubTelemetry != nil {
+ handlers := &rpc.ClientGlobalAPIHandlers{}
+ if c.options.RequestHandler != nil {
+ handlers.LlmInference = newCopilotRequestAdapter(c.options.RequestHandler, func() *rpc.ServerLlmInferenceAPI {
+ if c.RPC == nil {
+ return nil
+ }
+ return c.RPC.LlmInference
+ })
+ }
+ if c.options.OnGitHubTelemetry != nil {
+ handlers.GitHubTelemetry = &gitHubTelemetryAdapter{callback: c.options.OnGitHubTelemetry}
+ }
+ rpc.RegisterClientGlobalAPIHandlers(c.client, handlers)
}
}
+// gitHubTelemetryAdapter adapts the OnGitHubTelemetry option to the generated
+// rpc.GitHubTelemetryHandler interface.
+type gitHubTelemetryAdapter struct {
+ callback func(notification *rpc.GitHubTelemetryNotification)
+}
+
+func (a *gitHubTelemetryAdapter) Event(request *rpc.GitHubTelemetryNotification) error {
+ defer func() { recover() }() // Ignore handler panics
+ a.callback(request)
+ return nil
+}
+
func (c *Client) handleSessionEvent(req sessionEventRequest) {
if req.SessionID == "" {
return
diff --git a/go/client_test.go b/go/client_test.go
index 059f098a0..bd48baacd 100644
--- a/go/client_test.go
+++ b/go/client_test.go
@@ -15,6 +15,7 @@ import (
"strings"
"sync"
"testing"
+ "time"
"github.com/github/copilot-sdk/go/internal/jsonrpc2"
"github.com/github/copilot-sdk/go/internal/truncbuffer"
@@ -2337,6 +2338,285 @@ func TestResumeSessionRequest_IncludeSubAgentStreamingEvents(t *testing.T) {
})
}
+func TestCreateSessionRequest_EnableGitHubTelemetryForwarding(t *testing.T) {
+ t.Run("forwards explicit true", func(t *testing.T) {
+ req := createSessionRequest{
+ EnableGitHubTelemetryForwarding: Bool(true),
+ }
+ 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["enableGitHubTelemetryForwarding"] != true {
+ t.Errorf("Expected enableGitHubTelemetryForwarding to be true, got %v", m["enableGitHubTelemetryForwarding"])
+ }
+ })
+
+ t.Run("omits when not set", func(t *testing.T) {
+ req := createSessionRequest{}
+ data, _ := json.Marshal(req)
+ var m map[string]any
+ json.Unmarshal(data, &m)
+ if _, ok := m["enableGitHubTelemetryForwarding"]; ok {
+ t.Error("Expected enableGitHubTelemetryForwarding to be omitted when not set")
+ }
+ })
+}
+
+func TestResumeSessionRequest_EnableGitHubTelemetryForwarding(t *testing.T) {
+ t.Run("forwards explicit true", func(t *testing.T) {
+ req := resumeSessionRequest{
+ SessionID: "s1",
+ EnableGitHubTelemetryForwarding: Bool(true),
+ }
+ 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["enableGitHubTelemetryForwarding"] != true {
+ t.Errorf("Expected enableGitHubTelemetryForwarding to be true, got %v", m["enableGitHubTelemetryForwarding"])
+ }
+ })
+
+ t.Run("omits when not set", func(t *testing.T) {
+ req := resumeSessionRequest{SessionID: "s1"}
+ data, _ := json.Marshal(req)
+ var m map[string]any
+ json.Unmarshal(data, &m)
+ if _, ok := m["enableGitHubTelemetryForwarding"]; ok {
+ t.Error("Expected enableGitHubTelemetryForwarding to be omitted when not set")
+ }
+ })
+}
+
+func TestClient_ForwardsGitHubTelemetryForwardingToSessionRequests(t *testing.T) {
+ rpcClient, server, _ := newRuntimeShutdownRpcPair(t)
+ t.Cleanup(server.Stop)
+ client := &Client{
+ client: rpcClient,
+ RPC: rpc.NewServerRPC(rpcClient),
+ sessions: make(map[string]*Session),
+ options: ClientOptions{OnGitHubTelemetry: func(*rpc.GitHubTelemetryNotification) {}},
+ }
+
+ createParams := make(chan json.RawMessage, 1)
+ server.SetRequestHandler("session.create", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) {
+ createParams <- append(json.RawMessage(nil), params...)
+ sessionID := sessionIDFromParams(t, params)
+ return []byte(`{"sessionId":"` + sessionID + `","workspacePath":"/workspace"}`), nil
+ })
+
+ if _, err := client.CreateSession(t.Context(), &SessionConfig{}); err != nil {
+ t.Fatalf("CreateSession failed: %v", err)
+ }
+ assertForwardingFlagTrue(t, <-createParams)
+
+ resumeParams := make(chan json.RawMessage, 1)
+ server.SetRequestHandler("session.resume", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) {
+ resumeParams <- append(json.RawMessage(nil), params...)
+ return []byte(`{"sessionId":"resumed","workspacePath":"/workspace"}`), nil
+ })
+
+ if _, err := client.ResumeSessionWithOptions(t.Context(), "resumed", &ResumeSessionConfig{}); err != nil {
+ t.Fatalf("ResumeSessionWithOptions failed: %v", err)
+ }
+ assertForwardingFlagTrue(t, <-resumeParams)
+}
+
+func assertForwardingFlagTrue(t *testing.T, params json.RawMessage) {
+ t.Helper()
+ var decoded map[string]any
+ if err := json.Unmarshal(params, &decoded); err != nil {
+ t.Fatalf("failed to unmarshal request params: %v", err)
+ }
+ if decoded["enableGitHubTelemetryForwarding"] != true {
+ t.Fatalf("expected enableGitHubTelemetryForwarding=true, got %v", decoded["enableGitHubTelemetryForwarding"])
+ }
+}
+
+func TestClient_OmitsGitHubTelemetryForwardingWhenNoHandler(t *testing.T) {
+ rpcClient, server, _ := newRuntimeShutdownRpcPair(t)
+ t.Cleanup(server.Stop)
+ client := &Client{
+ client: rpcClient,
+ RPC: rpc.NewServerRPC(rpcClient),
+ sessions: make(map[string]*Session),
+ options: ClientOptions{},
+ }
+
+ createParams := make(chan json.RawMessage, 1)
+ server.SetRequestHandler("session.create", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) {
+ createParams <- append(json.RawMessage(nil), params...)
+ sessionID := sessionIDFromParams(t, params)
+ return []byte(`{"sessionId":"` + sessionID + `","workspacePath":"/workspace"}`), nil
+ })
+
+ if _, err := client.CreateSession(t.Context(), &SessionConfig{}); err != nil {
+ t.Fatalf("CreateSession failed: %v", err)
+ }
+ assertForwardingFlagAbsent(t, <-createParams)
+
+ resumeParams := make(chan json.RawMessage, 1)
+ server.SetRequestHandler("session.resume", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) {
+ resumeParams <- append(json.RawMessage(nil), params...)
+ return []byte(`{"sessionId":"resumed","workspacePath":"/workspace"}`), nil
+ })
+
+ if _, err := client.ResumeSessionWithOptions(t.Context(), "resumed", &ResumeSessionConfig{}); err != nil {
+ t.Fatalf("ResumeSessionWithOptions failed: %v", err)
+ }
+ assertForwardingFlagAbsent(t, <-resumeParams)
+}
+
+func assertForwardingFlagAbsent(t *testing.T, params json.RawMessage) {
+ t.Helper()
+ var decoded map[string]any
+ if err := json.Unmarshal(params, &decoded); err != nil {
+ t.Fatalf("failed to unmarshal request params: %v", err)
+ }
+ if _, ok := decoded["enableGitHubTelemetryForwarding"]; ok {
+ t.Fatalf("expected enableGitHubTelemetryForwarding to be omitted, got %v", decoded["enableGitHubTelemetryForwarding"])
+ }
+}
+
+func TestClient_ForwardsGitHubTelemetryForwardingOnConnect(t *testing.T) {
+ rpcClient, server, _ := newRuntimeShutdownRpcPair(t)
+ t.Cleanup(server.Stop)
+ client := &Client{
+ client: rpcClient,
+ RPC: rpc.NewServerRPC(rpcClient),
+ internalRPC: rpc.NewInternalServerRPC(rpcClient),
+ sessions: make(map[string]*Session),
+ options: ClientOptions{OnGitHubTelemetry: func(*rpc.GitHubTelemetryNotification) {}},
+ }
+
+ connectParams := make(chan json.RawMessage, 1)
+ server.SetRequestHandler("connect", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) {
+ connectParams <- append(json.RawMessage(nil), params...)
+ return []byte(`{"ok":true,"protocolVersion":3,"version":"test"}`), nil
+ })
+
+ if err := client.verifyProtocolVersion(t.Context()); err != nil {
+ t.Fatalf("verifyProtocolVersion failed: %v", err)
+ }
+ assertForwardingFlagTrue(t, <-connectParams)
+}
+
+func TestClient_OmitsGitHubTelemetryForwardingOnConnectWhenNoHandler(t *testing.T) {
+ rpcClient, server, _ := newRuntimeShutdownRpcPair(t)
+ t.Cleanup(server.Stop)
+ client := &Client{
+ client: rpcClient,
+ RPC: rpc.NewServerRPC(rpcClient),
+ internalRPC: rpc.NewInternalServerRPC(rpcClient),
+ sessions: make(map[string]*Session),
+ options: ClientOptions{},
+ }
+
+ connectParams := make(chan json.RawMessage, 1)
+ server.SetRequestHandler("connect", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) {
+ connectParams <- append(json.RawMessage(nil), params...)
+ return []byte(`{"ok":true,"protocolVersion":3,"version":"test"}`), nil
+ })
+
+ if err := client.verifyProtocolVersion(t.Context()); err != nil {
+ t.Fatalf("verifyProtocolVersion failed: %v", err)
+ }
+ assertForwardingFlagAbsent(t, <-connectParams)
+}
+
+func TestGitHubTelemetryNotificationRoutesToCallback(t *testing.T) {
+ // The runtime forwards telemetry via a JSON-RPC *notification* (no id).
+ // Drive a real Content-Length-framed notification through the transport and
+ // verify that a real Client wired with OnGitHubTelemetry routes it to the
+ // callback through the client's own client-global handler registration
+ // (setupNotificationHandler), rather than registering the adapter by hand.
+ clientConn, serverConn := net.Pipe()
+ defer clientConn.Close()
+ defer serverConn.Close()
+
+ rpcClient := jsonrpc2.NewClient(clientConn, clientConn)
+ rpcClient.Start()
+ defer rpcClient.Stop()
+
+ // Drain the client->server direction so net.Pipe writes never block.
+ go func() {
+ buf := make([]byte, 4096)
+ for {
+ if _, err := serverConn.Read(buf); err != nil {
+ return
+ }
+ }
+ }()
+
+ received := make(chan *rpc.GitHubTelemetryNotification, 1)
+ client := &Client{
+ client: rpcClient,
+ RPC: rpc.NewServerRPC(rpcClient),
+ sessions: make(map[string]*Session),
+ options: ClientOptions{
+ OnGitHubTelemetry: func(n *rpc.GitHubTelemetryNotification) { received <- n },
+ },
+ }
+ // setupNotificationHandler is what registers the gitHubTelemetryAdapter when
+ // OnGitHubTelemetry is set; exercising it here covers the real client wiring.
+ client.setupNotificationHandler()
+
+ notification := map[string]any{
+ "jsonrpc": "2.0",
+ "method": "gitHubTelemetry.event",
+ "params": map[string]any{
+ "sessionId": "sess-telemetry",
+ "restricted": true,
+ "event": map[string]any{
+ "kind": "tool_call_executed",
+ "metrics": map[string]any{"duration_ms": 12.5},
+ "properties": map[string]any{"tool": "shell"},
+ },
+ },
+ }
+ data, err := json.Marshal(notification)
+ if err != nil {
+ t.Fatalf("marshal notification: %v", err)
+ }
+ go func() {
+ _, _ = fmt.Fprintf(serverConn, "Content-Length: %d\r\n\r\n%s", len(data), data)
+ }()
+
+ select {
+ case n := <-received:
+ sessionID := ""
+ if n.SessionID != nil {
+ sessionID = *n.SessionID
+ }
+ if sessionID != "sess-telemetry" {
+ t.Errorf("session id = %q, want sess-telemetry", sessionID)
+ }
+ if !n.Restricted {
+ t.Error("expected restricted to be true")
+ }
+ if n.Event.Kind != "tool_call_executed" {
+ t.Errorf("kind = %q, want tool_call_executed", n.Event.Kind)
+ }
+ if n.Event.Metrics["duration_ms"] != 12.5 {
+ t.Errorf("metrics[duration_ms] = %v, want 12.5", n.Event.Metrics["duration_ms"])
+ }
+ if n.Event.Properties["tool"] != "shell" {
+ t.Errorf("properties[tool] = %q, want shell", n.Event.Properties["tool"])
+ }
+ case <-time.After(2 * time.Second):
+ t.Fatal("timed out waiting for telemetry notification")
+ }
+}
+
func TestCreateSessionRequest_EnableOnDemandInstructionDiscovery(t *testing.T) {
t.Run("forwards explicit true", func(t *testing.T) {
req := createSessionRequest{
diff --git a/go/internal/e2e/client_options_e2e_test.go b/go/internal/e2e/client_options_e2e_test.go
index aa42be1f3..0d3c802b0 100644
--- a/go/internal/e2e/client_options_e2e_test.go
+++ b/go/internal/e2e/client_options_e2e_test.go
@@ -10,6 +10,7 @@ import (
copilot "github.com/github/copilot-sdk/go"
"github.com/github/copilot-sdk/go/internal/e2e/testharness"
+ "github.com/github/copilot-sdk/go/rpc"
)
// Mirrors the E2E portions of dotnet/test/ClientOptionsTests.cs (snapshot category "client_options").
@@ -198,6 +199,315 @@ func TestClientOptionsE2E(t *testing.T) {
}
})
+ t.Run("should forward advanced session creation options to the CLI", func(t *testing.T) {
+ ctx := testharness.NewTestContext(t)
+ cliPath := filepath.Join(ctx.WorkDir, "fake-cli-"+randomHex(t)+".js")
+ capturePath := filepath.Join(ctx.WorkDir, "fake-cli-capture-"+randomHex(t)+".json")
+ if err := os.WriteFile(cliPath, []byte(fakeStdioCliScript), 0644); err != nil {
+ t.Fatalf("Failed to write fake CLI script: %v", err)
+ }
+
+ client := ctx.NewClient(func(opts *copilot.ClientOptions) {
+ opts.Connection = copilot.StdioConnection{Path: cliPath, Args: []string{"--capture-file", capturePath}}
+ opts.GitHubToken = "advanced-create-client-token"
+ opts.UseLoggedInUser = copilot.Bool(false)
+ })
+ t.Cleanup(func() { client.ForceStop() })
+
+ if err := client.Start(t.Context()); err != nil {
+ t.Fatalf("Start failed: %v", err)
+ }
+
+ sessionID := "advanced-session-id"
+ workingDirectory := t.TempDir()
+ configDirectory := t.TempDir()
+ embeddingCacheStorage := "in-memory"
+ organizationCustomInstructions := "organization guidance"
+ maxAiCredits := float64(42)
+ extensionSDKPath := filepath.Join(ctx.WorkDir, "extension-sdk")
+ session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
+ SessionID: sessionID,
+ ClientName: "go-sdk-e2e-client",
+ Model: "claude-sonnet-4.5",
+ ReasoningEffort: "low",
+ ReasoningSummary: copilot.ReasoningSummaryNone,
+ ContextTier: copilot.ContextTierLongContext,
+ ConfigDirectory: configDirectory,
+ EnableConfigDiscovery: copilot.Bool(true),
+ SkipEmbeddingRetrieval: copilot.Bool(true),
+ EmbeddingCacheStorage: &embeddingCacheStorage,
+ OrganizationCustomInstructions: &organizationCustomInstructions,
+ EnableOnDemandInstructionDiscovery: copilot.Bool(true),
+ EnableFileHooks: copilot.Bool(false),
+ EnableHostGitOperations: copilot.Bool(false),
+ EnableSessionStore: copilot.Bool(false),
+ EnableSkills: copilot.Bool(false),
+ WorkingDirectory: workingDirectory,
+ Streaming: copilot.Bool(true),
+ IncludeSubAgentStreamingEvents: copilot.Bool(false),
+ AvailableTools: []string{"read_file"},
+ ExcludedTools: []string{"bash"},
+ ExcludedBuiltInAgents: []string{"legacy-agent"},
+ EnableSessionTelemetry: copilot.Bool(false),
+ EnableCitations: copilot.Bool(true),
+ SessionLimits: &rpc.SessionLimitsConfig{MaxAiCredits: &maxAiCredits},
+ SkipCustomInstructions: copilot.Bool(true),
+ CustomAgentsLocalOnly: copilot.Bool(true),
+ CoauthorEnabled: copilot.Bool(false),
+ ManageScheduleEnabled: copilot.Bool(false),
+ GitHubToken: "advanced-create-session-token",
+ RemoteSession: rpc.RemoteSessionModeExport,
+ SkillDirectories: []string{"skills"},
+ PluginDirectories: []string{"plugins"},
+ InstructionDirectories: []string{"instructions"},
+ DisabledSkills: []string{"disabled-skill"},
+ EnableMCPApps: true,
+ Canvases: []copilot.CanvasDeclaration{{
+ ID: "canvas",
+ DisplayName: "Canvas",
+ Description: "Canvas description",
+ InputSchema: map[string]any{"type": "object"},
+ }},
+ RequestCanvasRenderer: copilot.Bool(true),
+ RequestExtensions: copilot.Bool(true),
+ ExtensionSDKPath: &extensionSDKPath,
+ ExtensionInfo: &copilot.ExtensionInfo{Source: "github-app", Name: "go-e2e-extension"},
+ ExpAssignments: map[string]any{"feature": "enabled"},
+ })
+ if err != nil {
+ t.Fatalf("CreateSession failed: %v", err)
+ }
+ session.Disconnect()
+
+ createReq := getCapturedRequest(t, capturePath, "session.create")
+ params, ok := createReq.Params.(map[string]any)
+ if !ok {
+ t.Fatalf("Expected session.create params object, got %T", createReq.Params)
+ }
+ expectedValues := map[string]any{
+ "sessionId": sessionID,
+ "clientName": "go-sdk-e2e-client",
+ "model": "claude-sonnet-4.5",
+ "reasoningEffort": "low",
+ "reasoningSummary": "none",
+ "contextTier": "long_context",
+ "configDir": configDirectory,
+ "enableConfigDiscovery": true,
+ "skipEmbeddingRetrieval": true,
+ "embeddingCacheStorage": embeddingCacheStorage,
+ "organizationCustomInstructions": organizationCustomInstructions,
+ "enableOnDemandInstructionDiscovery": true,
+ "enableFileHooks": false,
+ "enableHostGitOperations": false,
+ "enableSessionStore": false,
+ "enableSkills": false,
+ "workingDirectory": workingDirectory,
+ "streaming": true,
+ "includeSubAgentStreamingEvents": false,
+ "enableSessionTelemetry": false,
+ "enableCitations": true,
+ "skipCustomInstructions": true,
+ "customAgentsLocalOnly": true,
+ "coauthorEnabled": false,
+ "manageScheduleEnabled": false,
+ "gitHubToken": "advanced-create-session-token",
+ "remoteSession": "export",
+ "requestMcpApps": true,
+ "requestCanvasRenderer": true,
+ "requestExtensions": true,
+ "extensionSdkPath": extensionSDKPath,
+ "envValueMode": "direct",
+ }
+ for key, expected := range expectedValues {
+ if params[key] != expected {
+ t.Fatalf("Expected %s=%#v, got %#v in %#v", key, expected, params[key], params)
+ }
+ }
+ assertStringArray(t, params["availableTools"], []string{"read_file"})
+ assertStringArray(t, params["excludedTools"], []string{"bash"})
+ assertStringArray(t, params["excludedBuiltinAgents"], []string{"legacy-agent"})
+ assertStringArray(t, params["skillDirectories"], []string{"skills"})
+ assertStringArray(t, params["pluginDirectories"], []string{"plugins"})
+ assertStringArray(t, params["instructionDirectories"], []string{"instructions"})
+ assertStringArray(t, params["disabledSkills"], []string{"disabled-skill"})
+ if params["sessionLimits"].(map[string]any)["maxAiCredits"] != maxAiCredits {
+ t.Fatalf("Expected sessionLimits to be forwarded, got %#v", params["sessionLimits"])
+ }
+ extensionInfo := params["extensionInfo"].(map[string]any)
+ if extensionInfo["source"] != "github-app" || extensionInfo["name"] != "go-e2e-extension" {
+ t.Fatalf("Expected extensionInfo to be forwarded, got %#v", extensionInfo)
+ }
+ canvases := params["canvases"].([]any)
+ canvas := canvases[0].(map[string]any)
+ if canvas["id"] != "canvas" || canvas["displayName"] != "Canvas" || canvas["description"] != "Canvas description" {
+ t.Fatalf("Expected canvas declaration to be forwarded, got %#v", canvas)
+ }
+ if params["expAssignments"].(map[string]any)["feature"] != "enabled" {
+ t.Fatalf("Expected expAssignments to be forwarded, got %#v", params["expAssignments"])
+ }
+ })
+
+ t.Run("should forward singular provider configuration on session creation", func(t *testing.T) {
+ ctx := testharness.NewTestContext(t)
+ cliPath := filepath.Join(ctx.WorkDir, "fake-cli-"+randomHex(t)+".js")
+ capturePath := filepath.Join(ctx.WorkDir, "fake-cli-capture-"+randomHex(t)+".json")
+ if err := os.WriteFile(cliPath, []byte(fakeStdioCliScript), 0644); err != nil {
+ t.Fatalf("Failed to write fake CLI script: %v", err)
+ }
+
+ client := ctx.NewClient(func(opts *copilot.ClientOptions) {
+ opts.Connection = copilot.StdioConnection{Path: cliPath, Args: []string{"--capture-file", capturePath}}
+ opts.GitHubToken = "provider-client-token"
+ opts.UseLoggedInUser = copilot.Bool(false)
+ })
+ t.Cleanup(func() { client.ForceStop() })
+
+ if err := client.Start(t.Context()); err != nil {
+ t.Fatalf("Start failed: %v", err)
+ }
+
+ session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
+ Provider: &copilot.ProviderConfig{
+ Type: "openai",
+ WireAPI: "responses",
+ Transport: "websockets",
+ BaseURL: "https://models.example.test/v1",
+ APIKey: "provider-key",
+ ModelID: "base-model",
+ WireModel: "wire-model",
+ MaxPromptTokens: 1000,
+ MaxOutputTokens: 2000,
+ Headers: map[string]string{"x-provider": "go"},
+ },
+ })
+ if err != nil {
+ t.Fatalf("CreateSession failed: %v", err)
+ }
+ session.Disconnect()
+
+ createReq := getCapturedRequest(t, capturePath, "session.create")
+ params := createReq.Params.(map[string]any)
+ provider := params["provider"].(map[string]any)
+ for key, expected := range map[string]any{
+ "type": "openai",
+ "wireApi": "responses",
+ "transport": "websockets",
+ "baseUrl": "https://models.example.test/v1",
+ "apiKey": "provider-key",
+ "modelId": "base-model",
+ "wireModel": "wire-model",
+ "maxPromptTokens": float64(1000),
+ "maxOutputTokens": float64(2000),
+ } {
+ if provider[key] != expected {
+ t.Fatalf("Expected provider.%s=%#v, got %#v in %#v", key, expected, provider[key], provider)
+ }
+ }
+ if provider["headers"].(map[string]any)["x-provider"] != "go" {
+ t.Fatalf("Expected provider headers to be forwarded, got %#v", provider["headers"])
+ }
+ })
+
+ t.Run("should forward advanced session resume options to the CLI", func(t *testing.T) {
+ ctx := testharness.NewTestContext(t)
+ cliPath := filepath.Join(ctx.WorkDir, "fake-cli-"+randomHex(t)+".js")
+ capturePath := filepath.Join(ctx.WorkDir, "fake-cli-capture-"+randomHex(t)+".json")
+ if err := os.WriteFile(cliPath, []byte(fakeStdioCliScript), 0644); err != nil {
+ t.Fatalf("Failed to write fake CLI script: %v", err)
+ }
+
+ client := ctx.NewClient(func(opts *copilot.ClientOptions) {
+ opts.Connection = copilot.StdioConnection{Path: cliPath, Args: []string{"--capture-file", capturePath}}
+ opts.GitHubToken = "advanced-resume-client-token"
+ opts.UseLoggedInUser = copilot.Bool(false)
+ })
+ t.Cleanup(func() { client.ForceStop() })
+
+ if err := client.Start(t.Context()); err != nil {
+ t.Fatalf("Start failed: %v", err)
+ }
+
+ workingDirectory := t.TempDir()
+ configDirectory := t.TempDir()
+ continuePendingWork := false
+ extensionSDKPath := filepath.Join(ctx.WorkDir, "resume-extension-sdk")
+ session, err := client.ResumeSession(t.Context(), "resume-session-id", &copilot.ResumeSessionConfig{
+ Model: "gpt-5-mini",
+ ReasoningEffort: "low",
+ ReasoningSummary: copilot.ReasoningSummaryNone,
+ ContextTier: copilot.ContextTierLongContext,
+ WorkingDirectory: workingDirectory,
+ ConfigDirectory: configDirectory,
+ EnableConfigDiscovery: copilot.Bool(false),
+ SuppressResumeEvent: true,
+ ContinuePendingWork: &continuePendingWork,
+ Streaming: copilot.Bool(true),
+ IncludeSubAgentStreamingEvents: copilot.Bool(false),
+ GitHubToken: "advanced-resume-session-token",
+ Canvases: []copilot.CanvasDeclaration{{
+ ID: "resume-canvas",
+ DisplayName: "Resume Canvas",
+ Description: "Resume canvas description",
+ InputSchema: map[string]any{"type": "object"},
+ }},
+ OpenCanvases: []rpc.OpenCanvasInstance{{
+ CanvasID: "resume-canvas",
+ ExtensionID: "github-app/go-e2e-extension",
+ InstanceID: "resume-instance",
+ Input: map[string]any{"value": "from-resume"},
+ }},
+ RequestCanvasRenderer: copilot.Bool(true),
+ RequestExtensions: copilot.Bool(true),
+ ExtensionSDKPath: &extensionSDKPath,
+ ExtensionInfo: &copilot.ExtensionInfo{Source: "github-app", Name: "go-e2e-extension"},
+ ExpAssignments: map[string]any{"resumeFeature": "enabled"},
+ })
+ if err != nil {
+ t.Fatalf("ResumeSession failed: %v", err)
+ }
+ session.Disconnect()
+
+ resumeReq := getCapturedRequest(t, capturePath, "session.resume")
+ params := resumeReq.Params.(map[string]any)
+ expectedValues := map[string]any{
+ "sessionId": "resume-session-id",
+ "model": "gpt-5-mini",
+ "reasoningEffort": "low",
+ "reasoningSummary": "none",
+ "contextTier": "long_context",
+ "workingDirectory": workingDirectory,
+ "configDir": configDirectory,
+ "enableConfigDiscovery": false,
+ "disableResume": true,
+ "continuePendingWork": false,
+ "streaming": true,
+ "includeSubAgentStreamingEvents": false,
+ "gitHubToken": "advanced-resume-session-token",
+ "requestCanvasRenderer": true,
+ "requestExtensions": true,
+ "extensionSdkPath": extensionSDKPath,
+ "envValueMode": "direct",
+ }
+ for key, expected := range expectedValues {
+ if params[key] != expected {
+ t.Fatalf("Expected resume %s=%#v, got %#v in %#v", key, expected, params[key], params)
+ }
+ }
+ openCanvases := params["openCanvases"].([]any)
+ openCanvas := openCanvases[0].(map[string]any)
+ if openCanvas["canvasId"] != "resume-canvas" || openCanvas["extensionId"] != "github-app/go-e2e-extension" ||
+ openCanvas["instanceId"] != "resume-instance" {
+ t.Fatalf("Expected open canvas state to be forwarded, got %#v", openCanvas)
+ }
+ extensionInfo := params["extensionInfo"].(map[string]any)
+ if extensionInfo["source"] != "github-app" || extensionInfo["name"] != "go-e2e-extension" {
+ t.Fatalf("Expected extensionInfo on resume, got %#v", extensionInfo)
+ }
+ if params["expAssignments"].(map[string]any)["resumeFeature"] != "enabled" {
+ t.Fatalf("Expected resume expAssignments to be forwarded, got %#v", params["expAssignments"])
+ }
+ })
+
}
// ---------------------------------------------------------------------------
@@ -353,8 +663,36 @@ func readCapture(t *testing.T, path string) capturedCli {
return c
}
-// fakeStdioCliScript is identical to the one used by the .NET / Python
-// equivalents (dotnet/test/ClientOptionsTests.cs and python/e2e/test_client_options.py).
+func getCapturedRequest(t *testing.T, path, method string) capturedRequest {
+ t.Helper()
+ capture := readCapture(t, path)
+ for _, request := range capture.Requests {
+ if request.Method == method {
+ return request
+ }
+ }
+ t.Fatalf("Expected %s request in capture, got %+v", method, capture.Requests)
+ return capturedRequest{}
+}
+
+func assertStringArray(t *testing.T, value any, expected []string) {
+ t.Helper()
+ items, ok := value.([]any)
+ if !ok {
+ t.Fatalf("Expected string array %v, got %#v", expected, value)
+ }
+ if len(items) != len(expected) {
+ t.Fatalf("Expected string array %v, got %#v", expected, items)
+ }
+ for i, expectedValue := range expected {
+ if items[i] != expectedValue {
+ t.Fatalf("Expected string array %v, got %#v", expected, items)
+ }
+ }
+}
+
+// fakeStdioCliScript is intentionally kept close to the fake CLIs used by the
+// other SDK client-options E2E tests, while still matching Go's request capture shape.
const fakeStdioCliScript = `
const fs = require("fs");
@@ -430,6 +768,11 @@ function handleMessage(message) {
writeResponse(message.id, { sessionId, workspacePath: null, capabilities: null });
return;
}
+ if (message.method === "session.resume") {
+ const sessionId = (message.params && message.params.sessionId) || "fake-session";
+ writeResponse(message.id, { sessionId, workspacePath: null, capabilities: null });
+ return;
+ }
writeResponse(message.id, {});
}
diff --git a/go/internal/e2e/copilot_request_helpers_test.go b/go/internal/e2e/copilot_request_helpers_test.go
index 7c6058207..81d14f4d9 100644
--- a/go/internal/e2e/copilot_request_helpers_test.go
+++ b/go/internal/e2e/copilot_request_helpers_test.go
@@ -128,6 +128,47 @@ func buildResponsesSSEBody(text, respID string) string {
return sb.String()
}
+// buildAnthropicMessageSSEBody returns a complete Anthropic Messages SSE body for a
+// streaming /messages response (message_start … message_stop). The buffered JSON
+// message is only valid for a non-streaming request; a streaming request expects
+// named SSE events or the runtime fails to finalize the message.
+func buildAnthropicMessageSSEBody(text string) string {
+ events := []struct {
+ name string
+ data map[string]any
+ }{
+ {"message_start", map[string]any{
+ "type": "message_start",
+ "message": map[string]any{
+ "id": "msg_stub_1", "type": "message", "role": "assistant",
+ "model": "claude-sonnet-4.5", "content": []any{},
+ "stop_reason": nil, "stop_sequence": nil,
+ "usage": map[string]any{"input_tokens": 5, "output_tokens": 1},
+ },
+ }},
+ {"content_block_start", map[string]any{
+ "type": "content_block_start", "index": 0,
+ "content_block": map[string]any{"type": "text", "text": ""},
+ }},
+ {"content_block_delta", map[string]any{
+ "type": "content_block_delta", "index": 0,
+ "delta": map[string]any{"type": "text_delta", "text": text},
+ }},
+ {"content_block_stop", map[string]any{"type": "content_block_stop", "index": 0}},
+ {"message_delta", map[string]any{
+ "type": "message_delta",
+ "delta": map[string]any{"stop_reason": "end_turn", "stop_sequence": nil},
+ "usage": map[string]any{"output_tokens": 7},
+ }},
+ {"message_stop", map[string]any{"type": "message_stop"}},
+ }
+ var sb strings.Builder
+ for _, event := range events {
+ sb.WriteString(sseFrame(event.name, event.data))
+ }
+ return sb.String()
+}
+
// buildInferenceResponse synthesizes a well-formed inference HTTP response.
func buildInferenceResponse(url string, bodyText string) *http.Response {
wantsStream := isStreamingRequest(bodyText)
@@ -167,6 +208,9 @@ func buildInferenceResponse(url string, bodyText string) *http.Response {
}
if strings.HasSuffix(u, "/messages") {
+ if wantsStream {
+ return buildSSEResponse(buildAnthropicMessageSSEBody(syntheticResponseText))
+ }
raw, _ := json.Marshal(map[string]any{
"id": "msg_stub_1",
"type": "message",
diff --git a/go/internal/e2e/github_telemetry_e2e_test.go b/go/internal/e2e/github_telemetry_e2e_test.go
new file mode 100644
index 000000000..aa26ba31f
--- /dev/null
+++ b/go/internal/e2e/github_telemetry_e2e_test.go
@@ -0,0 +1,68 @@
+package e2e
+
+import (
+ "sync"
+ "testing"
+ "time"
+
+ copilot "github.com/github/copilot-sdk/go"
+ "github.com/github/copilot-sdk/go/internal/e2e/testharness"
+ "github.com/github/copilot-sdk/go/rpc"
+)
+
+func TestGitHubTelemetryE2E(t *testing.T) {
+ t.Run("should forward github telemetry for a live session", func(t *testing.T) {
+ ctx := testharness.NewTestContext(t)
+ ctx.ConfigureForTest(t)
+
+ var mu sync.Mutex
+ var notifications []*rpc.GitHubTelemetryNotification
+ client := ctx.NewClient(func(opts *copilot.ClientOptions) {
+ opts.OnGitHubTelemetry = func(notification *rpc.GitHubTelemetryNotification) {
+ mu.Lock()
+ notifications = append(notifications, notification)
+ mu.Unlock()
+ }
+ })
+ t.Cleanup(func() { client.ForceStop() })
+
+ session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
+ OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
+ })
+ if err != nil {
+ t.Fatalf("CreateSession failed: %v", err)
+ }
+ t.Cleanup(func() { session.Disconnect() })
+
+ notification := waitForGitHubTelemetryNotification(t, &mu, ¬ifications, 30*time.Second)
+ if notification.SessionID == nil || *notification.SessionID == "" {
+ t.Fatal("Expected a non-empty SessionID")
+ }
+ if notification.Event.Kind == "" {
+ t.Fatal("Expected a non-empty Event.Kind")
+ }
+ })
+}
+
+func waitForGitHubTelemetryNotification(t *testing.T, mu *sync.Mutex, notifications *[]*rpc.GitHubTelemetryNotification, timeout time.Duration) *rpc.GitHubTelemetryNotification {
+ t.Helper()
+
+ deadline := time.Now().Add(timeout)
+ for time.Now().Before(deadline) {
+ mu.Lock()
+ if len(*notifications) > 0 {
+ notification := (*notifications)[0]
+ mu.Unlock()
+ if notification != nil {
+ return notification
+ }
+ t.Fatal("Received nil GitHub telemetry notification")
+ }
+ mu.Unlock()
+
+ time.Sleep(50 * time.Millisecond)
+ }
+
+ t.Fatalf("Timed out waiting for GitHub telemetry notification after %s", timeout)
+ return nil
+}
diff --git a/go/internal/e2e/mcp_oauth_e2e_test.go b/go/internal/e2e/mcp_oauth_e2e_test.go
index e423f12d1..795904306 100644
--- a/go/internal/e2e/mcp_oauth_e2e_test.go
+++ b/go/internal/e2e/mcp_oauth_e2e_test.go
@@ -218,7 +218,7 @@ func TestMCPOAuthE2E(t *testing.T) {
}
t.Cleanup(func() { session.Disconnect() })
- waitForMCPServerStatus(t, session, serverName, rpc.MCPServerStatusFailed)
+ waitForMCPServerStatus(t, session, serverName, rpc.MCPServerStatusNeedsAuth)
if observedRequest.ServerName != serverName {
t.Fatalf("Expected serverName %q, got %q", serverName, observedRequest.ServerName)
}
@@ -226,6 +226,77 @@ func TestMCPOAuthE2E(t *testing.T) {
t.Fatalf("Unexpected auth request reason: %q", observedRequest.Reason)
}
})
+
+ t.Run("resolve pending MCP OAuth request through RPC", func(t *testing.T) {
+ ctx := testharness.NewTestContext(t)
+ ctx.ConfigureWithoutSnapshot(t)
+ client := ctx.NewClient()
+ defer client.ForceStop()
+
+ baseURL := startOAuthMCPServer(t)
+ serverName := "oauth-direct-rpc-mcp"
+ requests := make(chan copilot.MCPAuthRequest, 1)
+ releaseHandler := make(chan struct{})
+
+ session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
+ OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
+ EnableMCPApps: true,
+ OnMCPAuthRequest: func(request copilot.MCPAuthRequest, _ copilot.MCPAuthInvocation) (*copilot.MCPAuthResult, error) {
+ requests <- request
+ <-releaseHandler
+ return copilot.MCPAuthResultCancelled(), nil
+ },
+ MCPServers: map[string]copilot.MCPServerConfig{
+ serverName: copilot.MCPHTTPServerConfig{
+ URL: baseURL + "/mcp",
+ Tools: []string{"*"},
+ },
+ },
+ })
+ if err != nil {
+ t.Fatalf("Failed to create session: %v", err)
+ }
+ t.Cleanup(func() { session.Disconnect() })
+
+ connected := make(chan error, 1)
+ go func() {
+ connected <- waitForMCPServerStatusResult(t.Context(), session, serverName, rpc.MCPServerStatusConnected, 60*time.Second)
+ }()
+
+ var request copilot.MCPAuthRequest
+ select {
+ case request = <-requests:
+ case <-time.After(30 * time.Second):
+ t.Fatal("Timed out waiting for MCP OAuth request")
+ }
+
+ tokenType := "Bearer"
+ expiresIn := int64(3600)
+ result, err := session.RPC.MCP.Oauth().HandlePendingRequest(t.Context(), &rpc.MCPOauthHandlePendingRequest{
+ RequestID: request.RequestID,
+ Result: rpc.MCPOauthPendingRequestResponseToken{
+ AccessToken: expectedMCPOAuthToken,
+ TokenType: &tokenType,
+ ExpiresIn: &expiresIn,
+ },
+ })
+ if err != nil {
+ close(releaseHandler)
+ t.Fatalf("HandlePendingRequest failed: %v", err)
+ }
+ close(releaseHandler)
+ if !result.Success {
+ t.Fatal("Expected direct MCP OAuth pending request resolution to succeed")
+ }
+
+ if err := <-connected; err != nil {
+ t.Fatal(err)
+ }
+ requestLog := fetchOAuthMCPRequests(t, baseURL)
+ if !hasAuthorization(requestLog, "Bearer "+expectedMCPOAuthToken) {
+ t.Fatal("Expected MCP request with token supplied through direct RPC")
+ }
+ })
}
type oauthMCPRequest struct {
diff --git a/go/internal/e2e/mcp_server_helpers_test.go b/go/internal/e2e/mcp_server_helpers_test.go
index 1860067ed..e7269b1e2 100644
--- a/go/internal/e2e/mcp_server_helpers_test.go
+++ b/go/internal/e2e/mcp_server_helpers_test.go
@@ -1,6 +1,8 @@
package e2e
import (
+ "context"
+ "fmt"
"path/filepath"
"testing"
"time"
@@ -33,10 +35,16 @@ func testMCPServers(t *testing.T, serverNames ...string) map[string]copilot.MCPS
func waitForMCPServerStatus(t *testing.T, session *copilot.Session, serverName string, expectedStatus rpc.MCPServerStatus) {
t.Helper()
+ if err := waitForMCPServerStatusResult(t.Context(), session, serverName, expectedStatus, 60*time.Second); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func waitForMCPServerStatusResult(ctx context.Context, session *copilot.Session, serverName string, expectedStatus rpc.MCPServerStatus, timeout time.Duration) error {
var lastStatus string
- deadline := time.Now().Add(60 * time.Second)
+ deadline := time.Now().Add(timeout)
for time.Now().Before(deadline) {
- result, err := session.RPC.MCP.List(t.Context())
+ result, err := session.RPC.MCP.List(ctx)
if err != nil {
lastStatus = err.Error()
} else {
@@ -46,7 +54,7 @@ func waitForMCPServerStatus(t *testing.T, session *copilot.Session, serverName s
continue
}
if server.Status == expectedStatus {
- return
+ return nil
}
lastStatus = string(server.Status)
break
@@ -55,5 +63,5 @@ func waitForMCPServerStatus(t *testing.T, session *copilot.Session, serverName s
time.Sleep(200 * time.Millisecond)
}
- t.Fatalf("%s did not reach %s; last status was %s", serverName, expectedStatus, lastStatus)
+ return fmt.Errorf("%s did not reach %s; last status was %s", serverName, expectedStatus, lastStatus)
}
diff --git a/go/internal/e2e/rpc_server_e2e_test.go b/go/internal/e2e/rpc_server_e2e_test.go
index ba661acdb..2510eb1d9 100644
--- a/go/internal/e2e/rpc_server_e2e_test.go
+++ b/go/internal/e2e/rpc_server_e2e_test.go
@@ -3,6 +3,7 @@ package e2e
import (
"fmt"
"path/filepath"
+ "runtime"
"strings"
"testing"
"time"
@@ -196,6 +197,44 @@ func TestRPCServerE2E(t *testing.T) {
}
})
+ t.Run("should return false for missing LLM response frames", func(t *testing.T) {
+ ctx := testharness.NewTestContext(t)
+ client := ctx.NewClient()
+ t.Cleanup(func() { client.ForceStop() })
+
+ if err := client.Start(t.Context()); err != nil {
+ t.Fatalf("Start failed: %v", err)
+ }
+
+ start, err := client.RPC.LlmInference.HttpResponseStart(t.Context(), &rpc.LlmInferenceHTTPResponseStartRequest{
+ RequestID: "missing-response-start-request",
+ Status: 200,
+ StatusText: rpcPtr("OK"),
+ Headers: map[string][]string{
+ "content-type": {"application/json"},
+ },
+ })
+ if err != nil {
+ t.Fatalf("LlmInference.HttpResponseStart failed: %v", err)
+ }
+ if start.Accepted {
+ t.Fatal("Expected Accepted=false for missing LLM response start request id")
+ }
+
+ end := true
+ chunk, err := client.RPC.LlmInference.HttpResponseChunk(t.Context(), &rpc.LlmInferenceHTTPResponseChunkRequest{
+ RequestID: "missing-response-chunk-request",
+ Data: "{}",
+ End: &end,
+ })
+ if err != nil {
+ t.Fatalf("LlmInference.HttpResponseChunk failed: %v", err)
+ }
+ if chunk.Accepted {
+ t.Fatal("Expected Accepted=false for missing LLM response chunk request id")
+ }
+ })
+
t.Run("should list find and inspect persisted session state", func(t *testing.T) {
ctx := testharness.NewTestContext(t)
token := "rpc-server-list-token-" + randomHex(t)
@@ -554,6 +593,82 @@ func TestRPCServerE2E(t *testing.T) {
t.Errorf("Expected skill path to end with %q, got %v", expectedSuffix, discovered.Path)
}
+ excludeHost := true
+ skillPaths, err := client.RPC.Skills.GetDiscoveryPaths(t.Context(), &rpc.SkillsGetDiscoveryPathsRequest{
+ ProjectPaths: []string{ctx.WorkDir},
+ ExcludeHostSkills: &excludeHost,
+ })
+ if err != nil {
+ t.Fatalf("Skills.GetDiscoveryPaths failed: %v", err)
+ }
+ projectSkillPath := findSkillDiscoveryPath(skillPaths.Paths, ctx.WorkDir)
+ if projectSkillPath == nil {
+ t.Fatalf("Expected skill discovery paths to include %q", ctx.WorkDir)
+ }
+ if strings.TrimSpace(projectSkillPath.Path) == "" {
+ t.Fatal("Expected non-empty skill discovery path")
+ }
+
+ agents, err := client.RPC.Agents.Discover(t.Context(), &rpc.AgentsDiscoverRequest{
+ ProjectPaths: []string{ctx.WorkDir},
+ ExcludeHostAgents: &excludeHost,
+ })
+ if err != nil {
+ t.Fatalf("Agents.Discover failed: %v", err)
+ }
+ for _, agent := range agents.Agents {
+ if strings.TrimSpace(agent.Name) == "" {
+ t.Fatalf("Expected discovered agent to have a name: %+v", agent)
+ }
+ }
+
+ agentPaths, err := client.RPC.Agents.GetDiscoveryPaths(t.Context(), &rpc.AgentsGetDiscoveryPathsRequest{
+ ProjectPaths: []string{ctx.WorkDir},
+ ExcludeHostAgents: &excludeHost,
+ })
+ if err != nil {
+ t.Fatalf("Agents.GetDiscoveryPaths failed: %v", err)
+ }
+ projectAgentPath := findAgentDiscoveryPath(agentPaths.Paths, ctx.WorkDir)
+ if projectAgentPath == nil {
+ t.Fatalf("Expected agent discovery paths to include %q", ctx.WorkDir)
+ }
+ if strings.TrimSpace(projectAgentPath.Path) == "" {
+ t.Fatal("Expected non-empty agent discovery path")
+ }
+
+ instructions, err := client.RPC.Instructions.Discover(t.Context(), &rpc.InstructionsDiscoverRequest{
+ ProjectPaths: []string{ctx.WorkDir},
+ ExcludeHostInstructions: &excludeHost,
+ })
+ if err != nil {
+ t.Fatalf("Instructions.Discover failed: %v", err)
+ }
+ for _, source := range instructions.Sources {
+ if strings.TrimSpace(source.ID) == "" || strings.TrimSpace(source.Label) == "" || strings.TrimSpace(source.SourcePath) == "" {
+ t.Fatalf("Expected discovered instruction source fields to be populated: %+v", source)
+ }
+ }
+
+ instructionPaths, err := client.RPC.Instructions.GetDiscoveryPaths(t.Context(), &rpc.InstructionsGetDiscoveryPathsRequest{
+ ProjectPaths: []string{ctx.WorkDir},
+ ExcludeHostInstructions: &excludeHost,
+ })
+ if err != nil {
+ t.Fatalf("Instructions.GetDiscoveryPaths failed: %v", err)
+ }
+ if len(instructionPaths.Paths) == 0 {
+ t.Fatal("Expected instruction discovery paths")
+ }
+ if !hasInstructionDiscoveryPath(instructionPaths.Paths, ctx.WorkDir) {
+ t.Fatalf("Expected instruction discovery paths to include %q", ctx.WorkDir)
+ }
+ for _, path := range instructionPaths.Paths {
+ if strings.TrimSpace(path.Path) == "" {
+ t.Fatalf("Expected non-empty instruction discovery path: %+v", path)
+ }
+ }
+
// Disable the skill globally and re-discover.
if _, err := client.RPC.Skills.Config().SetDisabledSkills(t.Context(), &rpc.SkillsConfigSetDisabledSkillsRequest{
DisabledSkills: []string{skillName},
@@ -615,6 +730,42 @@ func findServerSkill(skills []rpc.ServerSkill, name string) *rpc.ServerSkill {
return nil
}
+func findSkillDiscoveryPath(paths []rpc.SkillDiscoveryPath, projectPath string) *rpc.SkillDiscoveryPath {
+ for i, path := range paths {
+ if path.ProjectPath != nil && path.PreferredForCreation && pathsEqual(*path.ProjectPath, projectPath) {
+ return &paths[i]
+ }
+ }
+ return nil
+}
+
+func findAgentDiscoveryPath(paths []rpc.AgentDiscoveryPath, projectPath string) *rpc.AgentDiscoveryPath {
+ for i, path := range paths {
+ if path.ProjectPath != nil && path.PreferredForCreation && pathsEqual(*path.ProjectPath, projectPath) {
+ return &paths[i]
+ }
+ }
+ return nil
+}
+
+func hasInstructionDiscoveryPath(paths []rpc.InstructionDiscoveryPath, projectPath string) bool {
+ for _, path := range paths {
+ if path.ProjectPath != nil && pathsEqual(*path.ProjectPath, projectPath) {
+ return true
+ }
+ }
+ return false
+}
+
+func pathsEqual(left, right string) bool {
+ left = filepath.Clean(left)
+ right = filepath.Clean(right)
+ if runtime.GOOS == "windows" {
+ return strings.EqualFold(left, right)
+ }
+ return left == right
+}
+
func saveSession(t *testing.T, client *copilot.Client, sessionID string) {
t.Helper()
if _, err := client.RPC.Sessions.Save(t.Context(), &rpc.SessionsSaveRequest{SessionID: sessionID}); err != nil {
diff --git a/go/internal/e2e/rpc_server_misc_e2e_test.go b/go/internal/e2e/rpc_server_misc_e2e_test.go
index 34b48b506..38b569798 100644
--- a/go/internal/e2e/rpc_server_misc_e2e_test.go
+++ b/go/internal/e2e/rpc_server_misc_e2e_test.go
@@ -5,6 +5,7 @@ import (
"testing"
"time"
+ copilot "github.com/github/copilot-sdk/go"
"github.com/github/copilot-sdk/go/internal/e2e/testharness"
"github.com/github/copilot-sdk/go/rpc"
)
@@ -25,6 +26,168 @@ func TestRpcServerMisc(t *testing.T) {
}
})
+ t.Run("should_get_set_and_clear_user_settings", func(t *testing.T) {
+ ctx.ConfigureForTest(t)
+ client := newStartedIsolatedPortedClient(t, ctx)
+ defer client.ForceStop()
+
+ initial, err := client.RPC.User.Settings().Get(t.Context())
+ if err != nil {
+ t.Fatalf("User.Settings.Get initial failed: %v", err)
+ }
+ if initial.Settings == nil {
+ t.Fatal("Expected settings map")
+ }
+ var key string
+ var value bool
+ for candidateKey, setting := range initial.Settings {
+ if candidateValue, ok := setting.Value.(bool); ok {
+ key = candidateKey
+ value = candidateValue
+ break
+ }
+ }
+ if key == "" {
+ t.Fatalf("Expected at least one boolean setting, got %+v", initial.Settings)
+ }
+ toggledValue := !value
+
+ set, err := client.RPC.User.Settings().Set(t.Context(), &rpc.UserSettingsSetRequest{
+ Settings: map[string]any{key: toggledValue},
+ })
+ if err != nil {
+ t.Fatalf("User.Settings.Set(toggle) failed: %v", err)
+ }
+ if len(set.ShadowedKeys) != 0 {
+ t.Fatalf("Expected no shadowed settings keys, got %+v", set.ShadowedKeys)
+ }
+ if _, err := client.RPC.User.Settings().Reload(t.Context()); err != nil {
+ t.Fatalf("User.Settings.Reload after set failed: %v", err)
+ }
+ afterSet, err := client.RPC.User.Settings().Get(t.Context())
+ if err != nil {
+ t.Fatalf("User.Settings.Get after set failed: %v", err)
+ }
+ metadata, ok := afterSet.Settings[key]
+ if !ok {
+ t.Fatalf("Expected setting %q in %+v", key, afterSet.Settings)
+ }
+ if metadata.Value != toggledValue || metadata.IsDefault {
+ t.Fatalf("Expected explicit true setting, got %+v", metadata)
+ }
+
+ clear, err := client.RPC.User.Settings().Set(t.Context(), &rpc.UserSettingsSetRequest{
+ Settings: map[string]any{key: nil},
+ })
+ if err != nil {
+ t.Fatalf("User.Settings.Set(null) failed: %v", err)
+ }
+ if len(clear.ShadowedKeys) != 0 {
+ t.Fatalf("Expected no shadowed settings keys from clear, got %+v", clear.ShadowedKeys)
+ }
+ if _, err := client.RPC.User.Settings().Reload(t.Context()); err != nil {
+ t.Fatalf("User.Settings.Reload after clear failed: %v", err)
+ }
+ afterClear, err := client.RPC.User.Settings().Get(t.Context())
+ if err != nil {
+ t.Fatalf("User.Settings.Get after clear failed: %v", err)
+ }
+ metadata, ok = afterClear.Settings[key]
+ if !ok {
+ t.Fatalf("Expected setting %q after clear in %+v", key, afterClear.Settings)
+ }
+ if !metadata.IsDefault {
+ t.Fatalf("Expected cleared setting to be default, got %+v", metadata)
+ }
+ })
+
+ t.Run("should_login_list_getcurrentauth_and_logout_account", func(t *testing.T) {
+ ctx.ConfigureForTest(t)
+ if err := ctx.SetCopilotUserByToken("go-account-token", map[string]interface{}{
+ "login": "go-account-user",
+ "copilot_plan": "individual_pro",
+ "endpoints": map[string]interface{}{
+ "api": ctx.ProxyURL,
+ "telemetry": "https://localhost:1/telemetry",
+ },
+ "analytics_tracking_id": "go-account-user-tracking-id",
+ }); err != nil {
+ t.Fatalf("SetCopilotUserByToken failed: %v", err)
+ }
+ client := newNoTokenClient(t, ctx)
+ defer client.ForceStop()
+
+ if err := client.Start(t.Context()); err != nil {
+ t.Fatalf("Start failed: %v", err)
+ }
+
+ initial, err := client.RPC.Account.GetCurrentAuth(t.Context())
+ if err != nil {
+ t.Fatalf("Account.GetCurrentAuth initial failed: %v", err)
+ }
+ if initial.AuthInfo != nil {
+ t.Fatalf("Expected no initial auth info, got %+v", initial.AuthInfo)
+ }
+
+ login, err := client.RPC.Account.Login(t.Context(), &rpc.AccountLoginRequest{
+ Host: "https://github.com",
+ Login: "go-account-user",
+ Token: "go-account-token",
+ })
+ if err != nil {
+ t.Fatalf("Account.Login failed: %v", err)
+ }
+ if login == nil {
+ t.Fatal("Expected login result")
+ }
+
+ current, err := client.RPC.Account.GetCurrentAuth(t.Context())
+ if err != nil {
+ t.Fatalf("Account.GetCurrentAuth after login failed: %v", err)
+ }
+ authInfo, ok := current.AuthInfo.(*rpc.UserAuthInfo)
+ if !ok {
+ t.Fatalf("Expected user auth info after login, got %#v", current.AuthInfo)
+ }
+ if authInfo.Login != "go-account-user" || authInfo.Host != "https://github.com" {
+ t.Fatalf("Unexpected current auth info: %+v", authInfo)
+ }
+
+ users, err := client.RPC.Account.GetAllUsers(t.Context())
+ if err != nil {
+ t.Fatalf("Account.GetAllUsers failed: %v", err)
+ }
+ if users == nil {
+ t.Fatal("Expected non-nil users result")
+ }
+ for _, user := range *users {
+ userInfo, ok := user.AuthInfo.(*rpc.UserAuthInfo)
+ if !ok {
+ t.Fatalf("Expected user auth info in all users, got %#v", user.AuthInfo)
+ }
+ if userInfo.Login == "go-account-user" && (user.Token == nil || *user.Token != "go-account-token") {
+ t.Fatalf("Expected logged-in user's token to round trip, got %+v", user)
+ }
+ }
+
+ logout, err := client.RPC.Account.Logout(t.Context(), &rpc.AccountLogoutRequest{
+ AuthInfo: authInfo,
+ })
+ if err != nil {
+ t.Fatalf("Account.Logout failed: %v", err)
+ }
+ if logout.HasMoreUsers {
+ t.Fatalf("Expected no users after isolated logout, got %+v", logout)
+ }
+ afterLogout, err := client.RPC.Account.GetCurrentAuth(t.Context())
+ if err != nil {
+ t.Fatalf("Account.GetCurrentAuth after logout failed: %v", err)
+ }
+ if afterLogout.AuthInfo != nil {
+ t.Fatalf("Expected no auth after logout, got %+v", afterLogout.AuthInfo)
+ }
+ })
+
t.Run("should_report_agent_registry_spawn_gate_closed", func(t *testing.T) {
ctx.ConfigureForTest(t)
client := newStartedIsolatedPortedClient(t, ctx)
@@ -91,3 +254,22 @@ func TestRpcServerMisc(t *testing.T) {
assertPortedContainsFold(t, message, "extension")
})
}
+
+func newNoTokenClient(t *testing.T, ctx *testharness.TestContext) *copilot.Client {
+ t.Helper()
+ env := append([]string{}, ctx.Env()...)
+ env = append(env,
+ "COPILOT_HOME="+t.TempDir(),
+ "GH_CONFIG_DIR="+t.TempDir(),
+ "GH_TOKEN=",
+ "GITHUB_TOKEN=",
+ "COPILOT_SDK_AUTH_TOKEN=",
+ )
+ useLoggedInUser := false
+ return copilot.NewClient(&copilot.ClientOptions{
+ Connection: copilot.StdioConnection{Path: ctx.CLIPath},
+ WorkingDirectory: ctx.WorkDir,
+ Env: env,
+ UseLoggedInUser: &useLoggedInUser,
+ })
+}
diff --git a/go/internal/e2e/rpc_session_state_extras_e2e_test.go b/go/internal/e2e/rpc_session_state_extras_e2e_test.go
index f4de1c186..1e33e8a8b 100644
--- a/go/internal/e2e/rpc_session_state_extras_e2e_test.go
+++ b/go/internal/e2e/rpc_session_state_extras_e2e_test.go
@@ -70,7 +70,7 @@ func TestRpcSessionStateExtras(t *testing.T) {
session := createPortedSession(t, client, nil)
defer session.Disconnect()
defer func() {
- _, _ = session.RPC.Permissions.SetAllowAll(t.Context(), &rpc.PermissionsSetAllowAllRequest{Enabled: false})
+ _, _ = session.RPC.Permissions.SetAllowAll(t.Context(), &rpc.PermissionsSetAllowAllRequest{Enabled: copilot.Bool(false)})
}()
initial, err := session.RPC.Permissions.GetAllowAll(t.Context())
@@ -81,7 +81,7 @@ func TestRpcSessionStateExtras(t *testing.T) {
t.Fatal("Allow-all should be disabled on a fresh session")
}
- enable, err := session.RPC.Permissions.SetAllowAll(t.Context(), &rpc.PermissionsSetAllowAllRequest{Enabled: true})
+ enable, err := session.RPC.Permissions.SetAllowAll(t.Context(), &rpc.PermissionsSetAllowAllRequest{Enabled: copilot.Bool(true)})
if err != nil {
t.Fatalf("Permissions.SetAllowAll(true) failed: %v", err)
}
@@ -96,7 +96,7 @@ func TestRpcSessionStateExtras(t *testing.T) {
t.Fatal("Expected allow-all to be enabled")
}
- disable, err := session.RPC.Permissions.SetAllowAll(t.Context(), &rpc.PermissionsSetAllowAllRequest{Enabled: false})
+ disable, err := session.RPC.Permissions.SetAllowAll(t.Context(), &rpc.PermissionsSetAllowAllRequest{Enabled: copilot.Bool(false)})
if err != nil {
t.Fatalf("Permissions.SetAllowAll(false) failed: %v", err)
}
@@ -176,6 +176,157 @@ func TestRpcSessionStateExtras(t *testing.T) {
}
})
+ t.Run("should_add_byok_provider_and_model_at_runtime", func(t *testing.T) {
+ ctx.ConfigureForTest(t)
+ session := createPortedSession(t, client, nil)
+ defer session.Disconnect()
+
+ apiKey := "provider-key"
+ providerType := rpc.ProviderConfigTypeOpenai
+ wireAPI := rpc.ProviderConfigWireAPICompletions
+ modelName := "Go Added Model"
+ maxPromptTokens := float64(4096)
+ result, err := session.RPC.Provider.Add(t.Context(), &rpc.ProviderAddRequest{
+ Providers: []rpc.NamedProviderConfig{{
+ Name: "go-e2e-provider",
+ Type: &providerType,
+ BaseURL: "https://models.example.test/v1",
+ APIKey: &apiKey,
+ Headers: map[string]string{"x-provider": "go"},
+ WireAPI: &wireAPI,
+ }},
+ Models: []rpc.ProviderModelConfig{{
+ ID: "small",
+ Provider: "go-e2e-provider",
+ Name: &modelName,
+ MaxPromptTokens: &maxPromptTokens,
+ }},
+ })
+ if err != nil {
+ t.Fatalf("Provider.Add failed: %v", err)
+ }
+ if len(result.Models) != 1 {
+ t.Fatalf("Expected one added provider model, got %+v", result.Models)
+ }
+
+ selectionID := "go-e2e-provider/small"
+ if _, err := session.RPC.Model.SwitchTo(t.Context(), &rpc.ModelSwitchToRequest{ModelID: selectionID}); err != nil {
+ t.Fatalf("Model.SwitchTo added model failed: %v", err)
+ }
+ current, err := session.RPC.Model.GetCurrent(t.Context())
+ if err != nil {
+ t.Fatalf("Model.GetCurrent after provider add failed: %v", err)
+ }
+ if current.ModelID == nil || *current.ModelID != selectionID {
+ t.Fatalf("Expected current model %q, got %+v", selectionID, current)
+ }
+ })
+
+ t.Run("should_return_empty_completions_when_host_does_not_provide_them", func(t *testing.T) {
+ ctx.ConfigureForTest(t)
+ session := createPortedSession(t, client, nil)
+ defer session.Disconnect()
+
+ result, err := session.RPC.Completions.Request(t.Context(), &rpc.CompletionsRequestRequest{
+ Text: "Use @ to mention context",
+ Offset: 5,
+ })
+ if err != nil {
+ t.Fatalf("Completions.Request failed: %v", err)
+ }
+ if result.Items == nil {
+ t.Fatal("Expected non-nil completion items list")
+ }
+ })
+
+ t.Run("should_report_visibility_as_unsynced_for_local_session", func(t *testing.T) {
+ ctx.ConfigureForTest(t)
+ session := createPortedSession(t, client, nil)
+ defer session.Disconnect()
+
+ status := rpc.SessionVisibilityStatusUnshared
+ set, err := session.RPC.Visibility.Set(t.Context(), &rpc.VisibilitySetRequest{Status: status})
+ if err != nil {
+ t.Fatalf("Visibility.Set failed: %v", err)
+ }
+ if set.Synced || set.Status != nil || set.ShareURL != nil {
+ t.Fatalf("Expected unsynced visibility set result, got %+v", set)
+ }
+ get, err := session.RPC.Visibility.Get(t.Context())
+ if err != nil {
+ t.Fatalf("Visibility.Get failed: %v", err)
+ }
+ if get.Synced || get.Status != nil || get.ShareURL != nil {
+ t.Fatalf("Expected unsynced visibility get result, got %+v", get)
+ }
+ })
+
+ t.Run("should_get_context_attribution_and_heaviest_messages_after_turn", func(t *testing.T) {
+ ctx.ConfigureForTest(t)
+ session := createPortedSession(t, client, nil)
+ defer session.Disconnect()
+
+ answer, err := session.SendAndWait(t.Context(), copilot.MessageOptions{Prompt: "Say CONTEXT_METADATA_OK exactly."})
+ if err != nil {
+ t.Fatalf("SendAndWait failed: %v", err)
+ }
+ if answer == nil {
+ t.Fatal("Expected final assistant message")
+ }
+
+ attribution, err := session.RPC.Metadata.GetContextAttribution(t.Context())
+ if err != nil {
+ t.Fatalf("Metadata.GetContextAttribution failed: %v", err)
+ }
+ if attribution == nil {
+ t.Fatal("Expected attribution result")
+ }
+ limit := int64(5)
+ heaviest, err := session.RPC.Metadata.GetContextHeaviestMessages(t.Context(), &rpc.MetadataContextHeaviestMessagesRequest{Limit: &limit})
+ if err != nil {
+ t.Fatalf("Metadata.GetContextHeaviestMessages failed: %v", err)
+ }
+ if heaviest.Messages == nil {
+ t.Fatal("Expected non-nil heaviest messages list")
+ }
+ })
+
+ t.Run("should_update_and_clear_live_subagent_settings", func(t *testing.T) {
+ ctx.ConfigureForTest(t)
+ session := createPortedSession(t, client, nil)
+ defer session.Disconnect()
+
+ contextTier := rpc.SubagentSettingsEntryContextTierLongContext
+ model := "gpt-5-mini"
+ reasoningEffort := "low"
+ update, err := session.RPC.Tools.UpdateSubagentSettings(t.Context(), &rpc.UpdateSubagentSettingsRequest{
+ Subagents: &rpc.SubagentSettings{
+ DisabledSubagents: []string{"legacy-agent"},
+ Agents: map[string]rpc.SubagentSettingsEntry{
+ "general-purpose": {
+ ContextTier: &contextTier,
+ Model: &model,
+ EffortLevel: &reasoningEffort,
+ },
+ },
+ },
+ })
+ if err != nil {
+ t.Fatalf("Tools.UpdateSubagentSettings failed: %v", err)
+ }
+ if update == nil {
+ t.Fatal("Expected update result")
+ }
+
+ clear, err := session.RPC.Tools.UpdateSubagentSettings(t.Context(), &rpc.UpdateSubagentSettingsRequest{})
+ if err != nil {
+ t.Fatalf("Tools.UpdateSubagentSettings clear failed: %v", err)
+ }
+ if clear == nil {
+ t.Fatal("Expected clear result")
+ }
+ })
+
t.Run("should_reload_session_plugins", func(t *testing.T) {
ctx.ConfigureForTest(t)
session := createPortedSession(t, client, nil)
diff --git a/go/internal/e2e/rpc_tasks_and_handlers_e2e_test.go b/go/internal/e2e/rpc_tasks_and_handlers_e2e_test.go
index 60ae3f1fd..0267f8d04 100644
--- a/go/internal/e2e/rpc_tasks_and_handlers_e2e_test.go
+++ b/go/internal/e2e/rpc_tasks_and_handlers_e2e_test.go
@@ -302,6 +302,39 @@ func TestRPCTasksAndHandlersE2E(t *testing.T) {
if locationApproval.Success {
t.Error("Expected Success=false for missing location approval request id")
}
+
+ sessionLimits, err := session.RPC.UI.HandlePendingSessionLimitsExhausted(t.Context(), &rpc.UIHandlePendingSessionLimitsExhaustedRequest{
+ RequestID: "missing-session-limits-request",
+ Response: rpc.UISessionLimitsExhaustedResponse{Action: rpc.UISessionLimitsExhaustedResponseActionCancel},
+ })
+ if err != nil {
+ t.Fatalf("UI.HandlePendingSessionLimitsExhausted failed: %v", err)
+ }
+ if sessionLimits.Success {
+ t.Error("Expected Success=false for missing session limits request id")
+ }
+
+ headers, err := session.RPC.MCP.Headers().HandlePendingHeadersRefreshRequest(t.Context(), &rpc.MCPHeadersHandlePendingHeadersRefreshRequestRequest{
+ RequestID: "missing-headers-refresh-request",
+ Result: rpc.MCPHeadersHandlePendingHeadersRefreshRequestHeaders{Headers: map[string]string{"authorization": "Bearer refreshed"}},
+ })
+ if err != nil {
+ t.Fatalf("MCP.Headers.HandlePendingHeadersRefreshRequest failed: %v", err)
+ }
+ if headers.Success {
+ t.Error("Expected Success=false for missing MCP headers refresh request id")
+ }
+
+ noHeaders, err := session.RPC.MCP.Headers().HandlePendingHeadersRefreshRequest(t.Context(), &rpc.MCPHeadersHandlePendingHeadersRefreshRequestRequest{
+ RequestID: "missing-headers-refresh-none-request",
+ Result: rpc.MCPHeadersHandlePendingHeadersRefreshRequestNone{},
+ })
+ if err != nil {
+ t.Fatalf("MCP.Headers.HandlePendingHeadersRefreshRequest none failed: %v", err)
+ }
+ if noHeaders.Success {
+ t.Error("Expected Success=false for missing MCP headers refresh none request id")
+ }
})
t.Run("should round trip rpc elicitation through config handler", func(t *testing.T) {
diff --git a/go/internal/e2e/testharness/context.go b/go/internal/e2e/testharness/context.go
index 2643980b7..6b6463749 100644
--- a/go/internal/e2e/testharness/context.go
+++ b/go/internal/e2e/testharness/context.go
@@ -158,6 +158,18 @@ func (c *TestContext) ConfigureForTest(t *testing.T) {
}
}
+// ConfigureWithoutSnapshot initializes the replay proxy without loading a recorded CAPI
+// exchange file. Use this for tests that serve all model-layer behavior locally but
+// still need proxy-backed auth and GitHub API endpoints.
+func (c *TestContext) ConfigureWithoutSnapshot(t *testing.T) {
+ t.Helper()
+
+ dummySnapshotPath := filepath.Join(c.WorkDir, "__no_snapshot__.yaml")
+ if err := c.proxy.Configure(dummySnapshotPath, c.WorkDir); err != nil {
+ t.Fatalf("Failed to configure proxy without snapshot: %v", err)
+ }
+}
+
// Close cleans up the test context resources.
func (c *TestContext) Close(testFailed bool) {
if c.proxy != nil {
diff --git a/go/rpc/zrpc.go b/go/rpc/zrpc.go
index 03cec0dc3..1a1ec84dd 100644
--- a/go/rpc/zrpc.go
+++ b/go/rpc/zrpc.go
@@ -28,7 +28,8 @@ type AbortResult struct {
Success bool `json:"success"`
}
-// Schema for the `AccountAllUsers` type.
+// Authenticated account entry returned by `account.getAllUsers`, with auth info and an
+// optional associated token.
// Experimental: AccountAllUsers is part of an experimental API and may change or be removed.
type AccountAllUsers struct {
// Authentication information for this user
@@ -106,7 +107,8 @@ type AccountLogoutResult struct {
HasMoreUsers bool `json:"hasMoreUsers"`
}
-// Schema for the `AccountQuotaSnapshot` type.
+// Quota usage snapshot for a Copilot quota type, including entitlement, used requests,
+// overage, reset date, and remaining percentage.
// Experimental: AccountQuotaSnapshot is part of an experimental API and may change or be
// removed.
type AccountQuotaSnapshot struct {
@@ -128,7 +130,8 @@ type AccountQuotaSnapshot struct {
UsedRequests int64 `json:"usedRequests"`
}
-// Schema for the `AgentDiscoveryPath` type.
+// Canonical directory where custom agents can be discovered or created, with scope,
+// preference, and optional project path.
// Experimental: AgentDiscoveryPath is part of an experimental API and may change or be
// removed.
type AgentDiscoveryPath struct {
@@ -159,7 +162,8 @@ type AgentGetCurrentResult struct {
Agent *AgentInfo `json:"agent,omitempty"`
}
-// Schema for the `AgentInfo` type.
+// Custom agent metadata, including identifiers, display details, source, tools, model, MCP
+// servers, skills, and file path.
// Experimental: AgentInfo is part of an experimental API and may change or be removed.
type AgentInfo struct {
// Description of the agent's purpose
@@ -429,18 +433,22 @@ type AgentsGetDiscoveryPathsRequest struct {
// Experimental: AllowAllPermissionSetResult is part of an experimental API and may change
// or be removed.
type AllowAllPermissionSetResult struct {
- // Authoritative allow-all state after the mutation
+ // Authoritative full allow-all state after the mutation
Enabled bool `json:"enabled"`
+ // Authoritative allow-all mode after the mutation
+ Mode *PermissionsAllowAllMode `json:"mode,omitempty"`
// Whether the operation succeeded
Success bool `json:"success"`
}
-// Current full allow-all permission state.
+// Current allow-all permission mode.
// Experimental: AllowAllPermissionState is part of an experimental API and may change or be
// removed.
type AllowAllPermissionState struct {
// Whether full allow-all permissions are currently active
Enabled bool `json:"enabled"`
+ // Current allow-all mode
+ Mode *PermissionsAllowAllMode `json:"mode,omitempty"`
}
// A user message attachment — a file, directory, code selection, blob, GitHub-anchored
@@ -852,7 +860,8 @@ func (r RawAuthInfoData) Type() AuthInfoType {
return r.Discriminator
}
-// Schema for the `ApiKeyAuthInfo` type.
+// Authentication-info variant for API-key authentication to a non-GitHub LLM provider,
+// carrying the secret `apiKey` and host.
// Experimental: APIKeyAuthInfo is part of an experimental API and may change or be removed.
type APIKeyAuthInfo struct {
// The API key. Treat as a secret.
@@ -870,7 +879,8 @@ func (APIKeyAuthInfo) Type() AuthInfoType {
return AuthInfoTypeAPIKey
}
-// Schema for the `CopilotApiTokenAuthInfo` type.
+// Authentication-info variant for direct Copilot API token auth sourced from environment
+// variables, with public GitHub host.
// Experimental: CopilotAPITokenAuthInfo is part of an experimental API and may change or be
// removed.
type CopilotAPITokenAuthInfo struct {
@@ -887,7 +897,8 @@ func (CopilotAPITokenAuthInfo) Type() AuthInfoType {
return AuthInfoTypeCopilotAPIToken
}
-// Schema for the `EnvAuthInfo` type.
+// Authentication-info variant for a token sourced from an environment variable, with host,
+// optional login, token, and env var name.
// Experimental: EnvAuthInfo is part of an experimental API and may change or be removed.
type EnvAuthInfo struct {
// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the
@@ -910,7 +921,8 @@ func (EnvAuthInfo) Type() AuthInfoType {
return AuthInfoTypeEnv
}
-// Schema for the `GhCliAuthInfo` type.
+// Authentication-info variant for GitHub CLI credentials, carrying host, login, and the `gh
+// auth token` value.
// Experimental: GhCLIAuthInfo is part of an experimental API and may change or be removed.
type GhCLIAuthInfo struct {
// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the
@@ -930,7 +942,8 @@ func (GhCLIAuthInfo) Type() AuthInfoType {
return AuthInfoTypeGhCLI
}
-// Schema for the `HMACAuthInfo` type.
+// Authentication-info variant for GitHub-internal HMAC auth, carrying the public GitHub
+// host and HMAC secret.
// Experimental: HMACAuthInfo is part of an experimental API and may change or be removed.
type HMACAuthInfo struct {
// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the
@@ -948,7 +961,8 @@ func (HMACAuthInfo) Type() AuthInfoType {
return AuthInfoTypeHMAC
}
-// Schema for the `TokenAuthInfo` type.
+// Authentication-info variant for SDK-configured token authentication, carrying host and
+// the secret token value.
// Experimental: TokenAuthInfo is part of an experimental API and may change or be removed.
type TokenAuthInfo struct {
// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the
@@ -966,7 +980,8 @@ func (TokenAuthInfo) Type() AuthInfoType {
return AuthInfoTypeToken
}
-// Schema for the `UserAuthInfo` type.
+// Authentication-info variant for OAuth user auth, with host and login; the token remains
+// in the runtime secret store.
// Experimental: UserAuthInfo is part of an experimental API and may change or be removed.
type UserAuthInfo struct {
// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the
@@ -1341,10 +1356,19 @@ type ConnectRemoteSessionParams struct {
SessionID string `json:"sessionId"`
}
-// Optional connection token presented by the SDK client during the handshake.
+// Parameters for the `server.connect` handshake: an optional connection token and optional
+// connection-level opt-ins (e.g. GitHub telemetry forwarding).
// Experimental: ConnectRequest is part of an experimental API and may change or be removed.
// Internal: ConnectRequest is an internal SDK API and is not part of the public surface.
type ConnectRequest struct {
+ // Opt this connection in to GitHub telemetry forwarding for its lifetime. When set, the
+ // runtime forwards every internal telemetry event it emits — across all sessions, plus
+ // sessionless events — to this connection over the `gitHubTelemetry.event` notification, in
+ // addition to the runtime's normal GitHub/CTS emission (dual-write). 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.
+ EnableGitHubTelemetryForwarding *bool `json:"enableGitHubTelemetryForwarding,omitempty"`
// Connection token; required when the server was started with COPILOT_CONNECTION_TOKEN
Token *string `json:"token,omitempty"`
}
@@ -1361,43 +1385,86 @@ type ConnectResult struct {
Version string `json:"version"`
}
+// A single large message currently in context.
+// Experimental: ContextHeaviestMessage is part of an experimental API and may change or be
+// removed.
+type ContextHeaviestMessage struct {
+ // Stable identifier for this message within the snapshot.
+ ID string `json:"id"`
+ // Human-readable source label, e.g. `tool: bash` or `skill: tmux`. Presentation-only.
+ Label string `json:"label"`
+ // Role of the chat message (`user`, `assistant`, or `tool`).
+ Role string `json:"role"`
+ // Token count currently in context for this individual message.
+ Tokens int64 `json:"tokens"`
+}
+
// 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: CopilotUserResponse is part of an experimental API and may change or be
// removed.
type CopilotUserResponse struct {
- AccessTypeSku *string `json:"access_type_sku,omitempty"`
- AnalyticsTrackingID *string `json:"analytics_tracking_id,omitempty"`
- AssignedDate *string `json:"assigned_date,omitempty"`
- CanSignupForLimited *bool `json:"can_signup_for_limited,omitempty"`
- CanUpgradePlan *bool `json:"can_upgrade_plan,omitempty"`
- ChatEnabled *bool `json:"chat_enabled,omitempty"`
- CLIRemoteControlEnabled *bool `json:"cli_remote_control_enabled,omitempty"`
- CloudSessionStorageEnabled *bool `json:"cloud_session_storage_enabled,omitempty"`
- CodexAgentEnabled *bool `json:"codex_agent_enabled,omitempty"`
- CopilotignoreEnabled *bool `json:"copilotignore_enabled,omitempty"`
- CopilotPlan *string `json:"copilot_plan,omitempty"`
- // Schema for the `CopilotUserResponseEndpoints` type.
- Endpoints *CopilotUserResponseEndpoints `json:"endpoints,omitempty"`
- IsMCPEnabled *bool `json:"is_mcp_enabled,omitempty"`
- IsStaff *bool `json:"is_staff,omitempty"`
- LimitedUserQuotas map[string]float64 `json:"limited_user_quotas,omitzero"`
- LimitedUserResetDate *string `json:"limited_user_reset_date,omitempty"`
- Login *string `json:"login,omitempty"`
- MonthlyQuotas map[string]float64 `json:"monthly_quotas,omitzero"`
- OrganizationList []CopilotUserResponseOrganizationListItem `json:"organization_list,omitzero"`
- OrganizationLoginList []string `json:"organization_login_list,omitzero"`
- QuotaResetDate *string `json:"quota_reset_date,omitempty"`
- QuotaResetDateUTC *string `json:"quota_reset_date_utc,omitempty"`
- // Schema for the `CopilotUserResponseQuotaSnapshots` type.
- QuotaSnapshots *CopilotUserResponseQuotaSnapshots `json:"quota_snapshots,omitempty"`
- RestrictedTelemetry *bool `json:"restricted_telemetry,omitempty"`
- Te *bool `json:"te,omitempty"`
- TokenBasedBilling *bool `json:"token_based_billing,omitempty"`
-}
-
-// Schema for the `CopilotUserResponseEndpoints` type.
+ // Copilot access SKU identifier (e.g. `free_limited_copilot`,
+ // `copilot_for_business_seat_quota`) used to gate model and feature access.
+ AccessTypeSku *string `json:"access_type_sku,omitempty"`
+ // Opaque analytics tracking identifier for the user, forwarded from the Copilot API.
+ AnalyticsTrackingID *string `json:"analytics_tracking_id,omitempty"`
+ // Date the Copilot seat was assigned to the user, if applicable.
+ AssignedDate *string `json:"assigned_date,omitempty"`
+ // Whether the user is eligible to sign up for the free/limited Copilot tier.
+ CanSignupForLimited *bool `json:"can_signup_for_limited,omitempty"`
+ // Whether the user is able to upgrade their Copilot plan.
+ CanUpgradePlan *bool `json:"can_upgrade_plan,omitempty"`
+ // Whether Copilot chat is enabled for the user.
+ ChatEnabled *bool `json:"chat_enabled,omitempty"`
+ // Whether CLI remote control is enabled for the user.
+ CLIRemoteControlEnabled *bool `json:"cli_remote_control_enabled,omitempty"`
+ // Whether cloud session storage is enabled for the user.
+ CloudSessionStorageEnabled *bool `json:"cloud_session_storage_enabled,omitempty"`
+ // Whether the Codex agent is enabled for the user.
+ CodexAgentEnabled *bool `json:"codex_agent_enabled,omitempty"`
+ // Whether `.copilotignore` content-exclusion support is enabled for the user.
+ CopilotignoreEnabled *bool `json:"copilotignore_enabled,omitempty"`
+ // Copilot plan name for the user (e.g. `individual`, `business`, `enterprise`).
+ CopilotPlan *string `json:"copilot_plan,omitempty"`
+ // Endpoint URLs from the raw Copilot `/copilot_internal/v2/token` user-response passthrough.
+ Endpoints *CopilotUserResponseEndpoints `json:"endpoints,omitempty"`
+ // Whether MCP (Model Context Protocol) support is enabled for the user.
+ IsMCPEnabled *bool `json:"is_mcp_enabled,omitempty"`
+ // Whether the user is a GitHub/Microsoft staff member.
+ IsStaff *bool `json:"is_staff,omitempty"`
+ // Per-category quota allotments for free/limited-tier users, keyed by quota category.
+ LimitedUserQuotas map[string]float64 `json:"limited_user_quotas,omitzero"`
+ // Date the free/limited-tier user's quotas next reset, as a raw string from the Copilot API.
+ LimitedUserResetDate *string `json:"limited_user_reset_date,omitempty"`
+ // GitHub login of the authenticated user.
+ Login *string `json:"login,omitempty"`
+ // Per-category monthly quota allotments, keyed by quota category.
+ MonthlyQuotas map[string]float64 `json:"monthly_quotas,omitzero"`
+ // Organizations the user belongs to, each with an optional login and display name.
+ OrganizationList []CopilotUserResponseOrganizationListItem `json:"organization_list,omitzero"`
+ // Logins of the organizations the user belongs to.
+ OrganizationLoginList []string `json:"organization_login_list,omitzero"`
+ // 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.
+ QuotaResetDate *string `json:"quota_reset_date,omitempty"`
+ // UTC-normalized form of `quota_reset_date` (the date the user's usage quota next resets).
+ QuotaResetDateUTC *string `json:"quota_reset_date_utc,omitempty"`
+ // Quota snapshot map from the raw Copilot user-response passthrough, with chat,
+ // completions, premium-interactions, and other entries.
+ QuotaSnapshots *CopilotUserResponseQuotaSnapshots `json:"quota_snapshots,omitempty"`
+ // Whether the user's telemetry is subject to restricted-data handling.
+ RestrictedTelemetry *bool `json:"restricted_telemetry,omitempty"`
+ // 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.
+ Te *bool `json:"te,omitempty"`
+ // Whether the account is on usage-based (token/AI-credit) billing rather than a fixed
+ // premium-request quota.
+ TokenBasedBilling *bool `json:"token_based_billing,omitempty"`
+}
+
+// Endpoint URLs from the raw Copilot `/copilot_internal/v2/token` user-response passthrough.
// Experimental: CopilotUserResponseEndpoints is part of an experimental API and may change
// or be removed.
type CopilotUserResponseEndpoints struct {
@@ -1412,70 +1479,122 @@ type CopilotUserResponseOrganizationListItem struct {
Name *string `json:"name,omitempty"`
}
-// Schema for the `CopilotUserResponseQuotaSnapshots` type.
+// Quota snapshot map from the raw Copilot user-response passthrough, with chat,
+// completions, premium-interactions, and other entries.
// Experimental: CopilotUserResponseQuotaSnapshots is part of an experimental API and may
// change or be removed.
type CopilotUserResponseQuotaSnapshots struct {
- // Schema for the `CopilotUserResponseQuotaSnapshotsChat` type.
+ // Chat quota snapshot from the raw Copilot user-response passthrough, with entitlement,
+ // overage, remaining quota, reset, and billing fields.
Chat *CopilotUserResponseQuotaSnapshotsChat `json:"chat,omitempty"`
- // Schema for the `CopilotUserResponseQuotaSnapshotsCompletions` type.
+ // Completions quota snapshot from the raw Copilot user-response passthrough, with
+ // entitlement, overage, remaining quota, reset, and billing fields.
Completions *CopilotUserResponseQuotaSnapshotsCompletions `json:"completions,omitempty"`
- // Schema for the `CopilotUserResponseQuotaSnapshotsPremiumInteractions` type.
+ // Premium-interactions quota snapshot from the raw Copilot user-response passthrough, with
+ // entitlement, overage, remaining quota, reset, and billing fields.
PremiumInteractions *CopilotUserResponseQuotaSnapshotsPremiumInteractions `json:"premium_interactions,omitempty"`
}
-// Schema for the `CopilotUserResponseQuotaSnapshotsChat` type.
+// Chat quota snapshot from the raw Copilot user-response passthrough, with entitlement,
+// overage, remaining quota, reset, and billing fields.
// Experimental: CopilotUserResponseQuotaSnapshotsChat is part of an experimental API and
// may change or be removed.
type CopilotUserResponseQuotaSnapshotsChat struct {
- Entitlement *float64 `json:"entitlement,omitempty"`
- HasQuota *bool `json:"has_quota,omitempty"`
- OverageCount *float64 `json:"overage_count,omitempty"`
- OveragePermitted *bool `json:"overage_permitted,omitempty"`
- PercentRemaining *float64 `json:"percent_remaining,omitempty"`
- QuotaID *string `json:"quota_id,omitempty"`
- QuotaRemaining *float64 `json:"quota_remaining,omitempty"`
- QuotaResetAt *float64 `json:"quota_reset_at,omitempty"`
- Remaining *float64 `json:"remaining,omitempty"`
- TimestampUTC *string `json:"timestamp_utc,omitempty"`
- TokenBasedBilling *bool `json:"token_based_billing,omitempty"`
- Unlimited *bool `json:"unlimited,omitempty"`
-}
-
-// Schema for the `CopilotUserResponseQuotaSnapshotsCompletions` type.
+ // Number of requests/units included in the entitlement for this period; `-1` denotes an
+ // unlimited entitlement.
+ Entitlement *float64 `json:"entitlement,omitempty"`
+ // Whether the user currently has quota available; when `false` and not unlimited, further
+ // requests are blocked until the quota resets.
+ HasQuota *bool `json:"has_quota,omitempty"`
+ // Count of additional pay-per-request usage consumed this period beyond the entitlement.
+ OverageCount *float64 `json:"overage_count,omitempty"`
+ // Whether usage may continue at pay-per-request rates once the entitlement is exhausted.
+ OveragePermitted *bool `json:"overage_permitted,omitempty"`
+ // Percentage of the entitlement remaining at the snapshot timestamp.
+ PercentRemaining *float64 `json:"percent_remaining,omitempty"`
+ // Identifier of the quota bucket this snapshot describes.
+ QuotaID *string `json:"quota_id,omitempty"`
+ // Amount of quota remaining at the snapshot timestamp.
+ QuotaRemaining *float64 `json:"quota_remaining,omitempty"`
+ // Unix epoch time, in seconds, when this quota next resets.
+ QuotaResetAt *float64 `json:"quota_reset_at,omitempty"`
+ // Remaining entitlement/quota amount at the snapshot timestamp.
+ Remaining *float64 `json:"remaining,omitempty"`
+ // UTC timestamp when this snapshot was captured.
+ TimestampUTC *string `json:"timestamp_utc,omitempty"`
+ // Whether this category uses usage-based (token/AI-credit) billing rather than a fixed
+ // premium-request count.
+ TokenBasedBilling *bool `json:"token_based_billing,omitempty"`
+ // Whether the entitlement for this category is unlimited.
+ Unlimited *bool `json:"unlimited,omitempty"`
+}
+
+// Completions quota snapshot from the raw Copilot user-response passthrough, with
+// entitlement, overage, remaining quota, reset, and billing fields.
// Experimental: CopilotUserResponseQuotaSnapshotsCompletions is part of an experimental API
// and may change or be removed.
type CopilotUserResponseQuotaSnapshotsCompletions struct {
- Entitlement *float64 `json:"entitlement,omitempty"`
- HasQuota *bool `json:"has_quota,omitempty"`
- OverageCount *float64 `json:"overage_count,omitempty"`
- OveragePermitted *bool `json:"overage_permitted,omitempty"`
- PercentRemaining *float64 `json:"percent_remaining,omitempty"`
- QuotaID *string `json:"quota_id,omitempty"`
- QuotaRemaining *float64 `json:"quota_remaining,omitempty"`
- QuotaResetAt *float64 `json:"quota_reset_at,omitempty"`
- Remaining *float64 `json:"remaining,omitempty"`
- TimestampUTC *string `json:"timestamp_utc,omitempty"`
- TokenBasedBilling *bool `json:"token_based_billing,omitempty"`
- Unlimited *bool `json:"unlimited,omitempty"`
-}
-
-// Schema for the `CopilotUserResponseQuotaSnapshotsPremiumInteractions` type.
+ // Number of requests/units included in the entitlement for this period; `-1` denotes an
+ // unlimited entitlement.
+ Entitlement *float64 `json:"entitlement,omitempty"`
+ // Whether the user currently has quota available; when `false` and not unlimited, further
+ // requests are blocked until the quota resets.
+ HasQuota *bool `json:"has_quota,omitempty"`
+ // Count of additional pay-per-request usage consumed this period beyond the entitlement.
+ OverageCount *float64 `json:"overage_count,omitempty"`
+ // Whether usage may continue at pay-per-request rates once the entitlement is exhausted.
+ OveragePermitted *bool `json:"overage_permitted,omitempty"`
+ // Percentage of the entitlement remaining at the snapshot timestamp.
+ PercentRemaining *float64 `json:"percent_remaining,omitempty"`
+ // Identifier of the quota bucket this snapshot describes.
+ QuotaID *string `json:"quota_id,omitempty"`
+ // Amount of quota remaining at the snapshot timestamp.
+ QuotaRemaining *float64 `json:"quota_remaining,omitempty"`
+ // Unix epoch time, in seconds, when this quota next resets.
+ QuotaResetAt *float64 `json:"quota_reset_at,omitempty"`
+ // Remaining entitlement/quota amount at the snapshot timestamp.
+ Remaining *float64 `json:"remaining,omitempty"`
+ // UTC timestamp when this snapshot was captured.
+ TimestampUTC *string `json:"timestamp_utc,omitempty"`
+ // Whether this category uses usage-based (token/AI-credit) billing rather than a fixed
+ // premium-request count.
+ TokenBasedBilling *bool `json:"token_based_billing,omitempty"`
+ // Whether the entitlement for this category is unlimited.
+ Unlimited *bool `json:"unlimited,omitempty"`
+}
+
+// Premium-interactions quota snapshot from the raw Copilot user-response passthrough, with
+// entitlement, overage, remaining quota, reset, and billing fields.
// Experimental: CopilotUserResponseQuotaSnapshotsPremiumInteractions is part of an
// experimental API and may change or be removed.
type CopilotUserResponseQuotaSnapshotsPremiumInteractions struct {
- Entitlement *float64 `json:"entitlement,omitempty"`
- HasQuota *bool `json:"has_quota,omitempty"`
- OverageCount *float64 `json:"overage_count,omitempty"`
- OveragePermitted *bool `json:"overage_permitted,omitempty"`
- PercentRemaining *float64 `json:"percent_remaining,omitempty"`
- QuotaID *string `json:"quota_id,omitempty"`
- QuotaRemaining *float64 `json:"quota_remaining,omitempty"`
- QuotaResetAt *float64 `json:"quota_reset_at,omitempty"`
- Remaining *float64 `json:"remaining,omitempty"`
- TimestampUTC *string `json:"timestamp_utc,omitempty"`
- TokenBasedBilling *bool `json:"token_based_billing,omitempty"`
- Unlimited *bool `json:"unlimited,omitempty"`
+ // Number of requests/units included in the entitlement for this period; `-1` denotes an
+ // unlimited entitlement.
+ Entitlement *float64 `json:"entitlement,omitempty"`
+ // Whether the user currently has quota available; when `false` and not unlimited, further
+ // requests are blocked until the quota resets.
+ HasQuota *bool `json:"has_quota,omitempty"`
+ // Count of additional pay-per-request usage consumed this period beyond the entitlement.
+ OverageCount *float64 `json:"overage_count,omitempty"`
+ // Whether usage may continue at pay-per-request rates once the entitlement is exhausted.
+ OveragePermitted *bool `json:"overage_permitted,omitempty"`
+ // Percentage of the entitlement remaining at the snapshot timestamp.
+ PercentRemaining *float64 `json:"percent_remaining,omitempty"`
+ // Identifier of the quota bucket this snapshot describes.
+ QuotaID *string `json:"quota_id,omitempty"`
+ // Amount of quota remaining at the snapshot timestamp.
+ QuotaRemaining *float64 `json:"quota_remaining,omitempty"`
+ // Unix epoch time, in seconds, when this quota next resets.
+ QuotaResetAt *float64 `json:"quota_reset_at,omitempty"`
+ // Remaining entitlement/quota amount at the snapshot timestamp.
+ Remaining *float64 `json:"remaining,omitempty"`
+ // UTC timestamp when this snapshot was captured.
+ TimestampUTC *string `json:"timestamp_utc,omitempty"`
+ // Whether this category uses usage-based (token/AI-credit) billing rather than a fixed
+ // premium-request count.
+ TokenBasedBilling *bool `json:"token_based_billing,omitempty"`
+ // Whether the entitlement for this category is unlimited.
+ Unlimited *bool `json:"unlimited,omitempty"`
}
// The currently selected model, reasoning effort, and context tier for the session. The
@@ -1513,6 +1632,142 @@ type CurrentToolMetadata struct {
NamespacedName *string `json:"namespacedName,omitempty"`
}
+// A file included in the redacted debug bundle.
+// Experimental: DebugCollectLogsCollectedEntry is part of an experimental API and may
+// change or be removed.
+type DebugCollectLogsCollectedEntry struct {
+ // Relative path of the file in the staged bundle/archive.
+ BundlePath string `json:"bundlePath"`
+ // Redacted output size in bytes.
+ SizeBytes int64 `json:"sizeBytes"`
+ // Source category for this entry.
+ Source DebugCollectLogsSource `json:"source"`
+}
+
+// Destination for the redacted debug bundle.
+// Experimental: DebugCollectLogsDestination is part of an experimental API and may change
+// or be removed.
+type DebugCollectLogsDestination interface {
+ debugCollectLogsDestination()
+ Kind() DebugCollectLogsDestinationKind
+}
+
+type RawDebugCollectLogsDestinationData struct {
+ Discriminator DebugCollectLogsDestinationKind
+ Raw json.RawMessage
+}
+
+func (RawDebugCollectLogsDestinationData) debugCollectLogsDestination() {}
+func (r RawDebugCollectLogsDestinationData) Kind() DebugCollectLogsDestinationKind {
+ return r.Discriminator
+}
+
+type DebugCollectLogsDestinationArchive struct {
+ // When true, create the archive atomically without overwriting an existing file by
+ // appending ` (N)` before the extension as needed. Defaults to false.
+ NoOverwrite *bool `json:"noOverwrite,omitempty"`
+ // Absolute or server-relative path for the .tgz archive to create.
+ OutputPath string `json:"outputPath"`
+}
+
+func (DebugCollectLogsDestinationArchive) debugCollectLogsDestination() {}
+func (DebugCollectLogsDestinationArchive) Kind() DebugCollectLogsDestinationKind {
+ return DebugCollectLogsDestinationKindArchive
+}
+
+type DebugCollectLogsDestinationDirectory struct {
+ // Directory where redacted files should be staged. The directory is created if needed.
+ OutputDirectory string `json:"outputDirectory"`
+}
+
+func (DebugCollectLogsDestinationDirectory) debugCollectLogsDestination() {}
+func (DebugCollectLogsDestinationDirectory) Kind() DebugCollectLogsDestinationKind {
+ return DebugCollectLogsDestinationKindDirectory
+}
+
+// A caller-provided server-local file or directory to include in the debug bundle.
+// Experimental: DebugCollectLogsEntry is part of an experimental API and may change or be
+// removed.
+type DebugCollectLogsEntry struct {
+ // Relative path to use inside the staged bundle/archive.
+ BundlePath string `json:"bundlePath"`
+ // Kind of source path to include.
+ Kind DebugCollectLogsEntryKind `json:"kind"`
+ // Server-local source path to read.
+ Path string `json:"path"`
+ // How text content from this entry should be redacted. Defaults to plain-text.
+ Redaction *DebugCollectLogsRedaction `json:"redaction,omitempty"`
+ // When true, collection fails if this entry cannot be read. Defaults to false, which
+ // records the entry in `skippedEntries`.
+ Required *bool `json:"required,omitempty"`
+}
+
+// Built-in session diagnostics to include in the bundle. Omitted fields default to true.
+// Experimental: DebugCollectLogsInclude is part of an experimental API and may change or be
+// removed.
+type DebugCollectLogsInclude struct {
+ // 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.
+ CurrentProcessLogPath *string `json:"currentProcessLogPath,omitempty"`
+ // Include the session event log (`events.jsonl`). Defaults to true.
+ Events *bool `json:"events,omitempty"`
+ // Server-local path to the session's events.jsonl file. Internal callers normally omit this
+ // and let the runtime derive it from the session.
+ EventsPath *string `json:"eventsPath,omitempty"`
+ // Maximum number of previous process logs to include. Defaults to 5.
+ PreviousProcessLogLimit *int64 `json:"previousProcessLogLimit,omitempty"`
+ // Server-local process log directory to search when `currentProcessLogPath` is unavailable,
+ // useful for collecting logs for inactive sessions.
+ ProcessLogDirectory *string `json:"processLogDirectory,omitempty"`
+ // Include process logs for the session. Defaults to true.
+ ProcessLogs *bool `json:"processLogs,omitempty"`
+ // Include interactive shell logs written under the session's `shell-logs` directory.
+ // Defaults to true.
+ ShellLogs *bool `json:"shellLogs,omitempty"`
+}
+
+// Options for collecting a redacted session debug bundle.
+// Experimental: DebugCollectLogsRequest is part of an experimental API and may change or be
+// removed.
+type DebugCollectLogsRequest struct {
+ // 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.
+ AdditionalEntries []DebugCollectLogsEntry `json:"additionalEntries,omitzero"`
+ // Where the redacted bundle should be written. Use `archive` to produce a .tgz, or
+ // `directory` to stage redacted files for caller-managed upload/post-processing.
+ Destination DebugCollectLogsDestination `json:"destination"`
+ // Which built-in session diagnostics to include. Omitted fields default to true.
+ Include *DebugCollectLogsInclude `json:"include,omitempty"`
+}
+
+// Result of collecting a redacted debug bundle.
+// Experimental: DebugCollectLogsResult is part of an experimental API and may change or be
+// removed.
+type DebugCollectLogsResult struct {
+ // Files included in the redacted bundle.
+ Entries []DebugCollectLogsCollectedEntry `json:"entries"`
+ // Destination kind that was written.
+ Kind DebugCollectLogsResultKind `json:"kind"`
+ // 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.
+ Path string `json:"path"`
+ // Optional files or directories that could not be included.
+ SkippedEntries []DebugCollectLogsSkippedEntry `json:"skippedEntries,omitzero"`
+}
+
+// An optional debug bundle entry that could not be included.
+// Experimental: DebugCollectLogsSkippedEntry is part of an experimental API and may change
+// or be removed.
+type DebugCollectLogsSkippedEntry struct {
+ // Relative path requested for this bundle entry.
+ BundlePath string `json:"bundlePath"`
+ // Server-local source path that could not be read.
+ Path *string `json:"path,omitempty"`
+ // Reason the entry was skipped.
+ Reason string `json:"reason"`
+}
+
// Canvas available in the current session.
// Experimental: DiscoveredCanvas is part of an experimental API and may change or be
// removed.
@@ -1533,7 +1788,8 @@ type DiscoveredCanvas struct {
InputSchema any `json:"inputSchema,omitempty"`
}
-// Schema for the `DiscoveredMcpServer` type.
+// MCP server discovered by `mcp.discover`, with config source, optional plugin source,
+// transport type, and enabled state.
// Experimental: DiscoveredMCPServer is part of an experimental API and may change or be
// removed.
type DiscoveredMCPServer struct {
@@ -1663,7 +1919,8 @@ type ExecuteCommandResult struct {
Error *string `json:"error,omitempty"`
}
-// Schema for the `Extension` type.
+// Discovered extension metadata, including source-qualified ID, name, discovery source,
+// status, and optional process ID.
// Experimental: Extension is part of an experimental API and may change or be removed.
type Extension struct {
// Source-qualified ID (e.g., 'project:my-ext', 'user:auth-helper',
@@ -1733,6 +1990,10 @@ type ExternalToolTextResultForLlm struct {
SessionLog *string `json:"sessionLog,omitempty"`
// Text result returned to the model
TextResultForLlm string `json:"textResultForLlm"`
+ // Tool references returned by a tool-search override: names of deferred tools to surface to
+ // the model. When set, the tool result is materialized as `tool_reference` content blocks
+ // (rather than plain text) so the model knows which deferred tools are now available.
+ ToolReferences []string `json:"toolReferences,omitzero"`
// Optional tool-specific telemetry
ToolTelemetry map[string]any `json:"toolTelemetry,omitzero"`
}
@@ -1907,7 +2168,8 @@ type RawExternalToolTextResultForLlmContentResourceDetailsData struct {
func (RawExternalToolTextResultForLlmContentResourceDetailsData) externalToolTextResultForLlmContentResourceDetails() {
}
-// Schema for the `EmbeddedBlobResourceContents` type.
+// Embedded binary resource contents identified by a URI, with an optional MIME type and a
+// base64-encoded blob.
// Experimental: EmbeddedBlobResourceContents is part of an experimental API and may change
// or be removed.
type EmbeddedBlobResourceContents struct {
@@ -1921,7 +2183,8 @@ type EmbeddedBlobResourceContents struct {
func (EmbeddedBlobResourceContents) externalToolTextResultForLlmContentResourceDetails() {}
-// Schema for the `EmbeddedTextResourceContents` type.
+// Embedded text resource contents identified by a URI, with an optional MIME type and a
+// text payload.
// Experimental: EmbeddedTextResourceContents is part of an experimental API and may change
// or be removed.
type EmbeddedTextResourceContents struct {
@@ -2074,8 +2337,8 @@ type GitHubTelemetryEventResult struct {
}
// Payload for a `gitHubTelemetry.event` notification: a single GitHub telemetry event the
-// runtime forwards to a host connection that opted into telemetry forwarding for the
-// session.
+// runtime forwards to a host connection that opted into telemetry forwarding during the
+// `server.connect` handshake.
// Experimental: GitHubTelemetryNotification is part of an experimental API and may change
// or be removed.
type GitHubTelemetryNotification struct {
@@ -2084,8 +2347,10 @@ type GitHubTelemetryNotification struct {
// Whether this is a restricted telemetry event (cli.restricted_telemetry). Hosts must route
// restricted events to first-party Microsoft stores only.
Restricted bool `json:"restricted"`
- // Session the telemetry event belongs to.
- SessionID string `json:"sessionId"`
+ // 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.
+ SessionID *string `json:"sessionId,omitempty"`
}
// Pending external tool call request ID, with the tool result or an error describing why it
@@ -2196,7 +2461,8 @@ type HistoryTruncateResult struct {
EventsRemoved int64 `json:"eventsRemoved"`
}
-// Schema for the `InstalledPlugin` type.
+// Installed plugin record from global state, with marketplace, version, install time,
+// enabled state, cache path, and source.
// Experimental: InstalledPlugin is part of an experimental API and may change or be removed.
type InstalledPlugin struct {
// Path where the plugin is cached locally
@@ -2244,7 +2510,8 @@ type InstalledPluginSource struct {
String *string
}
-// Schema for the `InstalledPluginSourceGitHub` type.
+// Source descriptor for a direct GitHub plugin install, with `owner/repo`, optional ref,
+// and optional subpath.
// Experimental: InstalledPluginSourceGitHub is part of an experimental API and may change
// or be removed.
type InstalledPluginSourceGitHub struct {
@@ -2255,7 +2522,7 @@ type InstalledPluginSourceGitHub struct {
Source InstalledPluginSourceGitHubSource `json:"source"`
}
-// Schema for the `InstalledPluginSourceLocal` type.
+// Source descriptor for a direct local plugin install, with a local filesystem path.
// Experimental: InstalledPluginSourceLocal is part of an experimental API and may change or
// be removed.
type InstalledPluginSourceLocal struct {
@@ -2264,7 +2531,8 @@ type InstalledPluginSourceLocal struct {
Source InstalledPluginSourceLocalSource `json:"source"`
}
-// Schema for the `InstalledPluginSourceUrl` type.
+// Source descriptor for a direct URL plugin install, with URL, optional ref, and optional
+// subpath.
// Experimental: InstalledPluginSourceURL is part of an experimental API and may change or
// be removed.
type InstalledPluginSourceURL struct {
@@ -2275,7 +2543,8 @@ type InstalledPluginSourceURL struct {
URL string `json:"url"`
}
-// Schema for the `InstructionDiscoveryPath` type.
+// Canonical file or directory where custom instructions can be discovered or created, with
+// location, kind, preference, and project path.
// Experimental: InstructionDiscoveryPath is part of an experimental API and may change or
// be removed.
type InstructionDiscoveryPath struct {
@@ -2334,7 +2603,8 @@ type InstructionsGetSourcesResult struct {
Sources []InstructionSource `json:"sources"`
}
-// Schema for the `InstructionSource` type.
+// 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
// removed.
type InstructionSource struct {
@@ -2402,9 +2672,35 @@ type LlmInferenceHTTPRequestChunkResult struct {
// Experimental: LlmInferenceHTTPRequestStartRequest is part of an experimental API and may
// change or be removed.
type LlmInferenceHTTPRequestStartRequest struct {
+ // Stable per-agent-instance id attributing this request to a specific agent trajectory.
+ // Present when the request originates from an agent turn; absent for requests issued
+ // outside any agent context (e.g. some SDK callers). A request with an `agentId` but no
+ // `parentAgentId` is a root-agent request; one carrying both is a subagent request. Sourced
+ // from the runtime's per-request agent context and surfaced on the envelope independently
+ // of transport, so it is available for both first-party (CAPI) and BYOK/custom-provider
+ // requests; on the CAPI transport the runtime derives the upstream `X-Agent-Task-Id` header
+ // from this same context. Consumers routing each provider call to a training trajectory
+ // should key on this rather than on lifecycle events, since it is available on the request
+ // path before sampling.
+ AgentID *string `json:"agentId,omitempty"`
Headers map[string][]string `json:"headers"`
+ // 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.
+ InteractionType *string `json:"interactionType,omitempty"`
// HTTP method, e.g. GET, POST.
Method string `json:"method"`
+ // Id of the parent agent that spawned the agent issuing this request. Present only for
+ // subagent requests; absent for root-agent requests and non-agent requests. Combined with
+ // `agentId`, this lets consumers attribute a call to a child trajectory versus the root.
+ // Like `agentId`, it comes from the runtime's per-request agent context independently of
+ // transport; on the CAPI transport the runtime derives the upstream `X-Parent-Agent-Id`
+ // header from this same context.
+ ParentAgentID *string `json:"parentAgentId,omitempty"`
// 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.
@@ -2500,7 +2796,8 @@ type LlmInferenceSetProviderResult struct {
Success bool `json:"success"`
}
-// Schema for the `LocalSessionMetadataValue` type.
+// Persisted local session metadata, including identifiers, timestamps, summary/name,
+// client, context, detached state, and task ID.
// Experimental: LocalSessionMetadataValue is part of an experimental API and may change or
// be removed.
type LocalSessionMetadataValue struct {
@@ -2616,7 +2913,8 @@ type MarketplacePluginInfo struct {
Name string `json:"name"`
}
-// Schema for the `MarketplaceRefreshEntry` type.
+// Per-marketplace refresh result, including marketplace name, success flag, and optional
+// failure error.
// Experimental: MarketplaceRefreshEntry is part of an experimental API and may change or be
// removed.
type MarketplaceRefreshEntry struct {
@@ -2647,7 +2945,7 @@ type MarketplaceRemoveResult struct {
Removed bool `json:"removed"`
}
-// Schema for the `McpAllowedServer` type.
+// MCP server allowed by policy, with server name and optional PII-free explanatory note.
// Experimental: MCPAllowedServer is part of an experimental API and may change or be
// removed.
type MCPAllowedServer struct {
@@ -2783,7 +3081,8 @@ type MCPAppsReadResourceResult struct {
Contents []MCPAppsResourceContent `json:"contents"`
}
-// Schema for the `McpAppsResourceContent` type.
+// MCP Apps resource content with URI, optional MIME type, text or base64 blob, and resource
+// metadata.
// Experimental: MCPAppsResourceContent is part of an experimental API and may change or be
// removed.
type MCPAppsResourceContent struct {
@@ -3017,7 +3316,8 @@ type MCPExecuteSamplingRequest struct {
type MCPExecuteSamplingResult struct {
}
-// Schema for the `McpFilteredServer` type.
+// MCP server filtered by policy, with name, reason, optional redacted reason, and
+// enterprise login.
// Experimental: MCPFilteredServer is part of an experimental API and may change or be
// removed.
type MCPFilteredServer struct {
@@ -3250,25 +3550,6 @@ func (MCPOauthPendingRequestResponseToken) Kind() MCPOauthPendingRequestResponse
return MCPOauthPendingRequestResponseKindToken
}
-// MCP OAuth request id and optional provider response.
-// Experimental: MCPOauthRespondRequest is part of an experimental API and may change or be
-// removed.
-type MCPOauthRespondRequest struct {
- // In-process OAuthClientProvider instance, or omitted to deny. Marked internal: cannot be
- // serialized across the JSON-RPC boundary.
- // Internal: Provider is part of the SDK's internal API surface and is not intended for
- // external use.
- Provider any `json:"provider,omitempty"`
- // OAuth request identifier from mcp.oauth_required
- RequestID string `json:"requestId"`
-}
-
-// Empty result after recording the MCP OAuth response.
-// Experimental: MCPOauthRespondResult is part of an experimental API and may change or be
-// removed.
-type MCPOauthRespondResult struct {
-}
-
// Registration parameters for an external MCP client.
// Experimental: MCPRegisterExternalClientRequest is part of an experimental API and may
// change or be removed.
@@ -3343,7 +3624,7 @@ type MCPSamplingExecutionResult struct {
Result *MCPExecuteSamplingResult `json:"result,omitempty"`
}
-// Schema for the `McpServer` type.
+// MCP server status entry, including config source/plugin source and any connection error.
// Experimental: MCPServer is part of an experimental API and may change or be removed.
type MCPServer struct {
// Error message if the server failed to connect
@@ -3541,7 +3822,7 @@ type MCPStopServerRequest struct {
ServerName string `json:"serverName"`
}
-// Schema for the `McpTools` type.
+// MCP tool metadata with tool name and optional description.
// Experimental: MCPTools is part of an experimental API and may change or be removed.
type MCPTools struct {
// Tool description, when provided.
@@ -3566,6 +3847,35 @@ type MemoryConfiguration struct {
Enabled bool `json:"enabled"`
}
+// Per-source attribution breakdown for the session's current context window, or null if
+// uninitialized.
+// Experimental: MetadataContextAttributionResult is part of an experimental API and may
+// change or be removed.
+type MetadataContextAttributionResult struct {
+ // Per-source context-window attribution, or null if the session has not yet been
+ // initialized (no system prompt or tool metadata cached).
+ ContextAttribution *SessionContextAttribution `json:"contextAttribution,omitempty"`
+}
+
+// Parameters for the heaviest-messages query.
+// Experimental: MetadataContextHeaviestMessagesRequest is part of an experimental API and
+// may change or be removed.
+type MetadataContextHeaviestMessagesRequest struct {
+ // Maximum number of messages to return, most-expensive first. Omit for the server default.
+ Limit *int64 `json:"limit,omitempty"`
+}
+
+// The heaviest individual messages in the session's context window, most-expensive first.
+// Experimental: MetadataContextHeaviestMessagesResult is part of an experimental API and
+// may change or be removed.
+type MetadataContextHeaviestMessagesResult struct {
+ // Heaviest messages, most-expensive first.
+ Messages []ContextHeaviestMessage `json:"messages"`
+ // Total token count of the current context window, so callers can compute each message's
+ // share without a second call.
+ TotalTokens int64 `json:"totalTokens"`
+}
+
// Model identifier and token limits used to compute the context-info breakdown.
// Experimental: MetadataContextInfoRequest is part of an experimental API and may change or
// be removed.
@@ -3692,7 +4002,8 @@ type MetadataSnapshotRemoteMetadataRepository struct {
Owner string `json:"owner"`
}
-// Schema for the `Model` type.
+// Copilot model metadata, including identifier, display name, capabilities, policy,
+// billing, reasoning efforts, and picker categories.
// Experimental: Model is part of an experimental API and may change or be removed.
type Model struct {
// Billing information
@@ -3948,6 +4259,8 @@ type ModelSwitchToRequest struct {
ReasoningEffort *string `json:"reasoningEffort,omitempty"`
// Reasoning summary mode to request for supported model clients
ReasoningSummary *ReasoningSummary `json:"reasoningSummary,omitempty"`
+ // Output verbosity level to request for supported models
+ Verbosity *Verbosity `json:"verbosity,omitempty"`
}
// The model identifier active on the session after the switch.
@@ -4056,7 +4369,8 @@ type OpenCanvasInstance struct {
URL *string `json:"url,omitempty"`
}
-// Schema for the `OptionsUpdateAdditionalContentExclusionPolicy` type.
+// Content-exclusion policy supplied to `session.options.update`, with rules, last-updated
+// data, and scope.
// Experimental: OptionsUpdateAdditionalContentExclusionPolicy is part of an experimental
// API and may change or be removed.
type OptionsUpdateAdditionalContentExclusionPolicy struct {
@@ -4066,18 +4380,21 @@ type OptionsUpdateAdditionalContentExclusionPolicy struct {
Scope OptionsUpdateAdditionalContentExclusionPolicyScope `json:"scope"`
}
-// Schema for the `OptionsUpdateAdditionalContentExclusionPolicyRule` type.
+// Single content-exclusion rule supplied to `session.options.update`, with paths, match
+// conditions, and source.
// Experimental: OptionsUpdateAdditionalContentExclusionPolicyRule is part of an
// experimental API and may change or be removed.
type OptionsUpdateAdditionalContentExclusionPolicyRule struct {
IfAnyMatch []string `json:"ifAnyMatch,omitzero"`
IfNoneMatch []string `json:"ifNoneMatch,omitzero"`
Paths []string `json:"paths"`
- // Schema for the `OptionsUpdateAdditionalContentExclusionPolicyRuleSource` type.
+ // Source descriptor for a `session.options.update` content-exclusion rule, with source name
+ // and type.
Source OptionsUpdateAdditionalContentExclusionPolicyRuleSource `json:"source"`
}
-// Schema for the `OptionsUpdateAdditionalContentExclusionPolicyRuleSource` type.
+// Source descriptor for a `session.options.update` content-exclusion rule, with source name
+// and type.
// Experimental: OptionsUpdateAdditionalContentExclusionPolicyRuleSource is part of an
// experimental API and may change or be removed.
type OptionsUpdateAdditionalContentExclusionPolicyRuleSource struct {
@@ -4085,7 +4402,8 @@ type OptionsUpdateAdditionalContentExclusionPolicyRuleSource struct {
Type string `json:"type"`
}
-// Schema for the `PendingPermissionRequest` type.
+// Pending permission prompt reconstructed from event history, with request ID and
+// user-facing prompt details.
// Experimental: PendingPermissionRequest is part of an experimental API and may change or
// be removed.
type PendingPermissionRequest struct {
@@ -4125,7 +4443,7 @@ func (r RawPermissionDecisionData) Kind() PermissionDecisionKind {
return r.Discriminator
}
-// Schema for the `PermissionDecisionApproved` type.
+// Permission-decision variant indicating the request was approved.
// Experimental: PermissionDecisionApproved is part of an experimental API and may change or
// be removed.
type PermissionDecisionApproved struct {
@@ -4136,7 +4454,8 @@ func (PermissionDecisionApproved) Kind() PermissionDecisionKind {
return PermissionDecisionKindApproved
}
-// Schema for the `PermissionDecisionApprovedForLocation` type.
+// Permission-decision variant indicating approval was persisted for a project location,
+// with approval details and location key.
// Experimental: PermissionDecisionApprovedForLocation is part of an experimental API and
// may change or be removed.
type PermissionDecisionApprovedForLocation struct {
@@ -4151,7 +4470,8 @@ func (PermissionDecisionApprovedForLocation) Kind() PermissionDecisionKind {
return PermissionDecisionKindApprovedForLocation
}
-// Schema for the `PermissionDecisionApprovedForSession` type.
+// Permission-decision variant indicating approval was remembered for the session, with
+// approval details.
// Experimental: PermissionDecisionApprovedForSession is part of an experimental API and may
// change or be removed.
type PermissionDecisionApprovedForSession struct {
@@ -4164,7 +4484,8 @@ func (PermissionDecisionApprovedForSession) Kind() PermissionDecisionKind {
return PermissionDecisionKindApprovedForSession
}
-// Schema for the `PermissionDecisionApproveForLocation` type.
+// Permission-decision request variant to approve and persist a permission for a project
+// location, with approval details and location key.
// Experimental: PermissionDecisionApproveForLocation is part of an experimental API and may
// change or be removed.
type PermissionDecisionApproveForLocation struct {
@@ -4179,7 +4500,8 @@ func (PermissionDecisionApproveForLocation) Kind() PermissionDecisionKind {
return PermissionDecisionKindApproveForLocation
}
-// Schema for the `PermissionDecisionApproveForSession` type.
+// Permission-decision request variant to approve for the rest of the session, with optional
+// tool approval or URL domain.
// Experimental: PermissionDecisionApproveForSession is part of an experimental API and may
// change or be removed.
type PermissionDecisionApproveForSession struct {
@@ -4194,7 +4516,7 @@ func (PermissionDecisionApproveForSession) Kind() PermissionDecisionKind {
return PermissionDecisionKindApproveForSession
}
-// Schema for the `PermissionDecisionApproveOnce` type.
+// Permission-decision request variant to approve only the current permission request.
// Experimental: PermissionDecisionApproveOnce is part of an experimental API and may change
// or be removed.
type PermissionDecisionApproveOnce struct {
@@ -4205,7 +4527,7 @@ func (PermissionDecisionApproveOnce) Kind() PermissionDecisionKind {
return PermissionDecisionKindApproveOnce
}
-// Schema for the `PermissionDecisionApprovePermanently` type.
+// Permission-decision request variant to permanently approve a URL domain across sessions.
// Experimental: PermissionDecisionApprovePermanently is part of an experimental API and may
// change or be removed.
type PermissionDecisionApprovePermanently struct {
@@ -4218,7 +4540,8 @@ func (PermissionDecisionApprovePermanently) Kind() PermissionDecisionKind {
return PermissionDecisionKindApprovePermanently
}
-// Schema for the `PermissionDecisionCancelled` type.
+// Permission-decision variant indicating the request was cancelled before use, with an
+// optional reason.
// Experimental: PermissionDecisionCancelled is part of an experimental API and may change
// or be removed.
type PermissionDecisionCancelled struct {
@@ -4231,7 +4554,8 @@ func (PermissionDecisionCancelled) Kind() PermissionDecisionKind {
return PermissionDecisionKindCancelled
}
-// Schema for the `PermissionDecisionDeniedByContentExclusionPolicy` type.
+// Permission-decision variant indicating denial by content-exclusion policy, with path and
+// message.
// Experimental: PermissionDecisionDeniedByContentExclusionPolicy is part of an experimental
// API and may change or be removed.
type PermissionDecisionDeniedByContentExclusionPolicy struct {
@@ -4246,7 +4570,8 @@ func (PermissionDecisionDeniedByContentExclusionPolicy) Kind() PermissionDecisio
return PermissionDecisionKindDeniedByContentExclusionPolicy
}
-// Schema for the `PermissionDecisionDeniedByPermissionRequestHook` type.
+// Permission-decision variant indicating denial by a permission request hook, with optional
+// message and interrupt flag.
// Experimental: PermissionDecisionDeniedByPermissionRequestHook is part of an experimental
// API and may change or be removed.
type PermissionDecisionDeniedByPermissionRequestHook struct {
@@ -4261,7 +4586,8 @@ func (PermissionDecisionDeniedByPermissionRequestHook) Kind() PermissionDecision
return PermissionDecisionKindDeniedByPermissionRequestHook
}
-// Schema for the `PermissionDecisionDeniedByRules` type.
+// Permission-decision variant indicating explicit denial by permission rules, with the
+// matching rules.
// Experimental: PermissionDecisionDeniedByRules is part of an experimental API and may
// change or be removed.
type PermissionDecisionDeniedByRules struct {
@@ -4274,7 +4600,8 @@ func (PermissionDecisionDeniedByRules) Kind() PermissionDecisionKind {
return PermissionDecisionKindDeniedByRules
}
-// Schema for the `PermissionDecisionDeniedInteractivelyByUser` type.
+// Permission-decision variant indicating the user denied an interactive prompt, with
+// optional feedback and force-reject flag.
// Experimental: PermissionDecisionDeniedInteractivelyByUser is part of an experimental API
// and may change or be removed.
type PermissionDecisionDeniedInteractivelyByUser struct {
@@ -4289,7 +4616,8 @@ func (PermissionDecisionDeniedInteractivelyByUser) Kind() PermissionDecisionKind
return PermissionDecisionKindDeniedInteractivelyByUser
}
-// Schema for the `PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser` type.
+// Permission-decision variant indicating no approval rule matched and user confirmation was
+// unavailable.
// Experimental: PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser is part of
// an experimental API and may change or be removed.
type PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser struct {
@@ -4300,7 +4628,8 @@ func (PermissionDecisionDeniedNoApprovalRuleAndCouldNotRequestFromUser) Kind() P
return PermissionDecisionKindDeniedNoApprovalRuleAndCouldNotRequestFromUser
}
-// Schema for the `PermissionDecisionReject` type.
+// Permission-decision request variant to reject a pending permission request, with optional
+// feedback.
// Experimental: PermissionDecisionReject is part of an experimental API and may change or
// be removed.
type PermissionDecisionReject struct {
@@ -4313,7 +4642,7 @@ func (PermissionDecisionReject) Kind() PermissionDecisionKind {
return PermissionDecisionKindReject
}
-// Schema for the `PermissionDecisionUserNotAvailable` type.
+// Permission-decision variant indicating no user was available to confirm the request.
// Experimental: PermissionDecisionUserNotAvailable is part of an experimental API and may
// change or be removed.
type PermissionDecisionUserNotAvailable struct {
@@ -4343,7 +4672,7 @@ func (r RawPermissionDecisionApproveForLocationApprovalData) Kind() PermissionDe
return r.Discriminator
}
-// Schema for the `PermissionDecisionApproveForLocationApprovalCommands` type.
+// Location-scoped approval details for specific command identifiers.
// Experimental: PermissionDecisionApproveForLocationApprovalCommands is part of an
// experimental API and may change or be removed.
type PermissionDecisionApproveForLocationApprovalCommands struct {
@@ -4357,7 +4686,7 @@ func (PermissionDecisionApproveForLocationApprovalCommands) Kind() PermissionDec
return PermissionDecisionApproveForLocationApprovalKindCommands
}
-// Schema for the `PermissionDecisionApproveForLocationApprovalCustomTool` type.
+// Location-scoped approval details for a custom tool, keyed by tool name.
// Experimental: PermissionDecisionApproveForLocationApprovalCustomTool is part of an
// experimental API and may change or be removed.
type PermissionDecisionApproveForLocationApprovalCustomTool struct {
@@ -4371,7 +4700,8 @@ func (PermissionDecisionApproveForLocationApprovalCustomTool) Kind() PermissionD
return PermissionDecisionApproveForLocationApprovalKindCustomTool
}
-// Schema for the `PermissionDecisionApproveForLocationApprovalExtensionManagement` type.
+// Location-scoped approval details for extension-management operations, optionally narrowed
+// by operation.
// Experimental: PermissionDecisionApproveForLocationApprovalExtensionManagement is part of
// an experimental API and may change or be removed.
type PermissionDecisionApproveForLocationApprovalExtensionManagement struct {
@@ -4386,8 +4716,8 @@ func (PermissionDecisionApproveForLocationApprovalExtensionManagement) Kind() Pe
return PermissionDecisionApproveForLocationApprovalKindExtensionManagement
}
-// Schema for the `PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess`
-// type.
+// Location-scoped approval details for an extension's permission-gated capability access,
+// keyed by extension name.
// Experimental: PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess is
// part of an experimental API and may change or be removed.
type PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess struct {
@@ -4401,7 +4731,8 @@ func (PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess) Kin
return PermissionDecisionApproveForLocationApprovalKindExtensionPermissionAccess
}
-// Schema for the `PermissionDecisionApproveForLocationApprovalMcp` type.
+// Location-scoped approval details for an MCP server tool, or all tools on the server when
+// `toolName` is null.
// Experimental: PermissionDecisionApproveForLocationApprovalMCP is part of an experimental
// API and may change or be removed.
type PermissionDecisionApproveForLocationApprovalMCP struct {
@@ -4417,7 +4748,7 @@ func (PermissionDecisionApproveForLocationApprovalMCP) Kind() PermissionDecision
return PermissionDecisionApproveForLocationApprovalKindMCP
}
-// Schema for the `PermissionDecisionApproveForLocationApprovalMcpSampling` type.
+// Location-scoped approval details for MCP sampling requests from a server.
// Experimental: PermissionDecisionApproveForLocationApprovalMCPSampling is part of an
// experimental API and may change or be removed.
type PermissionDecisionApproveForLocationApprovalMCPSampling struct {
@@ -4431,7 +4762,7 @@ func (PermissionDecisionApproveForLocationApprovalMCPSampling) Kind() Permission
return PermissionDecisionApproveForLocationApprovalKindMCPSampling
}
-// Schema for the `PermissionDecisionApproveForLocationApprovalMemory` type.
+// Location-scoped approval details for writes to long-term memory.
// Experimental: PermissionDecisionApproveForLocationApprovalMemory is part of an
// experimental API and may change or be removed.
type PermissionDecisionApproveForLocationApprovalMemory struct {
@@ -4443,7 +4774,7 @@ func (PermissionDecisionApproveForLocationApprovalMemory) Kind() PermissionDecis
return PermissionDecisionApproveForLocationApprovalKindMemory
}
-// Schema for the `PermissionDecisionApproveForLocationApprovalRead` type.
+// Location-scoped approval details for read-only filesystem operations.
// Experimental: PermissionDecisionApproveForLocationApprovalRead is part of an experimental
// API and may change or be removed.
type PermissionDecisionApproveForLocationApprovalRead struct {
@@ -4455,7 +4786,7 @@ func (PermissionDecisionApproveForLocationApprovalRead) Kind() PermissionDecisio
return PermissionDecisionApproveForLocationApprovalKindRead
}
-// Schema for the `PermissionDecisionApproveForLocationApprovalWrite` type.
+// Location-scoped approval details for filesystem write operations.
// Experimental: PermissionDecisionApproveForLocationApprovalWrite is part of an
// experimental API and may change or be removed.
type PermissionDecisionApproveForLocationApprovalWrite struct {
@@ -4486,7 +4817,7 @@ func (r RawPermissionDecisionApproveForSessionApprovalData) Kind() PermissionDec
return r.Discriminator
}
-// Schema for the `PermissionDecisionApproveForSessionApprovalCommands` type.
+// Session-scoped approval details for specific command identifiers.
// Experimental: PermissionDecisionApproveForSessionApprovalCommands is part of an
// experimental API and may change or be removed.
type PermissionDecisionApproveForSessionApprovalCommands struct {
@@ -4500,7 +4831,7 @@ func (PermissionDecisionApproveForSessionApprovalCommands) Kind() PermissionDeci
return PermissionDecisionApproveForSessionApprovalKindCommands
}
-// Schema for the `PermissionDecisionApproveForSessionApprovalCustomTool` type.
+// Session-scoped approval details for a custom tool, keyed by tool name.
// Experimental: PermissionDecisionApproveForSessionApprovalCustomTool is part of an
// experimental API and may change or be removed.
type PermissionDecisionApproveForSessionApprovalCustomTool struct {
@@ -4514,7 +4845,8 @@ func (PermissionDecisionApproveForSessionApprovalCustomTool) Kind() PermissionDe
return PermissionDecisionApproveForSessionApprovalKindCustomTool
}
-// Schema for the `PermissionDecisionApproveForSessionApprovalExtensionManagement` type.
+// Session-scoped approval details for extension-management operations, optionally narrowed
+// by operation.
// Experimental: PermissionDecisionApproveForSessionApprovalExtensionManagement is part of
// an experimental API and may change or be removed.
type PermissionDecisionApproveForSessionApprovalExtensionManagement struct {
@@ -4529,8 +4861,8 @@ func (PermissionDecisionApproveForSessionApprovalExtensionManagement) Kind() Per
return PermissionDecisionApproveForSessionApprovalKindExtensionManagement
}
-// Schema for the `PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess`
-// type.
+// Session-scoped approval details for an extension's permission-gated capability access,
+// keyed by extension name.
// Experimental: PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess is
// part of an experimental API and may change or be removed.
type PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess struct {
@@ -4544,7 +4876,8 @@ func (PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess) Kind
return PermissionDecisionApproveForSessionApprovalKindExtensionPermissionAccess
}
-// Schema for the `PermissionDecisionApproveForSessionApprovalMcp` type.
+// Session-scoped approval details for an MCP server tool, or all tools on the server when
+// `toolName` is null.
// Experimental: PermissionDecisionApproveForSessionApprovalMCP is part of an experimental
// API and may change or be removed.
type PermissionDecisionApproveForSessionApprovalMCP struct {
@@ -4559,7 +4892,7 @@ func (PermissionDecisionApproveForSessionApprovalMCP) Kind() PermissionDecisionA
return PermissionDecisionApproveForSessionApprovalKindMCP
}
-// Schema for the `PermissionDecisionApproveForSessionApprovalMcpSampling` type.
+// Session-scoped approval details for MCP sampling requests from a server.
// Experimental: PermissionDecisionApproveForSessionApprovalMCPSampling is part of an
// experimental API and may change or be removed.
type PermissionDecisionApproveForSessionApprovalMCPSampling struct {
@@ -4573,7 +4906,7 @@ func (PermissionDecisionApproveForSessionApprovalMCPSampling) Kind() PermissionD
return PermissionDecisionApproveForSessionApprovalKindMCPSampling
}
-// Schema for the `PermissionDecisionApproveForSessionApprovalMemory` type.
+// Session-scoped approval details for writes to long-term memory.
// Experimental: PermissionDecisionApproveForSessionApprovalMemory is part of an
// experimental API and may change or be removed.
type PermissionDecisionApproveForSessionApprovalMemory struct {
@@ -4585,7 +4918,7 @@ func (PermissionDecisionApproveForSessionApprovalMemory) Kind() PermissionDecisi
return PermissionDecisionApproveForSessionApprovalKindMemory
}
-// Schema for the `PermissionDecisionApproveForSessionApprovalRead` type.
+// Session-scoped approval details for read-only filesystem operations.
// Experimental: PermissionDecisionApproveForSessionApprovalRead is part of an experimental
// API and may change or be removed.
type PermissionDecisionApproveForSessionApprovalRead struct {
@@ -4597,7 +4930,7 @@ func (PermissionDecisionApproveForSessionApprovalRead) Kind() PermissionDecision
return PermissionDecisionApproveForSessionApprovalKindRead
}
-// Schema for the `PermissionDecisionApproveForSessionApprovalWrite` type.
+// Session-scoped approval details for filesystem write operations.
// Experimental: PermissionDecisionApproveForSessionApprovalWrite is part of an experimental
// API and may change or be removed.
type PermissionDecisionApproveForSessionApprovalWrite struct {
@@ -4773,7 +5106,8 @@ type PermissionRequestResult struct {
Success bool `json:"success"`
}
-// Schema for the `PermissionRule` type.
+// A permission approval or denial rule matched against a tool request, identified by a rule
+// kind with an optional argument value.
// Experimental: PermissionRule is part of an experimental API and may change or be removed.
type PermissionRule struct {
// Argument value matched against the request, or null when the rule kind has no argument
@@ -4794,7 +5128,8 @@ type PermissionRulesSet struct {
Denied []PermissionRule `json:"denied"`
}
-// Schema for the `PermissionsConfigureAdditionalContentExclusionPolicy` type.
+// Content-exclusion policy supplied to `session.permissions.configure`, with rules,
+// last-updated data, and scope.
// Experimental: PermissionsConfigureAdditionalContentExclusionPolicy is part of an
// experimental API and may change or be removed.
type PermissionsConfigureAdditionalContentExclusionPolicy struct {
@@ -4805,18 +5140,21 @@ type PermissionsConfigureAdditionalContentExclusionPolicy struct {
Scope PermissionsConfigureAdditionalContentExclusionPolicyScope `json:"scope"`
}
-// Schema for the `PermissionsConfigureAdditionalContentExclusionPolicyRule` type.
+// Single content-exclusion rule supplied to `session.permissions.configure`, with paths,
+// match conditions, and source.
// Experimental: PermissionsConfigureAdditionalContentExclusionPolicyRule is part of an
// experimental API and may change or be removed.
type PermissionsConfigureAdditionalContentExclusionPolicyRule struct {
IfAnyMatch []string `json:"ifAnyMatch,omitzero"`
IfNoneMatch []string `json:"ifNoneMatch,omitzero"`
Paths []string `json:"paths"`
- // Schema for the `PermissionsConfigureAdditionalContentExclusionPolicyRuleSource` type.
+ // Source descriptor for a `session.permissions.configure` content-exclusion rule, with
+ // source name and type.
Source PermissionsConfigureAdditionalContentExclusionPolicyRuleSource `json:"source"`
}
-// Schema for the `PermissionsConfigureAdditionalContentExclusionPolicyRuleSource` type.
+// Source descriptor for a `session.permissions.configure` content-exclusion rule, with
+// source name and type.
// Experimental: PermissionsConfigureAdditionalContentExclusionPolicyRuleSource is part of
// an experimental API and may change or be removed.
type PermissionsConfigureAdditionalContentExclusionPolicyRuleSource struct {
@@ -4892,7 +5230,7 @@ func (r RawPermissionsLocationsAddToolApprovalDetailsData) Kind() PermissionsLoc
return r.Discriminator
}
-// Schema for the `PermissionsLocationsAddToolApprovalDetailsCommands` type.
+// Location-persisted tool approval details for specific command identifiers.
// Experimental: PermissionsLocationsAddToolApprovalDetailsCommands is part of an
// experimental API and may change or be removed.
type PermissionsLocationsAddToolApprovalDetailsCommands struct {
@@ -4906,7 +5244,7 @@ func (PermissionsLocationsAddToolApprovalDetailsCommands) Kind() PermissionsLoca
return PermissionsLocationsAddToolApprovalDetailsKindCommands
}
-// Schema for the `PermissionsLocationsAddToolApprovalDetailsCustomTool` type.
+// Location-persisted tool approval details for a custom tool, keyed by tool name.
// Experimental: PermissionsLocationsAddToolApprovalDetailsCustomTool is part of an
// experimental API and may change or be removed.
type PermissionsLocationsAddToolApprovalDetailsCustomTool struct {
@@ -4920,7 +5258,8 @@ func (PermissionsLocationsAddToolApprovalDetailsCustomTool) Kind() PermissionsLo
return PermissionsLocationsAddToolApprovalDetailsKindCustomTool
}
-// Schema for the `PermissionsLocationsAddToolApprovalDetailsExtensionManagement` type.
+// Location-persisted tool approval details for extension-management operations, optionally
+// narrowed by operation.
// Experimental: PermissionsLocationsAddToolApprovalDetailsExtensionManagement is part of an
// experimental API and may change or be removed.
type PermissionsLocationsAddToolApprovalDetailsExtensionManagement struct {
@@ -4935,7 +5274,8 @@ func (PermissionsLocationsAddToolApprovalDetailsExtensionManagement) Kind() Perm
return PermissionsLocationsAddToolApprovalDetailsKindExtensionManagement
}
-// Schema for the `PermissionsLocationsAddToolApprovalDetailsExtensionPermissionAccess` type.
+// Location-persisted tool approval details for an extension's permission-gated capability
+// access, keyed by extension name.
// Experimental: PermissionsLocationsAddToolApprovalDetailsExtensionPermissionAccess is part
// of an experimental API and may change or be removed.
type PermissionsLocationsAddToolApprovalDetailsExtensionPermissionAccess struct {
@@ -4949,7 +5289,8 @@ func (PermissionsLocationsAddToolApprovalDetailsExtensionPermissionAccess) Kind(
return PermissionsLocationsAddToolApprovalDetailsKindExtensionPermissionAccess
}
-// Schema for the `PermissionsLocationsAddToolApprovalDetailsMcp` type.
+// Location-persisted tool approval details for an MCP server tool, or all tools when
+// `toolName` is null.
// Experimental: PermissionsLocationsAddToolApprovalDetailsMCP is part of an experimental
// API and may change or be removed.
type PermissionsLocationsAddToolApprovalDetailsMCP struct {
@@ -4964,7 +5305,7 @@ func (PermissionsLocationsAddToolApprovalDetailsMCP) Kind() PermissionsLocations
return PermissionsLocationsAddToolApprovalDetailsKindMCP
}
-// Schema for the `PermissionsLocationsAddToolApprovalDetailsMcpSampling` type.
+// Location-persisted tool approval details for MCP sampling requests from a server.
// Experimental: PermissionsLocationsAddToolApprovalDetailsMCPSampling is part of an
// experimental API and may change or be removed.
type PermissionsLocationsAddToolApprovalDetailsMCPSampling struct {
@@ -4978,7 +5319,7 @@ func (PermissionsLocationsAddToolApprovalDetailsMCPSampling) Kind() PermissionsL
return PermissionsLocationsAddToolApprovalDetailsKindMCPSampling
}
-// Schema for the `PermissionsLocationsAddToolApprovalDetailsMemory` type.
+// Location-persisted tool approval details for writes to long-term memory.
// Experimental: PermissionsLocationsAddToolApprovalDetailsMemory is part of an experimental
// API and may change or be removed.
type PermissionsLocationsAddToolApprovalDetailsMemory struct {
@@ -4990,7 +5331,7 @@ func (PermissionsLocationsAddToolApprovalDetailsMemory) Kind() PermissionsLocati
return PermissionsLocationsAddToolApprovalDetailsKindMemory
}
-// Schema for the `PermissionsLocationsAddToolApprovalDetailsRead` type.
+// Location-persisted tool approval details for read-only filesystem operations.
// Experimental: PermissionsLocationsAddToolApprovalDetailsRead is part of an experimental
// API and may change or be removed.
type PermissionsLocationsAddToolApprovalDetailsRead struct {
@@ -5001,7 +5342,7 @@ func (PermissionsLocationsAddToolApprovalDetailsRead) Kind() PermissionsLocation
return PermissionsLocationsAddToolApprovalDetailsKindRead
}
-// Schema for the `PermissionsLocationsAddToolApprovalDetailsWrite` type.
+// Location-persisted tool approval details for filesystem write operations.
// Experimental: PermissionsLocationsAddToolApprovalDetailsWrite is part of an experimental
// API and may change or be removed.
type PermissionsLocationsAddToolApprovalDetailsWrite struct {
@@ -5095,12 +5436,19 @@ type PermissionsResetSessionApprovalsResult struct {
Success bool `json:"success"`
}
-// Whether to enable full allow-all permissions for the session.
+// Allow-all mode to apply for the session.
// Experimental: PermissionsSetAllowAllRequest is part of an experimental API and may change
// or be removed.
type PermissionsSetAllowAllRequest struct {
- // Whether to enable full allow-all permissions
- Enabled bool `json:"enabled"`
+ // Legacy full allow-all toggle. Prefer `mode`; when `mode` is omitted, `enabled: true` is
+ // treated as `mode: "on"` and any other value is treated as `mode: "off"`.
+ Enabled *bool `json:"enabled,omitempty"`
+ // Allow-all mode to apply. `on` enables full allow-all; `auto` enables advisory LLM
+ // auto-approval; `off` disables both.
+ Mode *PermissionsAllowAllMode `json:"mode,omitempty"`
+ // Optional model id for the `auto` mode auto-approval LLM judging. Only meaningful when
+ // `mode` is `auto`; ignored otherwise. When omitted, the session's active model is used.
+ Model *string `json:"model,omitempty"`
// Optional source for allow-all telemetry. Defaults to `rpc` when omitted for SDK callers.
Source *PermissionsSetAllowAllSource `json:"source,omitempty"`
}
@@ -5256,7 +5604,7 @@ type PlanUpdateRequest struct {
Content string `json:"content"`
}
-// Schema for the `Plugin` type.
+// Session plugin metadata, with name, marketplace, optional version, and enabled state.
// Experimental: Plugin is part of an experimental API and may change or be removed.
type Plugin struct {
// Whether the plugin is currently enabled
@@ -5390,6 +5738,10 @@ type PluginsReloadRequest struct {
DeferRepoHooks *bool `json:"deferRepoHooks,omitempty"`
// Re-run custom-agent discovery after refreshing plugins. Defaults to true.
ReloadCustomAgents *bool `json:"reloadCustomAgents,omitempty"`
+ // 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 *bool `json:"reloadExtensions,omitempty"`
// 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 *bool `json:"reloadHooks,omitempty"`
@@ -5422,7 +5774,8 @@ type PluginsUpdateRequest struct {
Name string `json:"name"`
}
-// Schema for the `PluginUpdateAllEntry` type.
+// Per-plugin result from updating all plugins, with versions, skills installed, success
+// flag, and optional error.
// Experimental: PluginUpdateAllEntry is part of an experimental API and may change or be
// removed.
type PluginUpdateAllEntry struct {
@@ -5462,16 +5815,6 @@ type PluginUpdateResult struct {
SkillsInstalled int64 `json:"skillsInstalled"`
}
-// Batch of spawn events plus a cursor for follow-up polls.
-// Experimental: PollSpawnedSessionsResult is part of an experimental API and may change or
-// be removed.
-type PollSpawnedSessionsResult struct {
- // Opaque cursor to pass back to receive only events after this batch.
- Cursor string `json:"cursor"`
- // Spawn events emitted since the supplied cursor.
- Events []SessionsPollSpawnedSessionsEvent `json:"events"`
-}
-
// BYOK providers and/or models to add to the session's registry at runtime. Both fields are
// optional; provide providers, models, or both.
// Experimental: ProviderAddRequest is part of an experimental API and may change or be
@@ -5646,7 +5989,8 @@ type ProviderTokenAcquireResult struct {
Token string `json:"token"`
}
-// Schema for the `PushAttachment` type.
+// Attachment union accepted by push input, covering files, directories, GitHub objects,
+// blobs, snippets, and extension context.
// Experimental: PushAttachment is part of an experimental API and may change or be removed.
type PushAttachment interface {
pushAttachment()
@@ -6018,7 +6362,8 @@ type QueuedCommandResult interface {
Handled() bool
}
-// Schema for the `QueuedCommandHandled` type.
+// Queued-command response indicating the host executed the command, with an optional flag
+// to stop queue processing.
// Experimental: QueuedCommandHandled is part of an experimental API and may change or be
// removed.
type QueuedCommandHandled struct {
@@ -6032,7 +6377,8 @@ func (QueuedCommandHandled) Handled() bool {
return true
}
-// Schema for the `QueuedCommandNotHandled` type.
+// Queued-command response indicating the host did not execute the command and the queue may
+// continue.
// Experimental: QueuedCommandNotHandled is part of an experimental API and may change or be
// removed.
type QueuedCommandNotHandled struct {
@@ -6043,7 +6389,8 @@ func (QueuedCommandNotHandled) Handled() bool {
return false
}
-// Schema for the `QueuePendingItems` type.
+// User-facing pending queue entry, with kind and display text for a queued message, slash
+// command, or model change.
// Experimental: QueuePendingItems is part of an experimental API and may change or be
// removed.
type QueuePendingItems struct {
@@ -6081,16 +6428,16 @@ type RegisterEventInterestParams struct {
// 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 the full
- // interactive OAuth flow to the consumer; when no interest is registered the runtime
- // installs a browserless fallback that silently reuses cached tokens). 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`.
+ // (e.g. `mcp.oauth_required`: when interest is registered the runtime delegates OAuth token
+ // acquisition to the consumer; when no interest is registered OAuth-required servers become
+ // needs-auth). 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`.
EventType string `json:"eventType"`
}
@@ -6200,6 +6547,12 @@ func (r RawRemoteControlStatusData) State() RemoteControlStatusState {
type RemoteControlStatusActive struct {
// Session id remote control is pointed at.
AttachedSessionID string `json:"attachedSessionId"`
+ // 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: AwaitingFirstMessage is part of the SDK's internal API surface and is not
+ // intended for external use.
+ AwaitingFirstMessage *bool `json:"awaitingFirstMessage,omitempty"`
// MC frontend URL for this session, when known.
FrontendURL *string `json:"frontendUrl,omitempty"`
// Whether the MC session may steer this session.
@@ -6422,14 +6775,10 @@ type SandboxConfigUserPolicyFilesystem struct {
// Experimental: SandboxConfigUserPolicyNetwork is part of an experimental API and may
// change or be removed.
type SandboxConfigUserPolicyNetwork struct {
- // Hosts allowed in addition to the base policy.
- AllowedHosts []string `json:"allowedHosts,omitzero"`
// Whether traffic to local/loopback addresses is allowed.
AllowLocalNetwork *bool `json:"allowLocalNetwork,omitempty"`
// Whether outbound network traffic is allowed at all.
AllowOutbound *bool `json:"allowOutbound,omitempty"`
- // Hosts explicitly blocked.
- BlockedHosts []string `json:"blockedHosts,omitzero"`
}
// macOS seatbelt-specific options.
@@ -6440,7 +6789,8 @@ type SandboxConfigUserPolicySeatbelt struct {
KeychainAccess *bool `json:"keychainAccess,omitempty"`
}
-// Schema for the `ScheduleEntry` type.
+// Scheduled prompt entry with ID, timing (`intervalMs`, `cron`, or `at`), prompt text,
+// recurrence, and next run time.
// Experimental: ScheduleEntry is part of an experimental API and may change or be removed.
type ScheduleEntry struct {
// Absolute fire time (epoch milliseconds) for a one-shot calendar schedule.
@@ -6588,7 +6938,8 @@ type ServerInstructionSourceList struct {
Sources []InstructionSource `json:"sources"`
}
-// Schema for the `ServerSkill` type.
+// Server-side skill metadata, including name, description, source, enabled/invocable state,
+// path, project path, and argument hint.
// Experimental: ServerSkill is part of an experimental API and may change or be removed.
type ServerSkill struct {
// Optional freeform hint describing the skill's expected arguments, from the
@@ -6698,6 +7049,52 @@ type SessionContext struct {
Repository *string `json:"repository,omitempty"`
}
+// Per-source token attribution snapshot for the current context window. The heaviest
+// individual messages are available separately via `metadata.getContextHeaviestMessages`.
+// Experimental: SessionContextAttribution is part of an experimental API and may change or
+// be removed.
+type SessionContextAttribution struct {
+ // Successful compaction history for the session.
+ Compactions SessionContextAttributionCompactions `json:"compactions"`
+ // Flat list of per-source attribution entries. Group by `kind` and render unrecognized
+ // kinds generically. Nesting and rollups are expressed via `parentId`.
+ Entries []SessionContextAttributionEntriesItem `json:"entries"`
+ // 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.
+ TotalTokens int64 `json:"totalTokens"`
+}
+
+// Successful compaction history for the session.
+type SessionContextAttributionCompactions struct {
+ // Number of successful compactions in this session.
+ Count int64 `json:"count"`
+}
+
+type SessionContextAttributionEntriesItem struct {
+ // Supplementary per-entry metadata (e.g. `messageCount`, `role`, `evictable`,
+ // `pluginSource`). Values are stringified; parse as needed and ignore unrecognized keys.
+ Attributes map[string]string `json:"attributes,omitzero"`
+ // 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`.
+ ID string `json:"id"`
+ // Source category for this entry. Not a closed set — tolerate unknown values. Known values
+ // today: `skill`, `subagent`, `mcpServer`, `tool`, `system`, `toolDefinition`, `plugin`.
+ Kind string `json:"kind"`
+ // Human-readable display label, e.g. `bash` or `skill: tmux`. Presentation-only; may be
+ // localized/reformatted without notice — do not key off it.
+ Label string `json:"label"`
+ // 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.
+ ParentID *string `json:"parentId,omitempty"`
+ // Token count currently in context attributable to this entry.
+ Tokens int64 `json:"tokens"`
+}
+
// Token-usage breakdown for the session's current context window
// Experimental: SessionContextInfo is part of an experimental API and may change or be
// removed.
@@ -6833,7 +7230,8 @@ type SessionFSReaddirResult struct {
Error *SessionFSError `json:"error,omitempty"`
}
-// Schema for the `SessionFsReaddirWithTypesEntry` type.
+// Directory entry returned by session filesystem `readdirWithTypes`, with name and entry
+// type.
// Experimental: SessionFSReaddirWithTypesEntry is part of an experimental API and may
// change or be removed.
type SessionFSReaddirWithTypesEntry struct {
@@ -7035,7 +7433,8 @@ type SessionFSWriteFileRequest struct {
SessionID string `json:"sessionId"`
}
-// Schema for the `SessionInstalledPlugin` type.
+// Installed plugin record for a session, with marketplace, version, install time, enabled
+// state, cache path, and source.
// Experimental: SessionInstalledPlugin is part of an experimental API and may change or be
// removed.
type SessionInstalledPlugin struct {
@@ -7065,7 +7464,8 @@ type SessionInstalledPluginSource struct {
String *string
}
-// Schema for the `SessionInstalledPluginSourceGitHub` type.
+// Source descriptor for a direct GitHub plugin install, with `owner/repo`, optional ref,
+// and optional subpath.
// Experimental: SessionInstalledPluginSourceGitHub is part of an experimental API and may
// change or be removed.
type SessionInstalledPluginSourceGitHub struct {
@@ -7076,7 +7476,7 @@ type SessionInstalledPluginSourceGitHub struct {
Source SessionInstalledPluginSourceGitHubSource `json:"source"`
}
-// Schema for the `SessionInstalledPluginSourceLocal` type.
+// Source descriptor for a direct local plugin install, with a local filesystem path.
// Experimental: SessionInstalledPluginSourceLocal is part of an experimental API and may
// change or be removed.
type SessionInstalledPluginSourceLocal struct {
@@ -7085,7 +7485,8 @@ type SessionInstalledPluginSourceLocal struct {
Source SessionInstalledPluginSourceLocalSource `json:"source"`
}
-// Schema for the `SessionInstalledPluginSourceUrl` type.
+// Source descriptor for a direct URL plugin install, with URL, optional ref, and optional
+// subpath.
// Experimental: SessionInstalledPluginSourceURL is part of an experimental API and may
// change or be removed.
type SessionInstalledPluginSourceURL struct {
@@ -7362,6 +7763,8 @@ type SessionOpenOptions struct {
// surface is experimental.
// Experimental: EnableCitations is part of an experimental API and may change or be removed.
EnableCitations *bool `json:"enableCitations,omitempty"`
+ // Opt-in: self-fetch and enforce enterprise managed settings at session bootstrap.
+ EnableManagedSettings *bool `json:"enableManagedSettings,omitempty"`
// Whether on-demand custom instruction discovery is enabled.
EnableOnDemandInstructionDiscovery *bool `json:"enableOnDemandInstructionDiscovery,omitempty"`
// Whether shell-script safety heuristics are enabled.
@@ -7448,13 +7851,16 @@ type SessionOpenOptions struct {
SkipCustomInstructions *bool `json:"skipCustomInstructions,omitempty"`
// Optional trajectory output file path.
TrajectoryFile *string `json:"trajectoryFile,omitempty"`
+ // Initial output verbosity level for supported models.
+ Verbosity *Verbosity `json:"verbosity,omitempty"`
// Working directory to anchor the session.
WorkingDirectory *string `json:"workingDirectory,omitempty"`
// Pre-resolved working-directory context for session startup.
WorkingDirectoryContext *SessionContext `json:"workingDirectoryContext,omitempty"`
}
-// Schema for the `SessionOpenOptionsAdditionalContentExclusionPolicy` type.
+// Content-exclusion policy supplied to `sessions.open` options, with rules, last-updated
+// data, and scope.
// Experimental: SessionOpenOptionsAdditionalContentExclusionPolicy is part of an
// experimental API and may change or be removed.
type SessionOpenOptionsAdditionalContentExclusionPolicy struct {
@@ -7465,18 +7871,19 @@ type SessionOpenOptionsAdditionalContentExclusionPolicy struct {
Scope SessionOpenOptionsAdditionalContentExclusionPolicyScope `json:"scope"`
}
-// Schema for the `SessionOpenOptionsAdditionalContentExclusionPolicyRule` type.
+// Single content-exclusion rule supplied to `sessions.open` options, with paths, match
+// conditions, and source.
// Experimental: SessionOpenOptionsAdditionalContentExclusionPolicyRule is part of an
// experimental API and may change or be removed.
type SessionOpenOptionsAdditionalContentExclusionPolicyRule struct {
IfAnyMatch []string `json:"ifAnyMatch,omitzero"`
IfNoneMatch []string `json:"ifNoneMatch,omitzero"`
Paths []string `json:"paths"`
- // Schema for the `SessionOpenOptionsAdditionalContentExclusionPolicyRuleSource` type.
+ // Source descriptor for a `sessions.open` content-exclusion rule, with source name and type.
Source SessionOpenOptionsAdditionalContentExclusionPolicyRuleSource `json:"source"`
}
-// Schema for the `SessionOpenOptionsAdditionalContentExclusionPolicyRuleSource` type.
+// Source descriptor for a `sessions.open` content-exclusion rule, with source name and type.
// Experimental: SessionOpenOptionsAdditionalContentExclusionPolicyRuleSource is part of an
// experimental API and may change or be removed.
type SessionOpenOptionsAdditionalContentExclusionPolicyRuleSource struct {
@@ -7563,6 +7970,15 @@ type SessionsOpenHandoff struct {
// Remote session metadata for the session to hand off (typically obtained from
// `sessions.list` with `source: "remote"`).
Metadata RemoteSessionMetadataValue `json:"metadata"`
+ // 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: OnConfirm is part of the SDK's internal API surface and is not intended for
+ // external use.
+ OnConfirm any `json:"onConfirm,omitempty"`
// 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`;
@@ -7792,6 +8208,107 @@ type SessionSetCredentialsResult struct {
Success bool `json:"success"`
}
+// Availability of built-in job tools surfaced to boundary consumers.
+// Experimental: SessionSettingsBuiltInToolAvailabilitySnapshot is part of an experimental
+// API and may change or be removed.
+type SessionSettingsBuiltInToolAvailabilitySnapshot struct {
+ CreatePullRequest *bool `json:"createPullRequest,omitempty"`
+ ReportProgress *bool `json:"reportProgress,omitempty"`
+}
+
+// Named Rust-owned settings predicate to evaluate for this session.
+// Experimental: SessionSettingsEvaluatePredicateRequest is part of an experimental API and
+// may change or be removed.
+type SessionSettingsEvaluatePredicateRequest struct {
+ // Predicate name. The runtime owns the raw feature-flag names and composition logic.
+ Name SessionSettingsPredicateName `json:"name"`
+ // Tool name for tool-scoped predicates such as trivial-change handling.
+ ToolName *string `json:"toolName,omitempty"`
+}
+
+// Result of evaluating a Rust-owned settings predicate.
+// Experimental: SessionSettingsEvaluatePredicateResult is part of an experimental API and
+// may change or be removed.
+type SessionSettingsEvaluatePredicateResult struct {
+ Enabled bool `json:"enabled"`
+}
+
+// Redacted job settings for a session. The job nonce is excluded.
+// Experimental: SessionSettingsJobSnapshot is part of an experimental API and may change or
+// be removed.
+type SessionSettingsJobSnapshot struct {
+ BuiltInToolAvailability *SessionSettingsBuiltInToolAvailabilitySnapshot `json:"builtInToolAvailability,omitempty"`
+ EventType *string `json:"eventType,omitempty"`
+ IsTriggerJob *bool `json:"isTriggerJob,omitempty"`
+}
+
+// Redacted model routing settings for a session.
+// Experimental: SessionSettingsModelSnapshot is part of an experimental API and may change
+// or be removed.
+type SessionSettingsModelSnapshot struct {
+ CallbackURL *string `json:"callbackUrl,omitempty"`
+ DefaultReasoningEffort *string `json:"defaultReasoningEffort,omitempty"`
+ InstanceID *string `json:"instanceId,omitempty"`
+ Model *string `json:"model,omitempty"`
+}
+
+// Online-evaluation settings safe to expose across the SDK boundary.
+// Experimental: SessionSettingsOnlineEvaluationSnapshot is part of an experimental API and
+// may change or be removed.
+type SessionSettingsOnlineEvaluationSnapshot struct {
+ DisableOnlineEvaluation *bool `json:"disableOnlineEvaluation,omitempty"`
+ EnableOnlineEvaluationOutputFile *bool `json:"enableOnlineEvaluationOutputFile,omitempty"`
+}
+
+// Redacted repository and GitHub host settings for a session.
+// Experimental: SessionSettingsRepoSnapshot is part of an experimental API and may change
+// or be removed.
+type SessionSettingsRepoSnapshot struct {
+ Branch *string `json:"branch,omitempty"`
+ Commit *string `json:"commit,omitempty"`
+ Host *string `json:"host,omitempty"`
+ HostProtocol *string `json:"hostProtocol,omitempty"`
+ ID *float64 `json:"id,omitempty"`
+ Name *string `json:"name,omitempty"`
+ OwnerID *float64 `json:"ownerId,omitempty"`
+ OwnerName *string `json:"ownerName,omitempty"`
+ PrCommitCount *float64 `json:"prCommitCount,omitempty"`
+ ReadWrite *bool `json:"readWrite,omitempty"`
+ SecretScanningURL *string `json:"secretScanningUrl,omitempty"`
+ ServerURL *string `json:"serverUrl,omitempty"`
+}
+
+// Redacted, serializable view of session runtime settings for SDK boundary consumers.
+// Secrets and raw feature flags are intentionally excluded.
+// Experimental: SessionSettingsSnapshot is part of an experimental API and may change or be
+// removed.
+type SessionSettingsSnapshot struct {
+ ClientName *string `json:"clientName,omitempty"`
+ Job SessionSettingsJobSnapshot `json:"job"`
+ Model SessionSettingsModelSnapshot `json:"model"`
+ OnlineEvaluation SessionSettingsOnlineEvaluationSnapshot `json:"onlineEvaluation"`
+ Repo SessionSettingsRepoSnapshot `json:"repo"`
+ StartTimeMs *float64 `json:"startTimeMs,omitempty"`
+ TimeoutMs *float64 `json:"timeoutMs,omitempty"`
+ Validation SessionSettingsValidationSnapshot `json:"validation"`
+ Version *string `json:"version,omitempty"`
+}
+
+// Redacted validation and memory-tool settings for a session.
+// Experimental: SessionSettingsValidationSnapshot is part of an experimental API and may
+// change or be removed.
+type SessionSettingsValidationSnapshot struct {
+ AdvisoryEnabled *bool `json:"advisoryEnabled,omitempty"`
+ CodeqlEnabled *bool `json:"codeqlEnabled,omitempty"`
+ CodeReviewEnabled *bool `json:"codeReviewEnabled,omitempty"`
+ CodeReviewModel *string `json:"codeReviewModel,omitempty"`
+ DependabotTimeout *float64 `json:"dependabotTimeout,omitempty"`
+ MemoryStoreEnabled *bool `json:"memoryStoreEnabled,omitempty"`
+ MemoryVoteEnabled *bool `json:"memoryVoteEnabled,omitempty"`
+ SecretScanningEnabled *bool `json:"secretScanningEnabled,omitempty"`
+ Timeout *float64 `json:"timeout,omitempty"`
+}
+
// UUID prefix to resolve to a unique session ID.
// Experimental: SessionsFindByPrefixRequest is part of an experimental API and may change
// or be removed.
@@ -7973,7 +8490,7 @@ type SessionsLoadDeferredRepoHooksRequest struct {
SessionID string `json:"sessionId"`
}
-// Schema for the `SessionsOpenProgress` type.
+// `sessions.open` handoff progress update with step, status, and optional message.
// Experimental: SessionsOpenProgress is part of an experimental API and may change or be
// removed.
type SessionsOpenProgress struct {
@@ -7985,25 +8502,6 @@ type SessionsOpenProgress struct {
Step SessionsOpenProgressStep `json:"step"`
}
-// Schema for the `SessionsPollSpawnedSessionsEvent` type.
-// Experimental: SessionsPollSpawnedSessionsEvent is part of an experimental API and may
-// change or be removed.
-type SessionsPollSpawnedSessionsEvent struct {
- // Session id of the newly-spawned session.
- SessionID string `json:"sessionId"`
-}
-
-// Experimental: SessionsPollSpawnedSessionsRequest is part of an experimental API and may
-// change or be removed.
-type SessionsPollSpawnedSessionsRequest struct {
- // Opaque cursor returned by a previous poll. Omit on the first call to receive any spawn
- // events buffered since the runtime started.
- Cursor *string `json:"cursor,omitempty"`
- // Milliseconds to wait for new spawn events when the cursor is at the tail. 0 (default)
- // returns immediately even if no events are buffered. Capped at 60000ms.
- WaitMs *int32 `json:"waitMs,omitempty"`
-}
-
// Age threshold and optional flags controlling which old sessions are pruned (or simulated
// when dryRun is true).
// Experimental: SessionsPruneOldRequest is part of an experimental API and may change or be
@@ -8288,6 +8786,8 @@ type SessionUpdateOptionsParams struct {
ToolFilterPrecedence *OptionsUpdateToolFilterPrecedence `json:"toolFilterPrecedence,omitempty"`
// Optional path for trajectory output.
TrajectoryFile *string `json:"trajectoryFile,omitempty"`
+ // Output verbosity level for supported models.
+ Verbosity *Verbosity `json:"verbosity,omitempty"`
// Absolute working-directory path for shell tools.
WorkingDirectory *string `json:"workingDirectory,omitempty"`
}
@@ -8395,7 +8895,8 @@ type ShutdownRequest struct {
Type *ShutdownType `json:"type,omitempty"`
}
-// Schema for the `Skill` type.
+// Skill metadata available to a session, with name, description, source, enabled/invocable
+// state, path, plugin, and argument hint.
// Experimental: Skill is part of an experimental API and may change or be removed.
type Skill struct {
// Optional freeform hint describing the skill's expected arguments, from the
@@ -8417,7 +8918,8 @@ type Skill struct {
UserInvocable bool `json:"userInvocable"`
}
-// Schema for the `SkillDiscoveryPath` type.
+// Canonical directory where skills can be discovered or created, with scope, preference,
+// and optional project path.
// Experimental: SkillDiscoveryPath is part of an experimental API and may change or be
// removed.
type SkillDiscoveryPath struct {
@@ -8510,7 +9012,7 @@ type SkillsGetInvokedResult struct {
Skills []SkillsInvokedSkill `json:"skills"`
}
-// Schema for the `SkillsInvokedSkill` type.
+// Skill invocation record with name, path, content, allowed tools, and turn number.
// Experimental: SkillsInvokedSkill is part of an experimental API and may change or be
// removed.
type SkillsInvokedSkill struct {
@@ -8536,7 +9038,8 @@ type SkillsLoadDiagnostics struct {
Warnings []string `json:"warnings"`
}
-// Schema for the `SlashCommandInfo` type.
+// Slash-command metadata with name, aliases, description, kind, input hint, execution
+// allowance, and schedulability.
// Experimental: SlashCommandInfo is part of an experimental API and may change or be
// removed.
type SlashCommandInfo struct {
@@ -8565,6 +9068,9 @@ type SlashCommandInfo struct {
// Experimental: SlashCommandInput is part of an experimental API and may change or be
// removed.
type SlashCommandInput struct {
+ // Optional literal choices the input accepts, each with a human-facing description; clients
+ // may render these as selectable options
+ Choices []SlashCommandInputChoice `json:"choices,omitzero"`
// Optional completion hint for the input (e.g. 'directory' for filesystem path completion)
Completion *SlashCommandInputCompletion `json:"completion,omitempty"`
// Hint to display when command input has not been provided
@@ -8577,6 +9083,16 @@ type SlashCommandInput struct {
Required *bool `json:"required,omitempty"`
}
+// A literal choice the command input accepts, with a human-facing description
+// Experimental: SlashCommandInputChoice is part of an experimental API and may change or be
+// removed.
+type SlashCommandInputChoice struct {
+ // Human-readable description shown alongside the choice
+ Description string `json:"description"`
+ // The literal choice value (e.g. 'on', 'off', 'show')
+ Name string `json:"name"`
+}
+
// Result of invoking the slash command (text output, prompt to send to the agent,
// completion, or subcommand selection).
// Experimental: SlashCommandInvocationResult is part of an experimental API and may change
@@ -8596,7 +9112,8 @@ func (r RawSlashCommandInvocationResultData) Kind() SlashCommandInvocationResult
return r.Discriminator
}
-// Schema for the `SlashCommandAgentPromptResult` type.
+// Slash-command invocation result that submits an agent prompt, with display prompt,
+// optional mode, and settings-change flag.
// Experimental: SlashCommandAgentPromptResult is part of an experimental API and may change
// or be removed.
type SlashCommandAgentPromptResult struct {
@@ -8616,7 +9133,8 @@ func (SlashCommandAgentPromptResult) Kind() SlashCommandInvocationResultKind {
return SlashCommandInvocationResultKindAgentPrompt
}
-// Schema for the `SlashCommandCompletedResult` type.
+// Slash-command invocation result indicating completion, with optional message and
+// settings-change flag.
// Experimental: SlashCommandCompletedResult is part of an experimental API and may change
// or be removed.
type SlashCommandCompletedResult struct {
@@ -8632,7 +9150,8 @@ func (SlashCommandCompletedResult) Kind() SlashCommandInvocationResultKind {
return SlashCommandInvocationResultKindCompleted
}
-// Schema for the `SlashCommandSelectSubcommandResult` type.
+// Slash-command invocation result asking the client to present subcommand options for a
+// parent command.
// Experimental: SlashCommandSelectSubcommandResult is part of an experimental API and may
// change or be removed.
type SlashCommandSelectSubcommandResult struct {
@@ -8652,7 +9171,7 @@ func (SlashCommandSelectSubcommandResult) Kind() SlashCommandInvocationResultKin
return SlashCommandInvocationResultKindSelectSubcommand
}
-// Schema for the `SlashCommandTextResult` type.
+// Slash-command invocation result containing text output plus Markdown/ANSI rendering flags.
// Experimental: SlashCommandTextResult is part of an experimental API and may change or be
// removed.
type SlashCommandTextResult struct {
@@ -8672,7 +9191,8 @@ func (SlashCommandTextResult) Kind() SlashCommandInvocationResultKind {
return SlashCommandInvocationResultKindText
}
-// Schema for the `SlashCommandSelectSubcommandOption` type.
+// Selectable slash-command subcommand option with name, description, and optional group
+// label.
// Experimental: SlashCommandSelectSubcommandOption is part of an experimental API and may
// change or be removed.
type SlashCommandSelectSubcommandOption struct {
@@ -8711,7 +9231,7 @@ type SubagentSettingsEntry struct {
Model *string `json:"model,omitempty"`
}
-// Schema for the `TaskInfo` type.
+// Tracked task union returned by task APIs, containing either an agent task or a shell task.
// Experimental: TaskInfo is part of an experimental API and may change or be removed.
type TaskInfo interface {
taskInfo()
@@ -8728,7 +9248,8 @@ func (r RawTaskInfoData) Type() TaskInfoType {
return r.Discriminator
}
-// Schema for the `TaskAgentInfo` type.
+// Tracked background agent task metadata, including IDs, status, timing, agent type,
+// prompt, model, result, and latest response.
// Experimental: TaskAgentInfo is part of an experimental API and may change or be removed.
type TaskAgentInfo struct {
// ISO 8601 timestamp when the current active period began
@@ -8777,7 +9298,8 @@ func (TaskAgentInfo) Type() TaskInfoType {
return TaskInfoTypeAgent
}
-// Schema for the `TaskShellInfo` type.
+// Tracked shell task metadata, including ID, command, status, timing, attachment/execution
+// mode, log path, and PID.
// Experimental: TaskShellInfo is part of an experimental API and may change or be removed.
type TaskShellInfo struct {
// Whether the shell runs inside a managed PTY session or as an independent background
@@ -8833,7 +9355,8 @@ func (r RawTaskProgressData) Type() TaskProgressType {
return r.Discriminator
}
-// Schema for the `TaskAgentProgress` type.
+// Progress snapshot for an agent task, with recent activity lines and optional latest
+// intent.
// Experimental: TaskAgentProgress is part of an experimental API and may change or be
// removed.
type TaskAgentProgress struct {
@@ -8848,7 +9371,8 @@ func (TaskAgentProgress) Type() TaskProgressType {
return TaskProgressTypeAgent
}
-// Schema for the `TaskShellProgress` type.
+// Progress snapshot for a shell task, with recent stdout/stderr output and optional process
+// ID.
// Experimental: TaskShellProgress is part of an experimental API and may change or be
// removed.
type TaskShellProgress struct {
@@ -8863,7 +9387,7 @@ func (TaskShellProgress) Type() TaskProgressType {
return TaskProgressTypeShell
}
-// Schema for the `TaskProgressLine` type.
+// Timestamped display line for task progress output or recent agent activity.
// Experimental: TaskProgressLine is part of an experimental API and may change or be
// removed.
type TaskProgressLine struct {
@@ -9033,7 +9557,8 @@ type TelemetrySetFeatureOverridesRequest struct {
Features map[string]string `json:"features"`
}
-// Schema for the `Tool` type.
+// Built-in tool metadata with identifier, optional namespaced name, description,
+// input-parameter schema, and usage instructions.
// Experimental: Tool is part of an experimental API and may change or be removed.
type Tool struct {
// Description of what the tool does
@@ -9095,7 +9620,8 @@ type UIElicitationArrayAnyOfFieldItems struct {
AnyOf []UIElicitationArrayAnyOfFieldItemsAnyOf `json:"anyOf"`
}
-// Schema for the `UIElicitationArrayAnyOfFieldItemsAnyOf` type.
+// Selectable option for a UI elicitation multi-select array item, with submitted value and
+// display label.
// Experimental: UIElicitationArrayAnyOfFieldItemsAnyOf is part of an experimental API and
// may change or be removed.
type UIElicitationArrayAnyOfFieldItemsAnyOf struct {
@@ -9115,7 +9641,7 @@ type UIElicitationArrayEnumFieldItems struct {
Type UIElicitationArrayEnumFieldItemsType `json:"type"`
}
-// Schema for the `UIElicitationFieldValue` type.
+// Submitted UI elicitation field value: string, number, boolean, or an array of strings.
// Experimental: UIElicitationFieldValue is part of an experimental API and may change or be
// removed.
type UIElicitationFieldValue interface {
@@ -9354,7 +9880,8 @@ func (UIElicitationStringOneOfField) Type() UIElicitationSchemaPropertyType {
return UIElicitationSchemaPropertyTypeString
}
-// Schema for the `UIElicitationStringOneOfFieldOneOf` type.
+// Selectable option for a UI elicitation single-select string field, with submitted value
+// and display label.
// Experimental: UIElicitationStringOneOfFieldOneOf is part of an experimental API and may
// change or be removed.
type UIElicitationStringOneOfFieldOneOf struct {
@@ -9392,7 +9919,8 @@ type UIEphemeralQueryResult struct {
Answer string `json:"answer"`
}
-// Schema for the `UIExitPlanModeResponse` type.
+// User response for a pending exit-plan-mode request, with approval state, selected action,
+// auto-approve flag, and feedback.
// Experimental: UIExitPlanModeResponse is part of an experimental API and may change or be
// removed.
type UIExitPlanModeResponse struct {
@@ -9435,7 +9963,8 @@ type UIHandlePendingElicitationRequest struct {
type UIHandlePendingExitPlanModeRequest struct {
// The unique request ID from the exit_plan_mode.requested event
RequestID string `json:"requestId"`
- // Schema for the `UIExitPlanModeResponse` type.
+ // User response for a pending exit-plan-mode request, with approval state, selected action,
+ // auto-approve flag, and feedback.
Response UIExitPlanModeResponse `json:"response"`
}
@@ -9485,7 +10014,8 @@ type UIHandlePendingSessionLimitsExhaustedRequest struct {
type UIHandlePendingUserInputRequest struct {
// The unique request ID from the user_input.requested event
RequestID string `json:"requestId"`
- // Schema for the `UIUserInputResponse` type.
+ // User response for a pending user-input request, with answer text and whether it was typed
+ // freeform.
Response UIUserInputResponse `json:"response"`
}
@@ -9532,7 +10062,8 @@ type UIUnregisterDirectAutoModeSwitchHandlerResult struct {
Unregistered bool `json:"unregistered"`
}
-// Schema for the `UIUserInputResponse` type.
+// User response for a pending user-input request, with answer text and whether it was typed
+// freeform.
// Experimental: UIUserInputResponse is part of an experimental API and may change or be
// removed.
type UIUserInputResponse struct {
@@ -9595,7 +10126,8 @@ type UsageMetricsCodeChanges struct {
LinesRemoved int64 `json:"linesRemoved"`
}
-// Schema for the `UsageMetricsModelMetric` type.
+// Per-model usage metrics, including request counts/costs, token usage, nano-AI units, and
+// per-token-type details.
// Experimental: UsageMetricsModelMetric is part of an experimental API and may change or be
// removed.
type UsageMetricsModelMetric struct {
@@ -9619,7 +10151,7 @@ type UsageMetricsModelMetricRequests struct {
Count int64 `json:"count"`
}
-// Schema for the `UsageMetricsModelMetricTokenDetail` type.
+// Per-model token-detail entry containing the accumulated token count for one token type.
// Experimental: UsageMetricsModelMetricTokenDetail is part of an experimental API and may
// change or be removed.
type UsageMetricsModelMetricTokenDetail struct {
@@ -9643,7 +10175,7 @@ type UsageMetricsModelMetricUsage struct {
ReasoningTokens *int64 `json:"reasoningTokens,omitempty"`
}
-// Schema for the `UsageMetricsTokenDetail` type.
+// Session-wide token-detail entry containing the accumulated token count for one token type.
// Experimental: UsageMetricsTokenDetail is part of an experimental API and may change or be
// removed.
type UsageMetricsTokenDetail struct {
@@ -9736,7 +10268,7 @@ func (r RawUserToolSessionApprovalData) Kind() UserToolSessionApprovalKind {
return r.Discriminator
}
-// Schema for the `UserToolSessionApprovalCommands` type.
+// Session-scoped tool-approval rule for specific shell command identifiers.
// Experimental: UserToolSessionApprovalCommands is part of an experimental API and may
// change or be removed.
type UserToolSessionApprovalCommands struct {
@@ -9749,7 +10281,7 @@ func (UserToolSessionApprovalCommands) Kind() UserToolSessionApprovalKind {
return UserToolSessionApprovalKindCommands
}
-// Schema for the `UserToolSessionApprovalCustomTool` type.
+// Session-scoped tool-approval rule for a custom tool, keyed by tool name.
// Experimental: UserToolSessionApprovalCustomTool is part of an experimental API and may
// change or be removed.
type UserToolSessionApprovalCustomTool struct {
@@ -9762,7 +10294,8 @@ func (UserToolSessionApprovalCustomTool) Kind() UserToolSessionApprovalKind {
return UserToolSessionApprovalKindCustomTool
}
-// Schema for the `UserToolSessionApprovalExtensionManagement` type.
+// Session-scoped tool-approval rule for extension-management operations, optionally
+// narrowed by operation.
// Experimental: UserToolSessionApprovalExtensionManagement is part of an experimental API
// and may change or be removed.
type UserToolSessionApprovalExtensionManagement struct {
@@ -9775,7 +10308,8 @@ func (UserToolSessionApprovalExtensionManagement) Kind() UserToolSessionApproval
return UserToolSessionApprovalKindExtensionManagement
}
-// Schema for the `UserToolSessionApprovalExtensionPermissionAccess` type.
+// Session-scoped tool-approval rule for an extension's permission-gated capability access,
+// keyed by extension name.
// Experimental: UserToolSessionApprovalExtensionPermissionAccess is part of an experimental
// API and may change or be removed.
type UserToolSessionApprovalExtensionPermissionAccess struct {
@@ -9788,7 +10322,8 @@ func (UserToolSessionApprovalExtensionPermissionAccess) Kind() UserToolSessionAp
return UserToolSessionApprovalKindExtensionPermissionAccess
}
-// Schema for the `UserToolSessionApprovalMcp` type.
+// Session-scoped tool-approval rule for an MCP server tool, or all tools on the server when
+// `toolName` is null.
// Experimental: UserToolSessionApprovalMCP is part of an experimental API and may change or
// be removed.
type UserToolSessionApprovalMCP struct {
@@ -9803,7 +10338,7 @@ func (UserToolSessionApprovalMCP) Kind() UserToolSessionApprovalKind {
return UserToolSessionApprovalKindMCP
}
-// Schema for the `UserToolSessionApprovalMemory` type.
+// Session-scoped tool-approval rule for writes to long-term memory.
// Experimental: UserToolSessionApprovalMemory is part of an experimental API and may change
// or be removed.
type UserToolSessionApprovalMemory struct {
@@ -9814,7 +10349,7 @@ func (UserToolSessionApprovalMemory) Kind() UserToolSessionApprovalKind {
return UserToolSessionApprovalKindMemory
}
-// Schema for the `UserToolSessionApprovalRead` type.
+// Session-scoped tool-approval rule for read-only filesystem operations.
// Experimental: UserToolSessionApprovalRead is part of an experimental API and may change
// or be removed.
type UserToolSessionApprovalRead struct {
@@ -9825,7 +10360,7 @@ func (UserToolSessionApprovalRead) Kind() UserToolSessionApprovalKind {
return UserToolSessionApprovalKindRead
}
-// Schema for the `UserToolSessionApprovalWrite` type.
+// Session-scoped tool-approval rule for filesystem write operations.
// Experimental: UserToolSessionApprovalWrite is part of an experimental API and may change
// or be removed.
type UserToolSessionApprovalWrite struct {
@@ -9908,7 +10443,8 @@ type WorkspaceDiffResult struct {
RequestedMode WorkspaceDiffMode `json:"requestedMode"`
}
-// Schema for the `WorkspacesCheckpoints` type.
+// Workspace checkpoint metadata with assigned number, human-readable title, and checkpoint
+// filename.
// Experimental: WorkspacesCheckpoints is part of an experimental API and may change or be
// removed.
type WorkspacesCheckpoints struct {
@@ -10364,6 +10900,67 @@ const (
CopilotAPITokenAuthInfoHostHTTPSGitHubCom CopilotAPITokenAuthInfoHost = "https://github.com"
)
+// Kind discriminator for DebugCollectLogsDestination.
+type DebugCollectLogsDestinationKind string
+
+const (
+ DebugCollectLogsDestinationKindArchive DebugCollectLogsDestinationKind = "archive"
+ DebugCollectLogsDestinationKindDirectory DebugCollectLogsDestinationKind = "directory"
+)
+
+// Kind of caller-provided debug log entry.
+// Experimental: DebugCollectLogsEntryKind is part of an experimental API and may change or
+// be removed.
+type DebugCollectLogsEntryKind string
+
+const (
+ // Include files from a server-local directory recursively.
+ DebugCollectLogsEntryKindDirectory DebugCollectLogsEntryKind = "directory"
+ // Include a single server-local file.
+ DebugCollectLogsEntryKindFile DebugCollectLogsEntryKind = "file"
+)
+
+// How a collected debug entry should be redacted before being staged.
+// Experimental: DebugCollectLogsRedaction is part of an experimental API and may change or
+// be removed.
+type DebugCollectLogsRedaction string
+
+const (
+ // Redact each non-empty line as a session event JSON object, falling back to plain-text
+ // redaction for malformed lines.
+ DebugCollectLogsRedactionEventsJsonl DebugCollectLogsRedaction = "events-jsonl"
+ // Redact the file as plain UTF-8 log text.
+ DebugCollectLogsRedactionPlainText DebugCollectLogsRedaction = "plain-text"
+)
+
+// Destination kind that was written.
+// Experimental: DebugCollectLogsResultKind is part of an experimental API and may change or
+// be removed.
+type DebugCollectLogsResultKind string
+
+const (
+ // A .tgz archive was written.
+ DebugCollectLogsResultKindArchive DebugCollectLogsResultKind = "archive"
+ // A directory containing redacted files was written.
+ DebugCollectLogsResultKindDirectory DebugCollectLogsResultKind = "directory"
+)
+
+// Source category for a collected debug bundle entry.
+// Experimental: DebugCollectLogsSource is part of an experimental API and may change or be
+// removed.
+type DebugCollectLogsSource string
+
+const (
+ // Caller-provided diagnostic entry.
+ DebugCollectLogsSourceAdditional DebugCollectLogsSource = "additional"
+ // Session event log.
+ DebugCollectLogsSourceEvents DebugCollectLogsSource = "events"
+ // Process log for the session.
+ DebugCollectLogsSourceProcessLog DebugCollectLogsSource = "process-log"
+ // Interactive shell log for the session.
+ DebugCollectLogsSourceShellLog DebugCollectLogsSource = "shell-log"
+)
+
// Server transport type: stdio, http, sse (deprecated), or memory
// Experimental: DiscoveredMCPServerType is part of an experimental API and may change or be
// removed.
@@ -11056,6 +11653,21 @@ const (
PermissionLocationTypeRepo PermissionLocationType = "repo"
)
+// Current or requested allow-all mode.
+// Experimental: PermissionsAllowAllMode is part of an experimental API and may change or be
+// removed.
+type PermissionsAllowAllMode string
+
+const (
+ // Permission requests follow the normal approval flow with an LLM advisory recommendation
+ // attached; clients may choose to auto-approve requests the judge evaluated as acceptable.
+ PermissionsAllowAllModeAuto PermissionsAllowAllMode = "auto"
+ // Permission requests follow the normal approval flow.
+ PermissionsAllowAllModeOff PermissionsAllowAllMode = "off"
+ // Tool, path, and URL permission requests are automatically approved.
+ PermissionsAllowAllModeOn PermissionsAllowAllMode = "on"
+)
+
// Allowed values for the `PermissionsConfigureAdditionalContentExclusionPolicyScope`
// enumeration.
// Experimental: PermissionsConfigureAdditionalContentExclusionPolicyScope is part of an
@@ -11524,6 +12136,53 @@ const (
SessionOpenParamsKindResumeLast SessionOpenParamsKind = "resumeLast"
)
+// Rust-owned settings predicates exposed across the SDK boundary. Raw feature-flag names
+// are intentionally not part of the contract.
+// Experimental: SessionSettingsPredicateName is part of an experimental API and may change
+// or be removed.
+type SessionSettingsPredicateName string
+
+const (
+ // Whether Claude Opus token-limit caps should be applied.
+ SessionSettingsPredicateNameCapClaudeOpusTokenLimitsEnabled SessionSettingsPredicateName = "capClaudeOpusTokenLimitsEnabled"
+ // Whether CCA should use the TypeScript autofind behavior.
+ SessionSettingsPredicateNameCcaUseTsAutofindEnabled SessionSettingsPredicateName = "ccaUseTsAutofindEnabled"
+ // Whether Chronicle integration is enabled.
+ SessionSettingsPredicateNameChronicleEnabled SessionSettingsPredicateName = "chronicleEnabled"
+ // Whether the co-author hook is enabled.
+ SessionSettingsPredicateNameCoAuthorHookEnabled SessionSettingsPredicateName = "coAuthorHookEnabled"
+ // Whether the CodeQL checker is enabled.
+ SessionSettingsPredicateNameCodeqlCheckerEnabled SessionSettingsPredicateName = "codeqlCheckerEnabled"
+ // Whether code-review behavior is enabled.
+ SessionSettingsPredicateNameCodeReviewFeatureEnabled SessionSettingsPredicateName = "codeReviewFeatureEnabled"
+ // Whether content-exclusion policy may self-fetch data.
+ SessionSettingsPredicateNameContentExclusionSelfFetchEnabled SessionSettingsPredicateName = "contentExclusionSelfFetchEnabled"
+ // Whether the Dependabot checker is enabled.
+ SessionSettingsPredicateNameDependabotCheckerEnabled SessionSettingsPredicateName = "dependabotCheckerEnabled"
+ // Whether the dependency checker is enabled.
+ SessionSettingsPredicateNameDependencyCheckerEnabled SessionSettingsPredicateName = "dependencyCheckerEnabled"
+ // Whether validation may run in parallel.
+ SessionSettingsPredicateNameParallelValidationEnabled SessionSettingsPredicateName = "parallelValidationEnabled"
+ // Whether runtime timing telemetry is enabled.
+ SessionSettingsPredicateNameRuntimeTimingTelemetryEnabled SessionSettingsPredicateName = "runtimeTimingTelemetryEnabled"
+ // Whether the security-tools feature flag enables security tool wiring.
+ SessionSettingsPredicateNameSecurityToolsEnabled SessionSettingsPredicateName = "securityToolsEnabled"
+ // Whether third-party security tools should receive the security prompt.
+ SessionSettingsPredicateNameThirdPartySecurityPromptEnabled SessionSettingsPredicateName = "thirdPartySecurityPromptEnabled"
+ // Whether trivial-change handling is enabled.
+ SessionSettingsPredicateNameTrivialChangeEnabled SessionSettingsPredicateName = "trivialChangeEnabled"
+ // Whether trivial-change handling is enabled for code review.
+ SessionSettingsPredicateNameTrivialChangeEnabledForCodeReview SessionSettingsPredicateName = "trivialChangeEnabledForCodeReview"
+ // Whether trivial-change handling is enabled for a specific tool.
+ SessionSettingsPredicateNameTrivialChangeEnabledForTool SessionSettingsPredicateName = "trivialChangeEnabledForTool"
+ // Whether trivial-change skip behavior is enabled.
+ SessionSettingsPredicateNameTrivialChangeSkipEnabled SessionSettingsPredicateName = "trivialChangeSkipEnabled"
+ // Whether trivial-change skip behavior is enabled for code review.
+ SessionSettingsPredicateNameTrivialChangeSkipEnabledForCodeReview SessionSettingsPredicateName = "trivialChangeSkipEnabledForCodeReview"
+ // Whether trivial-change skip behavior is enabled for a specific tool.
+ SessionSettingsPredicateNameTrivialChangeSkipEnabledForTool SessionSettingsPredicateName = "trivialChangeSkipEnabledForTool"
+)
+
// Task type determines the handoff strategy (CCA fetches events; CLI prepares a transient
// session).
// Experimental: SessionsOpenHandoffTaskType is part of an experimental API and may change
@@ -11922,6 +12581,19 @@ const (
UserToolSessionApprovalKindWrite UserToolSessionApprovalKind = "write"
)
+// Output verbosity level for supported models
+// Experimental: Verbosity is part of an experimental API and may change or be removed.
+type Verbosity string
+
+const (
+ // Request a more detailed response.
+ VerbosityHigh Verbosity = "high"
+ // Request a terse response.
+ VerbosityLow Verbosity = "low"
+ // Request a medium amount of response detail.
+ VerbosityMedium Verbosity = "medium"
+)
+
// Type of change represented by this file diff.
// Experimental: WorkspaceDiffFileChangeType is part of an experimental API and may change
// or be removed.
@@ -13550,33 +14222,6 @@ func (a *InternalServerSessionsAPI) GetPersistedRemoteSteerable(ctx context.Cont
return &result, nil
}
-// PollSpawnedSessions cursor-based long-poll for sessions spawned by the runtime (e.g. in
-// response to a Mission Control `start_session` command). The cursor is an opaque token;
-// pass it back to receive only spawn events that occurred AFTER the cursor was issued. Omit
-// the cursor on the first call to receive any events buffered since the runtime started.
-// Internal: this is a CLI background-daemon plumbing primitive. SDK consumers that need to
-// react to runtime-spawned sessions should subscribe to a higher-level event stream rather
-// than driving a long-poll loop.
-//
-// RPC method: sessions.pollSpawnedSessions.
-//
-// Parameters: Cursor and optional long-poll wait for polling runtime-spawned sessions.
-//
-// Returns: Batch of spawn events plus a cursor for follow-up polls.
-// Internal: PollSpawnedSessions is part of the SDK's internal handshake/plumbing; external
-// callers should not use it.
-func (a *InternalServerSessionsAPI) PollSpawnedSessions(ctx context.Context, params *SessionsPollSpawnedSessionsRequest) (*PollSpawnedSessionsResult, error) {
- raw, err := a.client.Request(ctx, "sessions.pollSpawnedSessions", params)
- if err != nil {
- return nil, err
- }
- var result PollSpawnedSessionsResult
- if err := json.Unmarshal(raw, &result); err != nil {
- return nil, err
- }
- return &result, nil
-}
-
// RegisterExtensionToolsOnSession registers extension-provided tools on the given session,
// gated by an optional `enabled` callback. Returns an opaque unsubscribe function the
// caller must invoke to deregister the tools when the extension is torn down. Marked
@@ -13622,7 +14267,8 @@ type InternalServerRPC struct {
//
// RPC method: connect.
//
-// Parameters: Optional connection token presented by the SDK client during the handshake.
+// Parameters: Parameters for the `server.connect` handshake: an optional connection token
+// and optional connection-level opt-ins (e.g. GitHub telemetry forwarding).
//
// Returns: Handshake result reporting the server's protocol version and package version on
// success.
@@ -14091,6 +14737,41 @@ func (a *CompletionsAPI) Request(ctx context.Context, params *CompletionsRequest
return &result, nil
}
+// Experimental: DebugAPI contains experimental APIs that may change or be removed.
+type DebugAPI sessionAPI
+
+// CollectLogs collects a redacted session debug log bundle into a local archive or staging
+// directory. The runtime includes session-owned logs by default and accepts caller-provided
+// diagnostic entries so host applications can add their own files without changing this API
+// shape.
+//
+// RPC method: session.debug.collectLogs.
+//
+// Parameters: Options for collecting a redacted session debug bundle.
+//
+// Returns: Result of collecting a redacted debug bundle.
+func (a *DebugAPI) CollectLogs(ctx context.Context, params *DebugCollectLogsRequest) (*DebugCollectLogsResult, error) {
+ req := map[string]any{"sessionId": a.sessionID}
+ if params != nil {
+ if params.AdditionalEntries != nil {
+ req["additionalEntries"] = params.AdditionalEntries
+ }
+ req["destination"] = params.Destination
+ if params.Include != nil {
+ req["include"] = *params.Include
+ }
+ }
+ raw, err := a.client.Request(ctx, "session.debug.collectLogs", req)
+ if err != nil {
+ return nil, err
+ }
+ var result DebugCollectLogsResult
+ if err := json.Unmarshal(raw, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
// Experimental: EventLogAPI contains experimental APIs that may change or be removed.
type EventLogAPI sessionAPI
@@ -15113,6 +15794,58 @@ func (a *MetadataAPI) ContextInfo(ctx context.Context, params *MetadataContextIn
return &result, nil
}
+// GetContextAttribution returns the experimental per-source attribution breakdown of the
+// session's current context window as a flat list of entries (skills, subagents, MCP
+// servers, built-in tools, plugin rollups, system/tool-definition costs, with nesting via
+// parentId), plus the successful compaction count. The heaviest individual messages are
+// available separately via `metadata.getContextHeaviestMessages`. Returns null until the
+// session has initialized its system prompt and tool metadata.
+//
+// RPC method: session.metadata.getContextAttribution.
+//
+// Returns: Per-source attribution breakdown for the session's current context window, or
+// null if uninitialized.
+func (a *MetadataAPI) GetContextAttribution(ctx context.Context) (*MetadataContextAttributionResult, error) {
+ req := map[string]any{"sessionId": a.sessionID}
+ raw, err := a.client.Request(ctx, "session.metadata.getContextAttribution", req)
+ if err != nil {
+ return nil, err
+ }
+ var result MetadataContextAttributionResult
+ if err := json.Unmarshal(raw, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+// GetContextHeaviestMessages returns the largest individual messages currently in the
+// session's context window, most-expensive first. Companion to
+// `metadata.getContextAttribution`. Returns an empty list until the session has initialized.
+//
+// RPC method: session.metadata.getContextHeaviestMessages.
+//
+// Parameters: Parameters for the heaviest-messages query.
+//
+// Returns: The heaviest individual messages in the session's context window, most-expensive
+// first.
+func (a *MetadataAPI) GetContextHeaviestMessages(ctx context.Context, params *MetadataContextHeaviestMessagesRequest) (*MetadataContextHeaviestMessagesResult, error) {
+ req := map[string]any{"sessionId": a.sessionID}
+ if params != nil {
+ if params.Limit != nil {
+ req["limit"] = *params.Limit
+ }
+ }
+ raw, err := a.client.Request(ctx, "session.metadata.getContextHeaviestMessages", req)
+ if err != nil {
+ return nil, err
+ }
+ var result MetadataContextHeaviestMessagesResult
+ if err := json.Unmarshal(raw, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
// IsProcessing reports whether the local session is currently processing user/agent
// messages.
//
@@ -15378,6 +16111,9 @@ func (a *ModelAPI) SwitchTo(ctx context.Context, params *ModelSwitchToRequest) (
if params.ReasoningSummary != nil {
req["reasoningSummary"] = *params.ReasoningSummary
}
+ if params.Verbosity != nil {
+ req["verbosity"] = *params.Verbosity
+ }
}
raw, err := a.client.Request(ctx, "session.model.switchTo", req)
if err != nil {
@@ -15626,6 +16362,9 @@ func (a *OptionsAPI) Update(ctx context.Context, params *SessionUpdateOptionsPar
if params.TrajectoryFile != nil {
req["trajectoryFile"] = *params.TrajectoryFile
}
+ if params.Verbosity != nil {
+ req["verbosity"] = *params.Verbosity
+ }
if params.WorkingDirectory != nil {
req["workingDirectory"] = *params.WorkingDirectory
}
@@ -15686,12 +16425,11 @@ func (a *PermissionsAPI) Configure(ctx context.Context, params *PermissionsConfi
return &result, nil
}
-// GetAllowAll returns whether full allow-all permissions are currently active for the
-// session.
+// GetAllowAll returns the current allow-all permission mode for the session.
//
// RPC method: session.permissions.getAllowAll.
//
-// Returns: Current full allow-all permission state.
+// Returns: Current allow-all permission mode.
func (a *PermissionsAPI) GetAllowAll(ctx context.Context) (*AllowAllPermissionState, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request(ctx, "session.permissions.getAllowAll", req)
@@ -15826,23 +16564,31 @@ func (a *PermissionsAPI) ResetSessionApprovals(ctx context.Context) (*Permission
return &result, nil
}
-// SetAllowAll enables or disables full allow-all permissions (tools, paths, and URLs) for
-// the session. Used by attach-mode clients (e.g. LocalRpcSession's `/allow-all` forwarder)
-// to flip the target session's permission state. Unlike `setApproveAll`, this swaps in the
-// unrestricted path and URL managers and emits `session.permissions_changed` on transition.
-// The result returns the authoritative post-mutation state so callers can update their
-// local mirrors without racing the `session.permissions_changed` notification on the same
-// wire.
+// SetAllowAll sets the allow-all permission mode for the session. Used by attach-mode
+// clients (e.g. LocalRpcSession's `/allow-all` forwarder) to flip the target session's
+// permission state. The `on` mode swaps in unrestricted path and URL managers and emits
+// `session.permissions_changed` on transition; the `auto` mode keeps normal prompt paths
+// active while attaching LLM safety recommendations. The result returns the authoritative
+// post-mutation state so callers can update their local mirrors without racing the
+// `session.permissions_changed` notification on the same wire.
//
// RPC method: session.permissions.setAllowAll.
//
-// Parameters: Whether to enable full allow-all permissions for the session.
+// Parameters: Allow-all mode to apply for the session.
//
// Returns: Indicates whether the operation succeeded and reports the post-mutation state.
func (a *PermissionsAPI) SetAllowAll(ctx context.Context, params *PermissionsSetAllowAllRequest) (*AllowAllPermissionSetResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
- req["enabled"] = params.Enabled
+ if params.Enabled != nil {
+ req["enabled"] = *params.Enabled
+ }
+ if params.Mode != nil {
+ req["mode"] = *params.Mode
+ }
+ if params.Model != nil {
+ req["model"] = *params.Model
+ }
if params.Source != nil {
req["source"] = *params.Source
}
@@ -16339,6 +17085,9 @@ func (a *PluginsAPI) Reload(ctx context.Context, params ...*PluginsReloadRequest
if requestParams.ReloadCustomAgents != nil {
req["reloadCustomAgents"] = *requestParams.ReloadCustomAgents
}
+ if requestParams.ReloadExtensions != nil {
+ req["reloadExtensions"] = *requestParams.ReloadExtensions
+ }
if requestParams.ReloadHooks != nil {
req["reloadHooks"] = *requestParams.ReloadHooks
}
@@ -17749,6 +18498,7 @@ type SessionRPC struct {
Canvas *CanvasAPI
Commands *CommandsAPI
Completions *CompletionsAPI
+ Debug *DebugAPI
EventLog *EventLogAPI
Extensions *ExtensionsAPI
Fleet *FleetAPI
@@ -17962,6 +18712,7 @@ func NewSessionRPC(client *jsonrpc2.Client, sessionID string) *SessionRPC {
r.Canvas = (*CanvasAPI)(&r.common)
r.Commands = (*CommandsAPI)(&r.common)
r.Completions = (*CompletionsAPI)(&r.common)
+ r.Debug = (*DebugAPI)(&r.common)
r.EventLog = (*EventLogAPI)(&r.common)
r.Extensions = (*ExtensionsAPI)(&r.common)
r.Fleet = (*FleetAPI)(&r.common)
@@ -18161,44 +18912,64 @@ func (a *InternalMCPAPI) UnregisterExternalClient(ctx context.Context, params *M
return &result, nil
}
-// Experimental: InternalMCPOauthAPI contains experimental APIs that may change or be
+// Experimental: InternalSettingsAPI contains experimental APIs that may change or be
// removed.
-type InternalMCPOauthAPI internalSessionAPI
+type InternalSettingsAPI internalSessionAPI
-// Responds to a pending MCP OAuth request with an in-process provider. This internal
-// CLI-only API accepts a live OAuthClientProvider instance and cannot be used over the SDK
-// JSON-RPC boundary. Use session.mcp.oauth.handlePendingRequest instead for the public
-// SDK-safe response path.
+// EvaluatePredicate evaluates a named Rust-owned settings predicate without exposing raw
+// feature flags. Internal: the raw feature-flag names and composition are runtime-internal,
+// so this predicate-evaluation helper is kept out of the public SDK surface and is callable
+// in-process only.
//
-// RPC method: session.mcp.oauth.respond.
+// RPC method: session.settings.evaluatePredicate.
//
-// Parameters: MCP OAuth request id and optional provider response.
+// Parameters: Named Rust-owned settings predicate to evaluate for this session.
//
-// Returns: Empty result after recording the MCP OAuth response.
-// Internal: Respond is part of the SDK's internal handshake/plumbing; external callers
-// should not use it.
-func (a *InternalMCPOauthAPI) Respond(ctx context.Context, params *MCPOauthRespondRequest) (*MCPOauthRespondResult, error) {
+// Returns: Result of evaluating a Rust-owned settings predicate.
+// Internal: EvaluatePredicate is part of the SDK's internal handshake/plumbing; external
+// callers should not use it.
+func (a *InternalSettingsAPI) EvaluatePredicate(ctx context.Context, params *SessionSettingsEvaluatePredicateRequest) (*SessionSettingsEvaluatePredicateResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
- if params.Provider != nil {
- req["provider"] = params.Provider
+ req["name"] = params.Name
+ if params.ToolName != nil {
+ req["toolName"] = *params.ToolName
}
- req["requestId"] = params.RequestID
}
- raw, err := a.client.Request(ctx, "session.mcp.oauth.respond", req)
+ raw, err := a.client.Request(ctx, "session.settings.evaluatePredicate", req)
if err != nil {
return nil, err
}
- var result MCPOauthRespondResult
+ var result SessionSettingsEvaluatePredicateResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
return &result, nil
}
-// Experimental: Oauth returns experimental APIs that may change or be removed.
-func (s *InternalMCPAPI) Oauth() *InternalMCPOauthAPI {
- return (*InternalMCPOauthAPI)(s)
+// Snapshot returns a redacted snapshot of session runtime settings, with secrets and raw
+// feature flags excluded. Internal: the runtime settings shape is a runtime-internal
+// surface and is deliberately kept out of the public SDK, because consumers should not
+// depend on the runtime's internal settings layout. It remains callable in-process and is
+// expected to be reworked as the runtime internals are consolidated.
+//
+// RPC method: session.settings.snapshot.
+//
+// Returns: Redacted, serializable view of session runtime settings for SDK boundary
+// consumers. Secrets and raw feature flags are intentionally excluded.
+// Internal: Snapshot is part of the SDK's internal handshake/plumbing; external callers
+// should not use it.
+func (a *InternalSettingsAPI) Snapshot(ctx context.Context) (*SessionSettingsSnapshot, error) {
+ req := map[string]any{"sessionId": a.sessionID}
+ raw, err := a.client.Request(ctx, "session.settings.snapshot", req)
+ if err != nil {
+ return nil, err
+ }
+ var result SessionSettingsSnapshot
+ if err := json.Unmarshal(raw, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
}
// InternalSessionRPC provides internal SDK session-scoped RPC methods (handshake helpers
@@ -18207,13 +18978,15 @@ type InternalSessionRPC struct {
// Reuse a single struct instead of allocating one for each service on the heap.
common internalSessionAPI
- MCP *InternalMCPAPI
+ MCP *InternalMCPAPI
+ Settings *InternalSettingsAPI
}
func NewInternalSessionRPC(client *jsonrpc2.Client, sessionID string) *InternalSessionRPC {
r := &InternalSessionRPC{}
r.common = internalSessionAPI{client: client, sessionID: sessionID}
r.MCP = (*InternalMCPAPI)(&r.common)
+ r.Settings = (*InternalSettingsAPI)(&r.common)
return r
}
@@ -18714,14 +19487,16 @@ func RegisterClientSessionAPIHandlers(client *jsonrpc2.Client, getHandlers func(
// removed.
type GitHubTelemetryHandler interface {
// Event forwards a single GitHub telemetry event to a host connection that opted into
- // telemetry forwarding for the session.
+ // telemetry forwarding during the `server.connect` handshake. Opted-in connections receive
+ // every event the runtime emits after the handshake — across all sessions, plus sessionless
+ // events (for example, `server.sendTelemetry` calls with no session id).
//
// RPC method: gitHubTelemetry.event.
//
// Parameters: Payload for a `gitHubTelemetry.event` notification: a single GitHub telemetry
- // event the runtime forwards to a host connection that opted into telemetry forwarding for
- // the session.
- Event(request *GitHubTelemetryNotification) (*GitHubTelemetryEventResult, error)
+ // event the runtime forwards to a host connection that opted into telemetry forwarding
+ // during the `server.connect` handshake.
+ Event(request *GitHubTelemetryNotification) error
}
// Experimental: LlmInferenceHandler contains experimental APIs that may change or be
@@ -18784,17 +19559,12 @@ func RegisterClientGlobalAPIHandlers(client *jsonrpc2.Client, handlers *ClientGl
return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)}
}
if handlers == nil || handlers.GitHubTelemetry == nil {
- return nil, &jsonrpc2.Error{Code: -32603, Message: "No gitHubTelemetry client-global handler registered"}
+ return nil, nil
}
- result, err := handlers.GitHubTelemetry.Event(&request)
- if err != nil {
+ if err := handlers.GitHubTelemetry.Event(&request); err != nil {
return nil, clientGlobalHandlerError(err)
}
- raw, err := json.Marshal(result)
- if err != nil {
- return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("Failed to marshal response: %v", err)}
- }
- return raw, nil
+ return nil, nil
})
client.SetRequestHandler("llmInference.httpRequestChunk", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) {
var request LlmInferenceHTTPRequestChunkRequest
diff --git a/go/rpc/zrpc_encoding.go b/go/rpc/zrpc_encoding.go
index aeccd9980..89bd609a6 100644
--- a/go/rpc/zrpc_encoding.go
+++ b/go/rpc/zrpc_encoding.go
@@ -669,6 +669,91 @@ func (r *CommandsRespondToQueuedCommandRequest) UnmarshalJSON(data []byte) error
return nil
}
+func unmarshalDebugCollectLogsDestination(data []byte) (DebugCollectLogsDestination, error) {
+ if string(data) == "null" {
+ return nil, nil
+ }
+ type rawUnion struct {
+ Kind DebugCollectLogsDestinationKind `json:"kind"`
+ }
+ var raw rawUnion
+ if err := json.Unmarshal(data, &raw); err != nil {
+ return nil, err
+ }
+
+ switch raw.Kind {
+ case DebugCollectLogsDestinationKindArchive:
+ var d DebugCollectLogsDestinationArchive
+ if err := json.Unmarshal(data, &d); err != nil {
+ return nil, err
+ }
+ return &d, nil
+ case DebugCollectLogsDestinationKindDirectory:
+ var d DebugCollectLogsDestinationDirectory
+ if err := json.Unmarshal(data, &d); err != nil {
+ return nil, err
+ }
+ return &d, nil
+ default:
+ return &RawDebugCollectLogsDestinationData{Discriminator: raw.Kind, Raw: data}, nil
+ }
+}
+
+func (r RawDebugCollectLogsDestinationData) MarshalJSON() ([]byte, error) {
+ if r.Raw != nil {
+ return r.Raw, nil
+ }
+ return json.Marshal(struct {
+ Kind DebugCollectLogsDestinationKind `json:"kind"`
+ }{
+ Kind: r.Discriminator,
+ })
+}
+
+func (r DebugCollectLogsDestinationArchive) MarshalJSON() ([]byte, error) {
+ type alias DebugCollectLogsDestinationArchive
+ return json.Marshal(struct {
+ Kind DebugCollectLogsDestinationKind `json:"kind"`
+ alias
+ }{
+ Kind: r.Kind(),
+ alias: alias(r),
+ })
+}
+
+func (r DebugCollectLogsDestinationDirectory) MarshalJSON() ([]byte, error) {
+ type alias DebugCollectLogsDestinationDirectory
+ return json.Marshal(struct {
+ Kind DebugCollectLogsDestinationKind `json:"kind"`
+ alias
+ }{
+ Kind: r.Kind(),
+ alias: alias(r),
+ })
+}
+
+func (r *DebugCollectLogsRequest) UnmarshalJSON(data []byte) error {
+ type rawDebugCollectLogsRequest struct {
+ AdditionalEntries []DebugCollectLogsEntry `json:"additionalEntries,omitzero"`
+ Destination json.RawMessage `json:"destination"`
+ Include *DebugCollectLogsInclude `json:"include,omitempty"`
+ }
+ var raw rawDebugCollectLogsRequest
+ if err := json.Unmarshal(data, &raw); err != nil {
+ return err
+ }
+ r.AdditionalEntries = raw.AdditionalEntries
+ if raw.Destination != nil {
+ value, err := unmarshalDebugCollectLogsDestination(raw.Destination)
+ if err != nil {
+ return err
+ }
+ r.Destination = value
+ }
+ r.Include = raw.Include
+ return nil
+}
+
func (r EventLogTypes) MarshalJSON() ([]byte, error) {
if r.String != nil {
return json.Marshal(r.String)
@@ -931,6 +1016,7 @@ func (r *ExternalToolTextResultForLlm) UnmarshalJSON(data []byte) error {
ResultType *string `json:"resultType,omitempty"`
SessionLog *string `json:"sessionLog,omitempty"`
TextResultForLlm string `json:"textResultForLlm"`
+ ToolReferences []string `json:"toolReferences,omitzero"`
ToolTelemetry map[string]any `json:"toolTelemetry,omitzero"`
}
var raw rawExternalToolTextResultForLlm
@@ -952,6 +1038,7 @@ func (r *ExternalToolTextResultForLlm) UnmarshalJSON(data []byte) error {
r.ResultType = raw.ResultType
r.SessionLog = raw.SessionLog
r.TextResultForLlm = raw.TextResultForLlm
+ r.ToolReferences = raw.ToolReferences
r.ToolTelemetry = raw.ToolTelemetry
return nil
}
@@ -3242,6 +3329,7 @@ func (r *SessionOpenOptions) UnmarshalJSON(data []byte) error {
DisabledInstructionSources []string `json:"disabledInstructionSources,omitzero"`
DisabledSkills []string `json:"disabledSkills,omitzero"`
EnableCitations *bool `json:"enableCitations,omitempty"`
+ EnableManagedSettings *bool `json:"enableManagedSettings,omitempty"`
EnableOnDemandInstructionDiscovery *bool `json:"enableOnDemandInstructionDiscovery,omitempty"`
EnableScriptSafety *bool `json:"enableScriptSafety,omitempty"`
EnableStreaming *bool `json:"enableStreaming,omitempty"`
@@ -3279,6 +3367,7 @@ func (r *SessionOpenOptions) UnmarshalJSON(data []byte) error {
SkillDirectories []string `json:"skillDirectories,omitzero"`
SkipCustomInstructions *bool `json:"skipCustomInstructions,omitempty"`
TrajectoryFile *string `json:"trajectoryFile,omitempty"`
+ Verbosity *Verbosity `json:"verbosity,omitempty"`
WorkingDirectory *string `json:"workingDirectory,omitempty"`
WorkingDirectoryContext *SessionContext `json:"workingDirectoryContext,omitempty"`
}
@@ -3311,6 +3400,7 @@ func (r *SessionOpenOptions) UnmarshalJSON(data []byte) error {
r.DisabledInstructionSources = raw.DisabledInstructionSources
r.DisabledSkills = raw.DisabledSkills
r.EnableCitations = raw.EnableCitations
+ r.EnableManagedSettings = raw.EnableManagedSettings
r.EnableOnDemandInstructionDiscovery = raw.EnableOnDemandInstructionDiscovery
r.EnableScriptSafety = raw.EnableScriptSafety
r.EnableStreaming = raw.EnableStreaming
@@ -3348,6 +3438,7 @@ func (r *SessionOpenOptions) UnmarshalJSON(data []byte) error {
r.SkillDirectories = raw.SkillDirectories
r.SkipCustomInstructions = raw.SkipCustomInstructions
r.TrajectoryFile = raw.TrajectoryFile
+ r.Verbosity = raw.Verbosity
r.WorkingDirectory = raw.WorkingDirectory
r.WorkingDirectoryContext = raw.WorkingDirectoryContext
return nil
diff --git a/go/rpc/zsession_encoding.go b/go/rpc/zsession_encoding.go
index 85c1bd449..1102e9bda 100644
--- a/go/rpc/zsession_encoding.go
+++ b/go/rpc/zsession_encoding.go
@@ -89,6 +89,12 @@ func (e *SessionEvent) UnmarshalJSON(data []byte) error {
return err
}
e.Data = &d
+ case SessionEventTypeAssistantToolCallDelta:
+ var d AssistantToolCallDeltaData
+ if err := json.Unmarshal(raw.Data, &d); err != nil {
+ return err
+ }
+ e.Data = &d
case SessionEventTypeAssistantTurnEnd:
var d AssistantTurnEndData
if err := json.Unmarshal(raw.Data, &d); err != nil {
diff --git a/go/rpc/zsession_events.go b/go/rpc/zsession_events.go
index 7d2a230a6..758b90b7d 100644
--- a/go/rpc/zsession_events.go
+++ b/go/rpc/zsession_events.go
@@ -62,6 +62,7 @@ const (
SessionEventTypeAssistantReasoning SessionEventType = "assistant.reasoning"
SessionEventTypeAssistantReasoningDelta SessionEventType = "assistant.reasoning_delta"
SessionEventTypeAssistantStreamingDelta SessionEventType = "assistant.streaming_delta"
+ SessionEventTypeAssistantToolCallDelta SessionEventType = "assistant.tool_call_delta"
SessionEventTypeAssistantTurnEnd SessionEventType = "assistant.turn_end"
SessionEventTypeAssistantTurnStart SessionEventType = "assistant.turn_start"
SessionEventTypeAssistantUsage SessionEventType = "assistant.usage"
@@ -315,6 +316,8 @@ func (*SessionBinaryAssetData) Type() SessionEventType { return SessionEventType
type SessionCompactionStartData struct {
// Token count from non-system messages (user, assistant, tool) at compaction start
ConversationTokens *int64 `json:"conversationTokens,omitempty"`
+ // Model identifier used for compaction, when known
+ Model *string `json:"model,omitempty"`
// Token count from system message(s) at compaction start
SystemTokens *int64 `json:"systemTokens,omitempty"`
// Token count from tool definitions at compaction start
@@ -527,6 +530,15 @@ type ElicitationRequestedData struct {
func (*ElicitationRequestedData) sessionEventData() {}
func (*ElicitationRequestedData) Type() SessionEventType { return SessionEventTypeElicitationRequested }
+// Empty payload for `session.background_tasks_changed`, indicating background task state changed.
+type SessionBackgroundTasksChangedData struct {
+}
+
+func (*SessionBackgroundTasksChangedData) sessionEventData() {}
+func (*SessionBackgroundTasksChangedData) Type() SessionEventType {
+ return SessionEventTypeSessionBackgroundTasksChanged
+}
+
// Empty payload; the event signals that the custom agent was deselected, returning to the default agent
type SubagentDeselectedData struct {
}
@@ -742,7 +754,7 @@ type AssistantUsageData struct {
// Copilot service request ID (x-copilot-service-request-id header) for CAPI log correlation
ServiceRequestID *string `json:"serviceRequestId,omitempty"`
// Time to first token in milliseconds. Only available for streaming requests
- TimeToFirstTokenMs *int64 `json:"timeToFirstTokenMs,omitempty"`
+ TimeToFirstTokenMs *float64 `json:"timeToFirstTokenMs,omitempty"`
}
func (*AssistantUsageData) sessionEventData() {}
@@ -811,10 +823,14 @@ type SessionModelChangeData struct {
PreviousReasoningEffort *string `json:"previousReasoningEffort,omitempty"`
// Reasoning summary mode before the model change, if applicable
PreviousReasoningSummary *ReasoningSummary `json:"previousReasoningSummary,omitempty"`
+ // Output verbosity level before the model change, if applicable
+ PreviousVerbosity *Verbosity `json:"previousVerbosity,omitempty"`
// Reasoning effort level after the model change, if applicable
ReasoningEffort *string `json:"reasoningEffort,omitempty"`
// Reasoning summary mode after the model change, if applicable
ReasoningSummary *ReasoningSummary `json:"reasoningSummary,omitempty"`
+ // Output verbosity level after the model change, if applicable
+ Verbosity *Verbosity `json:"verbosity,omitempty"`
}
func (*SessionModelChangeData) sessionEventData() {}
@@ -889,6 +905,166 @@ type SessionIdleData struct {
func (*SessionIdleData) sessionEventData() {}
func (*SessionIdleData) Type() SessionEventType { return SessionEventTypeSessionIdle }
+// Payload of `session.canvas.closed` with the closed canvas instance ID, provider ID, and canvas ID.
+// Experimental: SessionCanvasClosedData is part of an experimental API and may change or be removed.
+type SessionCanvasClosedData struct {
+ // Provider-local canvas identifier
+ CanvasID string `json:"canvasId"`
+ // Owning provider identifier
+ ExtensionID string `json:"extensionId"`
+ // Stable caller-supplied identifier of the canvas instance that was closed
+ InstanceID string `json:"instanceId"`
+}
+
+func (*SessionCanvasClosedData) sessionEventData() {}
+func (*SessionCanvasClosedData) Type() SessionEventType { return SessionEventTypeSessionCanvasClosed }
+
+// Payload of `session.canvas.opened` with canvas instance and provider IDs plus optional title, status, URL, and input.
+// Experimental: SessionCanvasOpenedData is part of an experimental API and may change or be removed.
+type SessionCanvasOpenedData struct {
+ // Provider-local canvas identifier
+ CanvasID string `json:"canvasId"`
+ // Owning provider identifier
+ ExtensionID string `json:"extensionId"`
+ // Owning extension display name, when available
+ ExtensionName *string `json:"extensionName,omitempty"`
+ // Input supplied when the instance was opened
+ Input any `json:"input,omitempty"`
+ // Stable caller-supplied canvas instance identifier
+ InstanceID string `json:"instanceId"`
+ // Provider-supplied status text
+ Status *string `json:"status,omitempty"`
+ // Rendered title
+ Title *string `json:"title,omitempty"`
+ // URL for web-rendered canvases
+ URL *string `json:"url,omitempty"`
+}
+
+func (*SessionCanvasOpenedData) sessionEventData() {}
+func (*SessionCanvasOpenedData) Type() SessionEventType { return SessionEventTypeSessionCanvasOpened }
+
+// Payload of `session.canvas.registry_changed` listing the canvas declarations currently available.
+// Experimental: SessionCanvasRegistryChangedData is part of an experimental API and may change or be removed.
+type SessionCanvasRegistryChangedData struct {
+ // Canvas declarations currently available
+ Canvases []CanvasRegistryChangedCanvas `json:"canvases"`
+}
+
+func (*SessionCanvasRegistryChangedData) sessionEventData() {}
+func (*SessionCanvasRegistryChangedData) Type() SessionEventType {
+ return SessionEventTypeSessionCanvasRegistryChanged
+}
+
+// Payload of `session.custom_agents_updated` with loaded custom agents plus non-fatal warnings and fatal errors.
+type SessionCustomAgentsUpdatedData struct {
+ // Array of loaded custom agent metadata
+ Agents []CustomAgentsUpdatedAgent `json:"agents"`
+ // Fatal errors from agent loading
+ Errors []string `json:"errors"`
+ // Non-fatal warnings from agent loading
+ Warnings []string `json:"warnings"`
+}
+
+func (*SessionCustomAgentsUpdatedData) sessionEventData() {}
+func (*SessionCustomAgentsUpdatedData) Type() SessionEventType {
+ return SessionEventTypeSessionCustomAgentsUpdated
+}
+
+// Payload of `session.extensions.attachments_pushed` with extension-contributed attachments for the next send.
+type SessionExtensionsAttachmentsPushedData struct {
+ // Attachments contributed by an extension; the host should surface these as composer pills and forward them via the next session.send call.
+ Attachments []Attachment `json:"attachments"`
+}
+
+func (*SessionExtensionsAttachmentsPushedData) sessionEventData() {}
+func (*SessionExtensionsAttachmentsPushedData) Type() SessionEventType {
+ return SessionEventTypeSessionExtensionsAttachmentsPushed
+}
+
+// Payload of `session.extensions_loaded` listing discovered extensions and their statuses.
+type SessionExtensionsLoadedData struct {
+ // Array of discovered extensions and their status
+ Extensions []ExtensionsLoadedExtension `json:"extensions"`
+}
+
+func (*SessionExtensionsLoadedData) sessionEventData() {}
+func (*SessionExtensionsLoadedData) Type() SessionEventType {
+ return SessionEventTypeSessionExtensionsLoaded
+}
+
+// Payload of `session.mcp_server_status_changed` for one MCP server's status and optional failure error.
+type SessionMCPServerStatusChangedData struct {
+ // Error message if the server entered a failed state
+ Error *string `json:"error,omitempty"`
+ // Name of the MCP server whose status changed
+ ServerName string `json:"serverName"`
+ // Connection status: connected, failed, needs-auth, pending, disabled, or not_configured
+ Status MCPServerStatus `json:"status"`
+}
+
+func (*SessionMCPServerStatusChangedData) sessionEventData() {}
+func (*SessionMCPServerStatusChangedData) Type() SessionEventType {
+ return SessionEventTypeSessionMCPServerStatusChanged
+}
+
+// Payload of `session.mcp_servers_loaded` listing MCP server status summaries.
+type SessionMCPServersLoadedData struct {
+ // Array of MCP server status summaries
+ Servers []MCPServersLoadedServer `json:"servers"`
+}
+
+func (*SessionMCPServersLoadedData) sessionEventData() {}
+func (*SessionMCPServersLoadedData) Type() SessionEventType {
+ return SessionEventTypeSessionMCPServersLoaded
+}
+
+// Payload of `session.skills_loaded` listing resolved skill metadata.
+type SessionSkillsLoadedData struct {
+ // Array of resolved skill metadata
+ Skills []SkillsLoadedSkill `json:"skills"`
+}
+
+func (*SessionSkillsLoadedData) sessionEventData() {}
+func (*SessionSkillsLoadedData) Type() SessionEventType { return SessionEventTypeSessionSkillsLoaded }
+
+// Payload of `session.tools_updated` identifying the model whose resolved tools were updated.
+type SessionToolsUpdatedData struct {
+ // Identifier of the model the resolved tools apply to.
+ Model string `json:"model"`
+}
+
+func (*SessionToolsUpdatedData) sessionEventData() {}
+func (*SessionToolsUpdatedData) Type() SessionEventType { return SessionEventTypeSessionToolsUpdated }
+
+// Payload of `user.message` with displayed and model-transformed content, attachments, source/delivery metadata, mode, and telemetry IDs.
+type UserMessageData struct {
+ // The agent mode that was active when this message was sent
+ AgentMode *UserMessageAgentMode `json:"agentMode,omitempty"`
+ // Files, selections, or GitHub references attached to the message
+ Attachments []Attachment `json:"attachments,omitzero"`
+ // The user's message text as displayed in the timeline
+ Content string `json:"content"`
+ // How this message was delivered to the agentic loop relative to loop state (idle-start vs. steering/queued while busy). The timing axis; combine with `source` (origin) for the full picture. Used for telemetry attribution.
+ Delivery *UserMessageDelivery `json:"delivery,omitempty"`
+ // CAPI interaction ID for correlating this user message with its turn
+ InteractionID *string `json:"interactionId,omitempty"`
+ // True when this user message was auto-injected by autopilot's continuation loop rather than typed by the user; used to distinguish autopilot-driven turns in telemetry.
+ IsAutopilotContinuation *bool `json:"isAutopilotContinuation,omitempty"`
+ // Path-backed native document attachments that stayed on the tagged_files path flow because native upload could not read them or would exceed the request size limit
+ NativeDocumentPathFallbackPaths []string `json:"nativeDocumentPathFallbackPaths,omitzero"`
+ // Parent agent task ID for background telemetry correlated to this user turn
+ ParentAgentTaskID *string `json:"parentAgentTaskId,omitempty"`
+ // Origin of this message, used for timeline filtering (e.g., "skill-pdf" for skill-injected messages that should be hidden from the user)
+ Source *string `json:"source,omitempty"`
+ // Normalized document MIME types that were sent natively instead of through tagged_files XML
+ SupportedNativeDocumentMIMETypes []string `json:"supportedNativeDocumentMimeTypes,omitzero"`
+ // Transformed version of the message sent to the model, with XML wrapping, timestamps, and other augmentations for prompt caching
+ TransformedContent *string `json:"transformedContent,omitempty"`
+}
+
+func (*UserMessageData) sessionEventData() {}
+func (*UserMessageData) Type() SessionEventType { return SessionEventTypeUserMessage }
+
// Permission request completion notification signaling UI dismissal
type PermissionCompletedData struct {
// Request ID of the resolved permission request; clients should dismiss any UI for this request
@@ -917,10 +1093,16 @@ type PermissionRequestedData struct {
func (*PermissionRequestedData) sessionEventData() {}
func (*PermissionRequestedData) Type() SessionEventType { return SessionEventTypePermissionRequested }
-// Permissions change details carrying the aggregate allow-all boolean transition.
+// Permissions change details carrying the aggregate allow-all transition.
type SessionPermissionsChangedData struct {
+ // Allow-all mode after the change
+ // Experimental: AllowAllPermissionMode is part of an experimental API and may change or be removed.
+ AllowAllPermissionMode *PermissionAllowAllMode `json:"allowAllPermissionMode,omitempty"`
// Aggregate allow-all flag after the change
AllowAllPermissions bool `json:"allowAllPermissions"`
+ // Allow-all mode before the change
+ // Experimental: PreviousAllowAllPermissionMode is part of an experimental API and may change or be removed.
+ PreviousAllowAllPermissionMode *PermissionAllowAllMode `json:"previousAllowAllPermissionMode,omitempty"`
// Aggregate allow-all flag before the change
PreviousAllowAllPermissions bool `json:"previousAllowAllPermissions"`
}
@@ -1081,175 +1263,6 @@ func (*SessionScheduleCreatedData) Type() SessionEventType {
return SessionEventTypeSessionScheduleCreated
}
-// Schema for the `BackgroundTasksChangedData` type.
-type SessionBackgroundTasksChangedData struct {
-}
-
-func (*SessionBackgroundTasksChangedData) sessionEventData() {}
-func (*SessionBackgroundTasksChangedData) Type() SessionEventType {
- return SessionEventTypeSessionBackgroundTasksChanged
-}
-
-// Schema for the `CanvasClosedData` type.
-// Experimental: SessionCanvasClosedData is part of an experimental API and may change or be removed.
-type SessionCanvasClosedData struct {
- // Provider-local canvas identifier
- CanvasID string `json:"canvasId"`
- // Owning provider identifier
- ExtensionID string `json:"extensionId"`
- // Stable caller-supplied identifier of the canvas instance that was closed
- InstanceID string `json:"instanceId"`
-}
-
-func (*SessionCanvasClosedData) sessionEventData() {}
-func (*SessionCanvasClosedData) Type() SessionEventType { return SessionEventTypeSessionCanvasClosed }
-
-// Schema for the `CanvasOpenedData` type.
-// Experimental: SessionCanvasOpenedData is part of an experimental API and may change or be removed.
-type SessionCanvasOpenedData struct {
- // Provider-local canvas identifier
- CanvasID string `json:"canvasId"`
- // Owning provider identifier
- ExtensionID string `json:"extensionId"`
- // Owning extension display name, when available
- ExtensionName *string `json:"extensionName,omitempty"`
- // Input supplied when the instance was opened
- Input any `json:"input,omitempty"`
- // Stable caller-supplied canvas instance identifier
- InstanceID string `json:"instanceId"`
- // Provider-supplied status text
- Status *string `json:"status,omitempty"`
- // Rendered title
- Title *string `json:"title,omitempty"`
- // URL for web-rendered canvases
- URL *string `json:"url,omitempty"`
-}
-
-func (*SessionCanvasOpenedData) sessionEventData() {}
-func (*SessionCanvasOpenedData) Type() SessionEventType { return SessionEventTypeSessionCanvasOpened }
-
-// Schema for the `CanvasRegistryChangedData` type.
-// Experimental: SessionCanvasRegistryChangedData is part of an experimental API and may change or be removed.
-type SessionCanvasRegistryChangedData struct {
- // Canvas declarations currently available
- Canvases []CanvasRegistryChangedCanvas `json:"canvases"`
-}
-
-func (*SessionCanvasRegistryChangedData) sessionEventData() {}
-func (*SessionCanvasRegistryChangedData) Type() SessionEventType {
- return SessionEventTypeSessionCanvasRegistryChanged
-}
-
-// Schema for the `CustomAgentsUpdatedData` type.
-type SessionCustomAgentsUpdatedData struct {
- // Array of loaded custom agent metadata
- Agents []CustomAgentsUpdatedAgent `json:"agents"`
- // Fatal errors from agent loading
- Errors []string `json:"errors"`
- // Non-fatal warnings from agent loading
- Warnings []string `json:"warnings"`
-}
-
-func (*SessionCustomAgentsUpdatedData) sessionEventData() {}
-func (*SessionCustomAgentsUpdatedData) Type() SessionEventType {
- return SessionEventTypeSessionCustomAgentsUpdated
-}
-
-// Schema for the `ExtensionsAttachmentsPushedData` type.
-type SessionExtensionsAttachmentsPushedData struct {
- // Attachments contributed by an extension; the host should surface these as composer pills and forward them via the next session.send call.
- Attachments []Attachment `json:"attachments"`
-}
-
-func (*SessionExtensionsAttachmentsPushedData) sessionEventData() {}
-func (*SessionExtensionsAttachmentsPushedData) Type() SessionEventType {
- return SessionEventTypeSessionExtensionsAttachmentsPushed
-}
-
-// Schema for the `ExtensionsLoadedData` type.
-type SessionExtensionsLoadedData struct {
- // Array of discovered extensions and their status
- Extensions []ExtensionsLoadedExtension `json:"extensions"`
-}
-
-func (*SessionExtensionsLoadedData) sessionEventData() {}
-func (*SessionExtensionsLoadedData) Type() SessionEventType {
- return SessionEventTypeSessionExtensionsLoaded
-}
-
-// Schema for the `McpServerStatusChangedData` type.
-type SessionMCPServerStatusChangedData struct {
- // Error message if the server entered a failed state
- Error *string `json:"error,omitempty"`
- // Name of the MCP server whose status changed
- ServerName string `json:"serverName"`
- // Connection status: connected, failed, needs-auth, pending, disabled, or not_configured
- Status MCPServerStatus `json:"status"`
-}
-
-func (*SessionMCPServerStatusChangedData) sessionEventData() {}
-func (*SessionMCPServerStatusChangedData) Type() SessionEventType {
- return SessionEventTypeSessionMCPServerStatusChanged
-}
-
-// Schema for the `McpServersLoadedData` type.
-type SessionMCPServersLoadedData struct {
- // Array of MCP server status summaries
- Servers []MCPServersLoadedServer `json:"servers"`
-}
-
-func (*SessionMCPServersLoadedData) sessionEventData() {}
-func (*SessionMCPServersLoadedData) Type() SessionEventType {
- return SessionEventTypeSessionMCPServersLoaded
-}
-
-// Schema for the `SkillsLoadedData` type.
-type SessionSkillsLoadedData struct {
- // Array of resolved skill metadata
- Skills []SkillsLoadedSkill `json:"skills"`
-}
-
-func (*SessionSkillsLoadedData) sessionEventData() {}
-func (*SessionSkillsLoadedData) Type() SessionEventType { return SessionEventTypeSessionSkillsLoaded }
-
-// Schema for the `ToolsUpdatedData` type.
-type SessionToolsUpdatedData struct {
- // Identifier of the model the resolved tools apply to.
- Model string `json:"model"`
-}
-
-func (*SessionToolsUpdatedData) sessionEventData() {}
-func (*SessionToolsUpdatedData) Type() SessionEventType { return SessionEventTypeSessionToolsUpdated }
-
-// Schema for the `UserMessageData` type.
-type UserMessageData struct {
- // The agent mode that was active when this message was sent
- AgentMode *UserMessageAgentMode `json:"agentMode,omitempty"`
- // Files, selections, or GitHub references attached to the message
- Attachments []Attachment `json:"attachments,omitzero"`
- // The user's message text as displayed in the timeline
- Content string `json:"content"`
- // How this message was delivered to the agentic loop relative to loop state (idle-start vs. steering/queued while busy). The timing axis; combine with `source` (origin) for the full picture. Used for telemetry attribution.
- Delivery *UserMessageDelivery `json:"delivery,omitempty"`
- // CAPI interaction ID for correlating this user message with its turn
- InteractionID *string `json:"interactionId,omitempty"`
- // True when this user message was auto-injected by autopilot's continuation loop rather than typed by the user; used to distinguish autopilot-driven turns in telemetry.
- IsAutopilotContinuation *bool `json:"isAutopilotContinuation,omitempty"`
- // Path-backed native document attachments that stayed on the tagged_files path flow because native upload could not read them or would exceed the request size limit
- NativeDocumentPathFallbackPaths []string `json:"nativeDocumentPathFallbackPaths,omitzero"`
- // Parent agent task ID for background telemetry correlated to this user turn
- ParentAgentTaskID *string `json:"parentAgentTaskId,omitempty"`
- // Origin of this message, used for timeline filtering (e.g., "skill-pdf" for skill-injected messages that should be hidden from the user)
- Source *string `json:"source,omitempty"`
- // Normalized document MIME types that were sent natively instead of through tagged_files XML
- SupportedNativeDocumentMIMETypes []string `json:"supportedNativeDocumentMimeTypes,omitzero"`
- // Transformed version of the message sent to the model, with XML wrapping, timestamps, and other augmentations for prompt caching
- TransformedContent *string `json:"transformedContent,omitempty"`
-}
-
-func (*UserMessageData) sessionEventData() {}
-func (*UserMessageData) Type() SessionEventType { return SessionEventTypeUserMessage }
-
// Self-paced schedule re-armed for its next run
type SessionScheduleRearmedData struct {
// Id of the self-paced schedule that was re-armed
@@ -1321,6 +1334,8 @@ type SessionStartData struct {
SessionLimits *SessionLimitsConfig `json:"sessionLimits,omitempty"`
// ISO 8601 timestamp when the session was created
StartTime time.Time `json:"startTime"`
+ // Output verbosity level used for model calls, if applicable (e.g. "low", "medium", "high")
+ Verbosity *Verbosity `json:"verbosity,omitempty"`
// Schema version number for the session event format
Version int64 `json:"version"`
}
@@ -1395,6 +1410,8 @@ type SessionResumeData struct {
SessionLimits *SessionLimitsConfig `json:"sessionLimits,omitempty"`
// True when this resume attached to a session that the runtime already had running in-memory (for example, an extension joining a session another client was actively driving). False (or omitted) for cold resumes — the runtime had to reconstitute the session from its persisted event log.
SessionWasActive *bool `json:"sessionWasActive,omitempty"`
+ // Output verbosity level used for model calls, if applicable (e.g. "low", "medium", "high")
+ Verbosity *Verbosity `json:"verbosity,omitempty"`
}
func (*SessionResumeData) sessionEventData() {}
@@ -1476,6 +1493,8 @@ type SkillInvokedData struct {
Content string `json:"content"`
// Description of the skill from its SKILL.md frontmatter
Description *string `json:"description,omitempty"`
+ // Model identifier active when the skill was invoked, when known
+ Model *string `json:"model,omitempty"`
// Name of the invoked skill
Name string `json:"name"`
// File path to the SKILL.md definition
@@ -1559,6 +1578,23 @@ func (*ToolExecutionPartialResultData) Type() SessionEventType {
return SessionEventTypeToolExecutionPartialResult
}
+// Streaming tool-call input delta for incremental tool-call updates
+type AssistantToolCallDeltaData struct {
+ // Raw provider tool input fragment to append for this tool call. Function/tool-use providers stream serialized JSON argument text (so newlines inside JSON string values may appear as escaped `\n` until the accumulated JSON is parsed); custom tool calls stream raw custom input.
+ InputDelta string `json:"inputDelta"`
+ // Tool call ID this delta belongs to, matching the corresponding assistant.message tool request
+ ToolCallID string `json:"toolCallId"`
+ // Name of the tool being invoked, when known from the stream
+ ToolName *string `json:"toolName,omitempty"`
+ // Tool call type, when known from the stream
+ ToolType *AssistantMessageToolRequestType `json:"toolType,omitempty"`
+}
+
+func (*AssistantToolCallDeltaData) sessionEventData() {}
+func (*AssistantToolCallDeltaData) Type() SessionEventType {
+ return SessionEventTypeAssistantToolCallDelta
+}
+
// Sub-agent completion details for successful execution
type SubagentCompletedData struct {
// Human-readable display name of the sub-agent
@@ -1761,6 +1797,8 @@ func (*AbortData) Type() SessionEventType { return SessionEventTypeAbort }
// Turn completion metadata including the turn identifier
type AssistantTurnEndData struct {
+ // Model identifier used for this turn, when known
+ Model *string `json:"model,omitempty"`
// Identifier of the turn that has ended, matching the corresponding assistant.turn_start event
TurnID string `json:"turnId"`
}
@@ -1772,6 +1810,8 @@ func (*AssistantTurnEndData) Type() SessionEventType { return SessionEventTypeAs
type AssistantTurnStartData struct {
// CAPI interaction ID for correlating this turn with upstream telemetry
InteractionID *string `json:"interactionId,omitempty"`
+ // Model identifier used for this turn, when known
+ Model *string `json:"model,omitempty"`
// Identifier for this turn within the agentic loop, typically a stringified turn number
TurnID string `json:"turnId"`
}
@@ -1924,7 +1964,7 @@ type AssistantUsageCopilotUsageTokenDetail struct {
TokenType string `json:"tokenType"`
}
-// Schema for the `AssistantUsageQuotaSnapshot` type.
+// Internal per-quota snapshot for assistant usage, including entitlement, consumed requests, overage, reset date, and remaining quota.
// Internal: AssistantUsageQuotaSnapshot is an internal SDK API and is not part of the public surface.
type AssistantUsageQuotaSnapshot struct {
// Total requests allowed by the entitlement
@@ -1962,7 +2002,7 @@ type AssistantUsageQuotaSnapshot struct {
UsedRequests int64 `json:"usedRequests"`
}
-// Schema for the `CanvasRegistryChangedCanvas` type.
+// A single canvas declaration in `session.canvas.registry_changed`, including provider IDs, display metadata, input schema, and actions.
// Experimental: CanvasRegistryChangedCanvas is part of an experimental API and may change or be removed.
type CanvasRegistryChangedCanvas struct {
// Actions the agent or host may invoke
@@ -1981,7 +2021,7 @@ type CanvasRegistryChangedCanvas struct {
InputSchema any `json:"inputSchema,omitempty"`
}
-// Schema for the `CanvasRegistryChangedCanvasAction` type.
+// A single action within a canvas declaration, with its name, optional description, and optional input schema.
// Experimental: CanvasRegistryChangedCanvasAction is part of an experimental API and may change or be removed.
type CanvasRegistryChangedCanvasAction struct {
// Action description
@@ -2121,7 +2161,7 @@ type CitationSpan struct {
StartIndex int64 `json:"startIndex"`
}
-// Schema for the `CommandsChangedCommand` type.
+// A single slash command available in the session, as listed by the `commands.changed` event.
type CommandsChangedCommand struct {
// Optional human-readable command description.
Description *string `json:"description,omitempty"`
@@ -2170,7 +2210,7 @@ type CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail struct {
TokenType string `json:"tokenType"`
}
-// Schema for the `CustomAgentsUpdatedAgent` type.
+// A single loaded custom agent in `session.custom_agents_updated`, with identity, source, tools, invocability, and model override.
type CustomAgentsUpdatedAgent struct {
// Description of what the agent does
Description string `json:"description"`
@@ -2200,7 +2240,7 @@ type ElicitationRequestedSchema struct {
Type ElicitationRequestedSchemaType `json:"type"`
}
-// Schema for the `ExtensionsLoadedExtension` type.
+// A single extension discovered by `session.extensions_loaded`, including qualified ID, source, and current status.
type ExtensionsLoadedExtension struct {
// Source-qualified extension ID (e.g., 'project:my-ext', 'user:auth-helper', 'plugin:my-plugin:my-ext')
ID string `json:"id"`
@@ -2240,11 +2280,11 @@ type MCPAppToolCallCompleteError struct {
// The tool's `_meta.ui` block at the time of the call, so consumers can decide whether to forward the result to the model without re-listing tools.
type MCPAppToolCallCompleteToolMeta struct {
- // Schema for the `McpAppToolCallCompleteToolMetaUI` type.
+ // MCP App tool `_meta.ui` resource URI and SEP-1865 visibility captured with an `mcp_app.tool_call_complete` result.
UI *MCPAppToolCallCompleteToolMetaUI `json:"ui,omitempty"`
}
-// Schema for the `McpAppToolCallCompleteToolMetaUI` type.
+// MCP App tool `_meta.ui` resource URI and SEP-1865 visibility captured with an `mcp_app.tool_call_complete` result.
type MCPAppToolCallCompleteToolMetaUI struct {
// `ui://` URI declared by the tool's `_meta.ui.resourceUri`
ResourceURI *string `json:"resourceUri,omitempty"`
@@ -2274,7 +2314,7 @@ type MCPOauthWwwAuthenticateParams struct {
Scope *string `json:"scope,omitempty"`
}
-// Schema for the `McpServersLoadedServer` type.
+// A single MCP server status summary in `session.mcp_servers_loaded`, including name, status, source, transport, and plugin metadata.
type MCPServersLoadedServer struct {
// Error message if the server failed to connect
Error *string `json:"error,omitempty"`
@@ -2310,6 +2350,15 @@ type ModelCallFailureRequestFingerprint struct {
ToolResultMessageCount int64 `json:"toolResultMessageCount"`
}
+// Auto-approval judge information attached to a permission request. Present (non-null) only when the session's allow-all mode is "auto"; its absence means auto mode was off and the judge did not evaluate the request. The `recommendation` conveys the judge's disposition for this request.
+// Experimental: PermissionAutoApproval is part of an experimental API and may change or be removed.
+type PermissionAutoApproval struct {
+ // Human-readable reason for the judge's recommendation, when available.
+ Reason *string `json:"reason,omitempty"`
+ // The auto-approval safety judge's outcome for this request.
+ Recommendation AutoApprovalRecommendation `json:"recommendation"`
+}
+
// Derived user-facing permission prompt details for UI consumers
type PermissionPromptRequest interface {
permissionPromptRequest()
@@ -2328,6 +2377,9 @@ func (r RawPermissionPromptRequest) Kind() PermissionPromptRequestKind {
// Shell command permission prompt
type PermissionPromptRequestCommands struct {
+ // Auto-approval judge information for this request; present only when auto mode is enabled.
+ // Experimental: AutoApproval is part of an experimental API and may change or be removed.
+ AutoApproval *PermissionAutoApproval `json:"autoApproval,omitempty"`
// Whether the UI can offer session-wide approval for this command pattern
CanOfferSessionApproval bool `json:"canOfferSessionApproval"`
// Command identifiers covered by this approval prompt
@@ -2351,6 +2403,9 @@ func (PermissionPromptRequestCommands) Kind() PermissionPromptRequestKind {
type PermissionPromptRequestCustomTool struct {
// Arguments to pass to the custom tool
Args any `json:"args,omitempty"`
+ // Auto-approval judge information for this request; present only when auto mode is enabled.
+ // Experimental: AutoApproval is part of an experimental API and may change or be removed.
+ AutoApproval *PermissionAutoApproval `json:"autoApproval,omitempty"`
// Tool call ID that triggered this permission request
ToolCallID *string `json:"toolCallId,omitempty"`
// Description of what the custom tool does
@@ -2366,6 +2421,9 @@ func (PermissionPromptRequestCustomTool) Kind() PermissionPromptRequestKind {
// Extension management permission prompt
type PermissionPromptRequestExtensionManagement struct {
+ // Auto-approval judge information for this request; present only when auto mode is enabled.
+ // Experimental: AutoApproval is part of an experimental API and may change or be removed.
+ AutoApproval *PermissionAutoApproval `json:"autoApproval,omitempty"`
// Name of the extension being managed
ExtensionName *string `json:"extensionName,omitempty"`
// The extension management operation (scaffold, reload)
@@ -2381,6 +2439,9 @@ func (PermissionPromptRequestExtensionManagement) Kind() PermissionPromptRequest
// Extension permission access prompt
type PermissionPromptRequestExtensionPermissionAccess struct {
+ // Auto-approval judge information for this request; present only when auto mode is enabled.
+ // Experimental: AutoApproval is part of an experimental API and may change or be removed.
+ AutoApproval *PermissionAutoApproval `json:"autoApproval,omitempty"`
// Capabilities the extension is requesting
Capabilities []string `json:"capabilities"`
// Name of the extension requesting permission access
@@ -2396,6 +2457,9 @@ func (PermissionPromptRequestExtensionPermissionAccess) Kind() PermissionPromptR
// Hook confirmation permission prompt
type PermissionPromptRequestHook struct {
+ // Auto-approval judge information for this request; present only when auto mode is enabled.
+ // Experimental: AutoApproval is part of an experimental API and may change or be removed.
+ AutoApproval *PermissionAutoApproval `json:"autoApproval,omitempty"`
// Optional message from the hook explaining why confirmation is needed
HookMessage *string `json:"hookMessage,omitempty"`
// Arguments of the tool call being gated
@@ -2415,6 +2479,9 @@ func (PermissionPromptRequestHook) Kind() PermissionPromptRequestKind {
type PermissionPromptRequestMCP struct {
// Arguments to pass to the MCP tool
Args any `json:"args,omitempty"`
+ // Auto-approval judge information for this request; present only when auto mode is enabled.
+ // Experimental: AutoApproval is part of an experimental API and may change or be removed.
+ AutoApproval *PermissionAutoApproval `json:"autoApproval,omitempty"`
// Name of the MCP server providing the tool
ServerName string `json:"serverName"`
// Tool call ID that triggered this permission request
@@ -2434,6 +2501,9 @@ func (PermissionPromptRequestMCP) Kind() PermissionPromptRequestKind {
type PermissionPromptRequestMemory struct {
// Whether this is a store or vote memory operation
Action *PermissionRequestMemoryAction `json:"action,omitempty"`
+ // Auto-approval judge information for this request; present only when auto mode is enabled.
+ // Experimental: AutoApproval is part of an experimental API and may change or be removed.
+ AutoApproval *PermissionAutoApproval `json:"autoApproval,omitempty"`
// Source references for the stored fact (store only)
Citations *string `json:"citations,omitempty"`
// Vote direction (vote only)
@@ -2457,6 +2527,9 @@ func (PermissionPromptRequestMemory) Kind() PermissionPromptRequestKind {
type PermissionPromptRequestPath struct {
// Underlying permission kind that needs path approval
AccessKind PermissionPromptRequestPathAccessKind `json:"accessKind"`
+ // Auto-approval judge information for this request; present only when auto mode is enabled.
+ // Experimental: AutoApproval is part of an experimental API and may change or be removed.
+ AutoApproval *PermissionAutoApproval `json:"autoApproval,omitempty"`
// File paths that require explicit approval
Paths []string `json:"paths"`
// Tool call ID that triggered this permission request
@@ -2470,6 +2543,9 @@ func (PermissionPromptRequestPath) Kind() PermissionPromptRequestKind {
// File read permission prompt
type PermissionPromptRequestRead struct {
+ // Auto-approval judge information for this request; present only when auto mode is enabled.
+ // Experimental: AutoApproval is part of an experimental API and may change or be removed.
+ AutoApproval *PermissionAutoApproval `json:"autoApproval,omitempty"`
// Human-readable description of why the file is being read
Intention string `json:"intention"`
// Path of the file or directory being read
@@ -2485,8 +2561,15 @@ func (PermissionPromptRequestRead) Kind() PermissionPromptRequestKind {
// URL access permission prompt
type PermissionPromptRequestURL struct {
+ // Auto-approval judge information for this request; present only when auto mode is enabled.
+ // Experimental: AutoApproval is part of an experimental API and may change or be removed.
+ AutoApproval *PermissionAutoApproval `json:"autoApproval,omitempty"`
// Human-readable description of why the URL is being accessed
Intention string `json:"intention"`
+ // True when this URL fetch is requesting to bypass the sandbox network policy: either the model set requestSandboxBypass: true, or the tool re-issued the request as an interactive bypass after the network policy denied the approved URL (host opted in via sandbox.allowBypass). This is a request, not a grant: the fetch runs only if the user approves this permission request. Hosts should highlight the elevated risk in the approval UI.
+ RequestSandboxBypass *bool `json:"requestSandboxBypass,omitempty"`
+ // Model-provided justification for the sandbox-bypass request. Only meaningful when requestSandboxBypass is true.
+ RequestSandboxBypassReason *string `json:"requestSandboxBypassReason,omitempty"`
// Tool call ID that triggered this permission request
ToolCallID *string `json:"toolCallId,omitempty"`
// URL to be fetched
@@ -2500,6 +2583,9 @@ func (PermissionPromptRequestURL) Kind() PermissionPromptRequestKind {
// File write permission prompt
type PermissionPromptRequestWrite struct {
+ // Auto-approval judge information for this request; present only when auto mode is enabled.
+ // Experimental: AutoApproval is part of an experimental API and may change or be removed.
+ AutoApproval *PermissionAutoApproval `json:"autoApproval,omitempty"`
// Whether the UI can offer session-wide approval for file write operations
CanOfferSessionApproval bool `json:"canOfferSessionApproval"`
// Unified diff showing the proposed changes
@@ -2697,6 +2783,10 @@ func (PermissionRequestShell) Kind() PermissionRequestKind {
type PermissionRequestURL struct {
// Human-readable description of why the URL is being accessed
Intention string `json:"intention"`
+ // True when this URL fetch is requesting to bypass the sandbox network policy: either the model set requestSandboxBypass: true, or the tool re-issued the request as an interactive bypass after the network policy denied the approved URL (host opted in via sandbox.allowBypass). This is a request, not a grant: the fetch runs only if the user approves this permission request. Hosts should highlight the elevated risk in the approval UI.
+ RequestSandboxBypass *bool `json:"requestSandboxBypass,omitempty"`
+ // Model-provided justification for the sandbox-bypass request. Only meaningful when requestSandboxBypass is true.
+ RequestSandboxBypassReason *string `json:"requestSandboxBypassReason,omitempty"`
// Tool call ID that triggered this permission request
ToolCallID *string `json:"toolCallId,omitempty"`
// URL to be fetched
@@ -2720,6 +2810,10 @@ type PermissionRequestWrite struct {
Intention string `json:"intention"`
// Complete new file contents for newly created files
NewFileContents *string `json:"newFileContents,omitempty"`
+ // True when a built-in file tool (apply_patch / str_replace_editor) asked to write a path the sandbox filesystem policy would block, and the host opted in via sandbox.allowBypass. This is a request, not a grant: the write happens unsandboxed only if the user approves this permission request. Hosts should highlight the elevated risk in the approval UI.
+ RequestSandboxBypass *bool `json:"requestSandboxBypass,omitempty"`
+ // Justification for the sandbox-bypass request. Only meaningful when requestSandboxBypass is true.
+ RequestSandboxBypassReason *string `json:"requestSandboxBypassReason,omitempty"`
// Tool call ID that triggered this permission request
ToolCallID *string `json:"toolCallId,omitempty"`
}
@@ -2729,7 +2823,7 @@ func (PermissionRequestWrite) Kind() PermissionRequestKind {
return PermissionRequestKindWrite
}
-// Schema for the `PermissionRequestShellCommand` type.
+// A parsed command identifier in a shell permission request, including whether it is read-only.
type PermissionRequestShellCommand struct {
// Command identifier (e.g., executable name)
Identifier string `json:"identifier"`
@@ -2737,7 +2831,7 @@ type PermissionRequestShellCommand struct {
ReadOnly bool `json:"readOnly"`
}
-// Schema for the `PermissionRequestShellPossibleUrl` type.
+// A URL that may be accessed by a command in a shell permission request.
type PermissionRequestShellPossibleURL struct {
// URL that may be accessed by the command
URL string `json:"url"`
@@ -2759,7 +2853,7 @@ func (r RawPermissionResult) Kind() PermissionResultKind {
return r.Discriminator
}
-// Schema for the `PermissionApproved` type.
+// Permission response variant indicating the request was approved without persisting an approval rule.
type PermissionApproved struct {
}
@@ -2768,7 +2862,7 @@ func (PermissionApproved) Kind() PermissionResultKind {
return PermissionResultKindApproved
}
-// Schema for the `PermissionApprovedForLocation` type.
+// Permission response variant that approves a request and persists the provided approval to a project location key.
type PermissionApprovedForLocation struct {
// The approval to persist for this location
Approval UserToolSessionApproval `json:"approval"`
@@ -2781,7 +2875,7 @@ func (PermissionApprovedForLocation) Kind() PermissionResultKind {
return PermissionResultKindApprovedForLocation
}
-// Schema for the `PermissionApprovedForSession` type.
+// Permission response variant that approves a request and remembers the provided approval for the rest of the session.
type PermissionApprovedForSession struct {
// The approval to add as a session-scoped rule
Approval UserToolSessionApproval `json:"approval"`
@@ -2792,7 +2886,7 @@ func (PermissionApprovedForSession) Kind() PermissionResultKind {
return PermissionResultKindApprovedForSession
}
-// Schema for the `PermissionCancelled` type.
+// Permission response variant indicating the request was cancelled before use, with an optional reason.
type PermissionCancelled struct {
// Optional explanation of why the request was cancelled
Reason *string `json:"reason,omitempty"`
@@ -2803,7 +2897,7 @@ func (PermissionCancelled) Kind() PermissionResultKind {
return PermissionResultKindCancelled
}
-// Schema for the `PermissionDeniedByContentExclusionPolicy` type.
+// Permission response variant denying a path under content exclusion policy, with the path and message.
type PermissionDeniedByContentExclusionPolicy struct {
// Human-readable explanation of why the path was excluded
Message string `json:"message"`
@@ -2816,7 +2910,7 @@ func (PermissionDeniedByContentExclusionPolicy) Kind() PermissionResultKind {
return PermissionResultKindDeniedByContentExclusionPolicy
}
-// Schema for the `PermissionDeniedByPermissionRequestHook` type.
+// Permission response variant denied by a permission-request hook, with optional message and interrupt flag.
type PermissionDeniedByPermissionRequestHook struct {
// Whether to interrupt the current agent turn
Interrupt *bool `json:"interrupt,omitempty"`
@@ -2829,7 +2923,7 @@ func (PermissionDeniedByPermissionRequestHook) Kind() PermissionResultKind {
return PermissionResultKindDeniedByPermissionRequestHook
}
-// Schema for the `PermissionDeniedByRules` type.
+// Permission response variant denied because matching approval rules explicitly blocked the request.
type PermissionDeniedByRules struct {
// Rules that denied the request
Rules []PermissionRule `json:"rules"`
@@ -2840,7 +2934,7 @@ func (PermissionDeniedByRules) Kind() PermissionResultKind {
return PermissionResultKindDeniedByRules
}
-// Schema for the `PermissionDeniedInteractivelyByUser` type.
+// Permission response variant denied in an interactive user prompt, with optional feedback and force-reject flag.
type PermissionDeniedInteractivelyByUser struct {
// Optional feedback from the user explaining the denial
Feedback *string `json:"feedback,omitempty"`
@@ -2853,7 +2947,7 @@ func (PermissionDeniedInteractivelyByUser) Kind() PermissionResultKind {
return PermissionResultKindDeniedInteractivelyByUser
}
-// Schema for the `PermissionDeniedNoApprovalRuleAndCouldNotRequestFromUser` type.
+// Permission response variant denied because no approval rule matched and user confirmation was unavailable.
type PermissionDeniedNoApprovalRuleAndCouldNotRequestFromUser struct {
}
@@ -2966,7 +3060,7 @@ type ShutdownCodeChanges struct {
LinesRemoved int64 `json:"linesRemoved"`
}
-// Schema for the `ShutdownModelMetric` type.
+// Per-model shutdown metrics with request counts, token usage, nano-AI units, and token details.
type ShutdownModelMetric struct {
// Request count and cost metrics
Requests ShutdownModelMetricRequests `json:"requests"`
@@ -2989,7 +3083,7 @@ type ShutdownModelMetricRequests struct {
Count *int64 `json:"count,omitempty"`
}
-// Schema for the `ShutdownModelMetricTokenDetail` type.
+// A token-type entry in a shutdown model metric, storing the accumulated token count.
type ShutdownModelMetricTokenDetail struct {
// Accumulated token count for this token type
TokenCount int64 `json:"tokenCount"`
@@ -3009,13 +3103,13 @@ type ShutdownModelMetricUsage struct {
ReasoningTokens *int64 `json:"reasoningTokens,omitempty"`
}
-// Schema for the `ShutdownTokenDetail` type.
+// A session-wide shutdown token-type entry storing the accumulated token count.
type ShutdownTokenDetail struct {
// Accumulated token count for this token type
TokenCount int64 `json:"tokenCount"`
}
-// Schema for the `SkillsLoadedSkill` type.
+// A single resolved skill in `session.skills_loaded`, including source, invocability, enabled state, path, and argument hint.
type SkillsLoadedSkill struct {
// Optional freeform hint describing the skill's expected arguments, from the `argument-hint` frontmatter field
ArgumentHint *string `json:"argumentHint,omitempty"`
@@ -3057,7 +3151,7 @@ func (r RawSystemNotification) Type() SystemNotificationType {
return r.Discriminator
}
-// Schema for the `SystemNotificationAgentCompleted` type.
+// System notification metadata for a background agent that completed or failed, including agent ID, type, status, description, and prompt.
type SystemNotificationAgentCompleted struct {
// Unique identifier of the background agent
AgentID string `json:"agentId"`
@@ -3076,7 +3170,7 @@ func (SystemNotificationAgentCompleted) Type() SystemNotificationType {
return SystemNotificationTypeAgentCompleted
}
-// Schema for the `SystemNotificationAgentIdle` type.
+// System notification metadata for a background agent that became idle, including agent ID, type, and description.
type SystemNotificationAgentIdle struct {
// Unique identifier of the background agent
AgentID string `json:"agentId"`
@@ -3091,7 +3185,7 @@ func (SystemNotificationAgentIdle) Type() SystemNotificationType {
return SystemNotificationTypeAgentIdle
}
-// Schema for the `SystemNotificationInstructionDiscovered` type.
+// System notification metadata for an instruction file discovered during tool access, including source, trigger file, and tool.
type SystemNotificationInstructionDiscovered struct {
// Human-readable label for the timeline (e.g., 'AGENTS.md from packages/billing/')
Description *string `json:"description,omitempty"`
@@ -3108,7 +3202,7 @@ func (SystemNotificationInstructionDiscovered) Type() SystemNotificationType {
return SystemNotificationTypeInstructionDiscovered
}
-// Schema for the `SystemNotificationNewInboxMessage` type.
+// System notification metadata for a new inbox message, including entry ID, sender details, and summary.
type SystemNotificationNewInboxMessage struct {
// Unique identifier of the inbox entry
EntryID string `json:"entryId"`
@@ -3125,7 +3219,7 @@ func (SystemNotificationNewInboxMessage) Type() SystemNotificationType {
return SystemNotificationTypeNewInboxMessage
}
-// Schema for the `SystemNotificationShellCompleted` type.
+// System notification metadata for a shell session that completed, including shell ID, optional exit code, and description.
type SystemNotificationShellCompleted struct {
// Human-readable description of the command
Description *string `json:"description,omitempty"`
@@ -3140,7 +3234,7 @@ func (SystemNotificationShellCompleted) Type() SystemNotificationType {
return SystemNotificationTypeShellCompleted
}
-// Schema for the `SystemNotificationShellDetachedCompleted` type.
+// System notification metadata for a detached shell session that completed, including shell ID and description.
type SystemNotificationShellDetachedCompleted struct {
// Human-readable description of the command
Description *string `json:"description,omitempty"`
@@ -3332,11 +3426,11 @@ type ToolExecutionCompleteToolDescription struct {
// MCP Apps metadata for UI resource association
type ToolExecutionCompleteToolDescriptionMeta struct {
- // Schema for the `ToolExecutionCompleteToolDescriptionMetaUI` type.
+ // MCP Apps tool `_meta.ui` resource URI and visibility captured on `tool.execution_complete`.
UI *ToolExecutionCompleteToolDescriptionMetaUI `json:"ui,omitempty"`
}
-// Schema for the `ToolExecutionCompleteToolDescriptionMetaUI` type.
+// MCP Apps tool `_meta.ui` resource URI and visibility captured on `tool.execution_complete`.
type ToolExecutionCompleteToolDescriptionMetaUI struct {
// URI of the UI resource
ResourceURI *string `json:"resourceUri,omitempty"`
@@ -3360,21 +3454,21 @@ type ToolExecutionCompleteUIResource struct {
// Resource-level UI metadata (CSP, permissions, visual preferences)
type ToolExecutionCompleteUIResourceMeta struct {
- // Schema for the `ToolExecutionCompleteUIResourceMetaUI` type.
+ // MCP Apps UI resource metadata for a completed tool result, including CSP, permissions, domain, and border preference.
UI *ToolExecutionCompleteUIResourceMetaUI `json:"ui,omitempty"`
}
-// Schema for the `ToolExecutionCompleteUIResourceMetaUI` type.
+// MCP Apps UI resource metadata for a completed tool result, including CSP, permissions, domain, and border preference.
type ToolExecutionCompleteUIResourceMetaUI struct {
- // Schema for the `ToolExecutionCompleteUIResourceMetaUICsp` type.
+ // CSP domain allowlists for an MCP Apps UI resource, including connect, resource, frame, and base URI domains.
Csp *ToolExecutionCompleteUIResourceMetaUICsp `json:"csp,omitempty"`
Domain *string `json:"domain,omitempty"`
- // Schema for the `ToolExecutionCompleteUIResourceMetaUIPermissions` type.
+ // Browser permission metadata for an MCP Apps UI resource, including camera, microphone, geolocation, and clipboard-write.
Permissions *ToolExecutionCompleteUIResourceMetaUIPermissions `json:"permissions,omitempty"`
PrefersBorder *bool `json:"prefersBorder,omitempty"`
}
-// Schema for the `ToolExecutionCompleteUIResourceMetaUICsp` type.
+// CSP domain allowlists for an MCP Apps UI resource, including connect, resource, frame, and base URI domains.
type ToolExecutionCompleteUIResourceMetaUICsp struct {
BaseURIDomains []string `json:"baseUriDomains,omitzero"`
ConnectDomains []string `json:"connectDomains,omitzero"`
@@ -3382,31 +3476,31 @@ type ToolExecutionCompleteUIResourceMetaUICsp struct {
ResourceDomains []string `json:"resourceDomains,omitzero"`
}
-// Schema for the `ToolExecutionCompleteUIResourceMetaUIPermissions` type.
+// Browser permission metadata for an MCP Apps UI resource, including camera, microphone, geolocation, and clipboard-write.
type ToolExecutionCompleteUIResourceMetaUIPermissions struct {
- // Schema for the `ToolExecutionCompleteUIResourceMetaUIPermissionsCamera` type.
+ // Marker object for camera permission on an MCP Apps UI resource.
Camera *ToolExecutionCompleteUIResourceMetaUIPermissionsCamera `json:"camera,omitempty"`
- // Schema for the `ToolExecutionCompleteUIResourceMetaUIPermissionsClipboardWrite` type.
+ // Marker object for clipboard-write permission on an MCP Apps UI resource.
ClipboardWrite *ToolExecutionCompleteUIResourceMetaUIPermissionsClipboardWrite `json:"clipboardWrite,omitempty"`
- // Schema for the `ToolExecutionCompleteUIResourceMetaUIPermissionsGeolocation` type.
+ // Marker object for geolocation permission on an MCP Apps UI resource.
Geolocation *ToolExecutionCompleteUIResourceMetaUIPermissionsGeolocation `json:"geolocation,omitempty"`
- // Schema for the `ToolExecutionCompleteUIResourceMetaUIPermissionsMicrophone` type.
+ // Marker object for microphone permission on an MCP Apps UI resource.
Microphone *ToolExecutionCompleteUIResourceMetaUIPermissionsMicrophone `json:"microphone,omitempty"`
}
-// Schema for the `ToolExecutionCompleteUIResourceMetaUIPermissionsCamera` type.
+// Marker object for camera permission on an MCP Apps UI resource.
type ToolExecutionCompleteUIResourceMetaUIPermissionsCamera struct {
}
-// Schema for the `ToolExecutionCompleteUIResourceMetaUIPermissionsClipboardWrite` type.
+// Marker object for clipboard-write permission on an MCP Apps UI resource.
type ToolExecutionCompleteUIResourceMetaUIPermissionsClipboardWrite struct {
}
-// Schema for the `ToolExecutionCompleteUIResourceMetaUIPermissionsGeolocation` type.
+// Marker object for geolocation permission on an MCP Apps UI resource.
type ToolExecutionCompleteUIResourceMetaUIPermissionsGeolocation struct {
}
-// Schema for the `ToolExecutionCompleteUIResourceMetaUIPermissionsMicrophone` type.
+// Marker object for microphone permission on an MCP Apps UI resource.
type ToolExecutionCompleteUIResourceMetaUIPermissionsMicrophone struct {
}
@@ -3430,11 +3524,11 @@ type ToolExecutionStartToolDescription struct {
// MCP Apps metadata for UI resource association
type ToolExecutionStartToolDescriptionMeta struct {
- // Schema for the `ToolExecutionStartToolDescriptionMetaUI` type.
+ // MCP Apps tool `_meta.ui` resource URI and visibility captured on `tool.execution_start`.
UI *ToolExecutionStartToolDescriptionMetaUI `json:"ui,omitempty"`
}
-// Schema for the `ToolExecutionStartToolDescriptionMetaUI` type.
+// MCP Apps tool `_meta.ui` resource URI and visibility captured on `tool.execution_start`.
type ToolExecutionStartToolDescriptionMetaUI struct {
// URI of the UI resource
ResourceURI *string `json:"resourceUri,omitempty"`
@@ -3486,6 +3580,21 @@ const (
AssistantUsageAPIEndpointWsResponses AssistantUsageAPIEndpoint = "ws:/responses"
)
+// Outcome of the auto-approval safety judge for a permission request. Present only when auto mode is enabled; its absence means the judge did not evaluate the request (auto mode was off).
+// Experimental: AutoApprovalRecommendation is part of an experimental API and may change or be removed.
+type AutoApprovalRecommendation string
+
+const (
+ // The judge evaluated the request and recommends automatically approving it.
+ AutoApprovalRecommendationApprove AutoApprovalRecommendation = "approve"
+ // The judge was consulted but did not return a usable recommendation, so the request requires explicit approval.
+ AutoApprovalRecommendationError AutoApprovalRecommendation = "error"
+ // Auto mode is enabled, but this request category is never auto-approvable (for example, sandbox-bypass requests), so the judge was not consulted.
+ AutoApprovalRecommendationExcluded AutoApprovalRecommendation = "excluded"
+ // The judge evaluated the request and does not recommend auto-approving it; explicit approval is required. Whether that means prompting, denying, or something else is the consumer's decision.
+ AutoApprovalRecommendationRequireApproval AutoApprovalRecommendation = "requireApproval"
+)
+
// The user's auto-mode-switch choice
type AutoModeSwitchResponse string
@@ -3749,6 +3858,19 @@ const (
OmittedBinaryTypeResource OmittedBinaryType = "resource"
)
+// Allow-all mode for the session.
+// Experimental: PermissionAllowAllMode is part of an experimental API and may change or be removed.
+type PermissionAllowAllMode string
+
+const (
+ // Permission requests follow the normal approval flow with an LLM advisory recommendation attached; clients may choose to auto-approve requests the judge evaluated as acceptable.
+ PermissionAllowAllModeAuto PermissionAllowAllMode = "auto"
+ // Permission requests follow the normal approval flow.
+ PermissionAllowAllModeOff PermissionAllowAllMode = "off"
+ // Tool, path, and URL permission requests are automatically approved.
+ PermissionAllowAllModeOn PermissionAllowAllMode = "on"
+)
+
// Kind discriminator for PermissionPromptRequest.
type PermissionPromptRequestKind string
diff --git a/go/types.go b/go/types.go
index 3586a2a91..1e424514e 100644
--- a/go/types.go
+++ b/go/types.go
@@ -122,6 +122,11 @@ type ClientOptions struct {
// this handler instead of issuing the calls itself. Works for both CAPI
// and BYOK sessions.
RequestHandler *CopilotRequestHandler
+ // OnGitHubTelemetry registers a connection-level callback (experimental)
+ // that receives GitHub telemetry events the runtime forwards for sessions
+ // opened by this client. When non-nil, every session created or resumed by
+ // this client opts into telemetry forwarding (enableGitHubTelemetryForwarding).
+ OnGitHubTelemetry func(notification *rpc.GitHubTelemetryNotification)
// Telemetry configures OpenTelemetry integration for the runtime.
// When non-nil, COPILOT_OTEL_ENABLED=true is set and any populated
// fields are mapped to the corresponding environment variables.
@@ -2081,6 +2086,7 @@ type createSessionRequest struct {
WorkingDirectory string `json:"workingDirectory,omitempty"`
Streaming *bool `json:"streaming,omitempty"`
IncludeSubAgentStreamingEvents *bool `json:"includeSubAgentStreamingEvents,omitempty"`
+ EnableGitHubTelemetryForwarding *bool `json:"enableGitHubTelemetryForwarding,omitempty"`
MCPServers map[string]MCPServerConfig `json:"mcpServers,omitempty"`
MCPOAuthTokenStorage string `json:"mcpOAuthTokenStorage,omitempty"`
EnvValueMode string `json:"envValueMode,omitempty"`
@@ -2179,6 +2185,7 @@ type resumeSessionRequest struct {
ContinuePendingWork *bool `json:"continuePendingWork,omitempty"`
Streaming *bool `json:"streaming,omitempty"`
IncludeSubAgentStreamingEvents *bool `json:"includeSubAgentStreamingEvents,omitempty"`
+ EnableGitHubTelemetryForwarding *bool `json:"enableGitHubTelemetryForwarding,omitempty"`
MCPServers map[string]MCPServerConfig `json:"mcpServers,omitempty"`
MCPOAuthTokenStorage string `json:"mcpOAuthTokenStorage,omitempty"`
EnvValueMode string `json:"envValueMode,omitempty"`
diff --git a/go/zsession_events.go b/go/zsession_events.go
index 8d11d4da5..24e726f7a 100644
--- a/go/zsession_events.go
+++ b/go/zsession_events.go
@@ -20,6 +20,7 @@ type (
AssistantReasoningData = rpc.AssistantReasoningData
AssistantReasoningDeltaData = rpc.AssistantReasoningDeltaData
AssistantStreamingDeltaData = rpc.AssistantStreamingDeltaData
+ AssistantToolCallDeltaData = rpc.AssistantToolCallDeltaData
AssistantTurnEndData = rpc.AssistantTurnEndData
AssistantTurnStartData = rpc.AssistantTurnStartData
AssistantUsageAPIEndpoint = rpc.AssistantUsageAPIEndpoint
@@ -50,6 +51,7 @@ type (
AttachmentSelectionDetailsEnd = rpc.AttachmentSelectionDetailsEnd
AttachmentSelectionDetailsStart = rpc.AttachmentSelectionDetailsStart
AttachmentType = rpc.AttachmentType
+ AutoApprovalRecommendation = rpc.AutoApprovalRecommendation
AutoModeSwitchCompletedData = rpc.AutoModeSwitchCompletedData
AutoModeSwitchRequestedData = rpc.AutoModeSwitchRequestedData
AutoModeSwitchResponse = rpc.AutoModeSwitchResponse
@@ -132,9 +134,11 @@ type (
OmittedBinaryResult = rpc.OmittedBinaryResult
OmittedBinaryType = rpc.OmittedBinaryType
PendingMessagesModifiedData = rpc.PendingMessagesModifiedData
+ PermissionAllowAllMode = rpc.PermissionAllowAllMode
PermissionApproved = rpc.PermissionApproved
PermissionApprovedForLocation = rpc.PermissionApprovedForLocation
PermissionApprovedForSession = rpc.PermissionApprovedForSession
+ PermissionAutoApproval = rpc.PermissionAutoApproval
PermissionCancelled = rpc.PermissionCancelled
PermissionCompletedData = rpc.PermissionCompletedData
PermissionDeniedByContentExclusionPolicy = rpc.PermissionDeniedByContentExclusionPolicy
@@ -329,6 +333,7 @@ type (
UserToolSessionApprovalMemory = rpc.UserToolSessionApprovalMemory
UserToolSessionApprovalRead = rpc.UserToolSessionApprovalRead
UserToolSessionApprovalWrite = rpc.UserToolSessionApprovalWrite
+ Verbosity = rpc.Verbosity
WorkingDirectoryContext = rpc.WorkingDirectoryContext
WorkingDirectoryContextHostType = rpc.WorkingDirectoryContextHostType
WorkspaceFileChangedOperation = rpc.WorkspaceFileChangedOperation
@@ -363,6 +368,10 @@ const (
AttachmentTypeGitHubTreeComparison = rpc.AttachmentTypeGitHubTreeComparison
AttachmentTypeGitHubURL = rpc.AttachmentTypeGitHubURL
AttachmentTypeSelection = rpc.AttachmentTypeSelection
+ AutoApprovalRecommendationApprove = rpc.AutoApprovalRecommendationApprove
+ AutoApprovalRecommendationError = rpc.AutoApprovalRecommendationError
+ AutoApprovalRecommendationExcluded = rpc.AutoApprovalRecommendationExcluded
+ AutoApprovalRecommendationRequireApproval = rpc.AutoApprovalRecommendationRequireApproval
AutoModeSwitchResponseNo = rpc.AutoModeSwitchResponseNo
AutoModeSwitchResponseYes = rpc.AutoModeSwitchResponseYes
AutoModeSwitchResponseYesAlways = rpc.AutoModeSwitchResponseYesAlways
@@ -441,6 +450,9 @@ const (
OmittedBinaryOmittedReasonTooLarge = rpc.OmittedBinaryOmittedReasonTooLarge
OmittedBinaryTypeImage = rpc.OmittedBinaryTypeImage
OmittedBinaryTypeResource = rpc.OmittedBinaryTypeResource
+ PermissionAllowAllModeAuto = rpc.PermissionAllowAllModeAuto
+ PermissionAllowAllModeOff = rpc.PermissionAllowAllModeOff
+ PermissionAllowAllModeOn = rpc.PermissionAllowAllModeOn
PermissionPromptRequestKindCommands = rpc.PermissionPromptRequestKindCommands
PermissionPromptRequestKindCustomTool = rpc.PermissionPromptRequestKindCustomTool
PermissionPromptRequestKindExtensionManagement = rpc.PermissionPromptRequestKindExtensionManagement
@@ -497,6 +509,7 @@ const (
SessionEventTypeAssistantReasoning = rpc.SessionEventTypeAssistantReasoning
SessionEventTypeAssistantReasoningDelta = rpc.SessionEventTypeAssistantReasoningDelta
SessionEventTypeAssistantStreamingDelta = rpc.SessionEventTypeAssistantStreamingDelta
+ SessionEventTypeAssistantToolCallDelta = rpc.SessionEventTypeAssistantToolCallDelta
SessionEventTypeAssistantTurnEnd = rpc.SessionEventTypeAssistantTurnEnd
SessionEventTypeAssistantTurnStart = rpc.SessionEventTypeAssistantTurnStart
SessionEventTypeAssistantUsage = rpc.SessionEventTypeAssistantUsage
@@ -647,6 +660,9 @@ const (
UserToolSessionApprovalKindMemory = rpc.UserToolSessionApprovalKindMemory
UserToolSessionApprovalKindRead = rpc.UserToolSessionApprovalKindRead
UserToolSessionApprovalKindWrite = rpc.UserToolSessionApprovalKindWrite
+ VerbosityHigh = rpc.VerbosityHigh
+ VerbosityLow = rpc.VerbosityLow
+ VerbosityMedium = rpc.VerbosityMedium
WorkingDirectoryContextHostTypeADO = rpc.WorkingDirectoryContextHostTypeADO
WorkingDirectoryContextHostTypeGitHub = rpc.WorkingDirectoryContextHostTypeGitHub
WorkspaceFileChangedOperationCreate = rpc.WorkspaceFileChangedOperationCreate
diff --git a/java/README.md b/java/README.md
index 2498df1f5..334db459f 100644
--- a/java/README.md
+++ b/java/README.md
@@ -32,14 +32,14 @@ Replace `${copilot.sdk.version}` with the latest release from Maven Central.