Skip to content

Releases: github/copilot-sdk

v1.0.0-beta.6

22 May 03:13
f4d22d7

Choose a tag to compare

v1.0.0-beta.6 Pre-release
Pre-release

Feature: Java SDK joins the monorepo

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!");

Feature: preMcpToolCall hook across all SDKs

Applications 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() } };
};

Feature: tool callbacks are now optional across all SDKs

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 = "..." });

Feature: sessionId on hook inputs — hooks now fire for sub-agents

All 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)

Feature: breaking API review changes for C#, TypeScript, and Go

These releases include coordinated, intentional breaking changes based on API review feedback. Key changes:

Connection configurationCliPath/Port/CliUrl properties are replaced by a single RuntimeConnection discriminated union:

  • TypeScript: new CopilotClient({ connection: RuntimeConnection.stdio(...) })
  • C#: new CopilotClientOptions { Connection = RuntimeConnection.Stdio(...) }
  • Go: CLIUrl equivalent updated

Convenience send overloadssend(string) / sendAndWait(string) string overloads added for all SDKs.

Lifecycle events — now a typed polymorphic hierarchy (SessionCreatedEvent, etc.) instead of stringly-typed discriminators.

C# specificsCopilotHomeBaseDirectory, delegate types replaced with Func<...>, LogLevel retyped to CopilotLogLevel, SessionConfigBase extracted. (#1343, #1357, #1360)

Feature: model field on CustomAgentConfig

When 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)

  • TypeScript: customAgents: [{ name: "my-agent", model: "gpt-4o", ... }]
  • C#: new CustomAgentConfig { Name = "my-agent", Model = "gpt-4o" }
  • Python: custom_agents=[{"name": "my-agent", "model": "gpt-4o"}]
  • Go: CustomAgentConfig{Name: "my-agent", Model: "gpt-4o"}

Feature: cloud session config support

Session creation now accepts a cloud option to request cloud-backed remote sessions with repository metadata, matching the new runtime capability. (#1306)

Feature: CopilotTool.DefineTool helper for .NET

The .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 */ });

