diff --git a/.github/workflows/dotnet-sdk-tests.yml b/.github/workflows/dotnet-sdk-tests.yml index d3b2ef162a..909742cdf8 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,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] + transport: ["default", "inprocess"] runs-on: ${{ matrix.os }} defaults: run: @@ -80,6 +81,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/dotnet/src/Client.cs b/dotnet/src/Client.cs index 72408e5c22..18ed2eeed0 100644 --- a/dotnet/src/Client.cs +++ b/dotnet/src/Client.cs @@ -79,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; @@ -135,13 +136,16 @@ private sealed record LifecycleSubscription(Type EventType, Action + /// 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. /// @@ -251,7 +287,16 @@ 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. + var ffiHost = FfiRuntimeHost.Create(ResolveCliPathForFfi(), GetNapiPrebuildsFolderOrThrow(), _options.Environment, _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; @@ -438,7 +483,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 @@ -478,6 +523,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) @@ -1795,12 +1847,14 @@ 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", @@ -2087,6 +2141,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); @@ -2099,7 +2204,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; @@ -2109,7 +2214,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) { @@ -2175,7 +2285,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; @@ -2378,7 +2488,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; @@ -2386,6 +2497,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 diff --git a/dotnet/src/FfiRuntimeHost.cs b/dotnet/src/FfiRuntimeHost.cs new file mode 100644 index 0000000000..210819de67 --- /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 b7b1f4b9f9..c90fb90e16 100644 --- a/dotnet/src/Generated/Rpc.cs +++ b/dotnet/src/Generated/Rpc.cs @@ -5903,30 +5903,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 @@ -21244,20 +21220,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. @@ -23696,8 +23658,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))] diff --git a/dotnet/src/GitHub.Copilot.SDK.csproj b/dotnet/src/GitHub.Copilot.SDK.csproj index 7a9fa2bdca..f48fb802d7 100644 --- a/dotnet/src/GitHub.Copilot.SDK.csproj +++ b/dotnet/src/GitHub.Copilot.SDK.csproj @@ -16,6 +16,7 @@ copilot.png github;copilot;sdk;jsonrpc;agent true + true true snupkg true diff --git a/dotnet/src/JsonRpc.cs b/dotnet/src/JsonRpc.cs index edd0534ab8..bf1684f17b 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/Types.cs b/dotnet/src/Types.cs index 37cb0ebe67..c49650ca6f 100644 --- a/dotnet/src/Types.cs +++ b/dotnet/src/Types.cs @@ -145,6 +145,19 @@ 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. + /// + public static InProcessRuntimeConnection ForInProcess() + => new(); } /// @@ -170,6 +183,18 @@ 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. +/// +public sealed class InProcessRuntimeConnection : RuntimeConnection +{ + internal InProcessRuntimeConnection() { } +} + /// /// Spawns a runtime child process listening on a TCP socket. Construct via /// . diff --git a/dotnet/src/build/GitHub.Copilot.SDK.targets b/dotnet/src/build/GitHub.Copilot.SDK.targets index 94b6515ea7..5a5e511811 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/E2E/ClientE2ETests.cs b/dotnet/test/E2E/ClientE2ETests.cs index 9972e3b336..5de6ce159a 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/Unit/ClientSessionLifetimeTests.cs b/dotnet/test/Unit/ClientSessionLifetimeTests.cs index a028a6c7ec..08d82764e6 100644 --- a/dotnet/test/Unit/ClientSessionLifetimeTests.cs +++ b/dotnet/test/Unit/ClientSessionLifetimeTests.cs @@ -423,7 +423,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/go/rpc/zrpc.go b/go/rpc/zrpc.go index 24599e5f3d..5343c518c4 100644 --- a/go/rpc/zrpc.go +++ b/go/rpc/zrpc.go @@ -3550,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. @@ -18884,46 +18865,6 @@ func (a *InternalMCPAPI) UnregisterExternalClient(ctx context.Context, params *M return &result, nil } -// Experimental: InternalMCPOauthAPI contains experimental APIs that may change or be -// removed. -type InternalMCPOauthAPI 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. -// -// RPC method: session.mcp.oauth.respond. -// -// Parameters: MCP OAuth request id and optional provider response. -// -// 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) { - req := map[string]any{"sessionId": a.sessionID} - if params != nil { - if params.Provider != nil { - req["provider"] = params.Provider - } - req["requestId"] = params.RequestID - } - raw, err := a.client.Request(ctx, "session.mcp.oauth.respond", req) - if err != nil { - return nil, err - } - var result MCPOauthRespondResult - 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) -} - // Experimental: InternalSettingsAPI contains experimental APIs that may change or be // removed. type InternalSettingsAPI internalSessionAPI diff --git a/go/rpc/zsession_events.go b/go/rpc/zsession_events.go index 5367f83e82..b16d76a9a7 100644 --- a/go/rpc/zsession_events.go +++ b/go/rpc/zsession_events.go @@ -753,7 +753,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() {} diff --git a/java/pom.xml b/java/pom.xml index bd89a12826..30e9644bba 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -86,7 +86,7 @@ DO NOT EDIT MANUALLY. Updated by the update-copilot-dependency workflow. --> - ^1.0.69-1 + ^1.0.69-2 diff --git a/java/scripts/codegen/package-lock.json b/java/scripts/codegen/package-lock.json index d08b6fc36e..c45524ea71 100644 --- a/java/scripts/codegen/package-lock.json +++ b/java/scripts/codegen/package-lock.json @@ -6,7 +6,7 @@ "": { "name": "copilot-sdk-java-codegen", "dependencies": { - "@github/copilot": "^1.0.69-1", + "@github/copilot": "^1.0.69-2", "json-schema": "^0.4.0", "tsx": "^4.22.4" } @@ -428,9 +428,9 @@ } }, "node_modules/@github/copilot": { - "version": "1.0.69-1", - "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.69-1.tgz", - "integrity": "sha512-3kWG41prhG/+bMdgW6QvPZXSji2oVGSxQICrUStnW954vvwg0Snabz5g2P3/1EM7BJqoecYSSNIo+vzznxpuTQ==", + "version": "1.0.69-2", + "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.69-2.tgz", + "integrity": "sha512-D/fvtb8RZVL0jbDjU5k7M2J08mr2eB0n7+NwUAJw/9+s1lmZBN6F3OqKh83Uo03d8oLW32ITJhqoxvs85pyiLw==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "detect-libc": "^2.1.2" @@ -439,20 +439,20 @@ "copilot": "npm-loader.js" }, "optionalDependencies": { - "@github/copilot-darwin-arm64": "1.0.69-1", - "@github/copilot-darwin-x64": "1.0.69-1", - "@github/copilot-linux-arm64": "1.0.69-1", - "@github/copilot-linux-x64": "1.0.69-1", - "@github/copilot-linuxmusl-arm64": "1.0.69-1", - "@github/copilot-linuxmusl-x64": "1.0.69-1", - "@github/copilot-win32-arm64": "1.0.69-1", - "@github/copilot-win32-x64": "1.0.69-1" + "@github/copilot-darwin-arm64": "1.0.69-2", + "@github/copilot-darwin-x64": "1.0.69-2", + "@github/copilot-linux-arm64": "1.0.69-2", + "@github/copilot-linux-x64": "1.0.69-2", + "@github/copilot-linuxmusl-arm64": "1.0.69-2", + "@github/copilot-linuxmusl-x64": "1.0.69-2", + "@github/copilot-win32-arm64": "1.0.69-2", + "@github/copilot-win32-x64": "1.0.69-2" } }, "node_modules/@github/copilot-darwin-arm64": { - "version": "1.0.69-1", - "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.69-1.tgz", - "integrity": "sha512-rCgRgY+5AUK4SEcVxNIHTV4Apl8NwtWwlDMiVIV8UtE+re2oq7ojq3CGSo4wzagHWUQSjEAEpwVBL6+NFnSVYw==", + "version": "1.0.69-2", + "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.69-2.tgz", + "integrity": "sha512-643mEEP/0FfZQvxNmg9UquVJv01gJ2QTdi2qabT/cPX2jLpgrPRjRvikX/XewAzGSUSzy4pyx5qyDYIr7TjUcw==", "cpu": [ "arm64" ], @@ -466,9 +466,9 @@ } }, "node_modules/@github/copilot-darwin-x64": { - "version": "1.0.69-1", - "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.69-1.tgz", - "integrity": "sha512-GnrRZziYWQrHJYpvbeZQoBWawbfOdVr43KgTqGru1ybVXh9BCtoYG/wcnIyla5ezlgNOtDphDg64cQHNhypgDQ==", + "version": "1.0.69-2", + "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.69-2.tgz", + "integrity": "sha512-Lx4+8lLJdI8bhA/pLWcRMuae3nxM7SivhWpS5lWsQyPrsdF5g1vYPtmo7ip3hc65jOxpzVWImc9FgQ8d5fKvOA==", "cpu": [ "x64" ], @@ -482,12 +482,15 @@ } }, "node_modules/@github/copilot-linux-arm64": { - "version": "1.0.69-1", - "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.69-1.tgz", - "integrity": "sha512-2Hls3xLhN4Gk1nEHzwEZ+0XySVAZeQa5Gz2KRXUbs+JJ0e0TikT7kKsGtK+1fhEgAFdZ721XvtvxB+LA32y/rQ==", + "version": "1.0.69-2", + "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.69-2.tgz", + "integrity": "sha512-IheFTABphOz4QIqTfN0sLwF57yZtOm0IWJbgUtQe9WkiduD9L8Ii1EtJKbpVPygIgwX4LbcYTCyCMglZjLPliw==", "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "SEE LICENSE IN LICENSE.md", "optional": true, "os": [ @@ -498,12 +501,15 @@ } }, "node_modules/@github/copilot-linux-x64": { - "version": "1.0.69-1", - "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.69-1.tgz", - "integrity": "sha512-MqBrjkhoynBYbrEqZjStKNXXIMEu+kSF2aUtGbotyz24vauAeg4lOf4E6uM41B53l1qoMoj34dQ+gPT+Tlvf6A==", + "version": "1.0.69-2", + "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.69-2.tgz", + "integrity": "sha512-FHMSL5sUqH55U2kyaRaUGNGguyr5SI2ce5FriyPnVQWvYUSuRbdfEo9mC8jeONecD0sO0FQuWwbMk2/JkQOHTA==", "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "SEE LICENSE IN LICENSE.md", "optional": true, "os": [ @@ -514,12 +520,15 @@ } }, "node_modules/@github/copilot-linuxmusl-arm64": { - "version": "1.0.69-1", - "resolved": "https://registry.npmjs.org/@github/copilot-linuxmusl-arm64/-/copilot-linuxmusl-arm64-1.0.69-1.tgz", - "integrity": "sha512-KfG+4vW53Aou5s6dYfAlrVIikIGvv8i3UQA+wGRJX0PvhB2Z2xje3+fcGhAGywghhCL/UjZT8rwaeyJWGvdrBg==", + "version": "1.0.69-2", + "resolved": "https://registry.npmjs.org/@github/copilot-linuxmusl-arm64/-/copilot-linuxmusl-arm64-1.0.69-2.tgz", + "integrity": "sha512-c8yvsxEUNjwaQOU8zO0VFg7LWqTDDvx2SV3rzNz4FSCxTZf0SmcZw6TczsTauKO/0hAq5lfLH4d1pJkTLQ62Zw==", "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "SEE LICENSE IN LICENSE.md", "optional": true, "os": [ @@ -530,12 +539,15 @@ } }, "node_modules/@github/copilot-linuxmusl-x64": { - "version": "1.0.69-1", - "resolved": "https://registry.npmjs.org/@github/copilot-linuxmusl-x64/-/copilot-linuxmusl-x64-1.0.69-1.tgz", - "integrity": "sha512-EgW/avqTW1vZp/7LfWotbUce9kkcpKELxn+PiVLGOcEFP/5/3nGt0mkXYpRJQJLwNcHTFFYLBfgLZSMJ3g1hTg==", + "version": "1.0.69-2", + "resolved": "https://registry.npmjs.org/@github/copilot-linuxmusl-x64/-/copilot-linuxmusl-x64-1.0.69-2.tgz", + "integrity": "sha512-9OQVqN3muGyBePmDY7jGsfhGfCAqvauSZqoWZfX+n28YtZrXTXR7IfGSuzBwZq/isOhopaIplmOc19ZYIMeCEw==", "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "SEE LICENSE IN LICENSE.md", "optional": true, "os": [ @@ -546,9 +558,9 @@ } }, "node_modules/@github/copilot-win32-arm64": { - "version": "1.0.69-1", - "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.69-1.tgz", - "integrity": "sha512-ySorVqbMWdSK21WvEUgSit4jTQcC+MnQeFF0ACWvtKj2q73dzXR6yh8AGJTXG2AzvEgVC2yY0TNAB28nk4zA+Q==", + "version": "1.0.69-2", + "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.69-2.tgz", + "integrity": "sha512-eEKJid8T+tI70dn+2UL4s2b2AQcoHaAmaJ6x/7qTksdVuaII27vuVO/yE4wpWkhYl+yvI3Ml/nkavgrms7Y/Pw==", "cpu": [ "arm64" ], @@ -562,9 +574,9 @@ } }, "node_modules/@github/copilot-win32-x64": { - "version": "1.0.69-1", - "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.69-1.tgz", - "integrity": "sha512-S7Oj7o27olpS70s7BaipcDsMif2/YoHj7KyQI/2aoXJG2xZb25wds65f/gTtsgOQOnnpCefywt/bHpX8Bw8wDQ==", + "version": "1.0.69-2", + "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.69-2.tgz", + "integrity": "sha512-usFpfQudpOEft/OYQaJ+c0MJOgP9bXZ1vctx5mRgC6d8+0dIRbLCZ5rVuir1K7zyS246uYHZgO/t0sMQH7pOdQ==", "cpu": [ "x64" ], diff --git a/java/scripts/codegen/package.json b/java/scripts/codegen/package.json index 5f3cebfadc..b49ecba30c 100644 --- a/java/scripts/codegen/package.json +++ b/java/scripts/codegen/package.json @@ -7,7 +7,7 @@ "generate:java": "tsx java.ts" }, "dependencies": { - "@github/copilot": "^1.0.69-1", + "@github/copilot": "^1.0.69-2", "json-schema": "^0.4.0", "tsx": "^4.22.4" } diff --git a/java/src/generated/java/com/github/copilot/generated/AssistantUsageEvent.java b/java/src/generated/java/com/github/copilot/generated/AssistantUsageEvent.java index 72953adc49..62cf9cfe85 100644 --- a/java/src/generated/java/com/github/copilot/generated/AssistantUsageEvent.java +++ b/java/src/generated/java/com/github/copilot/generated/AssistantUsageEvent.java @@ -52,7 +52,7 @@ public record AssistantUsageEventData( /** Duration of the API call in milliseconds */ @JsonProperty("duration") Long duration, /** Time to first token in milliseconds. Only available for streaming requests */ - @JsonProperty("timeToFirstTokenMs") Long timeToFirstTokenMs, + @JsonProperty("timeToFirstTokenMs") Double timeToFirstTokenMs, /** Average inter-token latency in milliseconds. Only available for streaming requests */ @JsonProperty("interTokenLatencyMs") Double interTokenLatencyMs, /** What initiated this API call (e.g., "sub-agent", "mcp-sampling"); absent for user-initiated calls */ diff --git a/java/src/generated/java/com/github/copilot/generated/rpc/SessionMcpOauthApi.java b/java/src/generated/java/com/github/copilot/generated/rpc/SessionMcpOauthApi.java index 7b5e93c416..7b7f7b82bd 100644 --- a/java/src/generated/java/com/github/copilot/generated/rpc/SessionMcpOauthApi.java +++ b/java/src/generated/java/com/github/copilot/generated/rpc/SessionMcpOauthApi.java @@ -30,22 +30,6 @@ public final class SessionMcpOauthApi { this.sessionId = sessionId; } - /** - * MCP OAuth request id and optional provider response. - *

- * Note: the {@code sessionId} field in the params record is overridden - * by the session-scoped wrapper; any value provided is ignored. - * - * @apiNote This method is experimental and may change in a future version. - * @since 1.0.0 - */ - @CopilotExperimental - public CompletableFuture respond(SessionMcpOauthRespondParams params) { - com.fasterxml.jackson.databind.node.ObjectNode _p = MAPPER.valueToTree(params); - _p.put("sessionId", this.sessionId); - return caller.invoke("session.mcp.oauth.respond", _p, Void.class); - } - /** * Pending MCP OAuth request ID and host-provided token or cancellation response. *

diff --git a/java/src/generated/java/com/github/copilot/generated/rpc/SessionMcpOauthRespondParams.java b/java/src/generated/java/com/github/copilot/generated/rpc/SessionMcpOauthRespondParams.java deleted file mode 100644 index 9757a95388..0000000000 --- a/java/src/generated/java/com/github/copilot/generated/rpc/SessionMcpOauthRespondParams.java +++ /dev/null @@ -1,34 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - *--------------------------------------------------------------------------------------------*/ - -// AUTO-GENERATED FILE - DO NOT EDIT -// Generated from: api.schema.json - -package com.github.copilot.generated.rpc; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.github.copilot.CopilotExperimental; -import javax.annotation.processing.Generated; - -/** - * MCP OAuth request id and optional provider response. - * - * @apiNote This method is experimental and may change in a future version. - * @since 1.0.0 - */ -@CopilotExperimental -@javax.annotation.processing.Generated("copilot-sdk-codegen") -@JsonInclude(JsonInclude.Include.NON_NULL) -@JsonIgnoreProperties(ignoreUnknown = true) -public record SessionMcpOauthRespondParams( - /** Target session identifier */ - @JsonProperty("sessionId") String sessionId, - /** OAuth request identifier from mcp.oauth_required */ - @JsonProperty("requestId") String requestId, - /** In-process OAuthClientProvider instance, or omitted to deny. Marked internal: cannot be serialized across the JSON-RPC boundary. */ - @JsonProperty("provider") Object provider -) { -} diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index b68b1267e1..98dc9f293d 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.0-dev", "license": "MIT", "dependencies": { - "@github/copilot": "^1.0.69-1", + "@github/copilot": "^1.0.69-2", "vscode-jsonrpc": "^8.2.1", "zod": "^4.3.6" }, @@ -699,9 +699,9 @@ } }, "node_modules/@github/copilot": { - "version": "1.0.69-1", - "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.69-1.tgz", - "integrity": "sha512-3kWG41prhG/+bMdgW6QvPZXSji2oVGSxQICrUStnW954vvwg0Snabz5g2P3/1EM7BJqoecYSSNIo+vzznxpuTQ==", + "version": "1.0.69-2", + "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.69-2.tgz", + "integrity": "sha512-D/fvtb8RZVL0jbDjU5k7M2J08mr2eB0n7+NwUAJw/9+s1lmZBN6F3OqKh83Uo03d8oLW32ITJhqoxvs85pyiLw==", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "detect-libc": "^2.1.2" @@ -710,20 +710,20 @@ "copilot": "npm-loader.js" }, "optionalDependencies": { - "@github/copilot-darwin-arm64": "1.0.69-1", - "@github/copilot-darwin-x64": "1.0.69-1", - "@github/copilot-linux-arm64": "1.0.69-1", - "@github/copilot-linux-x64": "1.0.69-1", - "@github/copilot-linuxmusl-arm64": "1.0.69-1", - "@github/copilot-linuxmusl-x64": "1.0.69-1", - "@github/copilot-win32-arm64": "1.0.69-1", - "@github/copilot-win32-x64": "1.0.69-1" + "@github/copilot-darwin-arm64": "1.0.69-2", + "@github/copilot-darwin-x64": "1.0.69-2", + "@github/copilot-linux-arm64": "1.0.69-2", + "@github/copilot-linux-x64": "1.0.69-2", + "@github/copilot-linuxmusl-arm64": "1.0.69-2", + "@github/copilot-linuxmusl-x64": "1.0.69-2", + "@github/copilot-win32-arm64": "1.0.69-2", + "@github/copilot-win32-x64": "1.0.69-2" } }, "node_modules/@github/copilot-darwin-arm64": { - "version": "1.0.69-1", - "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.69-1.tgz", - "integrity": "sha512-rCgRgY+5AUK4SEcVxNIHTV4Apl8NwtWwlDMiVIV8UtE+re2oq7ojq3CGSo4wzagHWUQSjEAEpwVBL6+NFnSVYw==", + "version": "1.0.69-2", + "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.69-2.tgz", + "integrity": "sha512-643mEEP/0FfZQvxNmg9UquVJv01gJ2QTdi2qabT/cPX2jLpgrPRjRvikX/XewAzGSUSzy4pyx5qyDYIr7TjUcw==", "cpu": [ "arm64" ], @@ -737,9 +737,9 @@ } }, "node_modules/@github/copilot-darwin-x64": { - "version": "1.0.69-1", - "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.69-1.tgz", - "integrity": "sha512-GnrRZziYWQrHJYpvbeZQoBWawbfOdVr43KgTqGru1ybVXh9BCtoYG/wcnIyla5ezlgNOtDphDg64cQHNhypgDQ==", + "version": "1.0.69-2", + "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.69-2.tgz", + "integrity": "sha512-Lx4+8lLJdI8bhA/pLWcRMuae3nxM7SivhWpS5lWsQyPrsdF5g1vYPtmo7ip3hc65jOxpzVWImc9FgQ8d5fKvOA==", "cpu": [ "x64" ], @@ -753,12 +753,15 @@ } }, "node_modules/@github/copilot-linux-arm64": { - "version": "1.0.69-1", - "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.69-1.tgz", - "integrity": "sha512-2Hls3xLhN4Gk1nEHzwEZ+0XySVAZeQa5Gz2KRXUbs+JJ0e0TikT7kKsGtK+1fhEgAFdZ721XvtvxB+LA32y/rQ==", + "version": "1.0.69-2", + "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.69-2.tgz", + "integrity": "sha512-IheFTABphOz4QIqTfN0sLwF57yZtOm0IWJbgUtQe9WkiduD9L8Ii1EtJKbpVPygIgwX4LbcYTCyCMglZjLPliw==", "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "SEE LICENSE IN LICENSE.md", "optional": true, "os": [ @@ -769,12 +772,15 @@ } }, "node_modules/@github/copilot-linux-x64": { - "version": "1.0.69-1", - "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.69-1.tgz", - "integrity": "sha512-MqBrjkhoynBYbrEqZjStKNXXIMEu+kSF2aUtGbotyz24vauAeg4lOf4E6uM41B53l1qoMoj34dQ+gPT+Tlvf6A==", + "version": "1.0.69-2", + "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.69-2.tgz", + "integrity": "sha512-FHMSL5sUqH55U2kyaRaUGNGguyr5SI2ce5FriyPnVQWvYUSuRbdfEo9mC8jeONecD0sO0FQuWwbMk2/JkQOHTA==", "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "SEE LICENSE IN LICENSE.md", "optional": true, "os": [ @@ -785,12 +791,15 @@ } }, "node_modules/@github/copilot-linuxmusl-arm64": { - "version": "1.0.69-1", - "resolved": "https://registry.npmjs.org/@github/copilot-linuxmusl-arm64/-/copilot-linuxmusl-arm64-1.0.69-1.tgz", - "integrity": "sha512-KfG+4vW53Aou5s6dYfAlrVIikIGvv8i3UQA+wGRJX0PvhB2Z2xje3+fcGhAGywghhCL/UjZT8rwaeyJWGvdrBg==", + "version": "1.0.69-2", + "resolved": "https://registry.npmjs.org/@github/copilot-linuxmusl-arm64/-/copilot-linuxmusl-arm64-1.0.69-2.tgz", + "integrity": "sha512-c8yvsxEUNjwaQOU8zO0VFg7LWqTDDvx2SV3rzNz4FSCxTZf0SmcZw6TczsTauKO/0hAq5lfLH4d1pJkTLQ62Zw==", "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "SEE LICENSE IN LICENSE.md", "optional": true, "os": [ @@ -801,12 +810,15 @@ } }, "node_modules/@github/copilot-linuxmusl-x64": { - "version": "1.0.69-1", - "resolved": "https://registry.npmjs.org/@github/copilot-linuxmusl-x64/-/copilot-linuxmusl-x64-1.0.69-1.tgz", - "integrity": "sha512-EgW/avqTW1vZp/7LfWotbUce9kkcpKELxn+PiVLGOcEFP/5/3nGt0mkXYpRJQJLwNcHTFFYLBfgLZSMJ3g1hTg==", + "version": "1.0.69-2", + "resolved": "https://registry.npmjs.org/@github/copilot-linuxmusl-x64/-/copilot-linuxmusl-x64-1.0.69-2.tgz", + "integrity": "sha512-9OQVqN3muGyBePmDY7jGsfhGfCAqvauSZqoWZfX+n28YtZrXTXR7IfGSuzBwZq/isOhopaIplmOc19ZYIMeCEw==", "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "SEE LICENSE IN LICENSE.md", "optional": true, "os": [ @@ -817,9 +829,9 @@ } }, "node_modules/@github/copilot-win32-arm64": { - "version": "1.0.69-1", - "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.69-1.tgz", - "integrity": "sha512-ySorVqbMWdSK21WvEUgSit4jTQcC+MnQeFF0ACWvtKj2q73dzXR6yh8AGJTXG2AzvEgVC2yY0TNAB28nk4zA+Q==", + "version": "1.0.69-2", + "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.69-2.tgz", + "integrity": "sha512-eEKJid8T+tI70dn+2UL4s2b2AQcoHaAmaJ6x/7qTksdVuaII27vuVO/yE4wpWkhYl+yvI3Ml/nkavgrms7Y/Pw==", "cpu": [ "arm64" ], @@ -833,9 +845,9 @@ } }, "node_modules/@github/copilot-win32-x64": { - "version": "1.0.69-1", - "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.69-1.tgz", - "integrity": "sha512-S7Oj7o27olpS70s7BaipcDsMif2/YoHj7KyQI/2aoXJG2xZb25wds65f/gTtsgOQOnnpCefywt/bHpX8Bw8wDQ==", + "version": "1.0.69-2", + "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.69-2.tgz", + "integrity": "sha512-usFpfQudpOEft/OYQaJ+c0MJOgP9bXZ1vctx5mRgC6d8+0dIRbLCZ5rVuir1K7zyS246uYHZgO/t0sMQH7pOdQ==", "cpu": [ "x64" ], diff --git a/nodejs/package.json b/nodejs/package.json index 78182894e6..23aface8b4 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -56,7 +56,7 @@ "author": "GitHub", "license": "MIT", "dependencies": { - "@github/copilot": "^1.0.69-1", + "@github/copilot": "^1.0.69-2", "vscode-jsonrpc": "^8.2.1", "zod": "^4.3.6" }, diff --git a/nodejs/src/generated/rpc.ts b/nodejs/src/generated/rpc.ts index 2262364997..2a5c0e70f9 100644 --- a/nodejs/src/generated/rpc.ts +++ b/nodejs/src/generated/rpc.ts @@ -6714,36 +6714,6 @@ export interface McpOauthLoginResult { */ authorizationUrl?: string; } -/** - * MCP OAuth request id and optional provider response. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpOauthRespondRequest". - */ -/** @experimental */ -/** @internal */ -export interface McpOauthRespondRequest { - /** - * OAuth request identifier from mcp.oauth_required - */ - requestId: string; - /** - * In-process OAuthClientProvider instance, or omitted to deny. Marked internal: cannot be serialized across the JSON-RPC boundary. - * - * @internal - */ - provider?: { - [k: string]: unknown | undefined; - }; -} -/** - * Empty result after recording the MCP OAuth response. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "McpOauthRespondResult". - */ -/** @experimental */ -export interface McpOauthRespondResult {} /** * Registration parameters for an external MCP client. * @@ -17560,18 +17530,6 @@ export function createInternalSessionRpc(connection: MessageConnection, sessionI */ unregisterExternalClient: async (params: McpUnregisterExternalClientRequest): Promise => connection.sendRequest("session.mcp.unregisterExternalClient", { sessionId, ...params }), - /** @experimental */ - oauth: { - /** - * 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. - * - * @param params MCP OAuth request id and optional provider response. - * - * @returns Empty result after recording the MCP OAuth response. - */ - respond: async (params: McpOauthRespondRequest): Promise => - connection.sendRequest("session.mcp.oauth.respond", { sessionId, ...params }), - }, }, /** @experimental */ settings: { diff --git a/python/copilot/generated/rpc.py b/python/copilot/generated/rpc.py index 1c12d2ce2e..c3a9897c86 100644 --- a/python/copilot/generated/rpc.py +++ b/python/copilot/generated/rpc.py @@ -3696,19 +3696,6 @@ def to_dict(self) -> dict: result["authorizationUrl"] = from_union([from_str, from_none], self.authorization_url) return result -# Experimental: this type is part of an experimental API and may change or be removed. -@dataclass -class MCPOauthRespondResult: - """Empty result after recording the MCP OAuth response.""" - @staticmethod - def from_dict(obj: Any) -> 'MCPOauthRespondResult': - assert isinstance(obj, dict) - return MCPOauthRespondResult() - - def to_dict(self) -> dict: - result: dict = {} - return result - # Experimental: this type is part of an experimental API and may change or be removed. # Internal: this type is an internal SDK API and is not part of the public surface. @dataclass @@ -22794,34 +22781,6 @@ def to_dict(self) -> dict: result["serverName"] = from_str(self.server_name) return result -# Experimental: this type is part of an experimental API and may change or be removed. -# Internal: this type is an internal SDK API and is not part of the public surface. -@dataclass -class MCPOauthRespondRequest: - """MCP OAuth request id and optional provider response.""" - - request_id: str - """OAuth request identifier from mcp.oauth_required""" - - provider: Any = None - """In-process OAuthClientProvider instance, or omitted to deny. Marked internal: cannot be - serialized across the JSON-RPC boundary. - """ - - @staticmethod - def from_dict(obj: Any) -> 'MCPOauthRespondRequest': - assert isinstance(obj, dict) - request_id = from_str(obj.get("requestId")) - provider = obj.get("provider") - return MCPOauthRespondRequest(request_id, provider) - - def to_dict(self) -> dict: - result: dict = {} - result["requestId"] = from_str(self.request_id) - if self.provider is not None: - result["provider"] = self.provider - return result - # Experimental: this type is part of an experimental API and may change or be removed. # Internal: this type is an internal SDK API and is not part of the public surface. @dataclass @@ -23780,8 +23739,6 @@ class RPC: mcp_oauth_login_request: MCPOauthLoginRequest mcp_oauth_login_result: MCPOauthLoginResult mcp_oauth_pending_request_response: MCPOauthPendingRequestResponse - mcp_oauth_respond_request: MCPOauthRespondRequest - mcp_oauth_respond_result: MCPOauthRespondResult mcp_register_external_client_request: MCPRegisterExternalClientRequest mcp_reload_with_config_request: MCPReloadWithConfigRequest mcp_remove_git_hub_result: MCPRemoveGitHubResult @@ -24612,8 +24569,6 @@ def from_dict(obj: Any) -> 'RPC': mcp_oauth_login_request = MCPOauthLoginRequest.from_dict(obj.get("McpOauthLoginRequest")) mcp_oauth_login_result = MCPOauthLoginResult.from_dict(obj.get("McpOauthLoginResult")) mcp_oauth_pending_request_response = MCPOauthPendingRequestResponse.from_dict(obj.get("McpOauthPendingRequestResponse")) - mcp_oauth_respond_request = MCPOauthRespondRequest.from_dict(obj.get("McpOauthRespondRequest")) - mcp_oauth_respond_result = MCPOauthRespondResult.from_dict(obj.get("McpOauthRespondResult")) mcp_register_external_client_request = MCPRegisterExternalClientRequest.from_dict(obj.get("McpRegisterExternalClientRequest")) mcp_reload_with_config_request = MCPReloadWithConfigRequest.from_dict(obj.get("McpReloadWithConfigRequest")) mcp_remove_git_hub_result = MCPRemoveGitHubResult.from_dict(obj.get("McpRemoveGitHubResult")) @@ -25185,7 +25140,7 @@ def from_dict(obj: Any) -> 'RPC': subagent_settings = from_union([SubagentSettings.from_dict, from_none], obj.get("SubagentSettings")) task_progress = from_union([TaskProgress.from_dict, from_none], obj.get("TaskProgress")) workspace_summary = from_union([WorkspaceSummary.from_dict, from_none], obj.get("WorkspaceSummary")) - return RPC(abort_request, abort_result, account_all_users, account_get_all_users_result, account_get_current_auth_result, account_get_quota_request, account_get_quota_result, account_login_request, account_login_result, account_logout_request, account_logout_result, account_quota_snapshot, adaptive_thinking_support, agent_discovery_path, agent_discovery_path_list, agent_discovery_path_scope, agent_get_current_result, agent_info, agent_info_source, agent_list, agent_registry_live_target_entry, agent_registry_live_target_entry_attention_kind, agent_registry_live_target_entry_kind, agent_registry_live_target_entry_last_terminal_event, agent_registry_live_target_entry_status, agent_registry_log_capture, agent_registry_log_capture_open_error_reason, agent_registry_spawn_error, agent_registry_spawn_permission_mode, agent_registry_spawn_registry_timeout, agent_registry_spawn_request, agent_registry_spawn_result, agent_registry_spawn_spawned, agent_registry_spawn_validation_error, agent_registry_spawn_validation_error_field, agent_registry_spawn_validation_error_reason, agent_reload_result, agents_discover_request, agent_select_request, agent_select_result, agents_get_discovery_paths_request, allow_all_permission_set_result, allow_all_permission_state, api_key_auth_info, auth_info, auth_info_type, cancel_user_requested_shell_command_result, canvas_action, canvas_action_invoke_request, canvas_action_invoke_result, canvas_close_request, canvas_host_context, canvas_host_context_capabilities, canvas_json_schema, canvas_list, canvas_list_open_result, canvas_open_request, canvas_provider_close_request, canvas_provider_invoke_action_request, canvas_provider_open_request, canvas_provider_open_result, canvas_session_context, capi_session_options, command_list, commands_handle_pending_command_request, commands_handle_pending_command_result, commands_invoke_request, commands_list_request, commands_respond_to_queued_command_request, commands_respond_to_queued_command_result, completions_get_trigger_characters_result, completions_request_request, completions_request_result, configure_session_extensions_params, connected_remote_session_metadata, connected_remote_session_metadata_kind, connected_remote_session_metadata_repository, connect_remote_session_params, connect_request, connect_result, content_filter_mode, context_heaviest_message, copilot_api_token_auth_info, copilot_user_response, copilot_user_response_endpoints, copilot_user_response_quota_snapshots, copilot_user_response_quota_snapshots_chat, copilot_user_response_quota_snapshots_completions, copilot_user_response_quota_snapshots_premium_interactions, current_model, current_tool_metadata, debug_collect_logs_collected_entry, debug_collect_logs_destination, debug_collect_logs_entry, debug_collect_logs_entry_kind, debug_collect_logs_include, debug_collect_logs_redaction, debug_collect_logs_request, debug_collect_logs_result, debug_collect_logs_result_kind, debug_collect_logs_skipped_entry, debug_collect_logs_source, discovered_canvas, discovered_mcp_server, discovered_mcp_server_type, enqueue_command_params, enqueue_command_result, env_auth_info, event_log_read_request, event_log_release_interest_result, event_log_tail_result, event_log_types, events_agent_scope, events_cursor_status, events_read_result, execute_command_params, execute_command_result, extension, extension_context_push_input, extension_list, extensions_disable_request, extensions_enable_request, extension_source, extension_status, external_tool_result, external_tool_text_result_for_llm, external_tool_text_result_for_llm_binary_results_for_llm, external_tool_text_result_for_llm_binary_results_for_llm_type, external_tool_text_result_for_llm_content, external_tool_text_result_for_llm_content_audio, external_tool_text_result_for_llm_content_image, external_tool_text_result_for_llm_content_resource, external_tool_text_result_for_llm_content_resource_details, external_tool_text_result_for_llm_content_resource_link, external_tool_text_result_for_llm_content_resource_link_icon, external_tool_text_result_for_llm_content_resource_link_icon_theme, external_tool_text_result_for_llm_content_shell_exit, external_tool_text_result_for_llm_content_terminal, external_tool_text_result_for_llm_content_text, filter_mapping, fleet_start_request, fleet_start_result, folder_trust_add_params, folder_trust_check_params, folder_trust_check_result, gh_cli_auth_info, git_hub_telemetry_client_info, git_hub_telemetry_event, git_hub_telemetry_notification, handle_pending_tool_call_request, handle_pending_tool_call_result, history_abort_manual_compaction_result, history_cancel_background_compaction_result, history_compact_context_window, history_compact_request, history_compact_result, history_summarize_for_handoff_result, history_truncate_request, history_truncate_result, hmac_auth_info, installed_plugin, installed_plugin_info, installed_plugin_source, installed_plugin_source_git_hub, installed_plugin_source_local, installed_plugin_source_url, instruction_discovery_path, instruction_discovery_path_kind, instruction_discovery_path_list, instruction_discovery_path_location, instructions_discover_request, instructions_get_discovery_paths_request, instructions_get_sources_result, instruction_source, instruction_source_location, instruction_source_type, llm_inference_headers, llm_inference_http_request_chunk_request, llm_inference_http_request_chunk_result, llm_inference_http_request_start_request, llm_inference_http_request_start_result, llm_inference_http_request_start_transport, llm_inference_http_response_chunk_error, llm_inference_http_response_chunk_request, llm_inference_http_response_chunk_result, llm_inference_http_response_start_request, llm_inference_http_response_start_result, llm_inference_set_provider_result, local_session_metadata_value, log_request, log_result, lsp_initialize_request, marketplace_add_result, marketplace_browse_result, marketplace_info, marketplace_list_result, marketplace_plugin_info, marketplace_refresh_entry, marketplace_refresh_result, marketplace_remove_result, mcp_allowed_server, mcp_apps_call_tool_request, mcp_apps_diagnose_capability, mcp_apps_diagnose_request, mcp_apps_diagnose_result, mcp_apps_diagnose_server, mcp_apps_host_context, mcp_apps_host_context_details, mcp_apps_host_context_details_available_display_mode, mcp_apps_host_context_details_display_mode, mcp_apps_host_context_details_platform, mcp_apps_host_context_details_theme, mcp_apps_list_tools_request, mcp_apps_list_tools_result, mcp_apps_read_resource_request, mcp_apps_read_resource_result, mcp_apps_resource_content, mcp_apps_set_host_context_details, mcp_apps_set_host_context_details_available_display_mode, mcp_apps_set_host_context_details_display_mode, mcp_apps_set_host_context_details_platform, mcp_apps_set_host_context_details_theme, mcp_apps_set_host_context_request, mcp_cancel_sampling_execution_params, mcp_cancel_sampling_execution_result, mcp_config_add_request, mcp_config_disable_request, mcp_config_enable_request, mcp_config_list, mcp_config_remove_request, mcp_config_update_request, mcp_configure_git_hub_request, mcp_configure_git_hub_result, mcp_disable_request, mcp_discover_request, mcp_discover_result, mcp_enable_request, mcp_execute_sampling_params, mcp_execute_sampling_request, mcp_execute_sampling_result, mcp_filtered_server, mcp_headers_handle_pending_headers_refresh_request, mcp_headers_handle_pending_headers_refresh_request_request, mcp_headers_handle_pending_headers_refresh_request_result, mcp_host_state, mcp_is_server_running_request, mcp_is_server_running_result, mcp_list_tools_request, mcp_list_tools_result, mcp_oauth_handle_pending_request, mcp_oauth_handle_pending_result, mcp_oauth_login_grant_type, mcp_oauth_login_request, mcp_oauth_login_result, mcp_oauth_pending_request_response, mcp_oauth_respond_request, mcp_oauth_respond_result, mcp_register_external_client_request, mcp_reload_with_config_request, mcp_remove_git_hub_result, mcp_restart_server_request, mcp_sampling_execution_action, mcp_sampling_execution_result, mcp_server, mcp_server_auth_config, mcp_server_auth_config_redirect_port, mcp_server_config, mcp_server_config_defer_tools, mcp_server_config_http, mcp_server_config_http_oauth_grant_type, mcp_server_config_http_type, mcp_server_config_stdio, mcp_server_failure_info, mcp_server_list, mcp_server_needs_auth_info, mcp_set_env_value_mode_details, mcp_set_env_value_mode_params, mcp_set_env_value_mode_result, mcp_start_server_request, mcp_start_servers_result, mcp_stop_server_request, mcp_tools, mcp_unregister_external_client_request, memory_configuration, metadata_context_attribution_result, metadata_context_heaviest_messages_request, metadata_context_heaviest_messages_result, metadata_context_info_request, metadata_context_info_result, metadata_is_processing_result, metadata_recompute_context_tokens_request, metadata_recompute_context_tokens_result, metadata_record_context_change_request, metadata_record_context_change_result, metadata_set_working_directory_request, metadata_set_working_directory_result, metadata_snapshot_current_mode, metadata_snapshot_remote_metadata, metadata_snapshot_remote_metadata_repository, metadata_snapshot_remote_metadata_task_type, model, model_billing, model_billing_token_prices, model_billing_token_prices_long_context, model_capabilities, model_capabilities_limits, model_capabilities_limits_vision, model_capabilities_override, model_capabilities_override_limits, model_capabilities_override_limits_vision, model_capabilities_override_supports, model_capabilities_supports, model_list, model_list_request, model_picker_category, model_picker_price_category, model_policy, model_policy_state, model_set_reasoning_effort_request, model_set_reasoning_effort_result, models_list_request, model_switch_to_request, model_switch_to_result, mode_set_request, named_provider_config, name_get_result, name_set_auto_request, name_set_auto_result, name_set_request, open_canvas_instance, options_update_additional_content_exclusion_policy, options_update_additional_content_exclusion_policy_rule, options_update_additional_content_exclusion_policy_rule_source, options_update_additional_content_exclusion_policy_scope, options_update_context_tier, options_update_env_value_mode, options_update_reasoning_summary, options_update_tool_filter_precedence, pending_permission_request, pending_permission_request_list, permission_decision, permission_decision_approved, permission_decision_approved_for_location, permission_decision_approved_for_session, permission_decision_approve_for_location, permission_decision_approve_for_location_approval, permission_decision_approve_for_location_approval_commands, permission_decision_approve_for_location_approval_custom_tool, permission_decision_approve_for_location_approval_extension_management, permission_decision_approve_for_location_approval_extension_permission_access, permission_decision_approve_for_location_approval_mcp, permission_decision_approve_for_location_approval_mcp_sampling, permission_decision_approve_for_location_approval_memory, permission_decision_approve_for_location_approval_read, permission_decision_approve_for_location_approval_write, permission_decision_approve_for_session, permission_decision_approve_for_session_approval, permission_decision_approve_for_session_approval_commands, permission_decision_approve_for_session_approval_custom_tool, permission_decision_approve_for_session_approval_extension_management, permission_decision_approve_for_session_approval_extension_permission_access, permission_decision_approve_for_session_approval_mcp, permission_decision_approve_for_session_approval_mcp_sampling, permission_decision_approve_for_session_approval_memory, permission_decision_approve_for_session_approval_read, permission_decision_approve_for_session_approval_write, permission_decision_approve_once, permission_decision_approve_permanently, permission_decision_cancelled, permission_decision_denied_by_content_exclusion_policy, permission_decision_denied_by_permission_request_hook, permission_decision_denied_by_rules, permission_decision_denied_interactively_by_user, permission_decision_denied_no_approval_rule_and_could_not_request_from_user, permission_decision_reject, permission_decision_request, permission_decision_user_not_available, permission_location_add_tool_approval_params, permission_location_apply_params, permission_location_apply_result, permission_location_resolve_params, permission_location_resolve_result, permission_location_type, permission_paths_add_params, permission_paths_allowed_check_params, permission_paths_allowed_check_result, permission_paths_config, permission_paths_list, permission_paths_update_primary_params, permission_paths_workspace_check_params, permission_paths_workspace_check_result, permission_prompt_shown_notification, permission_request_result, permission_rules_set, permissions_allow_all_mode, permissions_configure_additional_content_exclusion_policy, permissions_configure_additional_content_exclusion_policy_rule, permissions_configure_additional_content_exclusion_policy_rule_source, permissions_configure_additional_content_exclusion_policy_scope, permissions_configure_params, permissions_configure_result, permissions_folder_trust_add_trusted_result, permissions_get_allow_all_request, permissions_locations_add_tool_approval_details, permissions_locations_add_tool_approval_details_commands, permissions_locations_add_tool_approval_details_custom_tool, permissions_locations_add_tool_approval_details_extension_management, permissions_locations_add_tool_approval_details_extension_permission_access, permissions_locations_add_tool_approval_details_mcp, permissions_locations_add_tool_approval_details_mcp_sampling, permissions_locations_add_tool_approval_details_memory, permissions_locations_add_tool_approval_details_read, permissions_locations_add_tool_approval_details_write, permissions_locations_add_tool_approval_result, permissions_modify_rules_params, permissions_modify_rules_result, permissions_modify_rules_scope, permissions_notify_prompt_shown_result, permissions_paths_add_result, permissions_paths_list_request, permissions_paths_update_primary_result, permissions_pending_requests_request, permissions_reset_session_approvals_request, permissions_reset_session_approvals_result, permissions_set_allow_all_request, permissions_set_allow_all_source, permissions_set_approve_all_request, permissions_set_approve_all_result, permissions_set_approve_all_source, permissions_set_required_request, permissions_set_required_result, permissions_urls_set_unrestricted_mode_result, permission_urls_config, permission_urls_set_unrestricted_mode_params, ping_request, ping_result, plan_read_result, plan_read_sql_todos_result, plan_read_sql_todos_with_dependencies_result, plan_sql_todo_dependency, plan_sql_todos_row, plan_update_request, plugin, plugin_install_result, plugin_list, plugin_list_result, plugins_disable_request, plugins_enable_request, plugins_install_request, plugins_marketplaces_add_request, plugins_marketplaces_browse_request, plugins_marketplaces_refresh_request, plugins_marketplaces_remove_request, plugins_reload_request, plugins_uninstall_request, plugins_update_request, plugin_update_all_entry, plugin_update_all_result, plugin_update_result, provider_add_request, provider_add_result, provider_config, provider_config_azure, provider_config_transport, provider_config_type, provider_config_wire_api, provider_endpoint, provider_endpoint_transport, provider_endpoint_type, provider_endpoint_wire_api, provider_get_endpoint_request, provider_model_config, provider_session_token, provider_token_acquire_request, provider_token_acquire_result, push_attachment, push_attachment_blob, push_attachment_directory, push_attachment_file, push_attachment_file_line_range, push_attachment_git_hub_actions_job, push_attachment_git_hub_commit, push_attachment_git_hub_file, push_attachment_git_hub_file_diff, push_attachment_git_hub_file_diff_side, push_attachment_git_hub_reference, push_attachment_git_hub_reference_type, push_attachment_git_hub_release, push_attachment_git_hub_repository, push_attachment_git_hub_snippet, push_attachment_git_hub_tree_comparison, push_attachment_git_hub_tree_comparison_side, push_attachment_git_hub_url, push_attachment_selection, push_attachment_selection_details, push_attachment_selection_details_end, push_attachment_selection_details_start, push_git_hub_repo_ref, queued_command_handled, queued_command_not_handled, queued_command_result, queue_pending_items, queue_pending_items_kind, queue_pending_items_result, queue_remove_most_recent_result, register_event_interest_params, register_event_interest_result, register_extension_tools_params, register_extension_tools_result, release_event_interest_params, remote_control_config, remote_control_config_existing_mc_session, remote_control_status, remote_control_status_active, remote_control_status_connecting, remote_control_status_error, remote_control_status_off, remote_control_status_result, remote_control_stop_result, remote_control_transfer_result, remote_enable_request, remote_enable_result, remote_notify_steerable_changed_request, remote_notify_steerable_changed_result, remote_session_connection_result, remote_session_metadata_repository, remote_session_metadata_task_type, remote_session_metadata_value, remote_session_mode, remote_session_repository, sandbox_config, sandbox_config_user_policy, sandbox_config_user_policy_experimental, sandbox_config_user_policy_experimental_seatbelt, sandbox_config_user_policy_filesystem, sandbox_config_user_policy_network, sandbox_config_user_policy_seatbelt, schedule_entry, schedule_list, schedule_stop_request, schedule_stop_result, secrets_add_filter_values_request, secrets_add_filter_values_result, send_agent_mode, send_attachments_to_message_params, send_mode, send_request, send_result, server_agent_list, server_instruction_source_list, server_skill, server_skill_list, session_activity, session_auth_status, session_bulk_delete_result, session_capability, session_completion_item, session_context, session_context_host_type, session_enrich_metadata_result, session_fs_append_file_request, session_fs_error, session_fs_error_code, session_fs_exists_request, session_fs_exists_result, session_fs_mkdir_request, session_fs_readdir_request, session_fs_readdir_result, session_fs_readdir_with_types_entry, session_fs_readdir_with_types_entry_type, session_fs_readdir_with_types_request, session_fs_readdir_with_types_result, session_fs_read_file_request, session_fs_read_file_result, session_fs_rename_request, session_fs_rm_request, session_fs_set_provider_capabilities, session_fs_set_provider_conventions, session_fs_set_provider_request, session_fs_set_provider_result, session_fs_sqlite_exists_request, session_fs_sqlite_exists_result, session_fs_sqlite_query_request, session_fs_sqlite_query_result, session_fs_sqlite_query_type, session_fs_stat_request, session_fs_stat_result, session_fs_write_file_request, session_installed_plugin, session_installed_plugin_source, session_installed_plugin_source_git_hub, session_installed_plugin_source_local, session_installed_plugin_source_url, session_list, session_list_entry, session_list_filter, session_load_deferred_repo_hooks_result, session_log_level, session_mcp_apps_call_tool_result, session_metadata_snapshot, session_mode, session_model_list, session_open_options, session_open_options_additional_content_exclusion_policy, session_open_options_additional_content_exclusion_policy_rule, session_open_options_additional_content_exclusion_policy_rule_source, session_open_options_additional_content_exclusion_policy_scope, session_open_options_env_value_mode, session_open_options_reasoning_summary, session_open_params, session_open_result, session_prune_result, sessions_bulk_delete_request, sessions_check_in_use_request, sessions_check_in_use_result, sessions_close_request, sessions_close_result, sessions_enrich_metadata_request, session_set_credentials_params, session_set_credentials_result, session_settings_built_in_tool_availability_snapshot, session_settings_evaluate_predicate_request, session_settings_evaluate_predicate_result, session_settings_job_snapshot, session_settings_model_snapshot, session_settings_online_evaluation_snapshot, session_settings_predicate_name, session_settings_repo_snapshot, session_settings_snapshot, session_settings_validation_snapshot, sessions_find_by_prefix_request, sessions_find_by_prefix_result, sessions_find_by_task_id_request, sessions_find_by_task_id_result, sessions_fork_request, sessions_fork_result, sessions_get_board_entry_count_request, sessions_get_board_entry_count_result, sessions_get_event_file_path_request, sessions_get_event_file_path_result, sessions_get_last_for_context_request, sessions_get_last_for_context_result, sessions_get_persisted_remote_steerable_request, sessions_get_persisted_remote_steerable_result, session_sizes, sessions_list_request, sessions_load_deferred_repo_hooks_request, sessions_open_attach, sessions_open_cloud, sessions_open_create, sessions_open_handoff, sessions_open_handoff_task_type, sessions_open_progress, sessions_open_progress_status, sessions_open_progress_step, sessions_open_remote, sessions_open_resume, sessions_open_resume_last, sessions_open_status, session_source, sessions_prune_old_request, sessions_register_extension_tools_on_session_options, sessions_release_lock_request, sessions_release_lock_result, sessions_reload_plugin_hooks_request, sessions_reload_plugin_hooks_result, sessions_save_request, sessions_save_result, sessions_set_additional_plugins_request, sessions_set_additional_plugins_result, sessions_set_remote_control_steering_request, sessions_start_remote_control_request, sessions_stop_remote_control_request, sessions_transfer_remote_control_request, session_telemetry_engagement, session_update_options_params, session_update_options_result, session_visibility_status, session_working_directory_context, session_working_directory_context_host_type, shell_cancel_user_requested_request, shell_exec_request, shell_exec_result, shell_execute_user_requested_request, shell_kill_request, shell_kill_result, shell_kill_signal, shutdown_request, skill, skill_discovery_path, skill_discovery_path_list, skill_discovery_scope, skill_list, skills_config_set_disabled_skills_request, skills_disable_request, skills_discover_request, skills_enable_request, skills_get_discovery_paths_request, skills_get_invoked_result, skills_invoked_skill, skills_load_diagnostics, slash_command_agent_prompt_result, slash_command_completed_result, slash_command_info, slash_command_input, slash_command_input_choice, slash_command_input_completion, slash_command_invocation_result, slash_command_kind, slash_command_select_subcommand_option, slash_command_select_subcommand_result, slash_command_text_result, subagent_settings_entry, subagent_settings_entry_context_tier, task_agent_info, task_agent_progress, task_execution_mode, task_info, task_list, task_progress_line, tasks_cancel_request, tasks_cancel_result, tasks_get_current_promotable_result, tasks_get_progress_request, tasks_get_progress_result, task_shell_info, task_shell_info_attachment_mode, task_shell_progress, tasks_promote_current_to_background_result, tasks_promote_to_background_request, tasks_promote_to_background_result, tasks_refresh_result, tasks_remove_request, tasks_remove_result, tasks_send_message_request, tasks_send_message_result, tasks_start_agent_request, tasks_start_agent_result, task_status, tasks_wait_for_pending_result, telemetry_set_feature_overrides_request, token_auth_info, tool, tool_list, tools_get_current_metadata_result, tools_initialize_and_validate_result, tools_list_request, tools_update_subagent_settings_result, ui_auto_mode_switch_response, ui_elicitation_array_any_of_field, ui_elicitation_array_any_of_field_items, ui_elicitation_array_any_of_field_items_any_of, ui_elicitation_array_enum_field, ui_elicitation_array_enum_field_items, ui_elicitation_field_value, ui_elicitation_request, ui_elicitation_response, ui_elicitation_response_action, ui_elicitation_response_content, ui_elicitation_result, ui_elicitation_schema, ui_elicitation_schema_property, ui_elicitation_schema_property_boolean, ui_elicitation_schema_property_number, ui_elicitation_schema_property_number_type, ui_elicitation_schema_property_string, ui_elicitation_schema_property_string_format, ui_elicitation_string_enum_field, ui_elicitation_string_one_of_field, ui_elicitation_string_one_of_field_one_of, ui_ephemeral_query_request, ui_ephemeral_query_result, ui_exit_plan_mode_action, ui_exit_plan_mode_response, ui_handle_pending_auto_mode_switch_request, ui_handle_pending_elicitation_request, ui_handle_pending_exit_plan_mode_request, ui_handle_pending_result, ui_handle_pending_sampling_request, ui_handle_pending_sampling_response, ui_handle_pending_session_limits_exhausted_request, ui_handle_pending_user_input_request, ui_register_direct_auto_mode_switch_handler_result, ui_session_limits_exhausted_response, ui_session_limits_exhausted_response_action, ui_unregister_direct_auto_mode_switch_handler_request, ui_unregister_direct_auto_mode_switch_handler_result, ui_user_input_response, update_subagent_settings_request, usage_get_metrics_result, usage_metrics_code_changes, usage_metrics_model_metric, usage_metrics_model_metric_requests, usage_metrics_model_metric_token_detail, usage_metrics_model_metric_usage, usage_metrics_token_detail, user_auth_info, user_requested_shell_command_result, user_setting_metadata, user_settings_get_result, user_settings_set_request, user_settings_set_result, visibility_get_result, visibility_set_request, visibility_set_result, workspace_diff_file_change, workspace_diff_file_change_type, workspace_diff_mode, workspace_diff_result, workspaces_checkpoints, workspaces_create_file_request, workspaces_diff_request, workspaces_get_workspace_result, workspaces_list_checkpoints_result, workspaces_list_files_result, workspaces_read_checkpoint_request, workspaces_read_checkpoint_result, workspaces_read_file_request, workspaces_read_file_result, workspaces_save_large_paste_request, workspaces_save_large_paste_result, workspace_summary_host_type, workspaces_workspace_details_host_type, session_context_attribution, session_context_info, subagent_settings, task_progress, workspace_summary) + return RPC(abort_request, abort_result, account_all_users, account_get_all_users_result, account_get_current_auth_result, account_get_quota_request, account_get_quota_result, account_login_request, account_login_result, account_logout_request, account_logout_result, account_quota_snapshot, adaptive_thinking_support, agent_discovery_path, agent_discovery_path_list, agent_discovery_path_scope, agent_get_current_result, agent_info, agent_info_source, agent_list, agent_registry_live_target_entry, agent_registry_live_target_entry_attention_kind, agent_registry_live_target_entry_kind, agent_registry_live_target_entry_last_terminal_event, agent_registry_live_target_entry_status, agent_registry_log_capture, agent_registry_log_capture_open_error_reason, agent_registry_spawn_error, agent_registry_spawn_permission_mode, agent_registry_spawn_registry_timeout, agent_registry_spawn_request, agent_registry_spawn_result, agent_registry_spawn_spawned, agent_registry_spawn_validation_error, agent_registry_spawn_validation_error_field, agent_registry_spawn_validation_error_reason, agent_reload_result, agents_discover_request, agent_select_request, agent_select_result, agents_get_discovery_paths_request, allow_all_permission_set_result, allow_all_permission_state, api_key_auth_info, auth_info, auth_info_type, cancel_user_requested_shell_command_result, canvas_action, canvas_action_invoke_request, canvas_action_invoke_result, canvas_close_request, canvas_host_context, canvas_host_context_capabilities, canvas_json_schema, canvas_list, canvas_list_open_result, canvas_open_request, canvas_provider_close_request, canvas_provider_invoke_action_request, canvas_provider_open_request, canvas_provider_open_result, canvas_session_context, capi_session_options, command_list, commands_handle_pending_command_request, commands_handle_pending_command_result, commands_invoke_request, commands_list_request, commands_respond_to_queued_command_request, commands_respond_to_queued_command_result, completions_get_trigger_characters_result, completions_request_request, completions_request_result, configure_session_extensions_params, connected_remote_session_metadata, connected_remote_session_metadata_kind, connected_remote_session_metadata_repository, connect_remote_session_params, connect_request, connect_result, content_filter_mode, context_heaviest_message, copilot_api_token_auth_info, copilot_user_response, copilot_user_response_endpoints, copilot_user_response_quota_snapshots, copilot_user_response_quota_snapshots_chat, copilot_user_response_quota_snapshots_completions, copilot_user_response_quota_snapshots_premium_interactions, current_model, current_tool_metadata, debug_collect_logs_collected_entry, debug_collect_logs_destination, debug_collect_logs_entry, debug_collect_logs_entry_kind, debug_collect_logs_include, debug_collect_logs_redaction, debug_collect_logs_request, debug_collect_logs_result, debug_collect_logs_result_kind, debug_collect_logs_skipped_entry, debug_collect_logs_source, discovered_canvas, discovered_mcp_server, discovered_mcp_server_type, enqueue_command_params, enqueue_command_result, env_auth_info, event_log_read_request, event_log_release_interest_result, event_log_tail_result, event_log_types, events_agent_scope, events_cursor_status, events_read_result, execute_command_params, execute_command_result, extension, extension_context_push_input, extension_list, extensions_disable_request, extensions_enable_request, extension_source, extension_status, external_tool_result, external_tool_text_result_for_llm, external_tool_text_result_for_llm_binary_results_for_llm, external_tool_text_result_for_llm_binary_results_for_llm_type, external_tool_text_result_for_llm_content, external_tool_text_result_for_llm_content_audio, external_tool_text_result_for_llm_content_image, external_tool_text_result_for_llm_content_resource, external_tool_text_result_for_llm_content_resource_details, external_tool_text_result_for_llm_content_resource_link, external_tool_text_result_for_llm_content_resource_link_icon, external_tool_text_result_for_llm_content_resource_link_icon_theme, external_tool_text_result_for_llm_content_shell_exit, external_tool_text_result_for_llm_content_terminal, external_tool_text_result_for_llm_content_text, filter_mapping, fleet_start_request, fleet_start_result, folder_trust_add_params, folder_trust_check_params, folder_trust_check_result, gh_cli_auth_info, git_hub_telemetry_client_info, git_hub_telemetry_event, git_hub_telemetry_notification, handle_pending_tool_call_request, handle_pending_tool_call_result, history_abort_manual_compaction_result, history_cancel_background_compaction_result, history_compact_context_window, history_compact_request, history_compact_result, history_summarize_for_handoff_result, history_truncate_request, history_truncate_result, hmac_auth_info, installed_plugin, installed_plugin_info, installed_plugin_source, installed_plugin_source_git_hub, installed_plugin_source_local, installed_plugin_source_url, instruction_discovery_path, instruction_discovery_path_kind, instruction_discovery_path_list, instruction_discovery_path_location, instructions_discover_request, instructions_get_discovery_paths_request, instructions_get_sources_result, instruction_source, instruction_source_location, instruction_source_type, llm_inference_headers, llm_inference_http_request_chunk_request, llm_inference_http_request_chunk_result, llm_inference_http_request_start_request, llm_inference_http_request_start_result, llm_inference_http_request_start_transport, llm_inference_http_response_chunk_error, llm_inference_http_response_chunk_request, llm_inference_http_response_chunk_result, llm_inference_http_response_start_request, llm_inference_http_response_start_result, llm_inference_set_provider_result, local_session_metadata_value, log_request, log_result, lsp_initialize_request, marketplace_add_result, marketplace_browse_result, marketplace_info, marketplace_list_result, marketplace_plugin_info, marketplace_refresh_entry, marketplace_refresh_result, marketplace_remove_result, mcp_allowed_server, mcp_apps_call_tool_request, mcp_apps_diagnose_capability, mcp_apps_diagnose_request, mcp_apps_diagnose_result, mcp_apps_diagnose_server, mcp_apps_host_context, mcp_apps_host_context_details, mcp_apps_host_context_details_available_display_mode, mcp_apps_host_context_details_display_mode, mcp_apps_host_context_details_platform, mcp_apps_host_context_details_theme, mcp_apps_list_tools_request, mcp_apps_list_tools_result, mcp_apps_read_resource_request, mcp_apps_read_resource_result, mcp_apps_resource_content, mcp_apps_set_host_context_details, mcp_apps_set_host_context_details_available_display_mode, mcp_apps_set_host_context_details_display_mode, mcp_apps_set_host_context_details_platform, mcp_apps_set_host_context_details_theme, mcp_apps_set_host_context_request, mcp_cancel_sampling_execution_params, mcp_cancel_sampling_execution_result, mcp_config_add_request, mcp_config_disable_request, mcp_config_enable_request, mcp_config_list, mcp_config_remove_request, mcp_config_update_request, mcp_configure_git_hub_request, mcp_configure_git_hub_result, mcp_disable_request, mcp_discover_request, mcp_discover_result, mcp_enable_request, mcp_execute_sampling_params, mcp_execute_sampling_request, mcp_execute_sampling_result, mcp_filtered_server, mcp_headers_handle_pending_headers_refresh_request, mcp_headers_handle_pending_headers_refresh_request_request, mcp_headers_handle_pending_headers_refresh_request_result, mcp_host_state, mcp_is_server_running_request, mcp_is_server_running_result, mcp_list_tools_request, mcp_list_tools_result, mcp_oauth_handle_pending_request, mcp_oauth_handle_pending_result, mcp_oauth_login_grant_type, mcp_oauth_login_request, mcp_oauth_login_result, mcp_oauth_pending_request_response, mcp_register_external_client_request, mcp_reload_with_config_request, mcp_remove_git_hub_result, mcp_restart_server_request, mcp_sampling_execution_action, mcp_sampling_execution_result, mcp_server, mcp_server_auth_config, mcp_server_auth_config_redirect_port, mcp_server_config, mcp_server_config_defer_tools, mcp_server_config_http, mcp_server_config_http_oauth_grant_type, mcp_server_config_http_type, mcp_server_config_stdio, mcp_server_failure_info, mcp_server_list, mcp_server_needs_auth_info, mcp_set_env_value_mode_details, mcp_set_env_value_mode_params, mcp_set_env_value_mode_result, mcp_start_server_request, mcp_start_servers_result, mcp_stop_server_request, mcp_tools, mcp_unregister_external_client_request, memory_configuration, metadata_context_attribution_result, metadata_context_heaviest_messages_request, metadata_context_heaviest_messages_result, metadata_context_info_request, metadata_context_info_result, metadata_is_processing_result, metadata_recompute_context_tokens_request, metadata_recompute_context_tokens_result, metadata_record_context_change_request, metadata_record_context_change_result, metadata_set_working_directory_request, metadata_set_working_directory_result, metadata_snapshot_current_mode, metadata_snapshot_remote_metadata, metadata_snapshot_remote_metadata_repository, metadata_snapshot_remote_metadata_task_type, model, model_billing, model_billing_token_prices, model_billing_token_prices_long_context, model_capabilities, model_capabilities_limits, model_capabilities_limits_vision, model_capabilities_override, model_capabilities_override_limits, model_capabilities_override_limits_vision, model_capabilities_override_supports, model_capabilities_supports, model_list, model_list_request, model_picker_category, model_picker_price_category, model_policy, model_policy_state, model_set_reasoning_effort_request, model_set_reasoning_effort_result, models_list_request, model_switch_to_request, model_switch_to_result, mode_set_request, named_provider_config, name_get_result, name_set_auto_request, name_set_auto_result, name_set_request, open_canvas_instance, options_update_additional_content_exclusion_policy, options_update_additional_content_exclusion_policy_rule, options_update_additional_content_exclusion_policy_rule_source, options_update_additional_content_exclusion_policy_scope, options_update_context_tier, options_update_env_value_mode, options_update_reasoning_summary, options_update_tool_filter_precedence, pending_permission_request, pending_permission_request_list, permission_decision, permission_decision_approved, permission_decision_approved_for_location, permission_decision_approved_for_session, permission_decision_approve_for_location, permission_decision_approve_for_location_approval, permission_decision_approve_for_location_approval_commands, permission_decision_approve_for_location_approval_custom_tool, permission_decision_approve_for_location_approval_extension_management, permission_decision_approve_for_location_approval_extension_permission_access, permission_decision_approve_for_location_approval_mcp, permission_decision_approve_for_location_approval_mcp_sampling, permission_decision_approve_for_location_approval_memory, permission_decision_approve_for_location_approval_read, permission_decision_approve_for_location_approval_write, permission_decision_approve_for_session, permission_decision_approve_for_session_approval, permission_decision_approve_for_session_approval_commands, permission_decision_approve_for_session_approval_custom_tool, permission_decision_approve_for_session_approval_extension_management, permission_decision_approve_for_session_approval_extension_permission_access, permission_decision_approve_for_session_approval_mcp, permission_decision_approve_for_session_approval_mcp_sampling, permission_decision_approve_for_session_approval_memory, permission_decision_approve_for_session_approval_read, permission_decision_approve_for_session_approval_write, permission_decision_approve_once, permission_decision_approve_permanently, permission_decision_cancelled, permission_decision_denied_by_content_exclusion_policy, permission_decision_denied_by_permission_request_hook, permission_decision_denied_by_rules, permission_decision_denied_interactively_by_user, permission_decision_denied_no_approval_rule_and_could_not_request_from_user, permission_decision_reject, permission_decision_request, permission_decision_user_not_available, permission_location_add_tool_approval_params, permission_location_apply_params, permission_location_apply_result, permission_location_resolve_params, permission_location_resolve_result, permission_location_type, permission_paths_add_params, permission_paths_allowed_check_params, permission_paths_allowed_check_result, permission_paths_config, permission_paths_list, permission_paths_update_primary_params, permission_paths_workspace_check_params, permission_paths_workspace_check_result, permission_prompt_shown_notification, permission_request_result, permission_rules_set, permissions_allow_all_mode, permissions_configure_additional_content_exclusion_policy, permissions_configure_additional_content_exclusion_policy_rule, permissions_configure_additional_content_exclusion_policy_rule_source, permissions_configure_additional_content_exclusion_policy_scope, permissions_configure_params, permissions_configure_result, permissions_folder_trust_add_trusted_result, permissions_get_allow_all_request, permissions_locations_add_tool_approval_details, permissions_locations_add_tool_approval_details_commands, permissions_locations_add_tool_approval_details_custom_tool, permissions_locations_add_tool_approval_details_extension_management, permissions_locations_add_tool_approval_details_extension_permission_access, permissions_locations_add_tool_approval_details_mcp, permissions_locations_add_tool_approval_details_mcp_sampling, permissions_locations_add_tool_approval_details_memory, permissions_locations_add_tool_approval_details_read, permissions_locations_add_tool_approval_details_write, permissions_locations_add_tool_approval_result, permissions_modify_rules_params, permissions_modify_rules_result, permissions_modify_rules_scope, permissions_notify_prompt_shown_result, permissions_paths_add_result, permissions_paths_list_request, permissions_paths_update_primary_result, permissions_pending_requests_request, permissions_reset_session_approvals_request, permissions_reset_session_approvals_result, permissions_set_allow_all_request, permissions_set_allow_all_source, permissions_set_approve_all_request, permissions_set_approve_all_result, permissions_set_approve_all_source, permissions_set_required_request, permissions_set_required_result, permissions_urls_set_unrestricted_mode_result, permission_urls_config, permission_urls_set_unrestricted_mode_params, ping_request, ping_result, plan_read_result, plan_read_sql_todos_result, plan_read_sql_todos_with_dependencies_result, plan_sql_todo_dependency, plan_sql_todos_row, plan_update_request, plugin, plugin_install_result, plugin_list, plugin_list_result, plugins_disable_request, plugins_enable_request, plugins_install_request, plugins_marketplaces_add_request, plugins_marketplaces_browse_request, plugins_marketplaces_refresh_request, plugins_marketplaces_remove_request, plugins_reload_request, plugins_uninstall_request, plugins_update_request, plugin_update_all_entry, plugin_update_all_result, plugin_update_result, provider_add_request, provider_add_result, provider_config, provider_config_azure, provider_config_transport, provider_config_type, provider_config_wire_api, provider_endpoint, provider_endpoint_transport, provider_endpoint_type, provider_endpoint_wire_api, provider_get_endpoint_request, provider_model_config, provider_session_token, provider_token_acquire_request, provider_token_acquire_result, push_attachment, push_attachment_blob, push_attachment_directory, push_attachment_file, push_attachment_file_line_range, push_attachment_git_hub_actions_job, push_attachment_git_hub_commit, push_attachment_git_hub_file, push_attachment_git_hub_file_diff, push_attachment_git_hub_file_diff_side, push_attachment_git_hub_reference, push_attachment_git_hub_reference_type, push_attachment_git_hub_release, push_attachment_git_hub_repository, push_attachment_git_hub_snippet, push_attachment_git_hub_tree_comparison, push_attachment_git_hub_tree_comparison_side, push_attachment_git_hub_url, push_attachment_selection, push_attachment_selection_details, push_attachment_selection_details_end, push_attachment_selection_details_start, push_git_hub_repo_ref, queued_command_handled, queued_command_not_handled, queued_command_result, queue_pending_items, queue_pending_items_kind, queue_pending_items_result, queue_remove_most_recent_result, register_event_interest_params, register_event_interest_result, register_extension_tools_params, register_extension_tools_result, release_event_interest_params, remote_control_config, remote_control_config_existing_mc_session, remote_control_status, remote_control_status_active, remote_control_status_connecting, remote_control_status_error, remote_control_status_off, remote_control_status_result, remote_control_stop_result, remote_control_transfer_result, remote_enable_request, remote_enable_result, remote_notify_steerable_changed_request, remote_notify_steerable_changed_result, remote_session_connection_result, remote_session_metadata_repository, remote_session_metadata_task_type, remote_session_metadata_value, remote_session_mode, remote_session_repository, sandbox_config, sandbox_config_user_policy, sandbox_config_user_policy_experimental, sandbox_config_user_policy_experimental_seatbelt, sandbox_config_user_policy_filesystem, sandbox_config_user_policy_network, sandbox_config_user_policy_seatbelt, schedule_entry, schedule_list, schedule_stop_request, schedule_stop_result, secrets_add_filter_values_request, secrets_add_filter_values_result, send_agent_mode, send_attachments_to_message_params, send_mode, send_request, send_result, server_agent_list, server_instruction_source_list, server_skill, server_skill_list, session_activity, session_auth_status, session_bulk_delete_result, session_capability, session_completion_item, session_context, session_context_host_type, session_enrich_metadata_result, session_fs_append_file_request, session_fs_error, session_fs_error_code, session_fs_exists_request, session_fs_exists_result, session_fs_mkdir_request, session_fs_readdir_request, session_fs_readdir_result, session_fs_readdir_with_types_entry, session_fs_readdir_with_types_entry_type, session_fs_readdir_with_types_request, session_fs_readdir_with_types_result, session_fs_read_file_request, session_fs_read_file_result, session_fs_rename_request, session_fs_rm_request, session_fs_set_provider_capabilities, session_fs_set_provider_conventions, session_fs_set_provider_request, session_fs_set_provider_result, session_fs_sqlite_exists_request, session_fs_sqlite_exists_result, session_fs_sqlite_query_request, session_fs_sqlite_query_result, session_fs_sqlite_query_type, session_fs_stat_request, session_fs_stat_result, session_fs_write_file_request, session_installed_plugin, session_installed_plugin_source, session_installed_plugin_source_git_hub, session_installed_plugin_source_local, session_installed_plugin_source_url, session_list, session_list_entry, session_list_filter, session_load_deferred_repo_hooks_result, session_log_level, session_mcp_apps_call_tool_result, session_metadata_snapshot, session_mode, session_model_list, session_open_options, session_open_options_additional_content_exclusion_policy, session_open_options_additional_content_exclusion_policy_rule, session_open_options_additional_content_exclusion_policy_rule_source, session_open_options_additional_content_exclusion_policy_scope, session_open_options_env_value_mode, session_open_options_reasoning_summary, session_open_params, session_open_result, session_prune_result, sessions_bulk_delete_request, sessions_check_in_use_request, sessions_check_in_use_result, sessions_close_request, sessions_close_result, sessions_enrich_metadata_request, session_set_credentials_params, session_set_credentials_result, session_settings_built_in_tool_availability_snapshot, session_settings_evaluate_predicate_request, session_settings_evaluate_predicate_result, session_settings_job_snapshot, session_settings_model_snapshot, session_settings_online_evaluation_snapshot, session_settings_predicate_name, session_settings_repo_snapshot, session_settings_snapshot, session_settings_validation_snapshot, sessions_find_by_prefix_request, sessions_find_by_prefix_result, sessions_find_by_task_id_request, sessions_find_by_task_id_result, sessions_fork_request, sessions_fork_result, sessions_get_board_entry_count_request, sessions_get_board_entry_count_result, sessions_get_event_file_path_request, sessions_get_event_file_path_result, sessions_get_last_for_context_request, sessions_get_last_for_context_result, sessions_get_persisted_remote_steerable_request, sessions_get_persisted_remote_steerable_result, session_sizes, sessions_list_request, sessions_load_deferred_repo_hooks_request, sessions_open_attach, sessions_open_cloud, sessions_open_create, sessions_open_handoff, sessions_open_handoff_task_type, sessions_open_progress, sessions_open_progress_status, sessions_open_progress_step, sessions_open_remote, sessions_open_resume, sessions_open_resume_last, sessions_open_status, session_source, sessions_prune_old_request, sessions_register_extension_tools_on_session_options, sessions_release_lock_request, sessions_release_lock_result, sessions_reload_plugin_hooks_request, sessions_reload_plugin_hooks_result, sessions_save_request, sessions_save_result, sessions_set_additional_plugins_request, sessions_set_additional_plugins_result, sessions_set_remote_control_steering_request, sessions_start_remote_control_request, sessions_stop_remote_control_request, sessions_transfer_remote_control_request, session_telemetry_engagement, session_update_options_params, session_update_options_result, session_visibility_status, session_working_directory_context, session_working_directory_context_host_type, shell_cancel_user_requested_request, shell_exec_request, shell_exec_result, shell_execute_user_requested_request, shell_kill_request, shell_kill_result, shell_kill_signal, shutdown_request, skill, skill_discovery_path, skill_discovery_path_list, skill_discovery_scope, skill_list, skills_config_set_disabled_skills_request, skills_disable_request, skills_discover_request, skills_enable_request, skills_get_discovery_paths_request, skills_get_invoked_result, skills_invoked_skill, skills_load_diagnostics, slash_command_agent_prompt_result, slash_command_completed_result, slash_command_info, slash_command_input, slash_command_input_choice, slash_command_input_completion, slash_command_invocation_result, slash_command_kind, slash_command_select_subcommand_option, slash_command_select_subcommand_result, slash_command_text_result, subagent_settings_entry, subagent_settings_entry_context_tier, task_agent_info, task_agent_progress, task_execution_mode, task_info, task_list, task_progress_line, tasks_cancel_request, tasks_cancel_result, tasks_get_current_promotable_result, tasks_get_progress_request, tasks_get_progress_result, task_shell_info, task_shell_info_attachment_mode, task_shell_progress, tasks_promote_current_to_background_result, tasks_promote_to_background_request, tasks_promote_to_background_result, tasks_refresh_result, tasks_remove_request, tasks_remove_result, tasks_send_message_request, tasks_send_message_result, tasks_start_agent_request, tasks_start_agent_result, task_status, tasks_wait_for_pending_result, telemetry_set_feature_overrides_request, token_auth_info, tool, tool_list, tools_get_current_metadata_result, tools_initialize_and_validate_result, tools_list_request, tools_update_subagent_settings_result, ui_auto_mode_switch_response, ui_elicitation_array_any_of_field, ui_elicitation_array_any_of_field_items, ui_elicitation_array_any_of_field_items_any_of, ui_elicitation_array_enum_field, ui_elicitation_array_enum_field_items, ui_elicitation_field_value, ui_elicitation_request, ui_elicitation_response, ui_elicitation_response_action, ui_elicitation_response_content, ui_elicitation_result, ui_elicitation_schema, ui_elicitation_schema_property, ui_elicitation_schema_property_boolean, ui_elicitation_schema_property_number, ui_elicitation_schema_property_number_type, ui_elicitation_schema_property_string, ui_elicitation_schema_property_string_format, ui_elicitation_string_enum_field, ui_elicitation_string_one_of_field, ui_elicitation_string_one_of_field_one_of, ui_ephemeral_query_request, ui_ephemeral_query_result, ui_exit_plan_mode_action, ui_exit_plan_mode_response, ui_handle_pending_auto_mode_switch_request, ui_handle_pending_elicitation_request, ui_handle_pending_exit_plan_mode_request, ui_handle_pending_result, ui_handle_pending_sampling_request, ui_handle_pending_sampling_response, ui_handle_pending_session_limits_exhausted_request, ui_handle_pending_user_input_request, ui_register_direct_auto_mode_switch_handler_result, ui_session_limits_exhausted_response, ui_session_limits_exhausted_response_action, ui_unregister_direct_auto_mode_switch_handler_request, ui_unregister_direct_auto_mode_switch_handler_result, ui_user_input_response, update_subagent_settings_request, usage_get_metrics_result, usage_metrics_code_changes, usage_metrics_model_metric, usage_metrics_model_metric_requests, usage_metrics_model_metric_token_detail, usage_metrics_model_metric_usage, usage_metrics_token_detail, user_auth_info, user_requested_shell_command_result, user_setting_metadata, user_settings_get_result, user_settings_set_request, user_settings_set_result, visibility_get_result, visibility_set_request, visibility_set_result, workspace_diff_file_change, workspace_diff_file_change_type, workspace_diff_mode, workspace_diff_result, workspaces_checkpoints, workspaces_create_file_request, workspaces_diff_request, workspaces_get_workspace_result, workspaces_list_checkpoints_result, workspaces_list_files_result, workspaces_read_checkpoint_request, workspaces_read_checkpoint_result, workspaces_read_file_request, workspaces_read_file_result, workspaces_save_large_paste_request, workspaces_save_large_paste_result, workspace_summary_host_type, workspaces_workspace_details_host_type, session_context_attribution, session_context_info, subagent_settings, task_progress, workspace_summary) def to_dict(self) -> dict: result: dict = {} @@ -25444,8 +25399,6 @@ def to_dict(self) -> dict: result["McpOauthLoginRequest"] = to_class(MCPOauthLoginRequest, self.mcp_oauth_login_request) result["McpOauthLoginResult"] = to_class(MCPOauthLoginResult, self.mcp_oauth_login_result) result["McpOauthPendingRequestResponse"] = to_class(MCPOauthPendingRequestResponse, self.mcp_oauth_pending_request_response) - result["McpOauthRespondRequest"] = to_class(MCPOauthRespondRequest, self.mcp_oauth_respond_request) - result["McpOauthRespondResult"] = to_class(MCPOauthRespondResult, self.mcp_oauth_respond_result) result["McpRegisterExternalClientRequest"] = to_class(MCPRegisterExternalClientRequest, self.mcp_register_external_client_request) result["McpReloadWithConfigRequest"] = to_class(MCPReloadWithConfigRequest, self.mcp_reload_with_config_request) result["McpRemoveGitHubResult"] = to_class(MCPRemoveGitHubResult, self.mcp_remove_git_hub_result) @@ -28067,25 +28020,11 @@ async def log(self, params: LogRequest, *, timeout: float | None = None) -> LogR return LogResult.from_dict(await self._client.request("session.log", params_dict, **_timeout_kwargs(timeout))) -# Experimental: this API group is experimental and may change or be removed. -class _InternalMcpOauthApi: - def __init__(self, client: "JsonRpcClient", session_id: str): - self._client = client - self._session_id = session_id - - async def _respond(self, params: MCPOauthRespondRequest, *, timeout: float | None = None) -> MCPOauthRespondResult: - "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.\n\nArgs:\n params: MCP OAuth request id and optional provider response.\n\nReturns:\n Empty result after recording the MCP OAuth response.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." - params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} - params_dict["sessionId"] = self._session_id - return MCPOauthRespondResult.from_dict(await self._client.request("session.mcp.oauth.respond", params_dict, **_timeout_kwargs(timeout))) - - # Experimental: this API group is experimental and may change or be removed. class _InternalMcpApi: def __init__(self, client: "JsonRpcClient", session_id: str): self._client = client self._session_id = session_id - self.oauth = _InternalMcpOauthApi(client, session_id) async def _reload_with_config(self, params: MCPReloadWithConfigRequest, *, timeout: float | None = None) -> MCPStartServersResult: "Reloads MCP server connections for the session with an explicit host-provided configuration.\n\nArgs:\n params: Opaque MCP reload configuration.\n\nReturns:\n MCP server startup filtering result.\n\n:meta private:\n\nInternal SDK API; not part of the public surface." @@ -28667,8 +28606,6 @@ async def handle_git_hub_telemetry_event(params: dict) -> None: "MCPOauthLoginResult", "MCPOauthPendingRequestResponse", "MCPOauthPendingRequestResponseKind", - "MCPOauthRespondRequest", - "MCPOauthRespondResult", "MCPRegisterExternalClientRequest", "MCPReloadWithConfigRequest", "MCPRemoveGitHubResult", diff --git a/python/copilot/generated/session_events.py b/python/copilot/generated/session_events.py index 59351d30f7..1d43b6fd53 100644 --- a/python/copilot/generated/session_events.py +++ b/python/copilot/generated/session_events.py @@ -1563,7 +1563,7 @@ def to_dict(self) -> dict: if self.service_request_id is not None: result["serviceRequestId"] = from_union([from_none, from_str], self.service_request_id) if self.time_to_first_token is not None: - result["timeToFirstTokenMs"] = from_union([from_none, to_timedelta_int], self.time_to_first_token) + result["timeToFirstTokenMs"] = from_union([from_none, to_timedelta], self.time_to_first_token) return result diff --git a/rust/src/generated/api_types.rs b/rust/src/generated/api_types.rs index d888320410..b7441255a0 100644 --- a/rust/src/generated/api_types.rs +++ b/rust/src/generated/api_types.rs @@ -324,8 +324,6 @@ pub mod rpc_methods { pub const SESSION_MCP_UNREGISTEREXTERNALCLIENT: &str = "session.mcp.unregisterExternalClient"; /// `session.mcp.isServerRunning` pub const SESSION_MCP_ISSERVERRUNNING: &str = "session.mcp.isServerRunning"; - /// `session.mcp.oauth.respond` - pub const SESSION_MCP_OAUTH_RESPOND: &str = "session.mcp.oauth.respond"; /// `session.mcp.oauth.handlePendingRequest` pub const SESSION_MCP_OAUTH_HANDLEPENDINGREQUEST: &str = "session.mcp.oauth.handlePendingRequest"; @@ -5581,37 +5579,6 @@ pub struct McpOauthLoginResult { pub authorization_url: Option, } -/// MCP OAuth request id and optional provider response. -/// -///

-/// -/// **Experimental.** This type is part of an experimental wire-protocol surface -/// and may change or be removed in future SDK or CLI releases. -/// -///
-#[derive(Debug, Clone, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub(crate) struct McpOauthRespondRequest { - /// In-process OAuthClientProvider instance, or omitted to deny. Marked internal: cannot be serialized across the JSON-RPC boundary. - #[doc(hidden)] - #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) provider: Option, - /// OAuth request identifier from mcp.oauth_required - pub request_id: RequestId, -} - -/// Empty result after recording the MCP OAuth response. -/// -///
-/// -/// **Experimental.** This type is part of an experimental wire-protocol surface -/// and may change or be removed in future SDK or CLI releases. -/// -///
-#[derive(Debug, Clone, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct McpOauthRespondResult {} - /// Registration parameters for an external MCP client. /// ///
@@ -17234,18 +17201,6 @@ pub struct SessionMcpIsServerRunningResult { pub running: bool, } -/// Empty result after recording the MCP OAuth response. -/// -///
-/// -/// **Experimental.** This type is part of an experimental wire-protocol surface -/// and may change or be removed in future SDK or CLI releases. -/// -///
-#[derive(Debug, Clone, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct SessionMcpOauthRespondResult {} - /// Indicates whether the pending MCP OAuth response was accepted. /// ///
diff --git a/rust/src/generated/rpc.rs b/rust/src/generated/rpc.rs index 0f7bf02122..b11a689fcf 100644 --- a/rust/src/generated/rpc.rs +++ b/rust/src/generated/rpc.rs @@ -5002,39 +5002,6 @@ pub struct SessionRpcMcpOauth<'a> { } impl<'a> SessionRpcMcpOauth<'a> { - /// 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. - /// - /// Wire method: `session.mcp.oauth.respond`. - /// - /// # Parameters - /// - /// * `params` - MCP OAuth request id and optional provider response. - /// - /// # Returns - /// - /// Empty result after recording the MCP OAuth response. - /// - ///
- /// - /// **Experimental.** This API is part of an experimental wire-protocol surface - /// and may change or be removed in future SDK or CLI releases. Pin both the - /// SDK and CLI versions if your code depends on it. - /// - ///
- pub(crate) async fn respond( - &self, - params: McpOauthRespondRequest, - ) -> Result { - let mut wire_params = serde_json::to_value(params)?; - wire_params["sessionId"] = serde_json::Value::String(self.session.id().to_string()); - let _value = self - .session - .client() - .call(rpc_methods::SESSION_MCP_OAUTH_RESPOND, Some(wire_params)) - .await?; - Ok(serde_json::from_value(_value)?) - } - /// 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. /// /// Wire method: `session.mcp.oauth.handlePendingRequest`. diff --git a/rust/src/generated/session_events.rs b/rust/src/generated/session_events.rs index fbb9b95109..6505cf4765 100644 --- a/rust/src/generated/session_events.rs +++ b/rust/src/generated/session_events.rs @@ -1836,7 +1836,7 @@ pub struct AssistantUsageData { pub service_request_id: Option, /// Time to first token in milliseconds. Only available for streaming requests #[serde(skip_serializing_if = "Option::is_none")] - pub time_to_first_token_ms: Option, + pub time_to_first_token_ms: Option, } /// Content-free structural summary of the failing request for diagnosing malformed 4xx calls diff --git a/rust/tests/e2e/rpc_mcp_lifecycle.rs b/rust/tests/e2e/rpc_mcp_lifecycle.rs index fc79828320..fa2b15d866 100644 --- a/rust/tests/e2e/rpc_mcp_lifecycle.rs +++ b/rust/tests/e2e/rpc_mcp_lifecycle.rs @@ -327,44 +327,6 @@ async fn should_configure_github_mcp_server() { .await; } -#[tokio::test] -async fn should_respond_to_mcp_oauth_request_without_pending_request() { - with_e2e_context( - "rpc_mcp_lifecycle", - "should_respond_to_mcp_oauth_request_without_pending_request", - |ctx| { - Box::pin(async move { - ctx.set_default_copilot_user(); - let host_server = "rpc-lifecycle-oauth-host"; - let client = ctx.start_client().await; - let session = - client - .create_session(ctx.approve_all_session_config().with_mcp_servers( - create_test_mcp_servers(ctx.repo_root(), host_server), - )) - .await - .expect("create session"); - wait_for_mcp_server_status(&session, host_server, McpServerStatus::Connected).await; - - let result = call_session_rpc( - &session, - "session.mcp.oauth.respond", - json!({ - "requestId": format!("missing-{}", uuid::Uuid::new_v4().simple()) - }), - ) - .await - .expect("respond to missing MCP OAuth request"); - assert!(result.is_object()); - - session.disconnect().await.expect("disconnect session"); - client.stop().await.expect("stop client"); - }) - }, - ) - .await; -} - fn create_test_mcp_servers( repo_root: &Path, server_name: &str, diff --git a/test/snapshots/rpc_mcp_lifecycle/should_respond_to_mcp_oauth_request_without_pending_request.yaml b/test/snapshots/rpc_mcp_lifecycle/should_respond_to_mcp_oauth_request_without_pending_request.yaml deleted file mode 100644 index 056351ddb4..0000000000 --- a/test/snapshots/rpc_mcp_lifecycle/should_respond_to_mcp_oauth_request_without_pending_request.yaml +++ /dev/null @@ -1,3 +0,0 @@ -models: - - claude-sonnet-4.5 -conversations: []