# Changelog All notable changes to the Copilot SDK are documented in this file. This changelog is automatically generated by an AI agent when stable releases are published. See [GitHub Releases](https://github.com/github/copilot-sdk/releases) for the full list. ## [Unreleased] ## [v1.0.13](https://github.com/github/copilot-sdk/releases/tag/v1.0.13) (2026-09-04) ### Feature: cancellation for host-owned external tools Host-owned external tool callbacks are now cancelled when their runtime request completes or their SDK session terminates. The cancellation primitive is idiomatic per SDK: .NET passes a request token to `AIFunction`, Node.js exposes `ToolInvocation.signal`, Go cancels `ToolInvocation.TraceContext`, Java cancels the returned `CompletableFuture`, Python cancels the handler task, and Rust drops the handler future. Go handlers that retain `TraceContext` for background work must derive a separate lifetime because the invocation context is cancelled when the request ends. ### Feature: declare application identity with client info Client options now accept optional client info (application name and version, integration name and version) across all six SDKs, exposed idiomatically per language (`clientInfo` in Node.js, `client_info` in Python and Rust, `ClientInfo` in Go and .NET, `setClientInfo` in Java). When set, the SDK forwards it on the `server.connect` handshake so the telemetry the runtime emits on the connection is attributed to the application and its Copilot integration instead of the runtime's own build. All fields are optional, and leaving client info unset keeps the runtime's default attribution. See [Client info](./docs/features/client-info.md). ### Feature: Node Agent Factories pagination and run notifications The experimental Node.js Agent Factories convenience API now supports paginated run history. Existing `session.factory.listRuns()` calls still return the runs array, while calls with `afterSeq`, `beforeSeq`, or `limit` return the full page with cursor and truncation metadata. Factory `run` and `resume` options now accept `notifyOnComplete` and `logPhaseNames`. The SDK forwards these options to the Copilot CLI for new and resumed runs. ### Feature: selectable `ask_user` session behavior Session create and cold resume now accept a language-specific `askUserVariant` option with `legacy` and `elicitation` values. SDK sessions retain the legacy question-and-answer tool by default. Select `elicitation` and provide an elicitation handler to expose the structured form-based `ask_user` tool. ### Feature: rotating session-scoped GitHub credentials All six SDKs can now acquire short-lived GitHub credentials through a session-scoped callback. The SDK registers the callback before session create or resume, maps `initial` and `refresh` requests to the owning session, and removes registrations on rollback, replacement, session close, and client close. Static per-session `gitHubToken` credentials remain supported and are mutually exclusive with the callback. Token responses use the shared tagged token/cancelled shape and require `expiresIn`, expressed as the positive number of seconds remaining when the callback completes. See [github/copilot-agent-runtime#16381](https://github.com/github/copilot-agent-runtime/pull/16381) for the runtime credential-authority implementation. Initial acquisition occurs during create or resume; cancellation, callback errors, and invalid credentials reject that operation instead of falling back to ambient authentication. Idle sessions refresh only before their next credential-consuming operation. ### Feature: extensions can request sensitive environment variables Copilot CLI extensions can now ask for named sensitive environment variables when they join a session. `joinSession()` accepts a `requestedEnvironmentVariables` option listing the variable names the extension needs. The CLI shows a permission prompt naming the extension and the exact variables requested. On approval, only those variables reach that extension and their values are written into the extension process's `process.env` before `joinSession()` resolves. On denial, `joinSession()` rejects, the extension does not load, and its tools never reach the model. An approval is remembered against the exact set of names the user saw, so an extension that later asks for one more variable prompts again. Names that are unset, or that the CLI does not filter from extensions, are not prompted for. This is the client half of the feature; it requires a Copilot CLI that supports extension environment access, and older CLIs ignore the request and grant nothing. ```ts import { joinSession } from "@github/copilot-sdk/extension"; const session = await joinSession({ requestedEnvironmentVariables: ["GITHUB_TOKEN"], }); const token = process.env.GITHUB_TOKEN; ``` ### Feature: early session-event subscription (Rust) The Rust SDK can now observe every event routed to a session, starting with that session's very first routed event. `Client::prepare_session` and `Client::prepare_resume_session` return an inert `PreparedSession` that owns the session's event channel, so a subscription can be installed *before* any protocol activity begins: ```rust let prepared = client.prepare_session( SessionConfig::default().with_event_buffer_capacity(2048), )?; let mut events = prepared.subscribe(); let session = prepared.start().await?; ``` Previously, `Session::subscribe` could only be called on the returned session, so events the runtime emitted while `session.create` / `session.resume` was still in flight were broadcast with no receiver installed and dropped. Ephemeral events such as `session.idle` are not persisted, so they could not be recovered with `getMessages` either. The guarantee is scoped to *routed* events. For cloud sessions where the server assigns the session ID, the SDK cannot route notifications until the `session.create` response arrives and the ID is known, so events emitted before that point are not routable to any session. Pin `session_id` on the config to get router registration before the RPC, and with it complete pre-response coverage. `prepare_*` is synchronous and inert: it validates the buffer capacity and allocates a local channel, and performs no router registration, task spawn, or wire activity until `start()` is first polled. `start(self)` consumes the handle and `PreparedSession` is not `Clone`, so a prepared session can never produce two event loops. Dropping an unstarted handle leaves no state behind; dropping a polled `start()` future cancels the startup and unregisters the session, so a retry with the same session ID succeeds. Session registrations now carry an ownership identity, so cleanup removes only the exact registration it owns and an abandoned startup can never evict a same-ID retry (or a session that replaced it). Both `SessionConfig` and `ResumeSessionConfig` gained a runtime-only `event_buffer_capacity` option (default 512, `Some(0)` rejected as an invalid config). The buffer is finite, so slow subscribers observe `Lagged` rather than applying backpressure; consumers that need a lossless view of a large startup burst must size the buffer accordingly or drain concurrently with `start()`. `create_session` and `resume_session` are unchanged wrappers over `prepare_*(...)?.start()` with identical RPC sequences and error kinds. ### Feature: host-injected managed settings permissions Session create and resume accept a new optional `managedSettings` option that injects an enterprise permissions policy at session startup, alongside the existing `enableManagedSettings` self-fetch flag. The current contract is permissions-only: `disableBypassPermissionsMode` (the literal `"disable"`), plus `deny`, `ask`, and `allow` rule lists. The layer composes restrictively with any server- or device-level managed settings (deny/ask are unioned, every present allow list must admit a tool, and `disableBypassPermissionsMode` is deny-wins). This layer is startup-only and is not persisted with the session, so it must be re-supplied on resume to remain in effect; omitting it on resume clears the previously injected layer. It can be combined with `enableManagedSettings`. Host injection requires Copilot CLI `1.0.79-5` or later and does not require an SDK protocol version bump. The generated session-event types also expose truthful injected-policy provenance: `session.managed_settings_resolved` can report `source` as `client` or `mixed`, with optional `clientManaged` metadata. ```ts const session = await client.createSession({ managedSettings: { permissions: { disableBypassPermissionsMode: "disable", deny: ["shell(rm*)"], ask: ["write"], }, }, }); ``` ```cs var session = await client.CreateSessionAsync(new SessionConfig { ManagedSettings = new ManagedSettings { Permissions = new ManagedSettingsPermissions { DisableBypassPermissionsMode = DisableBypassPermissionsMode.Disable, Deny = ["shell(rm*)"], Ask = ["write"], }, }, }); ``` ### Feature: Auto model routing tier controls Sessions can now steer `auto` model routing toward efficiency, balance, or intelligence. An Auto tier can be set at session creation, and a new `setAutoTier` (and equivalent `setModel` option) lets sessions stage or reset a tier preference afterward, since the runtime only commits a staged preference on the next successful `auto` model turn. ([#2437](https://github.com/github/copilot-sdk/pull/2437), [#2514](https://github.com/github/copilot-sdk/pull/2514)) ```py await session.set_auto_tier("efficiency") ``` ### Feature: sandbox bypass and non-object external tool arguments Sandbox configuration now exposes `allowBypass` across all six SDKs. External tool overrides such as `apply_patch` can also receive non-object JSON argument values, which previously failed before reaching the host handler in .NET. ([#2372](https://github.com/github/copilot-sdk/pull/2372), [#2496](https://github.com/github/copilot-sdk/pull/2496)) ### Feature: host-resolved feature flag overrides Session create and resume now accept a `featureFlags` map across all six SDKs, forwarding host-resolved overrides while preserving the distinction between an unset map and an explicitly empty one. ([#2451](https://github.com/github/copilot-sdk/pull/2451)) ### Other changes - feature: use `session.detach` instead of `session.destroy` for SDK session cleanup so disconnecting one client no longer tears down a shared session for other owners ([#2307](https://github.com/github/copilot-sdk/pull/2307)) - bugfix: **[Rust]** answer the request ID when a tool handler panics ([#2311](https://github.com/github/copilot-sdk/pull/2311)) - bugfix: **[Go]** close failed session event loops ([#2360](https://github.com/github/copilot-sdk/pull/2360)) - bugfix: support bracketed IPv6 runtime URLs ([#2200](https://github.com/github/copilot-sdk/pull/2200)) - bugfix: **[Python]** serialize native values in tool results ([#2374](https://github.com/github/copilot-sdk/pull/2374)) - bugfix: **[Rust]** prevent orphaned CLI processes ([#2292](https://github.com/github/copilot-sdk/pull/2292)) - improvement: **[Rust]** default `ClientMode::Empty` to no built-in skills ([#2410](https://github.com/github/copilot-sdk/pull/2410)) - improvement: **[Go]** auto-detect bundler package name and avoid duplicate license downloads ([#2452](https://github.com/github/copilot-sdk/pull/2452), [#2453](https://github.com/github/copilot-sdk/pull/2453)) ### New contributors - @lukehoban made their first contribution in [#2292](https://github.com/github/copilot-sdk/pull/2292) - @scordio made their first contribution in [#2382](https://github.com/github/copilot-sdk/pull/2382) - @OllieinCanada made their first contribution in [#2374](https://github.com/github/copilot-sdk/pull/2374) - @gimenete made their first contribution in [#2458](https://github.com/github/copilot-sdk/pull/2458) - @gwwar made their first contribution in [#2464](https://github.com/github/copilot-sdk/pull/2464) - @Pybsama made their first contribution in [#2163](https://github.com/github/copilot-sdk/pull/2163) - @green3sf made their first contribution in [#2360](https://github.com/github/copilot-sdk/pull/2360) - @gokhanarkan made their first contribution in [#2532](https://github.com/github/copilot-sdk/pull/2532) ## [v1.0.7](https://github.com/github/copilot-sdk/releases/tag/v1.0.7) (2026-07-16) ### Feature: in-process (FFI) transport The SDK can now host the Copilot runtime in-process by loading the native runtime library via its C ABI (FFI), eliminating the overhead of spawning a child process. This experimental transport is available for Node.js, Rust, Python, and Go. ([#1953](https://github.com/github/copilot-sdk/pull/1953), [#1915](https://github.com/github/copilot-sdk/pull/1915), [#1975](https://github.com/github/copilot-sdk/pull/1975), [#1976](https://github.com/github/copilot-sdk/pull/1976)) ```ts const client = new CopilotClient({ connection: RuntimeConnection.forInProcess() }); ``` ```cs var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForInProcess() }); ``` ### Feature: tool search configuration A new `toolSearch` session option controls how the SDK defers tools when the total tool count exceeds a threshold. When enabled (the default), excess MCP and external tools are surfaced on demand through the built-in `tool_search_tool` rather than pre-loaded into every prompt. Tool results can also include `toolReferences` to link cited sources back to the tool that produced them. ([#1933](https://github.com/github/copilot-sdk/pull/1933)) ```ts const session = await client.createSession({ toolSearch: { defer: "auto" }, }); ``` ```cs var session = await client.CreateSessionAsync(new SessionConfig { ToolSearch = new ToolSearchConfig { Defer = "auto" }, }); ``` ### Feature: opaque metadata passthrough on tool definitions Tool definitions now accept an optional `metadata` bag that is forwarded verbatim in `session.create` and `session.resume` RPC calls. This lets hosts attach namespaced, implementation-specific metadata to tools without expanding the typed public contract; unknown keys are preserved and round-tripped untouched. ([#1864](https://github.com/github/copilot-sdk/pull/1864)) ```ts session.defineTool("my-tool", { metadata: { "myapp:priority": 1 } }, handler); ``` ```cs session.DefineTool("my-tool", new ToolOptions { Metadata = new() { ["myapp:priority"] = 1 } }, handler); ``` ### Other changes - feature: **[All SDKs]** add `canvasProvider` field to session create/resume config so hosts can supply a stable canvas-provider identity that survives cold resume ([#1847](https://github.com/github/copilot-sdk/pull/1847)) - feature: **[All SDKs]** forward `enableManagedSettings` flag in session create/resume for enterprise managed-settings enforcement ([#1925](https://github.com/github/copilot-sdk/pull/1925)) - feature: **[All SDKs]** propagate `agentId`, `parentAgentId`, and `interactionType` from LLM inference start frames into request-handler contexts ([#1949](https://github.com/github/copilot-sdk/pull/1949)) - improvement: **[Rust]** make tool schema and MCP server serialization deterministic by replacing `HashMap` with `IndexMap` ([#1931](https://github.com/github/copilot-sdk/pull/1931)) - improvement: **[Rust]** use `native-tls` for the build-time CLI download ([#1964](https://github.com/github/copilot-sdk/pull/1964)) - bugfix: **[.NET]** avoid Windows in-process test teardown deadlock ([#1997](https://github.com/github/copilot-sdk/pull/1997)) ### New contributors - @agoncal made their first contribution in [#1951](https://github.com/github/copilot-sdk/pull/1951) - @Shivam60 made their first contribution in [#1964](https://github.com/github/copilot-sdk/pull/1964) - @rinceyuan made their first contribution in [#1978](https://github.com/github/copilot-sdk/pull/1978) - @belaltaher8 made their first contribution in [#1864](https://github.com/github/copilot-sdk/pull/1864) ## [java/v1.0.6](https://github.com/github/copilot-sdk/releases/tag/java/v1.0.6) (2026-07-08) ### Feature: inline lambda tool definitions Developers can now define tools directly at the call site using `ToolDefinition.from(...)` with typed lambda handlers and `Param.of(...)` parameter metadata — no separate annotated class required. Async variants (`fromAsync`) and `ToolInvocation` context injection (`fromWithToolInvocation`) are also available. ([#1895](https://github.com/github/copilot-sdk/pull/1895)) ```java ToolDefinition greet = ToolDefinition.from( "greet", "Greets a user by name", Param.of(String.class, "name", "The user's name"), name -> "Hello, " + name + "!"); ``` ### Other changes - bugfix: **[Java]** preserve explicit null map values in JSON-RPC params so user setting clears reach the CLI ([#1906](https://github.com/github/copilot-sdk/pull/1906)) - feature: **[Java]** add experimental `onGitHubTelemetry` callback on `CopilotClientOptions` for receiving forwarded GitHub telemetry events ([#1835](https://github.com/github/copilot-sdk/pull/1835)) ## [java/v1.0.5-01](https://github.com/github/copilot-sdk/releases/tag/java/v1.0.5-01) (2026-07-01) ### Feature: new session options — citations, agent exclusions, and credit limits Three new options are available on `SessionConfig` and `ResumeSessionConfig`. `enableCitations` (experimental) enables native model citations for supported providers; `excludedBuiltInAgents` hides named built-in agents from discovery; and `sessionLimits` sets a per-session AI-credit budget. ([#1865](https://github.com/github/copilot-sdk/pull/1865)) ```java SessionConfig config = new SessionConfig() .setEnableCitations(true) .setExcludedBuiltInAgents(List.of("copilot")) .setSessionLimits(new SessionLimitsConfig(100.0)); ``` ### New contributors - @coleflennikenmsft made their first contribution in [#1854](https://github.com/github/copilot-sdk/pull/1854) - @szabta89 made their first contribution in [#1856](https://github.com/github/copilot-sdk/pull/1856) ## [v1.0.5](https://github.com/github/copilot-sdk/releases/tag/v1.0.5) (2026-07-01) ### Feature: MCP OAuth host token handlers SDK applications can now handle OAuth challenges from MCP servers that require host-provided authentication. Register an `onMcpAuthRequest` callback on the session config and the SDK will invoke it whenever an MCP server responds with a `401 WWW-Authenticate` challenge; return an access token (or cancel the request). Supports initial auth, refresh, reauth, and upscope flows across all SDKs. ([#1669](https://github.com/github/copilot-sdk/pull/1669)) ```ts const session = await client.createSession({ onMcpAuthRequest: async (request) => ({ accessToken: await myIdentityProvider.getToken(request.serverUrl), }), }); ``` ```cs var session = await client.CreateSessionAsync(new SessionConfig { OnMcpAuthRequest = async ctx => McpAuthResult.FromToken(new McpAuthToken { AccessToken = await myIdentityProvider.GetTokenAsync(ctx.ServerUrl) }), }); ``` ### Feature: session options for citations, excluded agents, and spending limits Three additional session configuration options are now available across all SDKs. ([#1865](https://github.com/github/copilot-sdk/pull/1865)) ```ts const session = await client.createSession({ enableCitations: true, excludedBuiltinAgents: ["github-search"], sessionLimits: { maxAiCredits: 10 }, }); ``` ```cs var session = await client.CreateSessionAsync(new SessionConfig { EnableCitations = true, ExcludedBuiltInAgents = ["github-search"], SessionLimits = new SessionLimitsConfig { MaxAiCredits = 10 }, }); ``` ### Other changes - improvement: **[All SDKs]** rename BYOK callback field `getBearerToken` → `bearerTokenProvider`; add `sessionId` to `ProviderTokenArgs` for per-session token scoping ([#1796](https://github.com/github/copilot-sdk/pull/1796)) - bugfix: **[Node]** fix MCP OAuth `registerInterest` sent before `session.resume`, causing "Session not found" errors when resuming a session with `onMcpAuthRequest` ([#1861](https://github.com/github/copilot-sdk/pull/1861)) - feature: **[Java]** `@CopilotTool` and `@CopilotToolParam` annotations with compile-time annotation processor for ergonomic tool registration via `ToolDefinition.fromObject()` ([#1792](https://github.com/github/copilot-sdk/pull/1792), [#1838](https://github.com/github/copilot-sdk/pull/1838)) - feature: **[Java]** `ToolInvocation` parameter injection in `@CopilotTool` methods for accessing session context without exposing it to the LLM schema ([#1832](https://github.com/github/copilot-sdk/pull/1832)) - feature: **[Rust]** add 9 GitHub-anchored variants to `Attachment` enum (`GitHubCommit`, `GitHubRelease`, `GitHubActionsJob`, `GitHubRepository`, `GitHubFileDiff`, `GitHubTreeComparison`, `GitHubUrl`, `GitHubFile`, `GitHubSnippet`) ([#1823](https://github.com/github/copilot-sdk/pull/1823)) ### New contributors - @pallaviraiturkar0 made their first contribution in [#1823](https://github.com/github/copilot-sdk/pull/1823) - @roji made their first contribution in [#1827](https://github.com/github/copilot-sdk/pull/1827) ## [java/v1.0.4](https://github.com/github/copilot-sdk/releases/tag/java/v1.0.4) (2026-06-25) ### Feature: HTTP request callback support Register a `CopilotRequestHandler` on the client to intercept every outbound LLM inference HTTP or WebSocket request — for both BYOK and CAPI — and mutate, replace, or fully forward it. Useful for logging, header injection, model substitution, or custom routing. ([#1689](https://github.com/github/copilot-sdk/pull/1689), [#1775](https://github.com/github/copilot-sdk/pull/1775), [#1784](https://github.com/github/copilot-sdk/pull/1784)) ```java final class MyHandler extends CopilotRequestHandler { @Override protected HttpResponse sendRequest(HttpRequest request, CopilotRequestContext ctx) throws Exception { HttpRequest mutated = HttpRequest.newBuilder(request, (n, v) -> true) .header("X-Debug-Session", ctx.sessionId() == null ? "none" : ctx.sessionId()) .build(); return super.sendRequest(mutated, ctx); } } CopilotClient client = new CopilotClient( new CopilotClientOptions().setRequestHandler(new MyHandler())); ``` ### Feature: `getBearerToken` callback for BYOK providers (Managed Identity) BYOK provider configs now accept a `getBearerToken` callback so the SDK consumer can resolve bearer tokens (e.g. Azure Managed Identity) on demand. The SDK takes zero Azure SDK dependency — the consumer supplies the callback using any identity library. ([#1748](https://github.com/github/copilot-sdk/pull/1748)) ```java var provider = new ProviderConfig() .setType("openai") .setBaseUrl(baseUrl) .setGetBearerToken(args -> cred.getToken(ctx).map(AccessToken::getToken).toFuture()); ``` ### Feature: experimental multi-provider BYOK registry Register multiple named providers and models on a single session via `NamedProviderConfig` and `ProviderModelConfig`. Custom agents can reference provider-qualified model IDs such as `"alpha/sonnet"`. This feature is experimental. ([#1718](https://github.com/github/copilot-sdk/pull/1718)) ### Feature: `preamble` system message section and `preserve` action Two new customization options for system message sections. `SystemMessageSections.PREAMBLE` targets only the identity preamble without affecting its sibling sub-sections (`identity` and `tool_instructions` are now documented as section groups). The new `preserve` action protects an individually-addressable section from a group-level `remove`. ([#1713](https://github.com/github/copilot-sdk/pull/1713)) ### Other changes - feature: add optional `memory` configuration (`MemoryConfiguration`) to session create and resume ([#1617](https://github.com/github/copilot-sdk/pull/1617)) - feature: `defer` parameter on tool definitions controls eager vs. lazy tool loading (`"auto"` or `"never"`) ([#1632](https://github.com/github/copilot-sdk/pull/1632)) - feature: `otlpProtocol` telemetry option for configuring OTLP export transport (`"http/json"` or `"http/protobuf"`) ([#1648](https://github.com/github/copilot-sdk/pull/1648)) - feature: `ModelBilling.tokenPrices` surfaced on public SDK types, exposing per-tier pricing and context window limits ([#1633](https://github.com/github/copilot-sdk/pull/1633)) - feature: `CapiSessionOptions.enableWebSocketResponses` and `ProviderConfig.transport` for WebSocket transport control on session create/resume ([#1711](https://github.com/github/copilot-sdk/pull/1711)) - improvement: call `runtime.shutdown` during client stop for deterministic OTEL telemetry flush before process cleanup ([#1667](https://github.com/github/copilot-sdk/pull/1667)) - improvement: rename `SystemPromptSections` → `SystemMessageSections` for cross-SDK consistency; old class deprecated with `forRemoval=true` ([#1683](https://github.com/github/copilot-sdk/pull/1683)) ### New contributors - @almaleksia made their first contribution in [#1632](https://github.com/github/copilot-sdk/pull/1632) - @dereklegenzoff made their first contribution in [#1711](https://github.com/github/copilot-sdk/pull/1711) - @ellismg made their first contribution in [#1750](https://github.com/github/copilot-sdk/pull/1750) ## [v1.0.2](https://github.com/github/copilot-sdk/releases/tag/v1.0.2) (2026-06-18) ### Feature: opt-in memory for sessions Sessions can now be configured with persistent memory, allowing the agent to recall information across turns. Set `memory: { enabled: true }` when creating or resuming a session; when omitted the runtime default applies. ([#1617](https://github.com/github/copilot-sdk/pull/1617)) ```ts const session = await client.createSession({ memory: { enabled: true }, }); ``` ```cs var session = await client.CreateSessionAsync(new SessionConfig { Memory = new MemoryConfiguration { Enabled = true } }); ``` ### Feature: `defer` parameter for tool definitions Tools now support a `defer` option controlling whether they are pre-loaded eagerly or surfaced lazily through tool search. Use `"auto"` (the default) to allow lazy loading, or `"never"` to force pre-loading. ([#1632](https://github.com/github/copilot-sdk/pull/1632)) ```ts defineTool("lookup_issue", { description: "Fetch issue details", parameters: z.object({ id: z.string() }), defer: "auto", handler: async ({ id }) => { /* ... */ }, }); ``` ```cs var tool = CopilotTool.DefineTool( async ([Description("Issue ID")] string id) => { /* ... */ }, toolOptions: new CopilotToolOptions { Defer = CopilotToolDefer.Auto }); ``` ### Other changes - feature: **[All SDKs]** add `otlpProtocol` telemetry option (`"http/json"` or `"http/protobuf"`) for configuring OTLP export transport ([#1648](https://github.com/github/copilot-sdk/pull/1648)) - feature: **[All SDKs]** surface `ModelBilling.tokenPrices` on public SDK types, exposing per-tier input/output/cache pricing and context window limits ([#1633](https://github.com/github/copilot-sdk/pull/1633)) - improvement: **[All SDKs]** call `runtime.shutdown` during normal client stop for deterministic OTEL telemetry flush before process cleanup ([#1667](https://github.com/github/copilot-sdk/pull/1667)) - improvement: **[Go]** thread `context.Context` through the JSON-RPC request path for proper cancellation support ([#1643](https://github.com/github/copilot-sdk/pull/1643)) - improvement: **[Java]** add `getOpenCanvases()` to `CopilotSession` to track currently open canvas instances, matching the other SDKs ([#1606](https://github.com/github/copilot-sdk/pull/1606)) - improvement: **[Java]** rename `SystemPromptSections` to `SystemMessageSections` for cross-SDK consistency; old class deprecated with `forRemoval=true` ([#1683](https://github.com/github/copilot-sdk/pull/1683)) - bugfix: **[Python]** round sub-millisecond durations in `to_timedelta_int` to avoid serialization errors ([#1668](https://github.com/github/copilot-sdk/pull/1668)) - bugfix: **[Rust]** skip CLI binary download in `build.rs` when `DOCS_RS` env var is set ([#1660](https://github.com/github/copilot-sdk/pull/1660)) ### New contributors - @andyfeller made their first contribution in [#1631](https://github.com/github/copilot-sdk/pull/1631) - @almaleksia made their first contribution in [#1632](https://github.com/github/copilot-sdk/pull/1632) - @idryzhov made their first contribution in [#1668](https://github.com/github/copilot-sdk/pull/1668) - @scottaddie made their first contribution in [#1636](https://github.com/github/copilot-sdk/pull/1636) ## [v0.2.2](https://github.com/github/copilot-sdk/releases/tag/v0.2.2) (2026-04-10) ### Feature: `enableConfigDiscovery` for automatic MCP and skill config loading Set `enableConfigDiscovery: true` when creating a session to let the runtime automatically discover MCP server configurations (`.mcp.json`, `.vscode/mcp.json`) and skill directories from the working directory. Discovered settings are merged with any explicitly provided values; explicit values take precedence on name collision. ([#1044](https://github.com/github/copilot-sdk/pull/1044)) ```ts const session = await client.createSession({ enableConfigDiscovery: true, }); ``` ```cs var session = await client.CreateSessionAsync(new SessionConfig { EnableConfigDiscovery = true, }); ``` - Python: `await client.create_session(enable_config_discovery=True)` - Go: `client.CreateSession(ctx, &copilot.SessionConfig{EnableConfigDiscovery: ptr(true)})` ## [v0.2.1](https://github.com/github/copilot-sdk/releases/tag/v0.2.1) (2026-04-03) ### Feature: commands and UI elicitation across all four SDKs Register slash commands that CLI users can invoke and drive interactive input dialogs from any SDK language. This feature was previously Node.js-only; it now ships in Python, Go, and .NET as well. ([#906](https://github.com/github/copilot-sdk/pull/906), [#908](https://github.com/github/copilot-sdk/pull/908), [#960](https://github.com/github/copilot-sdk/pull/960)) ```ts const session = await client.createSession({ onPermissionRequest: approveAll, commands: [{ name: "summarize", description: "Summarize the conversation", handler: async (context) => { /* ... */ }, }], onElicitationRequest: async (context) => { if (context.type === "confirm") return { action: "confirm" }; }, }); // Drive dialogs from the session const confirmed = await session.ui.confirm({ message: "Proceed?" }); const choice = await session.ui.select({ message: "Pick one", options: ["A", "B"] }); ``` ```cs var session = await client.CreateSessionAsync(new SessionConfig { OnPermissionRequest = PermissionHandler.ApproveAll, Commands = [ new CommandDefinition { Name = "summarize", Description = "Summarize the conversation", Handler = async (context) => { /* ... */ }, } ], }); // Drive dialogs from the session var confirmed = await session.Ui.ConfirmAsync(new ConfirmOptions { Message = "Proceed?" }); ``` > **⚠️ Breaking change (Node.js):** The `onElicitationRequest` handler signature changed from two arguments (`request, invocation`) to a single `ElicitationContext` that combines both. Update callers to use `context.sessionId` and `context.message` directly. ### Feature: `session.getMetadata` across all SDKs Efficiently fetch metadata for a single session by ID without listing all sessions. Returns `undefined`/`null` (not an error) when the session is not found. ([#899](https://github.com/github/copilot-sdk/pull/899)) - TypeScript: `const meta = await client.getSessionMetadata(sessionId);` - C#: `var meta = await client.GetSessionMetadataAsync(sessionId);` - Python: `meta = await client.get_session_metadata(session_id)` - Go: `meta, err := client.GetSessionMetadata(ctx, sessionID)` ### Feature: `sessionFs` for virtualizing per-session storage (Node SDK) Supply a custom `sessionFs` adapter in Node SDK session config to redirect the runtime's per-session storage (event log, large output files) to any backing store — useful for serverless deployments or custom persistence layers. ([#917](https://github.com/github/copilot-sdk/pull/917)) ### Other changes - bugfix: structured tool results (with `toolTelemetry`, `resultType`, etc.) now sent via RPC as objects instead of being stringified, preserving metadata for Node, Go, and Python SDKs ([#970](https://github.com/github/copilot-sdk/pull/970)) - feature: **[Python]** `CopilotClient` and `CopilotSession` now support `async with` for automatic resource cleanup ([#475](https://github.com/github/copilot-sdk/pull/475)) - improvement: **[Python]** `copilot.types` module removed; import types directly from `copilot` ([#871](https://github.com/github/copilot-sdk/pull/871)) - improvement: **[Python]** `workspace_path` now accepts any `os.PathLike` and `session.workspace_path` returns a `pathlib.Path` ([#901](https://github.com/github/copilot-sdk/pull/901)) - improvement: **[Go]** simplified `rpc` package API: renamed structs drop the redundant `Rpc` infix (e.g. `ModelRpcApi` → `ModelApi`) ([#905](https://github.com/github/copilot-sdk/pull/905)) - fix: **[Go]** `Session.SetModel` now takes a pointer for optional options instead of a variadic argument ([#904](https://github.com/github/copilot-sdk/pull/904)) ### New contributors - @Sumanth007 made their first contribution in [#475](https://github.com/github/copilot-sdk/pull/475) - @jongalloway made their first contribution in [#957](https://github.com/github/copilot-sdk/pull/957) - @Morabbin made their first contribution in [#970](https://github.com/github/copilot-sdk/pull/970) - @schneidafunk made their first contribution in [#998](https://github.com/github/copilot-sdk/pull/998) ## [v0.2.0](https://github.com/github/copilot-sdk/releases/tag/v0.2.0) (2026-03-20) This is a big update with a broad round of API refinements, new capabilities, and cross-SDK consistency improvements that have shipped incrementally through preview releases since v0.1.32. ## Highlights ### Fine-grained system prompt customization A new `"customize"` mode for `systemMessage` lets you surgically edit individual sections of the Copilot system prompt — without replacing the entire thing. Ten sections are configurable: `identity`, `tone`, `tool_efficiency`, `environment_context`, `code_change_rules`, `guidelines`, `safety`, `tool_instructions`, `custom_instructions`, and `last_instructions`. Each section supports four static actions (`replace`, `remove`, `append`, `prepend`) and a `transform` callback that receives the current rendered content and returns modified text — useful for regex mutations, conditional edits, or logging what the prompt contains. ([#816](https://github.com/github/copilot-sdk/pull/816)) ```ts const session = await client.createSession({ onPermissionRequest: approveAll, systemMessage: { mode: "customize", sections: { identity: { action: (current) => current.replace("GitHub Copilot", "Acme Assistant"), }, tone: { action: "replace", content: "Be concise and professional." }, code_change_rules: { action: "remove" }, }, }, }); ``` ```cs var session = await client.CreateSessionAsync(new SessionConfig { OnPermissionRequest = PermissionHandler.ApproveAll, SystemMessage = new SystemMessageConfig { Mode = SystemMessageMode.Customize, Sections = new Dictionary { ["identity"] = new() { Transform = current => Task.FromResult(current.Replace("GitHub Copilot", "Acme Assistant")), }, ["tone"] = new() { Action = SectionOverrideAction.Replace, Content = "Be concise and professional." }, ["code_change_rules"] = new() { Action = SectionOverrideAction.Remove }, }, }, }); ``` ### OpenTelemetry support across all SDKs All four SDK languages now support distributed tracing with the Copilot CLI. Set `telemetry` in your client options to configure an OTLP exporter; W3C trace context is automatically propagated on `session.create`, `session.resume`, and `session.send`, and restored in tool handlers so tool execution is linked to the originating trace. ([#785](https://github.com/github/copilot-sdk/pull/785)) ```ts const client = new CopilotClient({ telemetry: { otlpEndpoint: "http://localhost:4318", sourceName: "my-app", }, }); ``` ```cs var client = new CopilotClient(new CopilotClientOptions { Telemetry = new TelemetryConfig { OtlpEndpoint = "http://localhost:4318", SourceName = "my-app", }, }); ``` - Python: `CopilotClient(SubprocessConfig(telemetry={"otlp_endpoint": "http://localhost:4318", "source_name": "my-app"}))` - Go: `copilot.NewClient(&copilot.ClientOptions{Telemetry: &copilot.TelemetryConfig{OTLPEndpoint: "http://localhost:4318", SourceName: "my-app"}})` ### Blob attachments for inline binary data A new `blob` attachment type lets you send images or other binary content directly to a session without writing to disk — useful when data is already in memory (screenshots, API responses, generated images). ([#731](https://github.com/github/copilot-sdk/pull/731)) ```ts await session.send({ prompt: "What's in this image?", attachments: [{ type: "blob", data: base64Str, mimeType: "image/png" }], }); ``` ```cs await session.SendAsync(new MessageOptions { Prompt = "What's in this image?", Attachments = [new UserMessageDataAttachmentsItemBlob { Data = base64Str, MimeType = "image/png" }], }); ``` ### Pre-select a custom agent at session creation You can now specify which custom agent should be active when a session starts, eliminating the need for a separate `session.rpc.agent.select()` call. ([#722](https://github.com/github/copilot-sdk/pull/722)) ```ts const session = await client.createSession({ customAgents: [ { name: "researcher", prompt: "You are a research assistant." }, { name: "editor", prompt: "You are a code editor." }, ], agent: "researcher", onPermissionRequest: approveAll, }); ``` ```cs var session = await client.CreateSessionAsync(new SessionConfig { CustomAgents = [ new CustomAgentConfig { Name = "researcher", Prompt = "You are a research assistant." }, new CustomAgentConfig { Name = "editor", Prompt = "You are a code editor." }, ], Agent = "researcher", OnPermissionRequest = PermissionHandler.ApproveAll, }); ``` --- ## New features - **`skipPermission` on tool definitions** — Tools can now be registered with `skipPermission: true` to bypass the confirmation prompt for low-risk operations like read-only queries. Available in all four SDKs. ([#808](https://github.com/github/copilot-sdk/pull/808)) - **`reasoningEffort` when switching models** — All SDKs now accept an optional `reasoningEffort` parameter in `setModel()` for models that support it. ([#712](https://github.com/github/copilot-sdk/pull/712)) - **Custom model listing for BYOK** — Applications using bring-your-own-key providers can supply `onListModels` in client options to override `client.listModels()` with their own model list. ([#730](https://github.com/github/copilot-sdk/pull/730)) - **`no-result` permission outcome** — Permission handlers can now return `"no-result"` so extensions can attach to sessions without actively answering permission requests. ([#802](https://github.com/github/copilot-sdk/pull/802)) - **`SessionConfig.onEvent` catch-all** — A new `onEvent` handler on session config is registered *before* the RPC is issued, guaranteeing that early events like `session.start` are never dropped. ([#664](https://github.com/github/copilot-sdk/pull/664)) - **Node.js CJS compatibility** — The Node.js SDK now ships both ESM and CJS builds, fixing crashes in VS Code extensions and other tools bundled with esbuild's `format: "cjs"`. No changes needed in consumer code. ([#546](https://github.com/github/copilot-sdk/pull/546)) - **Experimental API annotations** — APIs marked experimental in the schema (agent, fleet, compaction groups) are now annotated in all four SDKs: `[Experimental]` in C#, `/** @experimental */` in TypeScript, and comments in Python and Go. ([#875](https://github.com/github/copilot-sdk/pull/875)) - **System notifications and session log APIs** — Updated to match the latest CLI runtime, adding `system.notification` events and a session log RPC API. ([#737](https://github.com/github/copilot-sdk/pull/737)) ## Improvements - **[.NET, Go]** Serialize event dispatch so handlers are invoked in registration order with no concurrent calls ([#791](https://github.com/github/copilot-sdk/pull/791)) - **[Go]** Detach CLI process lifespan from the context passed to `Client.Start` so cancellation no longer kills the child process ([#689](https://github.com/github/copilot-sdk/pull/689)) - **[Go]** Stop RPC client logging expected EOF errors ([#609](https://github.com/github/copilot-sdk/pull/609)) - **[.NET]** Emit XML doc comments from schema descriptions in generated RPC code ([#724](https://github.com/github/copilot-sdk/pull/724)) - **[.NET]** Use lazy property initialization in generated RPC classes ([#725](https://github.com/github/copilot-sdk/pull/725)) - **[.NET]** Add `DebuggerDisplay` attribute to `SessionEvent` for easier debugging ([#726](https://github.com/github/copilot-sdk/pull/726)) - **[.NET]** Optional RPC params are now represented as optional method params for forward-compatible generated code ([#733](https://github.com/github/copilot-sdk/pull/733)) - **[.NET]** Replace `Task.WhenAny` + `Task.Delay` timeout pattern with `.WaitAsync(TimeSpan)` ([#805](https://github.com/github/copilot-sdk/pull/805)) - **[.NET]** Add NuGet package icon ([#688](https://github.com/github/copilot-sdk/pull/688)) - **[Node]** Don't resolve `cliPath` when `cliUrl` is already set ([#787](https://github.com/github/copilot-sdk/pull/787)) ## New RPC methods We've added low-level RPC methods to control a lot more of what's going on in the session. These are emerging APIs that don't yet have friendly wrappers, and some may be flagged as experimental or subject to change. - `session.rpc.skills.list()`, `.enable(name)`, `.disable(name)`, `.reload()` - `session.rpc.mcp.list()`, `.enable(name)`, `.disable(name)`, `.reload()` - `session.rpc.extensions.list()`, `.enable(name)`, `.disable(name)`, `.reload()` - `session.rpc.plugins.list()` - `session.rpc.ui.elicitation(...)` — structured user input - `session.rpc.shell.exec(command)`, `.kill(pid)` - `session.log(message, level, ephemeral)` In an forthcoming update, we'll add friendlier wrappers for these. ## Bug fixes - **[.NET]** Fix `SessionEvent.ToJson()` failing for events with `JsonElement`-backed payloads (`assistant.message`, `tool.execution_start`, etc.) ([#868](https://github.com/github/copilot-sdk/pull/868)) - **[.NET]** Add fallback `TypeInfoResolver` for `StreamJsonRpc.RequestId` to fix NativeAOT compatibility ([#783](https://github.com/github/copilot-sdk/pull/783)) - **[.NET]** Fix codegen for discriminated unions nested within other types ([#736](https://github.com/github/copilot-sdk/pull/736)) - **[.NET]** Handle unknown session event types gracefully instead of throwing ([#881](https://github.com/github/copilot-sdk/pull/881)) --- ## ⚠️ Breaking changes ### All SDKs - **`autoRestart` removed** — The `autoRestart` option has been deprecated across all SDKs (it was never fully implemented). The property still exists but has no effect and will be removed in a future release. Remove any references to `autoRestart` from your client options. ([#803](https://github.com/github/copilot-sdk/pull/803)) ### Python The Python SDK received a significant API surface overhaul in this release, replacing loosely-typed `TypedDict` config objects with proper keyword arguments and dataclasses. These changes improve IDE autocompletion, type safety, and readability. - **`CopilotClient` constructor redesigned** — The `CopilotClientOptions` TypedDict has been replaced by two typed config dataclasses. ([#793](https://github.com/github/copilot-sdk/pull/793)) ```python # Before (v0.1.x) client = CopilotClient({"cli_url": "localhost:3000"}) client = CopilotClient({"cli_path": "/usr/bin/copilot", "log_level": "debug"}) # After (v0.2.0) client = CopilotClient(ExternalServerConfig(url="localhost:3000")) client = CopilotClient(SubprocessConfig(cli_path="/usr/bin/copilot", log_level="debug")) ``` - **`create_session()` and `resume_session()` now take keyword arguments** instead of a `SessionConfig` / `ResumeSessionConfig` TypedDict. `on_permission_request` is now a required keyword argument. ([#587](https://github.com/github/copilot-sdk/pull/587)) ```python # Before session = await client.create_session({ "on_permission_request": PermissionHandler.approve_all, "model": "gpt-4.1", }) # After session = await client.create_session( on_permission_request=PermissionHandler.approve_all, model="gpt-4.1", ) ``` - **`send()` and `send_and_wait()` take a positional `prompt` string** instead of a `MessageOptions` TypedDict. Attachments and mode are now keyword arguments. ([#814](https://github.com/github/copilot-sdk/pull/814)) ```python # Before await session.send({"prompt": "Hello!"}) await session.send_and_wait({"prompt": "What is 2+2?"}) # After await session.send("Hello!") await session.send_and_wait("What is 2+2?") ``` - **`MessageOptions`, `SessionConfig`, and `ResumeSessionConfig` removed from public API** — These TypedDicts are no longer exported. Use the new keyword-argument signatures directly. ([#587](https://github.com/github/copilot-sdk/pull/587), [#814](https://github.com/github/copilot-sdk/pull/814)) - **Internal modules renamed to private** — `copilot.jsonrpc`, `copilot.sdk_protocol_version`, and `copilot.telemetry` are now `copilot._jsonrpc`, `copilot._sdk_protocol_version`, and `copilot._telemetry`. If you were importing from these modules directly, update your imports. ([#884](https://github.com/github/copilot-sdk/pull/884)) - **Typed overloads for `CopilotClient.on()`** — Event registration now uses typed overloads for better autocomplete. This shouldn't break existing code but changes the type signature. ([#589](https://github.com/github/copilot-sdk/pull/589)) ### Go - **`Client.Start()` context no longer kills the CLI process** — Previously, canceling the `context.Context` passed to `Start()` would terminate the spawned CLI process (it used `exec.CommandContext`). Now the CLI process lifespan is independent of that context — call `client.Stop()` or `client.ForceStop()` to shut it down. ([#689](https://github.com/github/copilot-sdk/pull/689)) - **`LogOptions.Ephemeral` changed from `bool` to `*bool`** — This enables proper three-state semantics (unset/true/false). Use `copilot.Bool(true)` instead of a bare `true`. ([#827](https://github.com/github/copilot-sdk/pull/827)) ```go // Before session.Log(ctx, copilot.LogOptions{Level: copilot.LevelInfo, Ephemeral: true}, "message") // After session.Log(ctx, copilot.LogOptions{Level: copilot.LevelInfo, Ephemeral: copilot.Bool(true)}, "message") ``` ## [v0.1.32](https://github.com/github/copilot-sdk/releases/tag/v0.1.32) (2026-03-07) ### Feature: backward compatibility with v2 CLI servers SDK applications written against the v3 API now also work when connected to a v2 CLI server, with no code changes required. The SDK detects the server's protocol version and automatically adapts v2 `tool.call` and `permission.request` messages into the same user-facing handlers used by v3. ([#706](https://github.com/github/copilot-sdk/pull/706)) ```ts const session = await client.createSession({ tools: [myTool], // unchanged — works with v2 and v3 servers onPermissionRequest: approveAll, }); ``` ```cs var session = await client.CreateSessionAsync(new SessionConfig { Tools = [myTool], // unchanged — works with v2 and v3 servers OnPermissionRequest = approveAll, }); ``` ## [v0.1.31](https://github.com/github/copilot-sdk/releases/tag/v0.1.31) (2026-03-07) ### Feature: multi-client tool and permission broadcasts (protocol v3) The SDK now uses protocol version 3, where the runtime broadcasts `external_tool.requested` and `permission.requested` as session events to all connected clients. This enables multi-client architectures where different clients contribute different tools, or where multiple clients observe the same permission prompts — if one client approves, all clients see the result. Your existing tool and permission handler code is unchanged. ([#686](https://github.com/github/copilot-sdk/pull/686)) ```ts // Two clients each register different tools; the agent can use both const session1 = await client1.createSession({ tools: [defineTool("search", { handler: doSearch })], onPermissionRequest: approveAll, }); const session2 = await client2.resumeSession(session1.id, { tools: [defineTool("analyze", { handler: doAnalyze })], onPermissionRequest: approveAll, }); ``` ```cs var session1 = await client1.CreateSessionAsync(new SessionConfig { Tools = [AIFunctionFactory.Create(DoSearch, "search")], OnPermissionRequest = PermissionHandlers.ApproveAll, }); var session2 = await client2.ResumeSessionAsync(session1.Id, new ResumeSessionConfig { Tools = [AIFunctionFactory.Create(DoAnalyze, "analyze")], OnPermissionRequest = PermissionHandlers.ApproveAll, }); ``` ### Feature: strongly-typed `PermissionRequestResultKind` for .NET and Go Rather than comparing `result.Kind` against undiscoverable magic strings like `"approved"` or `"denied-interactively-by-user"`, .NET and Go now provide typed constants. Node and Python already had typed unions for this; this brings full parity. ([#631](https://github.com/github/copilot-sdk/pull/631)) ```cs session.OnPermissionCompleted += (e) => { if (e.Result.Kind == PermissionRequestResultKind.Approved) { /* ... */ } if (e.Result.Kind == PermissionRequestResultKind.DeniedInteractivelyByUser) { /* ... */ } }; ``` ```go // Go: PermissionKindApproved, PermissionKindDeniedByRules, // PermissionKindDeniedCouldNotRequestFromUser, PermissionKindDeniedInteractivelyByUser if result.Kind == copilot.PermissionKindApproved { /* ... */ } ``` ### Other changes - feature: **[Python]** **[Go]** add `get_last_session_id()` / `GetLastSessionID()` for SDK-wide parity (was already available in Node and .NET) ([#671](https://github.com/github/copilot-sdk/pull/671)) - improvement: **[Python]** add `timeout` parameter to generated RPC methods, allowing callers to override the default 30s timeout for long-running operations ([#681](https://github.com/github/copilot-sdk/pull/681)) - bugfix: **[Go]** `PermissionRequest` fields are now properly typed (`ToolName`, `Diff`, `Path`, etc.) instead of a generic `Extra map[string]any` catch-all ([#685](https://github.com/github/copilot-sdk/pull/685)) ## [v0.1.30](https://github.com/github/copilot-sdk/releases/tag/v0.1.30) (2026-03-03) ### Feature: support overriding built-in tools Applications can now override built-in tools such as `grep`, `edit_file`, or `read_file`. To do this, register a custom tool with the same name and set the override flag. Without the flag, the runtime will return an error if the name clashes with a built-in. ([#636](https://github.com/github/copilot-sdk/pull/636)) ```ts import { defineTool } from "@github/copilot-sdk"; const session = await client.createSession({ tools: [defineTool("grep", { overridesBuiltInTool: true, handler: async (params) => `CUSTOM_GREP_RESULT: ${params.query}`, })], onPermissionRequest: approveAll, }); ``` ```cs var grep = AIFunctionFactory.Create( ([Description("Search query")] string query) => $"CUSTOM_GREP_RESULT: {query}", "grep", "Custom grep implementation", new AIFunctionFactoryOptions { AdditionalProperties = new ReadOnlyDictionary( new Dictionary { ["is_override"] = true }) }); ``` ### Feature: simpler API for changing model mid-session While `session.rpc.model.switchTo()` already worked, there is now a convenience method directly on the session object. ([#621](https://github.com/github/copilot-sdk/pull/621)) - TypeScript: `await session.setModel("gpt-4.1")` - C#: `await session.SetModelAsync("gpt-4.1")` - Python: `await session.set_model("gpt-4.1")` - Go: `err := session.SetModel(ctx, "gpt-4.1")` ### Other changes - improvement: **[C#]** use event delegate for thread-safe, insertion-ordered event handler dispatch ([#624](https://github.com/github/copilot-sdk/pull/624)) - improvement: **[C#]** deduplicate `OnDisposeCall` and improve implementation ([#626](https://github.com/github/copilot-sdk/pull/626)) - improvement: **[C#]** remove unnecessary `SemaphoreSlim` locks for handler fields ([#625](https://github.com/github/copilot-sdk/pull/625)) - bugfix: **[Python]** correct `PermissionHandler.approve_all` type annotations ([#618](https://github.com/github/copilot-sdk/pull/618)) ### New contributors - @giulio-leone made their first contribution in [#618](https://github.com/github/copilot-sdk/pull/618)