Other changes

  • feature: [C#] add netstandard2.0 and net10 target frameworks (#1320)
  • feature: [C#] publish .snupkg symbols package to NuGet.org (#1345)
  • bugfix: [C#] honor preinstalled CLI path in MSBuild targets (#1318)
  • bugfix: [C#] fix argument validation edge cases (#1322, #1328)
  • feature: [Node] export generated session event types (#1316)
  • feature: make MCPStdioServerConfig.args optional across all SDKs (#1347)
  • feature: add remote_session field to all SDK SessionConfig types (#1295)
  • improvement: hide deprecated APIs where supported by the language (#1293)
  • bugfix: [Python] fix from_dict() round-trip for optional fields with schema defaults (#1313)
  • improvement: [Go] replace RPC quicktype generation with native Go codegen (#1234)
  • improvement: [Go] generate typed union interfaces and bool-discriminated unions (#1252, #1284)
  • improvement: [Rust] derive Default on generated types (#1272)

New contributors

  • @tiagonbotelho made their first contribution in #1306

Generated by Release Changelog Generator · ● 6.2M

rust/v1.0.0-beta.6

22 May 03:13
f4d22d7

Choose a tag to compare

rust/v1.0.0-beta.6 Pre-release
Pre-release

What's Changed

New Contributors

Full Changelog: rust/v1.0.0-beta.4...rust/v1.0.0-beta.6

v1.0.0-beta.4

13 May 09:36
4e3dc73

Choose a tag to compare

v1.0.0-beta.4 Pre-release
Pre-release

Feature: typed Go union interfaces

Go SDK union types are now modelled as typed interfaces with concrete variants instead of flattened structs with many optional fields. Callers can switch on concrete variants and get compile-time safety — invalid union states that were previously representable are no longer possible. Unknown union members and session event payloads are preserved rather than dropped. (#1252)

switch v := event.Data.(type) {
case *SessionEventDataAssistantMessage:
    fmt.Println(v.Content)
case *RawSessionEventData:
    // forward-compatible: unknown future event type preserved
}

Feature: experimental schema type annotations

Generated types that carry stability: "experimental" in the protocol schema now surface language-appropriate markers so callers get compiler warnings when using unstable APIs. (#1267)

  • C#: [Experimental("GitHub.Copilot.SDK.Experimental")]
  • TypeScript: @experimental JSDoc tag
  • Go/Python: doc-comment warning
  • Rust: #[doc = "⚠️ Experimental"]

Other changes

  • improvement: [Go] replace quicktype-based RPC codegen with a custom schema-aware generator; preserves distinct named types that quicktype previously merged due to identical structure, and aligns generated casing with the repo's naming policy — note: this is a breaking change for Go callers using generated RPC types (#1234)
  • bugfix: [Go] CLI stderr is now captured and included in startup errors, making failure root causes (missing module, auth error, version mismatch) immediately visible instead of showing a generic opaque message (#863)

New contributors

  • @claudiogodoy99 made their first contribution in #863

Generated by Release Changelog Generator · ● 302.2K

rust/v1.0.0-beta.4

13 May 09:36
4e3dc73

Choose a tag to compare

What's Changed

New Contributors

Full Changelog: rust-v0.1.0...rust/v1.0.0-beta.4

v1.0.0-beta.3

08 May 16:10
ce56eb8

Choose a tag to compare

Feature: mode handler APIs for plan approval and rate-limit recovery

Applications can now register callbacks for exitPlanMode.request and autoModeSwitch.request from the Copilot runtime, giving full control over plan-mode transitions and automatic model switching after rate-limit events. (#1228)

const session = await client.createSession({
  onExitPlanMode: async (request) => ({ approved: true }),
  onAutoModeSwitch: (request) => "yes",
});
var session = await client.CreateSessionAsync(new SessionConfig
{
    OnExitPlanMode = (request, _) => Task.FromResult(new ExitPlanModeResult { Approved = true }),
    OnAutoModeSwitch = (request, _) => Task.FromResult(AutoModeSwitchResponse.Yes),
});
  • Python: on_exit_plan_mode / on_auto_mode_switch kwargs on create_session()
  • Go: ExitPlanModeHandler / AutoModeSwitchHandler fields on SessionConfig

Feature: SDK tracing diagnostics

The .NET, Python, and Rust SDKs now emit structured diagnostic logs covering CLI startup, TCP connection, JSON-RPC request timing, session lifecycle, and error paths. (#1217)

var client = new CopilotClient(new CopilotClientOptions
{
    Logger = loggerFactory.CreateLogger<CopilotClient>(),
});

Python emits logs via stdlib logging under copilot.* loggers at DEBUG level. Rust uses tracing structured fields; wire up a tracing_subscriber as usual.

Feature: enableSessionTelemetry session option

A new enableSessionTelemetry option on SessionConfig and ResumeSessionConfig lets applications explicitly enable or disable the runtime's internal session telemetry. (#1224)

const session = await client.createSession({ enableSessionTelemetry: true });
var session = await client.CreateSessionAsync(new SessionConfig { EnableSessionTelemetry = true });

Other changes

  • bugfix: [C#] session-event enums are now string-backed readonly structs, preventing deserialization failures when the runtime adds new enum values (#1226)
  • bugfix: [Rust] binary tool result resource blobs now default to application/octet-stream when mimeType is absent (#1222)

New contributors

  • @sunbrye made their first contribution in #1208
  • @cschleiden made their first contribution in #1222
  • @IeuanWalker made their first contribution in #1232

Generated by Release Changelog Generator · ● 225.2K

Generated by Release Changelog Generator · ● 1.3M

v1.0.0-beta.2

06 May 20:02
06bfc5d

Choose a tag to compare

v1.0.0-beta.2 Pre-release
Pre-release

Feature: remote session support

Applications can now enable remote session support across all SDKs, providing parity with the CLI's --remote flag. There are two complementary mechanisms: a client-level option that enables remote for all sessions, and per-session RPC methods to toggle remote on demand. (#1192)

Always-on via client option:

const client = new CopilotClient({ remote: true });
session.on("session.info", (event) => {
  if (event.data.infoType === "remote") {
    console.log("Remote URL:", event.data.url);
  }
});
var client = new CopilotClient(new CopilotClientOptions { Remote = true });
session.OnSessionInfo += (e) => {
    if (e.InfoType == "remote")
        Console.WriteLine($"Remote URL: {e.Url}");
};

On-demand via RPC:

const result = await session.rpc.remote.enable();
console.log("Remote URL:", result.url);
await session.rpc.remote.disable();
var result = await session.Rpc.Remote.EnableAsync();
Console.WriteLine($"Remote URL: {result.Url}");
await session.Rpc.Remote.DisableAsync();
  • Python: await session.rpc.remote.enable() / session.rpc.remote.disable()
  • Go: session.RPC.Remote.Enable(ctx) / session.RPC.Remote.Disable(ctx)

Other changes

  • improvement: [Rust] align Rust SDK public surface with C#, Go, Python, and TypeScript — removes autoModeSwitch, exitPlanMode, disabled_mcp_servers; adds available_tools/disabled_skills to ResumeSessionConfig; expands tool results with binary payloads and MCP CallToolResult conversion (#1212)
  • improvement: [Rust] internalize env_value_mode for cross-SDK parity — envValueMode is now always sent as "direct" on the wire, consistent with all other SDKs (#1215)

Generated by Release Changelog Generator · ● 225.2K

rust-v0.1.0

06 May 14:12
19b4ad5

Choose a tag to compare

rust-v0.1.0 Pre-release
Pre-release
chore: Release package github-copilot-sdk version 0.1.0

v1.0.0-beta.1

04 May 12:53
6a0e065

Choose a tag to compare

v1.0.0-beta.1 Pre-release
Pre-release

This is the first beta release of the Copilot SDK. The release includes all features we have committed to including in the upcoming General Availability (GA) release.

But note - we're not stopping here! Before GA, we still plan to add more top-requested features, as well as any critical bugfixes. We'll also carry out a final round of API reviews and will likely make further breaking changes to streamline naming before it locks down at 1.0.0.

Highlights of 1.0.0 Beta 1 include custom instruction directories, configurable data directories, TCP connection tokens for headless servers, and a more self-contained .NET distribution (eliminating third-party dependencies).


New features

Custom instruction directories

Sessions can now specify additional directories to search for custom instruction files via the instructionDirectories option on session create and resume config. This lets applications point the CLI at project-specific or team-shared instruction files beyond the default locations. (#1190)

// TypeScript
const session = await client.createSession({
  onPermissionRequest: approveAll,
  instructionDirectories: [
    "/repo/.copilot/instructions",
    "/shared/team-instructions",
  ],
});
// C#
var session = await client.CreateSessionAsync(new() {
    OnPermissionRequest = PermissionHandler.ApproveAll,
    InstructionDirectories = ["/repo/.copilot/instructions", "/shared/team-instructions"],
});
  • Python: await client.create_session(on_permission_request=..., instruction_directories=["/repo/.copilot/instructions"])
  • Go: client.CreateSession(ctx, &copilot.SessionConfig{InstructionDirectories: []string{"/repo/.copilot/instructions"}})

TCP connection token

When the SDK spawns a CLI server in TCP mode, it now auto-generates a connection token to authenticate the handshake — closing the loopback listener to unauthorized connections by default. For applications connecting to an externally managed TCP server that requires a token, the new tcpConnectionToken client option lets you supply it explicitly. (#1176)

// TypeScript
// After starting runtime with env var COPILOT_CONNECTION_TOKEN=<some_uuid>
const client = new CopilotClient({
  cliUrl: "localhost:3000",
  tcpConnectionToken: "<some_uuid>",
});
// C#
// After starting runtime with env var COPILOT_CONNECTION_TOKEN=<some_uuid>
var client = new CopilotClient(new() {
    CliUrl = "localhost:3000",
    TcpConnectionToken = "<some_uuid>",
});
  • Python: CopilotClient(ExternalServerConfig(url="localhost:3000", tcp_connection_token="<some_uuid>"))
  • Go: copilot.NewClient(&copilot.ClientOptions{CLIUrl: "localhost:3000", TCPConnectionToken: "<some_uuid>"})

Configurable Copilot data directory

A new copilotHome client option controls where the CLI stores session state, configuration, and other persistent data. This is useful for isolating data across environments, running multiple CLI instances side-by-side, or customizing the storage location for containerized deployments. Defaults to ~/.copilot when not set, and is applicable only when the SDK spawns the CLI process (ignored when connecting to an external server via cliUrl). (#1191).

const client = new CopilotClient({ copilotHome: "/var/data/copilot" });

If you need more control than simply passing a directory path, consider the existing and more advanced SessionFs API. This lets you map all session storage into your own custom storage through callbacks, for example to store data in the cloud or in a database. See Improved SessionFs provider API in the 0.3.0 release - full docs coming soon.


Other changes and improvements

[.NET] Improved NativeAOT and trimming compatibility by replacing the StreamJsonRpc dependency with a custom JSON-RPC implementation, reducing external dependencies and deployment overhead (#1170)

Bug fixes

[.NET] Fix AOT serialization for SetForegroundSessionIdAsync() by adding a source-generated request type (#1144)


⚠️ Breaking changes

RPC type renames

Schema updates in this release renamed several generated types across all SDKs. If your code references these types by name (via imports or type annotations), you'll need to update:

Previous Now
PermissionCompletedResult PermissionResult
PermissionCompletedKind PermissionResultKind
ToolsHandlePendingToolCallRequest HandlePendingToolCallRequest
HandleToolCallResult HandlePendingToolCallResult

The ToolCallResult type and ToolsHandlePendingToolCall type alias have been removed and replaced by the types above.

Cross-language note: As with previous releases, the same logical renames apply across all four SDKs with language-appropriate casing.

[.NET] StreamJsonRpc dependency removed

The .NET SDK no longer depends on StreamJsonRpc, having replaced it with a custom JSON-RPC implementation (#1170). If your application was relying on StreamJsonRpc as a transitive dependency from the SDK, you'll need to add a direct reference to your project.

New contributors

  • @Encryptoid made their first contribution in #1144

v0.3.0

24 Apr 16:06
dd2dcbc

Choose a tag to compare

This release adds new capabilities — per-session authentication, scoped permissions, agent-level tool and skill control, MCP interop utilities, and more — alongside a broad naming cleanup across all four SDK languages. As we close in on a GA release, we've done a deep clean on our naming to bring it closer to the final state, reducing the amount of churn you should expect in subsequent releases. The result is a more consistent, more readable API surface across the board.


New features

Per-session GitHub authentication

Sessions can now carry their own GitHub identity. Different sessions on the same CLI server can have different GitHub users, Copilot plans, and quota limits.

const session = await client.createSession({
    onPermissionRequest: approveAll,
    gitHubToken: userAToken, // Session-level identity
});

This is independent of the client-level gitHubToken (which authenticates the CLI process itself, and is not required if all sessions bring their own auth). The session-level token determines the identity used for content exclusion, model routing, and quota checks.

Per-agent tool visibility

A new defaultAgent.excludedTools option lets you hide tools from the default agent while keeping them available to custom sub-agents, enabling the orchestrator pattern where the default agent delegates to specialized sub-agents. (#1098)

Per-agent skills

Custom agents can now declare skills: string[] to eagerly inject specific skills into their context at startup. Skills are opt-in — agents receive no skills by default, and sub-agents do not inherit skills from the parent. (#995)

Sub-agent streaming content

When streaming is enabled, assistant.message_delta and assistant.reasoning_delta events are now also delivered for sub-agents. Each event carries an agentId field identifying which sub-agent produced it (absent for the root agent). If your application renders all streaming deltas to the UI, you'll want to filter by agentId (or for pure back-compat, set includeSubAgentStreamingEvents: false on SessionConfig to get the old behavior of only streaming main-agent content updates). (#1108)

Session idle timeout

A new sessionIdleTimeoutSeconds client option configures automatic session cleanup after inactivity. When set, sessions without activity for the specified duration are cleaned up. Disabled by default (sessions live indefinitely). Previously, sessions would always time out after 30 minutes of idleness - this change fixes that. (#1093)

Custom HTTP headers for BYOK model providers

Provider headers and per-message requestHeaders can now be passed through createSession, resumeSession, and send, enabling custom header forwarding to bring-your-own-key model providers. (#1094)

MCP CallToolResult conversion

A new convertMcpCallToolResult() utility function converts MCP CallToolResult objects (with content arrays of text, image, and resource blocks) into the SDK's ToolResultObject format. This makes it easy to use MCP tool servers as backends for SDK tool handlers. (#1049)

ProviderConfig exported

ProviderConfig is now re-exported from the Node.js and Python SDK entry points, so consumers no longer need to duplicate the type locally when configuring Responses API providers. (#1048)

New RPC methods

Additional low-level RPC methods are now available via session.rpc:

  • session.rpc.skills.config.setDisabledSkills(), session.rpc.skills.discover()
  • session.rpc.mcp.config.enable(), session.rpc.mcp.config.disable(), session.rpc.mcp.discover(), session.rpc.mcp.oauthLogin()
  • session.rpc.permissions.setApproveAll(), session.rpc.permissions.resetSessionApprovals()
  • session.rpc.instructions.getSources()
  • session.rpc.usage.getMetrics()
  • session.rpc.name.get(), session.rpc.name.set()

Changes and improvements

Scoped permission approvals

Permission handlers can now return scoped approvals instead of just one-shot decisions. Two new kind values are available:

  • "approve-for-session" — Approves a permission for the remainder of the session, with a scoped rule specifying what's approved (commands, read, write, MCP, MCP sampling, memory, or custom tool).
  • "approve-for-location" — Persists an approval to the workspace location, so it applies across future sessions too.

The existing approval vocabulary has also been clarified to better describe each outcome:

Previous Now
"approved" "approve-once"
"denied-interactively-by-user" "reject"
"denied-no-approval-rule-and-could-not-request-from-user" "user-not-available"

The "denied-by-rules", "denied-by-content-exclusion-policy", and "denied-by-permission-request-hook" outcomes have been removed from the handler result type — these are now handled server-side and never reach the SDK permission handler.

The built-in approveAll handler has been updated and now returns { kind: "approve-once" }. The PermissionRequest.kind field now also covers "memory" and "hook" permission types in addition to the existing "shell", "write", "mcp", "read", "url", and "custom-tool".

Dedicated session event types

Session events now have individually named types instead of being a single large inline union. In Node.js, the SessionEvent type is still available as a union of all event types, but each event now has a corresponding *Event interface and *Data type that you can import and use directly. Python and .NET received the same treatment — Python now has per-event typed classes, and .NET has dedicated event types with rich typing (long, DateTimeOffset, Guid, TimeSpan, data annotations, etc.).

import type { AssistantMessageData } from "@github/copilot-sdk";

session.onEvent("assistant.message", (event) => {
    // event.data is AssistantMessageData — importable and reusable
});

The runtime JSON shape is unchanged — existing event-handling code continues to work.

MCP server config types clarified

MCP server configuration types have been renamed to match MCP protocol terminology (#1051):

Previous Now
MCPLocalServerConfig MCPStdioServerConfig
MCPRemoteServerConfig MCPHTTPServerConfig (covers both HTTP and SSE transports)

The type field value correspondingly changes from "local"/"remote" to "stdio"/"http".

Improved SessionFs provider API

The SessionFs API now uses an idiomatic SessionFsProvider interface where methods take plain arguments and signal errors by throwing, instead of the previous RPC-shaped interface with parameter objects and error-result returns. Supply your provider via the createSessionFsHandler callback on SessionConfig:

createSessionFsHandler: (session) => ({
    readFile: async (path) => {
        return await fs.readFile(path, "utf8"); // throw on error
    },
    stat: async (path) => {
        const s = await fs.stat(path);
        return { size: s.size, isDirectory: s.isDirectory(), ... };
    },
    // ... other methods with plain args, throw on error
})

githubToken/GithubToken casing corrected

The githubToken/GithubToken property on CopilotClientOptions has been corrected to gitHubToken/GitHubToken (capital H) for consistency with GitHub's branding across all SDKs.

Sub-agent streaming deltas now included by default

Streaming sessions now receive assistant.message_delta and assistant.reasoning_delta events from sub-agents as well as the root agent. If your code renders all deltas without checking the source, sub-agent content will be interleaved with the main agent's output. To handle this, either filter on event.agentId (absent for the root agent) or set includeSubAgentStreamingEvents: false on SessionConfig to suppress sub-agent deltas entirely. (#1108)

Additional improvements

  • [Node] Model capabilities are now normalized for models that omit supports or limits fields (e.g., embedding models), preventing runtime errors. (cf5694c)
  • [Node] CLI startup timeout is now cleared when stop is requested, avoiding unnecessary 10-second delay. (#1046)
  • [.NET] Richer typing: integerlong, format: date-timeDateTimeOffset, format: uuidGuid, format: durationTimeSpan; data annotations ([Range], [RegularExpression], [Url], etc.). (#1067)
  • [.NET] Deprecated APIs are now annotated with [Obsolete] with descriptive messages. (#1099)
  • [Python] Dedicated per-event typed session event classes. (#1063)
  • SDK status changed to public preview. (#1054)

⚠️ Type and naming changes

As we close in on a GA release, we've done a deep clean on type naming across all four SDK languages to bring names closer to their final state. The goal is to reduce churn in subsequent releases — these names are now cleaner, more consistent, and better reflect what each type represents.

The changes follow a few simple rules:

  1. *Params*Request — parameter types now use...
Read more

v0.3.0-preview.1

24 Apr 14:24
dd2dcbc

Choose a tag to compare

v0.3.0-preview.1 Pre-release
Pre-release

This release adds new capabilities — per-session authentication, scoped permissions, agent-level tool and skill control, MCP interop utilities, and more — alongside a broad naming cleanup across all four SDK languages. As we close in on a GA release, we've done a deep clean on our naming to bring it closer to the final state, reducing the amount of churn you should expect in subsequent releases. The result is a more consistent, more readable API surface across the board.


New features

Per-session GitHub authentication

Sessions can now carry their own GitHub identity. Different sessions on the same CLI server can have different GitHub users, Copilot plans, and quota limits.

const session = await client.createSession({
    onPermissionRequest: approveAll,
    gitHubToken: userAToken, // Session-level identity
});

This is independent of the client-level gitHubToken (which authenticates the CLI process itself, and is not required if all sessions bring their own auth). The session-level token determines the identity used for content exclusion, model routing, and quota checks.

Per-agent tool visibility

A new defaultAgent.excludedTools option lets you hide tools from the default agent while keeping them available to custom sub-agents, enabling the orchestrator pattern where the default agent delegates to specialized sub-agents. (#1098)

Per-agent skills

Custom agents can now declare skills: string[] to eagerly inject specific skills into their context at startup. Skills are opt-in — agents receive no skills by default, and sub-agents do not inherit skills from the parent. (#995)

Sub-agent streaming content

When streaming is enabled, assistant.message_delta and assistant.reasoning_delta events are now also delivered for sub-agents. Each event carries an agentId field identifying which sub-agent produced it (absent for the root agent). If your application renders all streaming deltas to the UI, you'll want to filter by agentId (or for pure back-compat, set includeSubAgentStreamingEvents: false on SessionConfig to get the old behavior of only streaming main-agent content updates). (#1108)

Session idle timeout

A new sessionIdleTimeoutSeconds client option configures automatic session cleanup after inactivity. When set, sessions without activity for the specified duration are cleaned up. Disabled by default (sessions live indefinitely). Previously, sessions would always time out after 30 minutes of idleness - this change fixes that. (#1093)

Custom HTTP headers for BYOK model providers

Provider headers and per-message requestHeaders can now be passed through createSession, resumeSession, and send, enabling custom header forwarding to bring-your-own-key model providers. (#1094)

MCP CallToolResult conversion

A new convertMcpCallToolResult() utility function converts MCP CallToolResult objects (with content arrays of text, image, and resource blocks) into the SDK's ToolResultObject format. This makes it easy to use MCP tool servers as backends for SDK tool handlers. (#1049)

ProviderConfig exported

ProviderConfig is now re-exported from the Node.js and Python SDK entry points, so consumers no longer need to duplicate the type locally when configuring Responses API providers. (#1048)

New RPC methods

Additional low-level RPC methods are now available via session.rpc:

  • session.rpc.skills.config.setDisabledSkills(), session.rpc.skills.discover()
  • session.rpc.mcp.config.enable(), session.rpc.mcp.config.disable(), session.rpc.mcp.discover(), session.rpc.mcp.oauthLogin()
  • session.rpc.permissions.setApproveAll(), session.rpc.permissions.resetSessionApprovals()
  • session.rpc.instructions.getSources()
  • session.rpc.usage.getMetrics()
  • session.rpc.name.get(), session.rpc.name.set()

Changes and improvements

Scoped permission approvals

Permission handlers can now return scoped approvals instead of just one-shot decisions. Two new kind values are available:

  • "approve-for-session" — Approves a permission for the remainder of the session, with a scoped rule specifying what's approved (commands, read, write, MCP, MCP sampling, memory, or custom tool).
  • "approve-for-location" — Persists an approval to the workspace location, so it applies across future sessions too.

The existing approval vocabulary has also been clarified to better describe each outcome:

Previous Now
"approved" "approve-once"
"denied-interactively-by-user" "reject"
"denied-no-approval-rule-and-could-not-request-from-user" "user-not-available"

The "denied-by-rules", "denied-by-content-exclusion-policy", and "denied-by-permission-request-hook" outcomes have been removed from the handler result type — these are now handled server-side and never reach the SDK permission handler.

The built-in approveAll handler has been updated and now returns { kind: "approve-once" }. The PermissionRequest.kind field now also covers "memory" and "hook" permission types in addition to the existing "shell", "write", "mcp", "read", "url", and "custom-tool".

Dedicated session event types

Session events now have individually named types instead of being a single large inline union. In Node.js, the SessionEvent type is still available as a union of all event types, but each event now has a corresponding *Event interface and *Data type that you can import and use directly. Python and .NET received the same treatment — Python now has per-event typed classes, and .NET has dedicated event types with rich typing (long, DateTimeOffset, Guid, TimeSpan, data annotations, etc.).

import type { AssistantMessageData } from "@github/copilot-sdk";

session.onEvent("assistant.message", (event) => {
    // event.data is AssistantMessageData — importable and reusable
});

The runtime JSON shape is unchanged — existing event-handling code continues to work.

MCP server config types clarified

MCP server configuration types have been renamed to match MCP protocol terminology (#1051):

Previous Now
MCPLocalServerConfig MCPStdioServerConfig
MCPRemoteServerConfig MCPHTTPServerConfig (covers both HTTP and SSE transports)

The type field value correspondingly changes from "local"/"remote" to "stdio"/"http".

Improved SessionFs provider API

The SessionFs API now uses an idiomatic SessionFsProvider interface where methods take plain arguments and signal errors by throwing, instead of the previous RPC-shaped interface with parameter objects and error-result returns. Supply your provider via the createSessionFsHandler callback on SessionConfig:

createSessionFsHandler: (session) => ({
    readFile: async (path) => {
        return await fs.readFile(path, "utf8"); // throw on error
    },
    stat: async (path) => {
        const s = await fs.stat(path);
        return { size: s.size, isDirectory: s.isDirectory(), ... };
    },
    // ... other methods with plain args, throw on error
})

githubToken/GithubToken casing corrected

The githubToken/GithubToken property on CopilotClientOptions has been corrected to gitHubToken/GitHubToken (capital H) for consistency with GitHub's branding across all SDKs.

Sub-agent streaming deltas now included by default

Streaming sessions now receive assistant.message_delta and assistant.reasoning_delta events from sub-agents as well as the root agent. If your code renders all deltas without checking the source, sub-agent content will be interleaved with the main agent's output. To handle this, either filter on event.agentId (absent for the root agent) or set includeSubAgentStreamingEvents: false on SessionConfig to suppress sub-agent deltas entirely. (#1108)

Additional improvements

  • [Node] Model capabilities are now normalized for models that omit supports or limits fields (e.g., embedding models), preventing runtime errors. (cf5694c)
  • [Node] CLI startup timeout is now cleared when stop is requested, avoiding unnecessary 10-second delay. (#1046)
  • [.NET] Richer typing: integerlong, format: date-timeDateTimeOffset, format: uuidGuid, format: durationTimeSpan; data annotations ([Range], [RegularExpression], [Url], etc.). (#1067)
  • [.NET] Deprecated APIs are now annotated with [Obsolete] with descriptive messages. (#1099)
  • [Python] Dedicated per-event typed session event classes. (#1063)
  • SDK status changed to public preview. (#1054)

⚠️ Type and naming changes

As we close in on a GA release, we've done a deep clean on type naming across all four SDK languages to bring names closer to their final state. The goal is to reduce churn in subsequent releases — these names are now cleaner, more consistent, and better reflect what each type represents.

The changes follow a few simple rules:

  1. *Params*Request — parameter types now use...
Read more