NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #3775 most downloaded on PyPI
Python SDK for GitHub Copilot CLI
Last release today
04 Oct 2026
Ships on a steady schedule
a new release about every 2 weeks
Nearly every release is documented
notes for 37 of 38 stable releases
1 version withdrawn
withdrawn after publishing
8 months old
90 releases · first in 2026
One column per month.
Nothing published for this version
Feature: replace session tools mid-session (experimental)
A live session's client-supplied tools and handlers can now be replaced in a single call without recreating the session. Built-in, MCP, and plugin tools are unaffected; pass an empty list to remove all of this client's tools. (ef04633)
await session.setTools([tool])await session.SetToolsAsync(tools)await session.set_tools([tool])session.SetTools(ctx, tools)session.setTools(tools).get()session.set_tools([tool]).await?Warning
Firewall blocked 2 domainsThe following domains were blocked by the firewall during workflow execution:
api.github.comgithub.com[!TIP]
api.github.com is blocked because GitHub API access uses the built-in GitHub tools by default. Instead of adding api.github.com to network.allowed, use tools.github.mode: gh-proxy for direct pre-authenticated GitHub CLI access without requiring network access to api.github.com:
tools:
github:
mode: gh-proxySee GitHub Tools for more information on gh-proxy mode.
To allow these domains, add them to the network.allowed list in your workflow frontmatter:
network:
allowed:
- defaults
- "api.github.com"
- "github.com"See Network Configuration for more information.
Generated by Release Notes Generator · copilot · auto · 26.9 AIC · ⌖ 5.65 AIC · ⊞ 10.4K
improvement: [C#] add a custom session event JSON converter and updated generated session event types for Copilot CLI 1.0.92-2
Warning
Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
github.comTo allow these domains, add them to the network.allowed list in your workflow frontmatter:
network:
allowed:
- defaults
- "github.com"See Network Configuration for more information.
Generated by Release Notes Generator · copilot · auto · 17.5 AIC · ⌖ 6.05 AIC · ⊞ 10.4K
Full Changelog : v1.0.16...v1.0.17-preview.1
Full Changelog: v1.0.16...v1.0.17-preview.1
Nothing published for this version
Internal dependency updates only: this release refreshes the SDK snapshot for Copilot CLI 1.0.90. It contains no other user-visible SDK changes since
Internal dependency updates only: this release refreshes the SDK snapshot for Copilot CLI 1.0.90. It contains no other user-visible SDK changes since v1.0.15.
Warning
Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
github.comTo allow these domains, add them to the network.allowed list in your workflow frontmatter:
network:
allowed:
- defaults
- "github.com"See Network Configuration for more information.
Generated by Release Notes Generator · copilot · auto · 18.8 AIC · ⌖ 6.11 AIC · ⊞ 10.3K
Internal dependency updates only (SDK snapshot updated for Copilot CLI 1.0.90-6).
Internal dependency updates only (SDK snapshot updated for Copilot CLI 1.0.90-6).
Full Changelog: runtime-1.0.89-1.unstable.r36638597907.ge270afd...v1.0.16-preview.0
Warning
Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
github.comTo allow these domains, add them to the network.allowed list in your workflow frontmatter:
network:
allowed:
- defaults
- "github.com"See Network Configuration for more information.
Generated by Release Notes Generator · copilot · auto · 23.7 AIC · ⌖ 5.81 AIC · ⊞ 10.3K
Feature: typed structured outputs for all six SDKs
Provide a JSON Schema, or use an idiomatic typed helper, to have the model return typed, validated output instead of free-form text. (#2590)
const answerSchema = z.object({ value: z.number().int() });
const answer = await session.sendAndWait("What is 19 + 23?", answerSchema);answer = await session.send_and_wait_typed("What is 19 + 23?", Answer)Go, Java, C#, and Rust get the same capability via copilot.SendAndWait[Answer], session.sendAndWait(prompt, Answer.class), SendAndWaitAsync<Answer>, and session.send_and_wait_typed(prompt).
The raw JSON data payload of a JSON-RPC error response can now be inspected in every SDK, so apps can branch on machine-readable error details. (#2664, #2732)
if let Some(data) = error.rpc_data() { println!("{data}"); }catch (JsonRpcException e) { JsonNode data = e.getData(); }All six SDKs expose a connection-global handler for the runtime's installations.confirm callback, letting apps present a human review before an MCP or Skill installation proceeds. The handler must return an explicit confirm/decline/cancel decision.
const client = new CopilotClient({
installationConfirmationHandler: async (request, context) => promptUser(request),
});Java, Python, Rust, C#, and Go get equivalent options (setInstallationConfirmationHandler, installation_confirmation_handler, with_installation_confirmation_handler, InstallationConfirmationHandler). Java also now exposes typed unions for MCP installation review payloads.
darwin-x64 (#2701)linuxmusl-x64 (Alpine) (#2715)FusionCritic generated diagnostics type@mohamedmansour made their first contribution in #2676@roblourens made their first contribution in #2700Warning
Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
github.comTo allow these domains, add them to the network.allowed list in your workflow frontmatter:
network:
allowed:
- defaults
- "github.com"See Network Configuration for more information.
Generated by Release Notes Generator · copilot · auto · 17.1 AIC · ⌖ 6.46 AIC · ⊞ 9K
Feature: experimental connection-global installation confirmation
All six SDKs now expose a connection-global handler for the runtime's installations.confirm callback, letting apps present a human review before an MCP or Skill installation proceeds. The handler receives the generated request plus a cancellation signal that fires when the review is retired or the connection closes, and must return an explicit confirm/decline/cancel decision — the SDK never infers approval.
const client = new CopilotClient({
installationConfirmationHandler: async (request, context) => {
return await promptUser(request); // "confirm" | "decline" | "cancel"
},
});var options = new CopilotClientOptions
{
InstallationConfirmationHandler = async (request, context) =>
await PromptUserAsync(request, context.CancellationToken),
};opts := copilot.ClientOptions{
InstallationConfirmationHandler: func(ctx context.Context, req *copilot.InstallationConfirmationRequest) (copilot.InstallationConfirmationDecision, error) {
return promptUser(ctx, req)
},
}Java, Python, and Rust get the equivalent setInstallationConfirmationHandler(...), installation_confirmation_handler, and with_installation_confirmation_handler options. Java additionally converts the previously untyped MCP installation/removal review payloads (InstallationConfirmationRequest.review(), McpInstallPlan.transportChoices(), McpInstallationManagementResultOutcome.getOutcome()) into sealed/typed unions, bringing it into line with the other SDKs.
FusionCritic generated diagnostics type for execution-phase model/reasoning-effort trackingWarning
Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
github.comTo allow these domains, add them to the network.allowed list in your workflow frontmatter:
network:
allowed:
- defaults
- "github.com"See Network Configuration for more information.
Generated by Release Notes Generator · copilot · auto · 169.2 AIC · ⌖ 5.87 AIC · ⊞ 9K
Feature: structured JSON-RPC error data in Go, .NET, and Java
Go, .NET, and Java can now inspect the raw JSON data payload of a JSON-RPC error response instead of only its code and message. This mirrors capabilities already available in TypeScript, Python, and Rust, letting apps branch on machine-readable error details. (#2732)
var rpcErr *copilot.RPCError
if errors.As(err, &rpcErr) {
fmt.Printf("RPC error %d: %s\n", rpcErr.Code, rpcErr.Message)
}catch (IOException ex) when (ex.InnerException is RemoteRpcException remote)
{
Console.Error.WriteLine($"RPC error {remote.ErrorCode}: {remote.Message}");
}catch (JsonRpcException e) {
JsonNode data = e.getData();
}Omitted data and explicit JSON null remain distinguishable in all three APIs, and existing error identity, wrapping, and formatting behavior are unchanged.
Warning
Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
github.comTo allow these domains, add them to the network.allowed list in your workflow frontmatter:
network:
allowed:
- defaults
- "github.com"See Network Configuration for more information.
Generated by Release Notes Generator · copilot · auto · 163.2 AIC · ⌖ 6.41 AIC · ⊞ 9K
Internal dependency updates only — this prerelease contains no user-visible SDK changes since v1.0.15-preview.1 . The only changes are automated Copil
Internal dependency updates only — this prerelease contains no user-visible SDK changes since v1.0.15-preview.1. The only changes are automated Copilot CLI snapshot updates for internal testing.
Full Changelog: v1.0.15-preview.1...v1.0.15-preview.2
Warning
Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
github.comTo allow these domains, add them to the network.allowed list in your workflow frontmatter:
network:
allowed:
- defaults
- "github.com"See Network Configuration for more information.
Generated by Release Notes Generator · copilot · auto · 59.3 AIC · ⌖ 8.22 AIC · ⊞ 9K
Internal dependency updates only — this prerelease contains no user-visible SDK changes since v1.0.15-preview.0 . The only changes are automated Copil
Internal dependency updates only — this prerelease contains no user-visible SDK changes since v1.0.15-preview.0. The only changes are automated Copilot CLI snapshot updates for internal testing.
Full Changelog: v1.0.15-preview.0...v1.0.15-preview.1
Warning
Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
github.comTo allow these domains, add them to the network.allowed list in your workflow frontmatter:
network:
allowed:
- defaults
- "github.com"See Network Configuration for more information.
Generated by Release Notes Generator · copilot · auto · 42.6 AIC · ⌖ 5.58 AIC · ⊞ 9K
Feature: typed structured outputs for all six SDKs
Provide a JSON Schema, or use an idiomatic typed helper, to have the model return typed, validated output instead of free-form text. (#2590)
const answerSchema = z.object({ value: z.number().int() });
const answer = await session.sendAndWait("What is 19 + 23?", answerSchema);class Answer(BaseModel):
value: int
answer = await session.send_and_wait_typed("What is 19 + 23?", Answer)var answer = await session.SendAndWaitAsync("What is 19 + 23?");
public sealed record Answer(int Value);Go, Java, and Rust get the same capability via copilot.SendAndWait[Answer], session.sendAndWait(prompt, Answer.class), and session.send_and_wait_typed(prompt) respectively.
copilot::Error now preserves the optional data payload from JSON-RPC errors so callers can inspect machine-readable error details instead of just the message. (#2664)
if let Some(data) = error.rpc_data() {
println!("{data}");
}darwin-x64 (#2701)linuxmusl-x64 (Alpine) (#2715)@roblourens made their first contribution in #2700Warning
Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
github.comTo allow these domains, add them to the network.allowed list in your workflow frontmatter:
network:
allowed:
- defaults
- "github.com"See Network Configuration for more information.
Generated by Release Changelog Generator · copilot · auto · 86.4 AIC · ⌖ 5.24 AIC · ⊞ 9.9K
Feature: typed message provenance for user, system, and agent sources
Messages sent through the SDK can now carry typed source provenance, distinguishing human user input, internal system injections, and identified agent- senders, so recipients can reliably tell agent input from human authorization. (#2573)
await session.send("Looks good to me.", { source: "agent-reviewer" });await session.send("Looks good to me.", source=AgentMessageSource("reviewer"))Sessions using auto model routing can now select the fast tier alongside the existing efficiency, balance, and intelligence tiers, giving integrators a latency-focused routing preset across all six SDKs. (#2669)
await session.setAutoTier("fast");The new managedSettings.clearCache RPC method wipes the persistent server-policy cache and drops the runtime's in-memory retained policy, giving hosts a primitive for a "force refresh account policy" action. (#2438)
await client.rpc.managedSettings.clearCache();await client.Rpc.ManagedSettings.ClearCacheAsync();SessionConfig and ResumeSessionConfig in the Rust SDK now accept an optional allowed_models list, letting hosts restrict which model IDs a session may use without duplicating runtime validation. (#2512)
let config = SessionConfig::default().with_allowed_models(["gpt-4o", "claude-3.7-sonnet"]);max_output_tokens to the model capabilities override, previously unreachable without an unsafe cast (#2569)PackAsTool packages so dotnet pack --no-build produces a working tool (#2557)connection_close callback-quiescence contract consistently across all six in-process C ABI adapters, preventing races with freed callback state during disposal (#2610, #2622)CatalogTrustEligibility unknown value and re-exporting shared session-event types (#2631)anyOf/oneOf handling (#2656)@aurokin made their first contribution in #2573@kondv made their first contribution in #2557@1fanwang made their first contribution in #2569@SamMorrowDrums made their first contribution in #2258@SandraAhlgrimm made their first contribution in #2603@jpbufe3 made their first contribution in #2512Warning
Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
github.comTo allow these domains, add them to the network.allowed list in your workflow frontmatter:
network:
allowed:
- defaults
- "github.com"See Network Configuration for more information.
Generated by Release Changelog Generator · copilot · auto · 73.3 AIC · ⌖ 9 AIC · ⊞ 10.3K
Feature: pause and resume durable factory runs at checkpoints
Agent Factories can now pause deliberately instead of only stopping at hard limits. Call ctx.pause(key) inside a factory body to register a durable, one-shot checkpoint that ends the current attempt; resuming replays the journal and returns from that checkpoint instead of redoing prior work. Callers can also pause a running attempt from outside the factory body. (#2537)
await ctx.step("prepare", prepareInput);
await ctx.pause("review-ready");
await ctx.agent("Review the prepared input");const paused = await session.factory.pause(runId);Warning
Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
github.comTo allow these domains, add them to the network.allowed list in your workflow frontmatter:
network:
allowed:
- defaults
- "github.com"See Network Configuration for more information.
Generated by Release Changelog Generator · copilot · auto · 52.5 AIC · ⌖ 5.57 AIC · ⊞ 10.3K
bugfix: [.NET] fix a vulnerable transitive SourceLink dependency
Sending a message can now declare its source as user, system, or an identified agent (serialized as agent-<id>), so recipients can reliably distinguish human input from system injections and forwarded agent output. Ordinary sends remain unaffected: source stays omitted unless the caller opts in. (#2573)
await session.send({ prompt: "Reviewed and approved.", source: "agent-reviewer" });await session.send(prompt="Reviewed and approved.", source=AgentMessageSource("reviewer"))session.Send(ctx, copilot.SendOptions{Source: copilot.MessageSourceAgent("reviewer")})Source = MessageSource.Agent("reviewer").setSource(MessageSource.agent("reviewer")).with_source(MessageSource::Agent("reviewer".into()))A new managedSettings.clearCache RPC wipes the persistent server-policy cache and drops the runtime's in-memory retained policy, so hosts can wire up a "sync account policy" action (for example VS Code's Developer: Sync Account Policy command). It's available in TypeScript, C#, Python, Go, and Rust; Java support follows once the underlying CLI release is pinned. (#2438)
await client.rpc.managedSettings.clearCache();max_output_tokens on model capability overrides (#2569)PackAsTool publish output so packed tools install correctly (#2557)Warning
Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
github.comTo allow these domains, add them to the network.allowed list in your workflow frontmatter:
network:
allowed:
- defaults
- "github.com"See Network Configuration for more information.
Generated by Release Changelog Generator · copilot · auto · 84.6 AIC · ⌖ 7 AIC · ⊞ 10.3K
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.
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.
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.
ask_user session behaviorSession 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.
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 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.
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.
import { joinSession } from "@github/copilot-sdk/extension";
const session = await joinSession({
requestedEnvironmentVariables: ["GITHUB_TOKEN"],
});
const token = process.env.GITHUB_TOKEN;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:
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.
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.
const session = await client.createSession({
managedSettings: {
permissions: {
disableBypassPermissionsMode: "disable",
deny: ["shell(rm*)"],
ask: ["write"],
},
},
});var session = await client.CreateSessionAsync(new SessionConfig
{
ManagedSettings = new ManagedSettings
{
Permissions = new ManagedSettingsPermissions
{
DisableBypassPermissionsMode = DisableBypassPermissionsMode.Disable,
Deny = ["shell(rm*)"],
Ask = ["write"],
},
},
});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, #2514)
await session.set_auto_tier("efficiency")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, #2496)
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)
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)ClientMode::Empty to no built-in skills (#2410)@lukehoban made their first contribution in #2292@scordio made their first contribution in #2382@OllieinCanada made their first contribution in #2374@gimenete made their first contribution in #2458@gwwar made their first contribution in #2464@Pybsama made their first contribution in #2163@green3sf made their first contribution in #2360@gokhanarkan made their first contribution in #2532Warning
Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
github.comTo allow these domains, add them to the network.allowed list in your workflow frontmatter:
network:
allowed:
- defaults
- "github.com"See Network Configuration for more information.
Generated by Release Changelog Generator · copilot · auto · 125.2 AIC · ⌖ 8.09 AIC · ⊞ 11.7K
Nothing published for this version
Nothing published for this version
Rust breaking change: PermissionResult::Decision changed from a tuple variant to a struct variant ( { decision, context } ). Code using result helpers…
Sessions can now opt into file-change tracking and rewind conversation history and tracked file changes to any prior checkpoint. Enable file tracking when creating a session, then use rewind to roll back. (#2321)
const session = await client.createSession({ enableFileChangeTracking: true });
// ...later
const points = await session.rpc.rewind.list();
await session.rpc.rewind.rewind({ rewindTarget: points[0].id });var session = await client.CreateSessionAsync(new SessionOptions { EnableFileChangeTracking = true });
var points = await session.Rpc.Rewind.ListAsync();
await session.Rpc.Rewind.RewindAsync(new RewindRequest { RewindTarget = points[0].Id });session = await client.create_session(enable_file_change_tracking=True)
points = await session.rpc.rewind.list()
await session.rpc.rewind.rewind(rewind_target=points[0].id)Sessions now support expiry-aware GitHub token callbacks in addition to static tokens. The SDK handles refresh requests from the runtime, so extensions always receive fresh credentials. (#2412)
const session = await client.createSession({
gitHubTokenProvider: async ({ host, reason }) => ({ token: await fetchToken(host) })
});var session = await client.CreateSessionAsync(new SessionOptions {
GitHubTokenProvider = async (req, ct) =>
new GitHubTokenResult { Token = await FetchTokenAsync(req.Host) }
});session, _ := client.CreateSession(ctx, copilot.SessionOptions{
GitHubTokenProvider: func(ctx context.Context, req copilot.TokenProviderRequest) (copilot.TokenProviderResult, error) {
return copilot.TokenProviderResult{Token: fetchToken(req.Host)}, nil
},
})The Java SDK now ships a bundled in-process Copilot CLI runtime for Linux x64/arm64, Windows x64/arm64, and Apple Silicon macOS. No separate CLI installation is needed on these platforms. (#2301, #2393, #2402, #2421, #2427)
The correct native classifier is resolved and loaded automatically at runtime — no configuration needed.
All six SDKs now spawn the dedicated copilot-runtime executable when managing their own subprocess connection, pairing the wrapper with the correct runtime.node addon for a leaner and more reliable process lifecycle. (#2395)
Host applications can now register trusted built-in plugin directories loaded before any session begins. Unlike ordinary --plugin-dir loading, these are registered via plugins.builtin.set and trusted by the host. (#2330)
const client = new CopilotClient({ builtinPluginDirectories: ['/path/to/plugins'] });let client = CopilotClient::new(CopilotClientOptions {
builtin_plugin_directories: vec![PathBuf::from("/path/to/plugins")],
..Default::default()
});Permission handlers can now attach optional decisionContext when replying to a permission request, letting the runtime attribute decisions to a person, host policy, or automated recommendation. Additive for all SDKs except Rust. (#2294)
session.onPermissionRequest(async (req) =>
createAttributedPermissionResult('approve_once', { source: 'policy' })
);async def handler(req):
return copilot.create_attributed_permission_result('approve_once', {'source': 'policy'})Rust breaking change:
PermissionResult::Decisionchanged from a tuple variant to a struct variant ({ decision, context }). Code using result helpers (approve_once()etc.) is unaffected; direct construction or pattern-matching onDecisionrequires migration.
joinSession() now accepts an env option listing the sensitive environment variable names the extension needs. The CLI prompts the user; on approval the values are written into process.env before joinSession resolves. (#2348)
const session = await host.joinSession(extensionId, { env: ['MY_API_KEY'] });ClientMode::Empty now excludes built-in skills by defaultWhen a session is created in empty mode, includedBuiltinSkills defaults to [] across all SDKs. Pass an explicit allowlist to opt individual built-in skills back in. (#2410)
Three improvements to the Agent Factories API in the Node SDK:
argsSchema on a factory so the CLI validates arguments before a run starts (#2315)session.factory.runs.list() supports cursor-based pagination for browsing full run history (#2431)All SDKs expose an askUserVariant option on session create and resume for structured ask-user tool behavior. Omitting it preserves legacy behavior. (#2432)
@lutzroeder made their first contribution in #2330@aymenfurter made their first contribution in #2294@lukehoban made their first contribution in #2292@scordio made their first contribution in #2382@OllieinCanada made their first contribution in #2374Generated by Release Changelog Generator · sonnet46 44.1 AIC · ⌖ 6.59 AIC · ⊞ 8.1K
Feature: rewind support across all SDKs
Sessions can now opt into file-change tracking and conversation rewind. When enableFileChangeTracking is enabled, the session records which files were changed during a conversation turn. You can then list pending rewind points, preview changes, and rewind the conversation history together with any tracked file modifications. (#2321)
const session = await client.createSession({ enableFileChangeTracking: true });
const points = await session.rpc.rewind.listPendingRewindPoints();
await session.rpc.rewind.rewind({ id: points[0].id });var session = await client.CreateSessionAsync(new SessionOptions { EnableFileChangeTracking = true });
var points = await session.Rpc.Rewind.ListPendingRewindPointsAsync();
await session.Rpc.Rewind.RewindAsync(new RewindRequest { Id = points[0].Id });session = await client.create_session(enable_file_change_tracking=True)
points = await session.rpc.rewind.list_pending_rewind_points()
await session.rpc.rewind.rewind(id=points[0].id)Sessions now support a dynamic, expiry-aware GitHub token callback as an alternative to a static gitHubToken. The SDK maps each host request (with host, session, and reason context) to your callback, handling concurrent-session isolation automatically. (#2412)
const session = await client.createSession({
gitHubTokenProvider: async ({ host }) => ({ token: await getToken(host), expiresIn: 3600 }),
});var session = await client.CreateSessionAsync(new SessionOptions
{
GitHubTokenProvider = async (req, ct) =>
new GitHubToken { Token = await GetTokenAsync(req.Host, ct), ExpiresIn = TimeSpan.FromHours(1) }
});session, err := client.CreateSession(ctx, copilot.SessionOptions{
GitHubTokenProvider: func(ctx context.Context, req copilot.GitHubTokenRequest) (copilot.GitHubToken, error) {
return copilot.GitHubToken{Token: getToken(req.Host), ExpiresIn: 3600}, nil
},
})Applications that ship their own built-in plugins can now register a trusted plugin directory at client startup. These plugins are registered with the runtime before any sessions are created, distinct from ordinary --plugin-dir loading. (#2330)
const client = new CopilotClient({ builtInPluginDirectories: ['/path/to/plugins'] });let client = CopilotClient::builder()
.built_in_plugin_directories(vec![PathBuf::from("/path/to/plugins")])
.build()?;Permission handlers can now attach a decisionContext so the runtime can attribute whether a decision came from a person, a host policy, or an automated recommendation. This is additive for TypeScript, C#, Go, Python, and Java. Rust clients that construct PermissionResult::Decision directly must migrate from the tuple variant to the new struct variant. (#2294)
session.onPermissionRequest(async (req) => {
return createAttributedPermissionResult('allow_once', { source: 'host-policy' });
});session.on_permission_request(|req| async move {
PermissionResult::approve_once().with_context(DecisionContext { source: "host-policy".into() })
});ClientMode::Empty now defaults to no built-in skillsWhen creating a session with ClientMode::Empty, built-in skills are now disabled by default. To opt specific skills in, supply an explicit includedBuiltinSkills allowlist. Custom skills via enableSkills and skillDirectories are unaffected. (#2410)
const session = await client.createSession({
clientMode: 'empty',
includedBuiltinSkills: ['grep'],
});The Java SDK now ships a bundled native CLI runtime for Linux x64, Linux ARM64, Windows x64, Windows ARM64, and Apple Silicon macOS. Applications on these platforms no longer need a separately installed Copilot CLI binary. (#2301, #2393, #2402, #2421, #2427)
JsonValue, ctx.agent() forwards agent/reasoningEffort/contextTier (#2309)argsSchema so the CLI validates caller arguments before starting a run (#2315)askUserVariant session option for structured ask-user tool selection (#2432)@lutzroeder made their first contribution in #2330@aymenfurter made their first contribution in #2294@lukehoban made their first contribution in #2292@scordio made their first contribution in #2382@OllieinCanada made their first contribution in #2374Generated by Release Changelog Generator · sonnet46 42.5 AIC · ⌖ 6.48 AIC · ⊞ 8.1K
Feature: rewind support across all SDKs
Sessions can now opt in to file-change tracking so that rewinding restores both conversation history and the files that were modified. Enable it with the new enableFileChangeTracking session option. (#2321)
const session = await client.startSession({ enableFileChangeTracking: true });var session = await client.StartSessionAsync(new SessionOptions { EnableFileChangeTracking = true });session = await client.start_session(enable_file_change_tracking=True)session, _ := client.StartSession(ctx, &copilot.SessionOptions{EnableFileChangeTracking: true})Session session = client.startSession(new SessionOptions().setEnableFileChangeTracking(true)).get();let session = client.start_session(SessionOptions { enable_file_change_tracking: Some(true), ..Default::default() }).await?;Applications can now supply a dynamic GitHub token callback instead of a static gitHubToken string. The runtime calls the callback before each token use, so short-lived tokens stay fresh across long-running sessions. (#2412)
const session = await client.startSession({
gitHubTokenProvider: async ({ host, reason }) => ({ token: await fetchToken(host) })
});var session = await client.StartSessionAsync(new SessionOptions
{
GitHubTokenProvider = async (request, ct) => new GitHubTokenResult(await FetchTokenAsync(request.Host))
});async def token_provider(request):
return GitHubTokenResult(token=await fetch_token(request.host))
session = await client.start_session(github_token_provider=token_provider)session, _ := client.StartSession(ctx, &copilot.SessionOptions{
GitHubTokenProvider: func(ctx context.Context, req copilot.GitHubTokenRequest) (copilot.GitHubTokenResult, error) {
return copilot.GitHubTokenResult{Token: fetchToken(req.Host)}, nil
},
})session = client.startSession(new SessionOptions()
.setGitHubTokenProvider((req, ct) ->
CompletableFuture.completedFuture(new GitHubTokenResult(fetchToken(req.getHost()))))).get();let session = client.start_session(SessionOptions {
github_token_provider: Some(Box::new(|req| Box::pin(async move { Ok(GitHubTokenResult { token: fetch_token(&req.host).await }) }))),
..Default::default()
}).await?;The Java SDK now supports an in-process connection mode that loads the Copilot runtime as a native library via JNA, eliminating the need for a separate CLI child process. Add the platform-specific classifier JAR to your project and use RuntimeConnection.forInProcess(). (#2301, #2393, #2402, #2421, #2427)
CopilotClientOptions options = new CopilotClientOptions()
.setConnection(RuntimeConnection.forInProcess());
CopilotClient client = new CopilotClient(options);
client.start().get();Host applications can now register a set of trusted, host-bundled plugin directories at startup. These directories are registered with plugins.builtin.set before any session is created. (#2330)
ClientMode.Empty defaults to no built-in skillsClientMode.Empty now deny-by-defaults includedBuiltinSkills to [], matching its deny-by-default behavior for all other built-in capabilities. Callers can still pass an explicit allowlist to opt in to specific runtime-bundled skills. (#2410)
Permission handlers can now attach decisionContext to let the runtime attribute decisions (human, policy, or automated recommendation). This is additive for TypeScript, Python, Go, C#, and Java. Rust clients that construct or match PermissionResult::Decision directly must migrate from the tuple variant to the new struct variant. (#2294)
return createAttributedPermissionResult(PermissionDecision.ApproveOnce, context);PermissionResult::Decision { decision: PermissionDecision::ApproveOnce, context: Some(ctx) }Node SDK extensions can now declare which sensitive environment variables they need. The CLI prompts the user and, on approval, injects the granted values before the extension starts. (#2348)
await joinSession({ env: ["MY_API_KEY", "MY_SECRET"] });argsSchema declarationNode SDK factories can now declare an argsSchema so the CLI validates caller arguments before starting a run, saving credits and preventing confusing runtime errors. (#2315)
session.defineFactory("my-factory", { argsSchema: { type: "object", properties: { query: { type: "string" } } } }, async (ctx) => { ... });ctx.agent() now forwards agent, reasoningEffort, and contextTier (#2309)Client is dropped (#2292)@lutzroeder made their first contribution in #2330@aymenfurter made their first contribution in #2294@lukehoban made their first contribution in #2292@scordio made their first contribution in #2382@OllieinCanada made their first contribution in #2374Generated by Release Changelog Generator · sonnet46 33.8 AIC · ⌖ 7.74 AIC · ⊞ 8.1K
Feature: ClientMode::Empty now disables built-in skills by default
ClientMode::Empty now disables built-in skills by defaultClientMode::Empty now applies deny-by-default isolation to runtime-bundled skills in addition to other built-in capabilities. includedBuiltinSkills defaults to [] in Empty mode; pass an explicit allowlist to re-enable specific skills. This behavior is consistent across all six SDKs. (#2410)
// Node — empty mode: built-in skills excluded by default
const session = await client.createSession({ mode: ClientMode.Empty });
// opt back in:
const session = await client.createSession({ mode: ClientMode.Empty, includedBuiltinSkills: ["edit"] });// C#
var session = await client.CreateSessionAsync(new SessionOptions { Mode = ClientMode.Empty });
// opt back in:
var session = await client.CreateSessionAsync(new SessionOptions { Mode = ClientMode.Empty, IncludedBuiltinSkills = ["edit"] });# Python
session = await client.create_session(mode=ClientMode.EMPTY)
# opt back in:
session = await client.create_session(mode=ClientMode.EMPTY, included_builtin_skills=["edit"])// Go
session, err := client.CreateSession(ctx, copilot.SessionOptions{Mode: copilot.ClientModeEmpty})
// opt back in:
session, err := client.CreateSession(ctx, copilot.SessionOptions{Mode: copilot.ClientModeEmpty, IncludedBuiltinSkills: []string{"edit"}})Generated by Release Changelog Generator · sonnet46 28.6 AIC · ⌖ 4.12 AIC · ⊞ 8.1K
Feature: rewind support across all SDKs
Sessions can now opt into file-change tracking and rewind conversation history along with tracked file changes. Enable the new enableFileChangeTracking session option to allow calling rewind later. (#2321)
const session = await client.createSession({ enableFileChangeTracking: true });
// later:
await session.rpc.conversation.rewind({ ...rewindPoint });var session = await client.CreateSessionAsync(new SessionOptions { EnableFileChangeTracking = true });session = await client.create_session(enable_file_change_tracking=True)session, err := client.CreateSession(ctx, copilot.SessionOptions{EnableFileChangeTracking: true})The Java SDK now ships platform-native classifier JARs that load the Copilot runtime directly in-process via JNA — no separate CLI child process required. Currently available for linux-x64, Windows x64, and Apple Silicon macOS. (#2301, #2393, #2402)
CopilotClientOptions options = new CopilotClientOptions()
.setConnection(RuntimeConnection.forInProcess());
CopilotClient client = new CopilotClient(options);
client.start().get();Permission handlers can now attach decisionContext so the runtime can attribute whether a decision came from a person, host policy, or an automated recommendation. This is additive for Node, Python, Go, .NET, and Java. Rust clients that construct or match PermissionResult::Decision directly must migrate to the new struct variant. (#2294)
createAttributedPermissionResult(result, context)copilot.create_attributed_permission_result(result, context)copilot.NewAttributedPermissionResult(result, context)DecisionContext on the permission decisionPermissionRequestResult.approveOnce().setDecisionContext(context)PermissionResult::approve_once().with_context(context)Applications can now register a set of host-bundled plugin directories that are trusted unconditionally and loaded before any user session begins. (#2330)
joinSession() now accepts an env option listing the sensitive environment variable names an extension needs. The CLI prompts the user for approval; if granted, the values are written into the extension's process.env before the session resolves. (#2348)
await joinSession({ env: ['MY_API_KEY', 'MY_SECRET'] });JsonValue, ctx.agent() forwards reasoningEffort and contextTier, resume error union narrowed to codes the runtime raises (#2309)argsSchema on FactoryMeta so the CLI can validate factory arguments before a run starts (#2315)@lutzroeder made their first contribution in #2330@aymenfurter made their first contribution in #2294@lukehoban made their first contribution in #2292@scordio made their first contribution in #2382@OllieinCanada made their first contribution in #2374Generated by Release Changelog Generator · sonnet46 36.8 AIC · ⌖ 4.91 AIC · ⊞ 8.1K
Feature: rewind support across all SDKs
Sessions now support rewinding conversation history and tracked file changes. Enable file-change tracking when creating a session, then rewind to a previous checkpoint to discard later turns and restore file state. (#2321)
const session = await client.createSession({ enableFileChangeTracking: true });
const rewindPoints = await session.rpc.rewind.listRewindPoints();
await session.rpc.rewind.rewind({ rewindPointId: rewindPoints[0].rewindPointId });session = await client.create_session(enable_file_change_tracking=True)
rewind_points = await session.rpc.rewind.list_rewind_points()
await session.rpc.rewind.rewind(rewind_point_id=rewind_points[0].rewind_point_id)session, _ := client.CreateSession(ctx, &copilot.SessionOptions{EnableFileChangeTracking: true})
points, _ := session.RPC.Rewind.ListRewindPoints(ctx)
_ = session.RPC.Rewind.Rewind(ctx, &copilot.RewindRequest{RewindPointId: points[0].RewindPointId})var session = await client.CreateSessionAsync(new SessionOptions { EnableFileChangeTracking = true });
var points = await session.Rpc.Rewind.ListRewindPointsAsync();
await session.Rpc.Rewind.RewindAsync(new RewindRequest { RewindPointId = points[0].RewindPointId });SessionOptions options = new SessionOptions().setEnableFileChangeTracking(true);
var session = client.createSession(options).get();
var points = session.getRpc().getRewind().listRewindPoints().get();
session.getRpc().getRewind().rewind(new RewindRequest().setRewindPointId(points.get(0).getRewindPointId())).get();let session = client.create_session(SessionOptions { enable_file_change_tracking: Some(true), ..Default::default() }).await?;
let points = session.rpc.rewind.list_rewind_points().await?;
session.rpc.rewind.rewind(RewindRequest { rewind_point_id: points[0].rewind_point_id.clone() }).await?;The Java SDK now supports an in-process connection mode on linux-x64 that loads the Copilot runtime as a native library via JNA — no separate CLI child process required. Add the copilot-sdk-java-runtime classifier JAR for your platform alongside the core SDK JAR. (#2301)
CopilotClientOptions options = new CopilotClientOptions()
.setConnection(RuntimeConnection.forInProcess());
CopilotClient client = new CopilotClient(options);
client.start().get();Permission handlers can now attach decisionContext so the runtime can attribute whether a decision came from a person, host policy, or an automated recommendation. This is additive for all SDKs. Note for Rust: PermissionResult::Decision changed from a tuple variant to a struct variant — callers that construct or match it directly must migrate. (#2294)
return createAttributedPermissionResult("allow_once", { source: "user" });return copilot.create_attributed_permission_result("allow_once", context)return copilot.NewAttributedPermissionResult("allow_once", context)return new PermissionDecision { Result = "allow_once", DecisionContext = context };return PermissionRequestResult.approveOnce().setDecisionContext(context);return PermissionResult::Decision { decision: PermissionDecision::ApproveOnce, context: Some(ctx) };Hosts can now register a trusted set of host-bundled plugin directories that are loaded before any session is created, distinct from user-managed --plugin-dir directories. (#2330)
Node extensions can now pass an env option to joinSession() listing the sensitive environment variable names they need. The CLI prompts the user for approval; if granted, the variables are written into the extension process before joinSession() resolves. (#2348)
await joinSession({ env: ["MY_SECRET_TOKEN", "API_KEY"] });argsSchema supportFactoryMeta now exposes an optional argsSchema field so factory authors can declare the argument shape their factory expects. The CLI validates call arguments against the schema before starting a run, surfacing malformed calls early without consuming credits. (#2315)
session.defineFactory("my-factory", { argsSchema: { type: "object", properties: { query: { type: "string" } } } }, async (ctx) => { /* ... */ });Client is dropped (#2292)FactoryResult/FactoryArguments now typed as JsonValue, ctx.agent() forwards reasoningEffort and contextTier, resume error union trimmed to real codes (#2309)@lutzroeder made their first contribution in #2330@aymenfurter made their first contribution in #2294@lukehoban made their first contribution in #2292Generated by Release Changelog Generator · sonnet46 37.7 AIC · ⌖ 5.53 AIC · ⊞ 8.1K
docs: correct the Python Customize Mode section IDs and action list by @examon in #2264
history.clearContext and Tool.isTerminal across all SDKs by @examon in #2129Full Changelog: v1.0.9...v1.0.11
Feature: rewind support across all SDKs
The Copilot runtime supports rewinding conversation history and tracked file changes. SDKs can now opt into file-change tracking via a new enableFileChangeTracking session option, and then use rewind to restore the session to an earlier checkpoint. (#2321)
// TypeScript
const session = await client.startSession({ enableFileChangeTracking: true });
const rewindPoints = await session.rpc.session.listRewindPoints();
await session.rpc.session.rewind({ rewindPointId: rewindPoints[0].id });// C#
var session = await client.StartSessionAsync(new SessionOptions { EnableFileChangeTracking = true });
var points = await session.Rpc.Session.ListRewindPointsAsync();
await session.Rpc.Session.RewindAsync(new RewindParams { RewindPointId = points[0].Id });# Python
session = await client.start_session(enable_file_change_tracking=True)
points = await session.rpc.session.list_rewind_points()
await session.rpc.session.rewind(rewind_point_id=points[0].id)// Go
session, _ := client.StartSession(ctx, &sdk.SessionOptions{EnableFileChangeTracking: true})
points, _ := session.RPC.Session.ListRewindPoints(ctx)
session.RPC.Session.Rewind(ctx, &sdk.RewindParams{RewindPointId: points[0].Id})// Java
SessionOptions options = new SessionOptions().setEnableFileChangeTracking(true);
CopilotSession session = client.startSession(options).get();
List<RewindPoint> points = session.getRpc().getSession().listRewindPoints().get();
session.getRpc().getSession().rewind(new RewindParams().setRewindPointId(points.get(0).getId())).get();// Rust
let session = client.start_session(SessionOptions { enable_file_change_tracking: Some(true), ..Default::default() }).await?;
let points = session.rpc().session().list_rewind_points().await?;
session.rpc().session().rewind(&RewindParams { rewind_point_id: points[0].id.clone() }).await?;The Java SDK now supports loading the Copilot runtime as a native library (via JNA) directly in-process on Linux x64, eliminating the need for a separate CLI child process. This mirrors the in-process mode already available in .NET and Rust. The feature is marked @CopilotExperimental. (#2301)
To use it, add the native runtime classifier JAR to your Maven dependencies and configure the connection:
<dependency>
<groupId>com.github</groupId>
<artifactId>copilot-sdk-java-runtime</artifactId>
<version>${copilot.version}</version>
<classifier>linux-x64</classifier>
</dependency>CopilotClientOptions options = new CopilotClientOptions()
.setConnection(RuntimeConnection.forInProcess());
CopilotClient client = new CopilotClient(options);
client.start().get();JsonValue, ctx.agent() forwards reasoningEffort and contextTier, and a factory body can no longer start a second top-level run (#2309)Generated by Release Changelog Generator · sonnet46 28.7 AIC · ⌖ 7.73 AIC · ⊞ 8.1K
Nothing published for this version
Nothing published for this version
Two new capabilities are available in every SDK language:
history.clearContext and Tool.isTerminal across all SDKsTwo new capabilities are available in every SDK language:
history.clearContext clears the conversation context (keeping system and developer messages) and seeds the fresh context window with a required first user message. It can only be called from inside a tool handler with a tool call in flight. Also picks up the new session.context_cleared event. (#2129)
Tool.isTerminal lets a tool declare that a successful call ends the agent turn instead of feeding the result back to the model for another round. A failed call leaves the loop running so the model can read the error and retry. (#2129)
const session = await joinSession({
tools: [{
name: "clear_context",
isTerminal: true,
defer: "never",
parameters: {
type: "object",
properties: { prompt: { type: "string" } },
required: ["prompt"],
},
handler: async ({ prompt }) => {
const { messagesCleared } = await session.rpc.history.clearContext({ prompt });
return { textResultForLlm: `Cleared ${messagesCleared} message(s).`, resultType: "success" };
},
}],
});
session.DefineTool("clear_context", new ToolOptions { IsTerminal = true, Defer = DeferMode.Never }, async (params) => {
var result = await session.Rpc.History.ClearContext(new ClearContextParams { Prompt = params.Prompt });
return ToolResult.Success($"Cleared {result.MessagesCleared} message(s).");
});
Hosts can now inject enterprise permission policy at session startup across all six SDKs. This is independent of the runtime's server-managed settings fetch path. (#2139)
const session = await createSession({
managedSettings: {
permissions: {
disableBypassPermissionsMode: "disable",
deny: ["shell"],
allow: ["read_file"],
},
},
});
var session = await CopilotClient.CreateSessionAsync(new SessionOptions {
ManagedSettings = new ManagedSettings {
Permissions = new ManagedPermissions {
DisableBypassPermissionsMode = "disable",
Deny = ["shell"],
Allow = ["read_file"],
}
}
});
serverName, toolName, args) in PermissionRequest.extensionData (#2276)@Chuxel made their first contribution in #2283Generated by Release Changelog Generator · sonnet46 19 AIC · ⌖ 5.28 AIC · ⊞ 8.6K
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.73, model: claude-sonnet-4.6, id: 31186148234, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/31186148234 -->
java: enforce non-blank @CopilotToolParam description at compile time by @rinceyuan in https://github.com/github/copilot-sdk/pull/1980
session.idle.backgroundTasks field with the current aborted field by @examon in https://github.com/github/copilot-sdk/pull/2232Full Changelog: https://github.com/github/copilot-sdk/compare/v1.0.8...v1.0.9
All SDKs now accept a githubMcpToolConfig option on session create/resume, exposing settings the runtime already supports. The most useful new control
All SDKs now accept a githubMcpToolConfig option on session create/resume, exposing settings the runtime already supports. The most useful new control is disableFormDeferral, which makes MCP write tools (like creating issues or PRs) execute directly instead of opening an interactive form — essential for autonomous workflows. (#2112)
const session = await client.createSession({
githubMcpToolConfig: { disableFormDeferral: true }
});
var session = await client.CreateSessionAsync(new SessionConfig {
GitHubMcpToolConfig = new GitHubMcpToolConfig { DisableFormDeferral = true }
});
A new enableExperimentalMode option lets SDK consumers control whether a session activates experimental runtime features. In empty mode the SDK defaults to false; in copilot-cli mode the runtime decides unless you set it explicitly. (#1600)
const session = await client.createSession({ enableExperimentalMode: true });
var session = await client.CreateSessionAsync(new SessionConfig { EnableExperimentalMode = true });
Sessions can now be created with an additionalDirectories field that exposes extra working directories to the session alongside the primary workspace. (#2180)
const session = await client.createSession({
additionalDirectories: ["/path/to/other/project"]
});
permission.requested events and permission handler callbacks now carry an optional managedApprovalRequired flag. When set, the permission must be approved by a person — built-in approve-all handlers refuse it loudly rather than silently approving, and custom handlers can inspect the flag to surface a proper UI prompt. (#2080)
mode='json' in tool results to avoid serialization errors (#2225)@joshspicer made their first contribution in #2080@connor4312 made their first contribution in #2112@DonJayamanne made their first contribution in #2180Generated by Release Changelog Generator · sonnet46 18.7 AIC · ⌖ 4.92 AIC · ⊞ 8.6K
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.73, model: claude-sonnet-4.6, id: 30870194454, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/30870194454 -->
bugfix: [Python] sessions.list() raised ValueError for any non-empty session list due to boolean-discriminated union decoding bug
sessions.list() raised ValueError for any non-empty session list due to boolean-discriminated union decoding bug (#2123)PermissionDecisionApproveForIonApproval) for permission approval types; now emits the correct schema-named aliases (PermissionDecisionApproveForSessionApproval, PermissionDecisionApproveForLocationApproval) (#1652)CustomAgentsLocalOnly was only sent via session.options.update after session creation, arriving too late to restrict agent discovery to the working directory; it is now included in the session.create and session.resume wire payloads (#1899)@abhinavgautam01 made their first contribution in #1652@arimu1 made their first contribution in #2032Generated by Release Changelog Generator · sonnet46 21.4 AIC · ⌖ 4.16 AIC · ⊞ 8.6K
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.73, model: claude-sonnet-4.6, id: 30652792188, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/30652792188 -->
Agent Factories let a trusted extension declare a JavaScript closure that orchestrates a fleet of subagents, then invoke it by name. The runtime invok
Agent Factories let a trusted extension declare a JavaScript closure that orchestrates a fleet of subagents, then invoke it by name. The runtime invokes the factory closure over a reverse RPC call, passing primitives to spawn subagents, journal results (so a resumed run replays completed work for free), compose work in parallel or as a pipeline, and report progress. (#2114)
import { defineFactory, joinSession } from "`@github/copilot-sdk`/extension";
const myFactory = defineFactory({
meta: { name: "my-factory", description: "Orchestrates subagents" },
run: async ({ spawnAgent, journal }) => {
const result = await spawnAgent({ prompt: "Summarize the repo" });
return journal("done", result);
},
});
const session = await joinSession({ factories: [myFactory] });
const run = await session.factory.run({ name: "my-factory", input: {} });
Everything is gated behind the runtime's agent_factories flag and billing gate, and all public types are marked @experimental.
@nytron88 made their first contribution in #2117@syedkazmi14 made their first contribution in #2101@smz202000 made their first contribution in #2019Generated by Release Changelog Generator · sonnet46 25.9 AIC · ⌖ 5.11 AIC · ⊞ 8.6K
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.73, model: claude-sonnet-4.6, id: 30575593646, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/30575593646 -->
Applications can now intercept the natural stopping point of the top-level agent across all SDKs. Return { decision: "block", reason } to enqueue a fo
agentStop lifecycle hookApplications can now intercept the natural stopping point of the top-level agent across all SDKs. Return { decision: "block", reason } to enqueue a follow-up message and keep the agent running; omit or return no decision to let it stop normally. (#2054)
session.hooks.agentStop(async ({ stopHookActive }) => {
if (stopHookActive) return; // don't block continuation turns
return { decision: "block", reason: "Run final validation and fix any failures." };
});
session.Hooks.AgentStop(async (input, ct) => {
if (input.StopHookActive) return null; // don't block continuation turns
return new AgentStopOutput { Decision = "block", Reason = "Run final validation and fix any failures." };
});
Client::start now exposes a StartupTimings struct that breaks down initialization latency into per-phase millisecond fields (process_spawn_ms, transport_setup_ms, handshake_ms, and more), making it easier to diagnose cold-start performance. (#2066)
[Java] custom JSON schema override for @CopilotToolParamThe @CopilotToolParam annotation now accepts an optional schema attribute for passing an explicit JSON Schema string, enabling support for third-party types that the built-in schema generator cannot automatically map. (#2069)
`@CopilotTool`("Schedule a deployment")
public String scheduleDeployment(
`@CopilotToolParam`(value = "Deployment time in ISO-8601",
schema = "{\"type\":\"string\",\"format\":\"date-time\"}")
com.acme.internal.AcmeDateTime deployTime) { ... }
@CopilotToolParam descriptions at compile time (#1980)@adirh3 made their first contribution in #2047Generated by Release Changelog Generator · sonnet46 45.2 AIC · ⌖ 4.94 AIC · ⊞ 8.6K
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.73, model: claude-sonnet-4.6, id: 30515313396, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/30515313396 -->
Custom sub-agents can now have their own reasoning effort level, independent of the parent session. When reasoningEffort is omitted on a custom agent,
Custom sub-agents can now have their own reasoning effort level, independent of the parent session. When reasoningEffort is omitted on a custom agent, the backend applies its own default — the session-level setting is not inherited. (#1981)
const session = await client.createSession({
customAgents: [{
name: "planner",
prompt: "You plan tasks.",
reasoningEffort: "high",
}],
});
var session = await client.CreateSessionAsync(new SessionOptions {
CustomAgents = [new CustomAgentConfig {
Name = "planner",
Prompt = "You plan tasks.",
ReasoningEffort = ReasoningEffort.High,
}],
});
expAssignments session config field across all SDKs (#2033)ask_user starving the per-session event loop (#2034)@lukewar made their first contribution in #1880[!WARNING] <details> <summary>Firewall blocked 1 domain</summary>
The following domain was blocked by the firewall during workflow execution:
awmgmcpgTo allow these domains, add them to the
network.allowedlist in your workflow frontmatter:network: allowed: - defaults - "awmgmcpg"See Network Configuration for more information.
</details>
Generated by Release Changelog Generator · 39.1 AIC · ⌖ 5.54 AIC · ⊞ 7.2K
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.70, model: claude-sonnet-4.6, id: 29965645125, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/29965645125 -->
You can now set a per-agent reasoning effort level on custom agent configurations. When omitted, the backend chooses its default; an explicit value ov
You can now set a per-agent reasoning effort level on custom agent configurations. When omitted, the backend chooses its default; an explicit value overrides the backend default for that specific agent without affecting the parent session. (#1981)
const config: CustomAgentConfig = {
name: "my-agent",
prompt: "...",
reasoningEffort: "high",
};
var config = new CustomAgentConfig {
Name = "my-agent",
Prompt = "...",
ReasoningEffort = "high",
};
[!WARNING] <details> <summary>Firewall blocked 1 domain</summary>
The following domain was blocked by the firewall during workflow execution:
awmgmcpgTo allow these domains, add them to the
network.allowedlist in your workflow frontmatter:network: allowed: - defaults - "awmgmcpg"See Network Configuration for more information.
</details>
Generated by Release Changelog Generator · 53.4 AIC · ⌖ 4.74 AIC · ⊞ 7.3K
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.70, model: claude-sonnet-4.6, id: 29849964843, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/29849964843 -->
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
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, #1915, #1975, #1976)
const client = new CopilotClient({ connection: RuntimeConnection.forInProcess() });
var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForInProcess() });
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)
const session = await client.createSession({
toolSearch: { defer: "auto" },
});
var session = await client.CreateSessionAsync(new SessionConfig
{
ToolSearch = new ToolSearchConfig { Defer = "auto" },
});
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)
session.defineTool("my-tool", { metadata: { "myapp:priority": 1 } }, handler);
session.DefineTool("my-tool", new ToolOptions { Metadata = new() { ["myapp:priority"] = 1 } }, handler);
canvasProvider field to session create/resume config so hosts can supply a stable canvas-provider identity that survives cold resume (#1847)enableManagedSettings flag in session create/resume for enterprise managed-settings enforcement (#1925)agentId, parentAgentId, and interactionType from LLM inference start frames into request-handler contexts (#1949)HashMap with IndexMap (#1931)native-tls for the build-time CLI download (#1964)@agoncal made their first contribution in #1951@Shivam60 made their first contribution in #1964@rinceyuan made their first contribution in #1978@belaltaher8 made their first contribution in #1864Full Changelog: https://github.com/github/copilot-sdk/compare/v1.0.6...v1.0.7
Generated by Release Changelog Generator · sonnet46 1.2M
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.55, model: claude-sonnet-4.6, id: 29510898443, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/29510898443 -->
Tool search lets the model discover tools on demand instead of loading every tool definition up front. When the active tool count exceeds the deferral
Tool search lets the model discover tools on demand instead of loading every tool definition up front. When the active tool count exceeds the deferral threshold, MCP and external tools are marked as deferred and surfaced through the built-in tool_search_tool. This release adds a toolSearch option to CreateSession/ResumeSession so applications can enable/disable the feature and tune the threshold. (#1933)
const session = await client.createSession({
toolSearch: { enabled: true, deferThreshold: 20 },
});
var session = await client.CreateSessionAsync(new SessionConfig
{
ToolSearch = new ToolSearchConfig { Enabled = true, DeferThreshold = 20 },
});
Tool results can now return toolReferences — a list of tool names chosen by a tool-search override — to narrow the active tool set before the next model turn.
The Python and Go SDKs now support loading the Copilot runtime as a native shared library in-process, matching the existing .NET, TypeScript, and Rust implementations. This avoids spawning a child process and communicates over the runtime's C ABI instead of stdio or TCP. (#1975, #1976)
Python — experimental, no new dependencies (uses stdlib ctypes):
from copilot import CopilotClient, RuntimeConnection
client = CopilotClient(connection=RuntimeConnection.for_inprocess())
Go — requires the copilot_inprocess build tag:
// build with: go build -tags copilot_inprocess
client, _ := sdk.NewClient(&sdk.ClientOptions{
Connection: &sdk.InProcessConnection{},
})
The SDK selects and provisions the native runtime automatically. Per-client Env, WorkingDirectory, and Telemetry settings are not supported with in-process transport (they cannot be isolated in a shared host process). Set COPILOT_SDK_DEFAULT_CONNECTION=inprocess to use in-process transport by default across your application.
@rinceyuan made their first contribution in #1978Generated by Release Changelog Generator · sonnet46 762.9K
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.55, model: claude-sonnet-4.6, id: 29385766972, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/29385766972 -->
The existing Transport::Stdio and Transport::Tcp variants are fully backward-compatible — no breaking changes for current consumers.
The Rust SDK can now host the Copilot runtime as an in-process cdylib instead of spawning a CLI subprocess. Select it with Transport::InProcess or set COPILOT_SDK_DEFAULT_CONNECTION=inprocess. (#1915)
let client = ClientOptions::new()
.transport(Transport::InProcess)
.build()?;
The existing Transport::Stdio and Transport::Tcp variants are fully backward-compatible — no breaking changes for current consumers.
rustls/ring to native-tls to resolve Microsoft Component Governance advisory (#1964)@Shivam60 made their first contribution in #1964Generated by Release Changelog Generator · sonnet46 447.1K
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.55, model: claude-sonnet-4.6, id: 29133943660, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/29133943660 -->
The Node.js SDK now supports an experimental in-process transport that hosts the Copilot runtime as a native library via FFI (using `koffi`, instead o
The Node.js SDK now supports an experimental in-process transport that hosts the Copilot runtime as a native library via FFI (using [koffi]((koffi.dev/redacted), instead of spawning a child process. This reduces process overhead and eliminates the need for a separate CLI installation when using a bundled native runtime. (#1953)
const connection = RuntimeConnection.forInProcess("/path/to/libcopilot-runtime.so");
const client = new CopilotClient({ runtimeConnection: connection });
canvasProvider field on session configAll SDKs (Node.js, .NET, Go, Python, Rust) now support an optional canvasProvider field on session create and resume config. This lets host connections supply a stable canvas-provider identity so host-provided canvases restore correctly across cold resume. (#1847)
canvasProvider: { id: "app:builtin:my-host", name: "My Host" }CanvasProvider = new CanvasProviderIdentity { Id = "app:builtin:my-host" }canvas_provider=CanvasProviderIdentity(id="app:builtin:my-host")CanvasProvider: &CanvasProviderIdentity{Id: "app:builtin:my-host"}Request handler callbacks across all SDKs (Node.js, Python, Go, .NET, Rust, Java) now expose agentId, parentAgentId, and interactionType from LLM inference request-start frames. This lets BYOK/CAPI request handlers identify which agent is making the inference request, and whether it is a subagent call. (#1949)
Generated by Release Changelog Generator · sonnet46 498.2K
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.55, model: claude-sonnet-4.6, id: 29070724716, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/29070724716 -->
Applications can now pass enableManagedSettings when creating or resuming a session to opt the runtime into enterprise managed-settings enforcement (b
enableManagedSettings for enterprise policy enforcement (all SDKs)Applications can now pass enableManagedSettings when creating or resuming a session to opt the runtime into enterprise managed-settings enforcement (bypass-permissions policy) using the session's gitHubToken. This is purely additive and opt-in — omitting it behaves exactly as before. (#1925)
const session = await client.createSession({
gitHubToken: "...",
enableManagedSettings: true,
});
var session = await client.CreateSessionAsync(new SessionConfig
{
GitHubToken = "...",
EnableManagedSettings = true,
});
enable_managed_settings=True kwarg on create_session / resume_sessionEnableManagedSettings: boolPtr(true) on SessionConfig / ResumeSessionConfig.with_enable_managed_settings(true) builder on SessionConfigsessionConfig.setEnableManagedSettings(true) on SessionConfigThe Rust SDK previously used HashMap for Tool.parameters and mcp_servers fields, causing random key ordering in serialized JSON each process startup. This busted the model provider's prompt cache on the system+tools prefix, increasing cost and latency. HashMap is now replaced with IndexMap for these model-visible maps. (#1931)
IndexMap mirrors HashMap's API and is re-exported as github_copilot_sdk::IndexMap — migration is mechanical:
// Before: use std::collections::HashMap;
// After:
use github_copilot_sdk::IndexMap; // same API, deterministic iteration order
Affected public types: Tool.parameters, mcp_servers on SessionConfig / ResumeSessionConfig / CustomAgentConfig, and the tool_parameters / try_tool_parameters return types.
@agoncal made their first contribution in #1951Generated by Release Changelog Generator · sonnet46 987.8K
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.55, model: claude-sonnet-4.6, id: 29030149715, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/29030149715 -->
Stream Anthropic /messages responses in E2E fake handlers by @stephentoub in https://github.com/github/copilot-sdk/pull/1868
Full Changelog: https://github.com/github/copilot-sdk/compare/v1.0.5...v1.0.6
Two new experimental methods on session.metadata provide per-source token attribution for the session's context window.
Two new experimental methods on session.metadata provide per-source token attribution for the session's context window. (#1886)
getContextAttribution() returns a flat list of attribution entries — skills, subagents, MCP servers, tools, plugins — each with a token count and hierarchical nesting via parentId. getContextHeaviestMessages() returns the largest individual messages currently in context, most-expensive first.
const attr = await session.metadata.getContextAttribution();
// attr.contextAttribution.entries → [{ kind: 'skill', id: 'skill:tmux', tokens: 1234, ... }, ...]
const heavy = await session.metadata.getContextHeaviestMessages({ limit: 10 });
var attr = await session.Metadata.GetContextAttributionAsync();
var heavy = await session.Metadata.GetContextHeaviestMessagesAsync(limit: 10);
SlashCommandInput now supports an optional choices field, allowing slash commands to declare selectable literal options with human-facing descriptions (#1886)ExternalToolTextResultForLlm now supports toolReferences for returning deferred tool names to the model from a tool-search override (#1886)Generated by Release Changelog Generator · claude-sonnet-4.6
Generated by Release Changelog Generator · sonnet46 1.8M
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.55, model: claude-sonnet-4.6, id: 28602028763, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/28602028763 -->
All SDKs now support an optional onGitHubTelemetry callback in ClientOptions that lets hosts receive per-session GitHub telemetry events forwarded by
All SDKs now support an optional onGitHubTelemetry callback in ClientOptions that lets hosts receive per-session GitHub telemetry events forwarded by the runtime. When a handler is registered, the client automatically opts sessions in via enableGitHubTelemetryRedirection and dispatches each incoming gitHubTelemetry.event notification to the callback. This feature is experimental, intentionally hidden from public IDE completion in C# ([EditorBrowsable(Never)]) and Rust (#[doc(hidden)]). (#1835)
const client = new CopilotClient({
onGitHubTelemetry: (notification) => { /* handle telemetry event */ },
});
var client = new CopilotClient(new CopilotClientOptions
{
OnGitHubTelemetry = (notification) => { /* handle telemetry event */ return Task.CompletedTask; },
});
Generated by Release Changelog Generator · sonnet46 1.2M
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.55, model: claude-sonnet-4.6, id: 28552536351, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/28552536351 -->
SDK applications can now handle OAuth challenges from MCP servers that require host-provided authentication. Register an onMcpAuthRequest callback on
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)
const session = await client.createSession({
onMcpAuthRequest: async (request) => ({
accessToken: await myIdentityProvider.getToken(request.serverUrl),
}),
});
var session = await client.CreateSessionAsync(new SessionConfig
{
OnMcpAuthRequest = async ctx =>
McpAuthResult.FromToken(new McpAuthToken
{
AccessToken = await myIdentityProvider.GetTokenAsync(ctx.ServerUrl)
}),
});
Three additional session configuration options are now available across all SDKs. (#1865)
const session = await client.createSession({
enableCitations: true,
excludedBuiltinAgents: ["github-search"],
sessionLimits: { maxAiCredits: 10 },
});
var session = await client.CreateSessionAsync(new SessionConfig
{
EnableCitations = true,
ExcludedBuiltInAgents = ["github-search"],
SessionLimits = new SessionLimitsConfig { MaxAiCredits = 10 },
});
getBearerToken → bearerTokenProvider; add sessionId to ProviderTokenArgs for per-session token scoping (#1796)registerInterest sent before session.resume, causing "Session not found" errors when resuming a session with onMcpAuthRequest (#1861)@CopilotTool and @CopilotToolParam annotations with compile-time annotation processor for ergonomic tool registration via ToolDefinition.fromObject() (#1792, #1838)ToolInvocation parameter injection in @CopilotTool methods for accessing session context without exposing it to the LLM schema (#1832)Attachment enum (GitHubCommit, GitHubRelease, GitHubActionsJob, GitHubRepository, GitHubFileDiff, GitHubTreeComparison, GitHubUrl, GitHubFile, GitHubSnippet) (#1823)@pallaviraiturkar0 made their first contribution in #1823@roji made their first contribution in #1827@coleflennikenmsft made their first contribution in #1854@szabta89 made their first contribution in #1856Full Changelog: https://github.com/github/copilot-sdk/compare/v1.0.4...v1.0.5
Generated by Release Changelog Generator · sonnet46 2.6M
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.55, model: claude-sonnet-4.6, id: 28527869621, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/28527869621 -->
When a Copilot session connects to an OAuth-protected MCP server, the SDK now calls back to your application to supply OAuth tokens. Register an onMcp
When a Copilot session connects to an OAuth-protected MCP server, the SDK now calls back to your application to supply OAuth tokens. Register an onMcpAuthRequest handler in the session config to provide tokens or cancel the request. (#1669)
const session = await client.startSession({
onMcpAuthRequest: async (request) => {
const token = await myOAuthFlow(request.serverUrl, request.reason);
return token ? { kind: "token", accessToken: token } : { kind: "cancelled" };
},
});
var session = await client.StartSessionAsync(new SessionConfig
{
OnMcpAuthRequest = async (ctx) =>
{
var token = await MyOAuthFlow(ctx.ServerUrl, ctx.Reason);
return token is not null
? McpAuthResult.FromToken(new McpAuthToken { AccessToken = token })
: McpAuthResult.Cancel();
},
});
sessionId in BYOK bearer-token callback; field renamed to bearerTokenProviderThe BYOK config field has been renamed from getBearerToken to bearerTokenProvider across all SDKs. The callback now also receives a sessionId, so a single callback shared across multiple sessions can scope token acquisition or caching per session. (#1796)
const client = new CopilotClient({
provider: {
bearerTokenProvider: async ({ providerName, sessionId }) => {
return await getTokenForSession(sessionId);
},
},
});
var client = new CopilotClient(new CopilotClientConfig
{
Provider = new ProviderConfig
{
BearerTokenProvider = async (args) => await GetTokenForSession(args.SessionId),
},
});
@CopilotTool annotation-based tool definitionJava applications can now define Copilot tools by annotating methods with @CopilotTool and @CopilotToolParam instead of building ToolDefinition objects manually. A compile-time annotation processor generates the metadata, and ToolDefinition.fromObject() registers all annotated methods at once. (#1792)
`@CopilotTool`("Get the current weather for a given city")
public String getWeather(
`@CopilotToolParam`(value = "The city", required = true) String city,
`@CopilotToolParam`(value = "Unit: celsius or fahrenheit", defaultValue = "celsius") String unit) {
return fetchWeather(city, unit);
}
List<ToolDefinition> tools = ToolDefinition.fromObject(new WeatherTools());
@CopilotTool methods can declare ToolInvocation as a hidden injected parameter to access runtime context such as sessionId (#1832)@Param annotation to @CopilotToolParam (#1838)Attachment enum (GitHubCommit, GitHubRelease, GitHubActionsJob, GitHubRepository, GitHubFileDiff, GitHubTreeComparison, GitHubUrl, GitHubFile, GitHubSnippet) (#1823)@pallaviraiturkar0 made their first contribution in #1823@roji made their first contribution in #1827Generated by Release Changelog Generator · sonnet46 1.5M
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.55, model: claude-sonnet-4.6, id: 28432082983, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/28432082983 -->
The BYOK bearer-token provider callback now receives a sessionId parameter, enabling per-session token scoping or caching. The configuration field has
sessionId and is renamed to bearerTokenProviderThe BYOK bearer-token provider callback now receives a sessionId parameter, enabling per-session token scoping or caching. The configuration field has been renamed from getBearerToken to bearerTokenProvider across all six SDKs (and the callback type to BearerTokenProvider), aligning with the existing *Provider naming convention. (#1796)
const client = new CopilotClient({
bearerTokenProvider: async ({ sessionId }) => getTokenForSession(sessionId),
});
var client = new CopilotClient(new CopilotClientOptions {
BearerTokenProvider = async (args) => await GetTokenForSessionAsync(args.SessionId),
});
@CopilotTool annotation for ergonomic Java tool registrationJava applications can now declare tools using the @CopilotTool and @Param annotations. The SDK's annotation processor generates the necessary metadata at compile time; use ToolDefinition.fromObject(...) to register an entire object's annotated methods without manual JSON schema construction. (#1792)
Note: This API is currently
@CopilotExperimental.
`@CopilotTool`("Get the current weather for a city")
public String getWeather(
`@Param`(value = "City name", required = true) String city,
`@Param`(value = "Unit: celsius or fahrenheit", required = false, defaultValue = "celsius") String unit) {
// implementation
}
// Registration:
List<ToolDefinition> tools = ToolDefinition.fromObject(new WeatherTools());
The Rust Attachment enum now includes all 9 GitHub-anchored reference types that the CLI can deliver — GitHubCommit, GitHubRelease, GitHubActionsJob, GitHubRepository, GitHubFileDiff, GitHubTreeComparison, GitHubUrl, GitHubFile, and GitHubSnippet. Previously these variants were silently dropped at the SDK boundary when received. (#1823)
@pallaviraiturkar0 made their first contribution in #1823Generated by Release Changelog Generator · sonnet46 1.1M
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.55, model: claude-sonnet-4.6, id: 28381408107, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/28381408107 -->
Add experimental multi-provider BYOK registry config across all six SDKs by @stephentoub in https://github.com/github/copilot-sdk/pull/1718
Full Changelog: https://github.com/github/copilot-sdk/compare/v1.0.2...v1.0.4
improvement: [Java] rename SystemPromptSections to SystemMessageSections for cross-SDK consistency; old class deprecated with forRemoval=true
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)
const session = await client.createSession({
memory: { enabled: true },
});
var session = await client.CreateSessionAsync(new SessionConfig
{
Memory = new MemoryConfiguration { Enabled = true }
});
defer parameter for tool definitionsTools 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)
defineTool("lookup_issue", {
description: "Fetch issue details",
parameters: z.object({ id: z.string() }),
defer: "auto",
handler: async ({ id }) => { /* ... */ },
});
var tool = CopilotTool.DefineTool(
async ([Description("Issue ID")] string id) => { /* ... */ },
toolOptions: new CopilotToolOptions { Defer = CopilotToolDefer.Auto });
otlpProtocol telemetry option ("http/json" or "http/protobuf") for configuring OTLP export transport (#1648)ModelBilling.tokenPrices on public SDK types, exposing per-tier input/output/cache pricing and context window limits (#1633)runtime.shutdown during normal client stop for deterministic OTEL telemetry flush before process cleanup (#1667)context.Context through the JSON-RPC request path for proper cancellation support (#1643)getOpenCanvases() to CopilotSession to track currently open canvas instances, matching the other SDKs (#1606)SystemPromptSections to SystemMessageSections for cross-SDK consistency; old class deprecated with forRemoval=true (#1683)to_timedelta_int to avoid serialization errors (#1668)build.rs when DOCS_RS env var is set (#1660)@andyfeller made their first contribution in #1631@almaleksia made their first contribution in #1632@idryzhov made their first contribution in #1668@scottaddie made their first contribution in #1636Generated by Release Changelog Generator · sonnet46 1.8M
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.55, model: claude-sonnet-4.6, id: 27729623733, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/27729623733 -->
improvement: [Java] generated types now propagate schema stability and deprecation metadata — experimental items gain @apiNote Javadoc and deprecated…
@CopilotExperimental compile-time gate for Java SDKThe Java SDK now ships a @CopilotExperimental annotation and a JSR 269 annotation processor that causes compilation to fail when experimental SDK APIs are referenced without opting in. Annotate a class or method with @AllowCopilotExperimental, or pass -Acopilot.experimental.allowed=true to the compiler to acknowledge the experimental status. (#1601)
// Opt in at the declaration level
`@AllowCopilotExperimental`
public class MyApp {
// experimental SDK types and methods may be used here
}
<!-- Or opt in for the entire compilation unit via Maven -->
<compilerArgs>
<arg>-Acopilot.experimental.allowed=true</arg>
</compilerArgs>
open_canvases snapshot now correctly shrinks when session.canvas.closed is emitted — previously closed canvases were never removed (#1604)pub(crate) instead of pub (#1596)@apiNote Javadoc and deprecated items gain @Deprecated (#1591)Generated by Release Changelog Generator · sonnet46 1.9M
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.55, model: claude-sonnet-4.6, id: 27291901369, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/27291901369 -->
Update vulnerable npm lockfile dependencies by @stephentoub in https://github.com/github/copilot-sdk/pull/1415
^1.0.52-1, add preMcpToolCall hook, fix PingResponse timestamp type by @edburns in https://github.com/github/copilot-sdk/pull/1389kind() method by @heaths in https://github.com/github/copilot-sdk/pull/1400session.mcp.apps.callTool result to JsonNode and harden mvn clean by @edburns in https://github.com/github/copilot-sdk/pull/1523@github/copilot dependency to ^1.0.57 by @edburns in https://github.com/github/copilot-sdk/pull/1546Full Changelog: https://github.com/github/copilot-sdk/compare/v0.3.0...v1.0.0
⚠️ Breaking change for Go callers. Key renames include:
All Go identifiers now use idiomatic uppercase initialisms as required by Go conventions. (#1527)
⚠️ Breaking change for Go callers. Key renames include:
Api → API, Rpc → RPC, Mcp → MCP, Sse → SSEUrl/Uri → URL/URI, Id → ID, Tcp → TCPAdo → ADO, Sdk → SDK, Fs → FSUriConnection → URIConnection, TcpConnection → TCPConnectionSessionConfig.EnableConfigDiscovery, ResumeSessionConfig.EnableConfigDiscovery, and ResumeSessionConfig.ContinuePendingWork are now *bool instead of bool, allowing callers to express explicit false (opt out) vs. unset (defer to runtime default). (#1536)
⚠️ Breaking change for Go callers. Use copilot.Bool(true) / copilot.Bool(false) to set a value, or leave the field nil to defer to the runtime default.
cfg := copilot.SessionConfig{
EnableConfigDiscovery: copilot.Bool(false), // explicitly opt out
}
Java callers can now retrieve responses from slash commands via the RPC layer. Previously it was possible to invoke slash commands but not to receive their responses programmatically. (#1520)
Generated types are no longer exposed under the internal generated sub-module. (#1535)
copilot.session_events.X and copilot.rpc.X instead of copilot.generated.*github_copilot_sdk::session_events::X and github_copilot_sdk::rpc::X instead of github_copilot_sdk::generated::*suppressResumeEvent to disableResume on the wire (#1529)session.mcp.apps.callTool result to JsonNode (#1523)__version__ from package metadata; align Node version sentinel (#1521)@dmytrostruk made their first contribution in #1515@willglas made their first contribution in #1529Generated by Release Changelog Generator · ● 1.4M
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.48, model: claude-sonnet-4.6, id: 26783077412, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/26783077412 -->
Nothing published for this version
Fixes a race condition in the .NET CopilotClient where the stderr reader could outlive the CLI process during shutdown, causing TaskScheduler.Unobserv
Fixes a race condition in the .NET CopilotClient where the stderr reader could outlive the CLI process during shutdown, causing TaskScheduler.UnobservedTaskException errors. The stderr pump now has its own cancellation token and connection cleanup properly coordinates pump shutdown before disposing the process. (#1136)
install_bundled_cli and HAS_BUNDLED_CLITwo new public APIs make it easier to access the bundled CLI path before a Client exists, eliminating the need for consumers to duplicate the cache-path resolution logic. (#1489)
// Check if a bundled CLI is available at compile time
if copilot_sdk::HAS_BUNDLED_CLI {
// Extract and get the path to the bundled CLI
if let Some(path) = copilot_sdk::install_bundled_cli() {
println!("Bundled CLI at: {}", path.display());
}
}
[!NOTE] <details> <summary>🔒 Integrity filter blocked 2 items</summary>
The following items were blocked because they don't meet the GitHub integrity level.
- #1136
search_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".- #868
search_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".To allow these resources, lower
min-integrityin your GitHub frontmatter:tools: github: min-integrity: approved # merged | approved | unapproved | none</details>
Generated by Release Changelog Generator · ● 2.4M
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.48, model: claude-sonnet-4.6, id: 26641549279, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/26641549279 -->
…with the Azure SDK for Rust design. This is a breaking change for Rust callers matching on error variants — update match arms to call .kind() instead.
CopilotClientMode.Empty for multi-tenant appsMulti-tenant applications can now opt into a hardened "empty" client mode that starts from a clean slate: no built-in tools, host integration disabled, system prompt sanitized, and storage explicitly required. This prevents user-specific state (plugins, custom agents, co-author trailers, etc.) from leaking across tenants. (#1428)
const client = new CopilotClient({
mode: "empty",
baseDirectory: "/tmp/per-tenant-state",
});
const session = await client.createSession({
onPermissionRequest: approveAll,
availableTools: new ToolSet()
.addBuiltIn(BuiltInTools.Isolated)
.addMcp("*"),
excludedTools: new ToolSet()
.addMcp("github-delete_repository"),
});
using var client = new CopilotClient(new CopilotClientOptions
{
Mode = CopilotClientMode.Empty,
BaseDirectory = "/tmp/per-tenant-state",
});
await using var session = await client.CreateSessionAsync(new SessionConfig
{
OnPermissionRequest = PermissionHandler.ApproveAll,
AvailableTools = new ToolSet()
.AddBuiltIn(BuiltInTools.Isolated)
.AddMcp("*"),
ExcludedTools = new ToolSet()
.AddMcp("github-delete_repository"),
});
A new postToolUseFailure / OnPostToolUseFailure hook lets SDK users observe failed tool executions and inject follow-up guidance, separate from the existing success-only postToolUse hook. Available across Node, Python, Go, .NET, and Rust. (#1421)
session.hooks.postToolUseFailure = async (event) => {
console.error(`Tool ${event.toolName} failed: ${event.error}`);
};
session.OnPostToolUseFailure = async (e, ct) =>
{
Console.Error.WriteLine($"Tool {e.ToolName} failed: {e.Error}");
};
agentMode on MessageOptionsAll six SDKs now expose an agentMode field on MessageOptions to set the per-message UI mode (interactive, plan, autopilot, shell). Previously there was no correct way to request plan/autopilot mode from the SDK. (#1438)
session.send(message, { agentMode: "plan" })session.SendAsync(message, new MessageOptions { AgentMode = "plan" })session.send(message, agent_mode="plan")session.Send(ctx, message, copilot.MessageOptions{AgentMode: "plan"})kind() methodRust SDK error types have been refactored from a flat #[non_exhaustive] enum to a struct-with-kind() pattern, aligning with the Azure SDK for Rust design. This is a breaking change for Rust callers matching on error variants — update match arms to call .kind() instead. (#1400)
error.data in the .NET client transport (#1425)@heaths made their first contribution in #1400Generated by Release Changelog Generator · ● 3.6M
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.48, model: claude-sonnet-4.6, id: 26535875210, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/26535875210 -->
> ⚠️ Breaking changes: This release includes breaking changes from the API review. See the breaking changes summary below and the detailed migration d…
To make it easier to keep track of what's changed during the beta period, these release notes cover all the updates since beta 1.
This release consolidates a major round of API review, adds new capabilities (remote sessions, MCP hook, mode handlers), and introduces the Rust SDK. Every SDK went through a thorough final API review, resulting in cleaner, more consistent, and more idiomatic APIs that we can support post-GA.
🚀 GA timeline: The 1.0.0 GA release is planned for approximately one week from now.
⚠️ Breaking changes: This release includes breaking changes from the API review. See the breaking changes summary below and the detailed migration doc that you can give as context to Copilot to help it update your app code quickly.
A new Rust SDK joins the family, bringing the same Copilot capabilities to Rust applications. It supports the full feature set — sessions, tools, hooks, streaming, MCP, permissions, telemetry, canvases, and remote sessions — with idiomatic Rust patterns throughout.
use github_copilot_sdk::{Client, ClientOptions, SessionConfig, permission::ApproveAllHandler};
let client = Client::new(ClientOptions::default());
client.start().await?;
let session = client.create_session(
SessionConfig::default()
.with_permission_handler(Arc::new(ApproveAllHandler))
).await?;
let reply = session.send_and_wait("Hello!").await?;
The Rust SDK ships with the Copilot runtime bundled by default — just add the crate and go. The runtime is downloaded when your app builds and is embedded in your distributable binary. Opt out of bundling with default-features = false if you manage the CLI yourself.
Remote sessions connect a local Copilot session to GitHub's backend services, producing a shareable URL that lets users access the session from GitHub web or mobile — useful for monitoring a locally-running agent from your phone, or sharing a session with a teammate. Enable it globally or toggle it per-session with session.rpc.remote.enable().
const client = new CopilotClient({
enableRemoteSessions: true,
});
// Each session emits a remote URL via session.info events
session.on("session.info", (event) => {
if (event.data.infoType === "remote") {
console.log("Remote URL:", event.data.url); // Share this or render as QR code
}
});
var client = new CopilotClient(new CopilotClientOptions {
EnableRemoteSessions = true,
});
Requirements: the user must be authenticated (gitHubToken or useLoggedInUser), and the session's working directory must be a GitHub repository. The enableRemoteSessions option only applies when the SDK spawns the CLI process (ignored when connecting to an external server).
Cloud sessions go a step further — the session runs entirely in the cloud rather than on the local machine. Pass a cloud option with repository metadata when creating a session:
const session = await client.createSession({
onPermissionRequest: approveAll,
cloud: {
repository: { owner: "github", name: "my-repo", branch: "main" },
},
});
Both features are available in all languages.
A new preMcpToolCall hook fires before every MCP tool invocation, giving your application the chance to inspect, modify, or block MCP tool calls. This is useful for adding authorization, logging, or stripping sensitive metadata from tool call arguments.
const session = await client.createSession({
onPermissionRequest: approveAll,
preMcpToolCall: async (context) => {
console.log(
`MCP tool: ${context.toolName} on server: ${context.serverName}`,
);
// Return modified args, or throw to block the call
return context.arguments;
},
});
var session = await client.CreateSessionAsync(new SessionConfig {
OnPermissionRequest = PermissionHandler.ApproveAll,
PreMcpToolCall = async (context) => {
Console.WriteLine($"MCP tool: {context.ToolName} on server: {context.ServerName}");
return context.Arguments;
},
});
Available in all languages.
Every SDK went through a comprehensive API review to make the developer experience cleaner and more idiomatic. The highlights:
Simplified client connection config — Instead of scattering transport options (cliPath, cliUrl, port, tcpConnectionToken, useStdio) across client options, there's now a single connection property with typed factory methods:
// Connect to an external server
const client = new CopilotClient({
connection: RuntimeConnection.forUri("http://localhost:3000"),
});
// Or spawn a local CLI over stdio (the default if no connection is specified)
const client = new CopilotClient({
connection: RuntimeConnection.forStdio(),
});
var client = new CopilotClient(new CopilotClientOptions {
Connection = RuntimeConnection.ForStdio(),
});
CopilotClient(connection=RuntimeConnection.for_uri("http://localhost:3000"))copilot.NewClient(&copilot.ClientOptions{Connection: copilot.UriConnection{Uri: "http://localhost:3000"}})Client::new(ClientOptions { connection: Some(RuntimeConnection::Uri { uri: "http://localhost:3000".into() }), ..Default::default() })send() now accepts a plain string — The most common case just got simpler:
// Before
const reply = await session.send({ prompt: "Hello!" });
// After
const reply = await session.send("Hello!");
// Full options still available:
const reply = await session.send({ prompt: "Analyze this", attachments: [...] });
Permission decisions are now typed factories instead of stringly-typed objects:
// Before
return new PermissionRequestResult { Kind = "approve-once" };
// After
return PermissionDecision.ApproveOnce();
// Also: PermissionDecision.Reject(), .UserNotAvailable(), .NoResult()
getMessages() → getEvents() — The method name now accurately reflects what it returns (the full event stream, not just messages).
See the breaking changes guide for the complete list of API changes per language.
onExitPlanModeRequest and onAutoModeSwitchRequest handlers let your app handle plan-approval flows and automatic mode switching (e.g., rate-limit recovery). Available in all languages.runtime_instructions system message section — A new section in the system message customization API for runtime-generated instructions, giving you another hook to inject or transform prompt content.enableSessionTelemetry — A per-session toggle to enable or disable telemetry collection, independent of the client-level telemetry config.ProviderConfig now supports modelId, wireModel, maxInputTokens, and maxOutputTokens, letting BYOK users decouple the model ID visible to agents from the wire model sent to the provider.rpc.* types by name, expect renames.This release includes breaking changes from a comprehensive API review. The changes are mechanical — mostly renames and reshaping — and make the APIs cleaner and more consistent as we finalize the 1.0.0 shape.
💡 Migrating your app? Pass the breaking changes document to GitHub Copilot and ask it to update your code. The document is structured as a machine-readable migration guide with before/after examples for every change.
| Change | All SDKs |
|---|---|
Client transport config → RuntimeConnection |
✅ |
copilotHome → baseDirectory |
✅ |
getMessages() → getEvents() |
✅ |
Permission results → PermissionDecision factories |
✅ (C#, Python, Rust) |
Handler renames (onExitPlanMode → onExitPlanModeRequest) |
✅ |
| Generated RPC type renames | ✅ |
Each language also has its own idiomatic changes beyond the shared ones above. See the detailed breaking changes document for the full per-language list.
improvement: hide deprecated APIs where supported
Applications can now declare and handle canvases — interactive UI surfaces hosted by the Copilot runtime. Register a single CanvasHandler on a session and receive routed canvas.open, canvas.close, and canvas.action.invoke events; call session.canvas.* for native host actions. (#1401)
session.setCanvasHandler({
onOpen: async (ctx) => { /* render canvas */ },
onAction: async (ctx) => { /* handle action */ },
onClose: async (ctx) => { /* cleanup */ },
});
session.SetCanvasHandler(new MyCanvasHandler());
Applications can enable remote sessions either at the client level (all sessions in a GitHub repo get a remote URL) or on demand mid-session. (#1192)
// Always-on via client option:
const client = new CopilotClient({ remote: true });
// On-demand per session:
const result = await session.rpc.remote.enable();
console.log("Remote URL:", result.url);
await session.rpc.remote.disable();
// Always-on:
var client = new CopilotClient(new CopilotClientOptions { Remote = true });
// On-demand:
var result = await session.Rpc.Remote.EnableAsync();
await session.Rpc.Remote.DisableAsync();
A new hook lets applications intercept MCP tool invocations before they execute — inspect, replace, or remove the _meta field sent to MCP servers. (#1366)
session.hooks.onPreMcpToolCall = async (input) => {
return { metaToUse: { ...input.meta, traceId: myTraceId } };
};
session.Hooks.OnPreMcpToolCall = async (input) =>
new PreMcpToolCallHookOutput { MetaToUse = new { traceId = myTraceId } };
Sessions can now be created with a cloud option to request cloud-backed remote sessions with repository metadata, without requiring a local CLI process. (#1306)
const session = await client.createSession({
cloud: { repository: { owner: "my-org", name: "my-repo" } },
});
var session = await client.CreateSessionAsync(new SessionConfig {
Cloud = new CloudSessionConfig { Repository = new RepositoryConfig { Owner = "my-org", Name = "my-repo" } }
});
The Rust SDK now bundles the Copilot CLI binary at publish time by default — no configuration needed to get a working binary. Opt out with default-features = false. (#1385)
# Default: CLI bundled automatically
copilot-sdk = "1.0.0-beta.7"
# Opt out of bundled CLI:
copilot-sdk = { version = "1.0.0-beta.7", default-features = false }
The Java SDK is now part of the monorepo, providing full parity with the other language SDKs including session management, tool registration, hooks, and E2E test coverage. (#1348, #1369, #1389)
var client = new CopilotClient();
var session = client.createSession(new SessionConfig()).join();
session.send("Hello from Java!").join();
The .NET, Python, and Rust SDKs now emit structured trace/log output covering CLI startup, JSON-RPC timing, session operations, and callback paths — making it easier to diagnose slow or failing connections. (#1217)
ILogger via structured fields and TimeSpan elapsed valueslogging with elapsed_ms, session_id, and request identifierstracing crate with structured fieldsCopilotTool.DefineTool is a typed wrapper around AIFunctionFactory.Create that applies Copilot-specific metadata (override flag, skip-permission behavior) without magic strings. (#1321)
var tool = CopilotTool.DefineTool("edit",
new CopilotToolOptions { IsOverride = true },
async (params) => { /* custom edit */ });
session.AddTool(tool);
All hook input types (PreToolUseHookInput, PostToolUseHookInput, SessionStartHookInput, etc.) now include a sessionId field, allowing applications to distinguish parent session hooks from sub-agent hooks. (#1290)
enableSessionTelemetry session option across all SDKs (#1224)model field to CustomAgentConfig across all SDKs (#1309)remote_session field to SessionConfig across all SDKs (#1295)runtime_instructions system message section across all SDKs (#1377)SessionFs SQLite support for runtime routing (#1299)MCPStdioServerConfig.args optional across all SDKs (#1347)netstandard and net10 targets (#1320)x-opaque-json to JsonElement at RPC params boundary (#1359)Ms suffix for duration properties in generated types (#1339).snupkg symbols package to NuGet.org (#1345)SetProcessDone race condition (#863)from_dict() round-trip for optional fields with schema defaults (#1313)@cschleiden made their first contribution in #1222@claudiogodoy99 made their first contribution in #863@tiagonbotelho made their first contribution in #1306Generated by Release Changelog Generator · ● 3.7M
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.48, model: claude-sonnet-4.6, id: 26370426039, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/26370426039 -->
These releases include coordinated, intentional breaking changes based on API review feedback. Key changes:
The Java SDK is now a first-class part of the github/copilot-sdk monorepo, with full CI, Maven publishing workflows, and generated types that stay in sync with the rest of the SDK family. (#1348)
CopilotClient client = new CopilotClient();
CopilotSession session = client.createSession(new SessionConfig());
session.send("Hello from Java!");
preMcpToolCall hook across all SDKsApplications can now intercept MCP tool invocations before they execute — useful for injecting, replacing, or removing the _meta field sent to MCP servers. The hook returns a tri-state result: return null to leave _meta unchanged, return a new object to replace it, or explicitly set metaToUse to null to strip it entirely. (#1366)
session.hooks.onPreMcpToolCall = async (input) => {
return { metaToUse: { traceId: myTraceId() } };
};
session.Hooks.OnPreMcpToolCall = async (input) => {
return new PreMcpToolCallHookOutput { MetaToUse = new { traceId = MyTraceId() } };
};
Tools and permission handlers can be declared without providing a callback, leaving them pending for manual resolution. This makes it easier to pause execution and resolve requests from event streams rather than inline callbacks. (#1308)
// Declare without a callback — permission requests stay pending
session.setPermissionHandler({ kinds: ["edit"] });
// Later, resume manually from an event
session.resolvePermissionRequest(event.requestId, { outcome: "allow" });
// Declaration-only tool — no callback supplied
session.DefineTool(new ToolDefinition { Name = "myTool", Description = "..." });
sessionId on hook inputs — hooks now fire for sub-agentsAll six hook input types (PreToolUseHookInput, PostToolUseHookInput, etc.) now carry a sessionId field. Hooks also fire for tool calls made by sub-agents spawned via the task tool, and input.sessionId lets you distinguish parent from sub-agent invocations. (#1290)
These releases include coordinated, intentional breaking changes based on API review feedback. Key changes:
Connection configuration — CliPath/Port/CliUrl properties are replaced by a single RuntimeConnection discriminated union:
new CopilotClient({ connection: RuntimeConnection.stdio(...) })new CopilotClientOptions { Connection = RuntimeConnection.Stdio(...) }CLIUrl equivalent updatedConvenience send overloads — send(string) / sendAndWait(string) string overloads added for all SDKs.
Lifecycle events — now a typed polymorphic hierarchy (SessionCreatedEvent, etc.) instead of stringly-typed discriminators.
C# specifics — CopilotHome → BaseDirectory, delegate types replaced with Func<...>, LogLevel retyped to CopilotLogLevel, SessionConfigBase extracted. (#1343, #1357, #1360)
model field on CustomAgentConfigWhen defining custom sub-agents programmatically, you can now specify which model to use. The runtime falls back to the parent session model if the specified model is unavailable. (#1309)
customAgents: [{ name: "my-agent", model: "gpt-4o", ... }]new CustomAgentConfig { Name = "my-agent", Model = "gpt-4o" }custom_agents=[{"name": "my-agent", "model": "gpt-4o"}]CustomAgentConfig{Name: "my-agent", Model: "gpt-4o"}Session creation now accepts a cloud option to request cloud-backed remote sessions with repository metadata, matching the new runtime capability. (#1306)
CopilotTool.DefineTool helper for .NETThe .NET SDK now provides a typed CopilotTool.DefineTool wrapper that applies Copilot-specific metadata (override flags, skip-permission behavior) without magic strings, aligning C# with the typed helper APIs already available in other SDKs. (#1321)
var tool = CopilotTool.DefineTool("edit", new CopilotToolOptions { IsOverride = true },
async (params, ctx) => { /* custom edit implementation */ });
netstandard2.0 and net10 target frameworks (#1320).snupkg symbols package to NuGet.org (#1345)MCPStdioServerConfig.args optional across all SDKs (#1347)remote_session field to all SDK SessionConfig types (#1295)from_dict() round-trip for optional fields with schema defaults (#1313)Default on generated types (#1272)@tiagonbotelho made their first contribution in #1306Generated by Release Changelog Generator · ● 6.2M
<!-- gh-aw-agentic-workflow: Release Changelog Generator, engine: copilot, version: 1.0.48, model: claude-sonnet-4.6, id: 26266286427, workflow_id: release-changelog, run: https://github.com/github/copilot-sdk/actions/runs/26266286427 -->
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →