Skip to content

Releases: github/copilot-sdk

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

v0.3.0-preview.0

21 Apr 15:07
a3e273c

Choose a tag to compare

v0.3.0-preview.0 Pre-release
Pre-release

What's Changed

  • Add Go submodule version tags for reproducible builds by @Copilot in #33
  • Correct backtick code block formatting by @leereilly in #43
  • Add minor updates to python sdk by @sugatoray in #45
  • Add tests to verify forward compatibility for unknown session event types by @Copilot in #35
  • fix(go): ensure reliable session event handler unsubscription by @nathfavour in #24
  • Fix Go e2e tests not running in CI by @SteveSandersonMS in #47
  • Fix JSON-RPC pipe reads >64KB by handling short reads by @Copilot in #31
  • Update @github/copilot to 0.0.387 by @devm33 in #54
  • Fix escape issue in client.ts by @doggy8088 in #56
  • Allow issue triage workflow to run for all users by @Copilot in #32
  • Improve abort tests across all SDKs; add Go unsubscribe tests by @SteveSandersonMS in #48
  • Add config dir to session options by @devm33 in #15
  • Update some snapshots; remove redundant ones by @SteveSandersonMS in #52
  • feat: add skillDirectories and disabledSkills to all SDKs by @friggeri in #57
  • Fix and unskip some skills E2E tests by @SteveSandersonMS in #69
  • Use STJ's polymorphism support instead of custom converter by @stephentoub in #70
  • Update CONTRIBUTING.md to clarify contribution types by @SteveSandersonMS in #68
  • Copilot SDK Cookbook by @aaronpowell in #80
  • Add getting started tutorial by @burkeholland in #63
  • Update README title and add demos folder by @ashleywolf in #75
  • Move docs to correct folder by @patniko in #82
  • Move examples and demos docs by @patniko in #83
  • Moving files into the correct locations by @aaronpowell in #84
  • Update README structure and add samples folder by @ashleywolf in #85
  • feat: add status, auth, and models metadata APIs to all SDKs by @friggeri in #77
  • Adding FAQ section to the README by @aaronpowell in #86
  • Make the .NET library NativeAOT compatible by @stephentoub in #81
  • Fix code formatting by @SteveSandersonMS in #90
  • fix: correct broken links in cookbook documentation by @GeekTrainer in #93
  • Fix .NET SDK prerequisites in CONTRIBUTING.md by @Copilot in #87
  • fix: remove temporary README.md replacement step from publish workflow by @patniko in #108
  • Modify npm init command for module type by @sinedied in #132
  • Document external CLI server connection by @Copilot in #103
  • Add agentic workflow for cross-SDK consistency enforcement by @Copilot in #95
  • Bump Python minimum version to 3.9+ by @Copilot in #151
  • Add missing list_sessions() method to Python SDK client by @Copilot in #153
  • Re-run uv lock and fix Python tests by @friggeri in #157
  • Document image attachment support in SDK READMEs by @Copilot in #150
  • Bump githubnext/gh-aw from 0.36.0 to 0.37.1 by @dependabot[bot] in #66
  • Adding .NET to the devcontainer by @aaronpowell in #88
  • Use Pydantic for weather parameters in get_weather by @adityagesh in #120
  • Add uv sync as alternative installation option by @harupy in #146
  • feat: Infinite Sessions by @jmoseley in #76
  • Fix BYOK FAQ: clarify it refers to API keys, not encryption keys by @mohamedaminehamdi in #174
  • Include community SDKs in README by @brunoborges in #178
  • docs: add MCP server usage documentation by @AnassKartit in #98
  • Add download badges to README by @Copilot in #156
  • docs: add .NET example for interactive weather assistant by @vicperdana in #119
  • chore: Update generated events to match schemas. by @jmoseley in #208
  • Add ListSessions and DeleteSession methods to Go SDK by @Copilot in #213
  • Remove samples directory, link to awesome-copilot resources by @Copilot in #210
  • Hide StreamJsonRpc implementation detail behind IOException by @Copilot in #202
  • Simplify Node.js example by @SteveSandersonMS in #221
  • Bump actions/download-artifact from 6.0.0 to 7.0.0 by @dependabot[bot] in #65
  • Bump actions/checkout from 5.0.1 to 6.0.1 by @dependabot[bot] in #67
  • Fixes #227 - Premium requests consumed while running py dev test by @vivganes in #228
  • Bump githubnext/gh-aw from 0.37.13 to 0.37.31 by @dependabot[bot] in #240
  • Consistently use Dataclasses in Python SDK by @Copilot in #216
  • Fix .NET CLI server mode code samples - add missing UseStdio = false by @Copilot in #232
  • Configure Copilot agent environment to match devcontainer by @Copilot in #236
  • Add provider info to docs by @patniko in #257
  • Fix formatting and update README structure by @doggy8088 in #258
  • Update docs to reflect you need version for Azure Foundry by @patniko in #260
  • Optimize CI: Split into separate workflows with native path filtering by @Copilot in #259
  • Add githubToken and useLoggedInUser options to all SDK clients by @friggeri in #237
  • feat: add hooks and user input handlers to all SDKs with e2e tests by @friggeri in #269
  • Add lsp config for dotnet. by @jmoseley in #234
  • docs: add hooks, user input, and auth options to SDK READMEs by @friggeri in #270
  • Add paths-ignore filters to SDK test workflows by @Copilot in #271
  • feat(nodejs): add typed event filtering to session.on() by @friggeri in #272
  • Add dependabot monitoring for npm, pip, gomod, and nuget by @Copilot in #273
  • Set default vscode formatter for Go by @qmuntal in #295
  • [go] Honor ClientOptions.UseStdio = false by @qmuntal in #296
  • [go] Honor empty ClientOptions.Env by @qmuntal in #297
  • Bump githubnext/gh-aw from 0.37.31 to 0.38.2 by @dependabot[bot] in #274
  • Bump @types/node from 25.0.3 to 25.1.0 in /test/harness by @dependabot[bot] in #275
  • Bump openai from 6.15.0 to 6.17.0 in /test/harness by @dependabot[bot] in #276
  • Consolidate path filters in SDK test workflows per GitHub Actions spec by @Copilot in #303
  • feat: add reasoning_effort support to all SDK clients by @friggeri in #302
  • Cache list_models across all SDK languages to prevent rate limiting under concurrency by @Copilot in #300
  • [go] rewrite interface{} to any by @qmuntal in #298
  • Removing cookbook from sdk repo by @aaronpowell in #316
  • Cleanup Go Client implementation by @qmuntal in #321
  • Fix ask-user test snapshots by @qmuntal in #319
  • Add a new line after model generating final response when tool call completes by @moonshade9 in #307
  • Replace Literal model type with string in Python SessionConfig by @Copilot in #325
  • Clarify FAQ: BYOK works without GitHub Copilot subscription by @lossyrob in #336
  • [go] make e2e and jsonrpc internal packages by @qmuntal in #339
  • Fail CI if snaps...
Read more

v0.2.2

10 Apr 09:03
6029b37

Choose a tag to compare

Feature: session filesystem support across all four SDKs

The sessionFs feature introduced earlier in Node.js is now available across .NET, Go, and Python too, so you can redirect session-scoped storage (events, checkpoints, temp files, workspace state) to your own backing store instead of the runtime's default local filesystem. This is especially useful for serverless and multi-tenant hosts. (#1036)

// TypeScript
const client = new CopilotClient({
  sessionFs: { initialCwd: "/", sessionStatePath: "/s", conventions: "posix" },
});

const session = await client.createSession({
    createSessionFsHandler: () => ({ readFile: async () => "...", writeFile: async () => { /* ... */ }, /* ... */ })
});
// C#
var client = new CopilotClient(new CopilotClientOptions {
    SessionFs = new()
    {
        InitialCwd = "/",
        SessionStatePath = "/",
        Conventions = SessionFsSetProviderRequestConventions.Posix
    }
});

var session = await client.CreateSessionAsync(new SessionConfig
{
    CreateSessionFsHandler = _ => new MySessionFsHandler(/* ... */) // e.g., map to in-memory storage, etc
});

For a full end-to-end sample of a multi-user hosted system using sessionFs, see https://github.com/github/copilot-sdk-server-sample

Feature: override model capabilities when creating a session or switching models

All SDKs can now override individual model capabilities such as vision support without replacing the full capabilities object. This makes BYOK and custom-provider scenarios easier, and lets you change behavior mid-session with setModel/SetModelAsync. (#1029)

const session = await client.createSession({
  modelCapabilities: { supports: { vision: false } },
});
await session.setModel("claude-sonnet-4.5", { modelCapabilities: { supports: { vision: true } } });
await session.SetModelAsync("claude-sonnet-4.5", reasoningEffort: null,
    modelCapabilities: new ModelCapabilitiesOverride { Supports = new ModelCapabilitiesOverrideSupports { Vision = true } });

Feature: enableConfigDiscovery for automatic MCP and skill discovery

All SDKs now expose enableConfigDiscovery, allowing the runtime to automatically discover MCP server configs and skill directories from the working directory and merge them with any explicitly supplied configuration. Explicit values still win on name collisions. (#1044)

const session = await client.createSession({
  enableConfigDiscovery: true,
});
var session = await client.CreateSessionAsync(new SessionConfig {
    EnableConfigDiscovery = true,
});

Improvement: safer per-event data types in Go

The Go SDK no longer flattens all session event payloads into one giant optional struct. event.Data is now a per-event typed interface, so adding a new event type no longer risks silently changing the shape of existing ones. (#1037)

switch d := event.Data.(type) {
case *copilot.AssistantMessageData:
    fmt.Println(d.Content)
}

⚠️ Breaking change (Go): event.Data is now a SessionEventData interface rather than a flat struct, so consumers must use type assertions or type switches. This update also applies some Go-style initialism renames such as UiUI and UriURI.

Other changes

  • bugfix: [.NET] [Go] ignore unknown hook types from newer CLI versions instead of failing the session, improving forward compatibility with runtime updates (#1013)
  • improvement: [Go] harden the internal JSON-RPC transport and framing logic, including stricter protocol validation and better handling of exact error payload JSON (#949)

v0.2.2-preview.0

07 Apr 17:52
8569d92

Choose a tag to compare

v0.2.2-preview.0 Pre-release
Pre-release

Other changes

  • bugfix: [C#] [Go] tolerate unknown hook types to prevent session hang (#1013)

    When the CLI invokes a hook type the SDK doesn't recognize (e.g. postToolUseFailure), .NET and Go were returning a JSON-RPC error that caused the CLI to terminate the session — appearing as a hang. Unknown hook types are now silently ignored, matching the existing Node.js behavior.

Note

🔒 Integrity filter blocked 43 items

The following items were blocked because they don't meet the GitHub integrity level.

  • 8569d92 list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • b4fa5d9 list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • 6565a3b list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • 0388810 list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • dfdc6a0 list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • c3fa6cb list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • 156cf1f list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • 200bfef list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • f7fd757 list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • da9921e list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • 7ecf1d8 list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • 588951e list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • 28d0a33 list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • dd42d42 list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • ad63b09 list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • ec72d41 list_commits: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • ... and 27 more items

To allow these resources, lower min-integrity in your GitHub frontmatter:

tools:
  github:
    min-integrity: approved  # merged | approved | unapproved | none

Generated by Release Changelog Generator

v0.2.1

03 Apr 20:19
0388b9d

Choose a tag to compare

Feature: commands and UI elicitation across all four SDKs

Register slash commands that CLI users can invoke and drive interactive input dialogs from any SDK language. This feature was previously Node.js-only; it now ships in Python, Go, and .NET as well. (#906, #908, #960)

const session = await client.createSession({
  onPermissionRequest: approveAll,
  commands: [{
    name: "summarize",
    description: "Summarize the conversation",
    handler: async (context) => { /* ... */ },
  }],
  onElicitationRequest: async (context) => {
    if (context.type === "confirm") return { action: "confirm" };
  },
});

// Drive dialogs from the session
const confirmed = await session.ui.confirm({ message: "Proceed?" });
const choice = await session.ui.select({ message: "Pick one", options: ["A", "B"] });
var session = await client.CreateSessionAsync(new SessionConfig {
    OnPermissionRequest = PermissionHandler.ApproveAll,
    Commands = [
        new CommandDefinition {
            Name = "summarize",
            Description = "Summarize the conversation",
            Handler = async (context) => { /* ... */ },
        }
    ],
});

// Drive dialogs from the session
var confirmed = await session.Ui.ConfirmAsync(new ConfirmOptions { Message = "Proceed?" });

⚠️ Breaking change (Node.js): The onElicitationRequest handler signature changed from two arguments (request, invocation) to a single ElicitationContext that combines both. Update callers to use context.sessionId and context.message directly.

Feature: session.getMetadata across all SDKs

Efficiently fetch metadata for a single session by ID without listing all sessions. Returns undefined/null (not an error) when the session is not found. (#899)

  • TypeScript: const meta = await client.getSessionMetadata(sessionId);
  • C#: var meta = await client.GetSessionMetadataAsync(sessionId);
  • Python: meta = await client.get_session_metadata(session_id)
  • Go: meta, err := client.GetSessionMetadata(ctx, sessionID)

Feature: sessionFs for virtualizing per-session storage (Node SDK)

Supply a custom sessionFs adapter in Node SDK session config to redirect the runtime's per-session storage (event log, large output files) to any backing store — useful for serverless deployments or custom persistence layers. (#917)

Other changes

  • bugfix: structured tool results (with toolTelemetry, resultType, etc.) now sent via RPC as objects instead of being stringified, preserving metadata for Node, Go, and Python SDKs (#970)
  • feature: [Python] CopilotClient and CopilotSession now support async with for automatic resource cleanup (#475)
  • improvement: [Python] copilot.types module removed; import types directly from copilot (#871)
  • improvement: [Python] workspace_path now accepts any os.PathLike and session.workspace_path returns a pathlib.Path (#901)
  • improvement: [Go] simplified rpc package API: renamed structs drop the redundant Rpc infix (e.g. ModelRpcApiModelApi) (#905)
  • fix: [Go] Session.SetModel now takes a pointer for optional options instead of a variadic argument (#904)

New contributors

  • @Sumanth007 made their first contribution in #475
  • @jongalloway made their first contribution in #957
  • @Morabbin made their first contribution in #970
  • @schneidafunk made their first contribution in #998

Note

🔒 Integrity filter blocked 2 items

The following items were blocked because they don't meet the GitHub integrity level.

  • #970 search_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
  • #475 search_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".

To allow these resources, lower min-integrity in your GitHub frontmatter:

tools:
  github:
    min-integrity: approved  # merged | approved | unapproved | none

Generated by Release Changelog Generator

v0.2.1-preview.2

02 Apr 13:00
1587e34

Choose a tag to compare

v0.2.1-preview.2 Pre-release
Pre-release

Feature: onElicitationRequest callback for elicitation provider support

[Node] SDK clients can now act as elicitation providers by registering an onElicitationRequest callback in SessionConfig. The SDK negotiates the requestElicitation capability with the runtime, listens for broadcast elicitation.requested events, invokes the handler, and responds automatically. (#908)

const session = await client.createSession({
  onElicitationRequest: async (request) => {
    // respond to structured user input requests broadcast by the CLI runtime
    return { type: "string", value: "user response" };
  },
});

Feature: getSessionMetadata API across all SDKs

All SDKs now expose an efficient O(1) lookup of a single session's metadata by ID — no need to call listSessions and filter client-side. (#899)

  • TypeScript: await client.getSessionMetadata(sessionId) — returns SessionMetadata | undefined
  • C#: await client.GetSessionMetadataAsync(sessionId) — returns SessionMetadata?
  • Python: await client.get_session_metadata(session_id) — returns SessionMetadata | None
  • Go: client.GetSessionMetadata(ctx, sessionID) — returns (*SessionMetadata, error)

Feature: async context manager support for Python client and session

[Python] CopilotClient and CopilotSession now implement the async context manager protocol for automatic resource cleanup. (#475)

async with CopilotClient() as client:
    async with await client.create_session() as session:
        response = await session.get_response("Hello")

Other changes

  • bugfix: [Node, Go, Python] structured ToolResultObject values were stringified before RPC, causing toolTelemetry and resultType to be silently lost on the server side (#970)
  • improvement: [All] update bundled runtime to 1.0.15-2, resolving a regression with postToolUse hooks (#978)

New contributors

  • @Sumanth007 made their first contribution in #475
  • @Morabbin made their first contribution in #970

Generated by Release Changelog Generator

Generated by Release Changelog Generator

v0.2.1-preview.1

25 Mar 17:43
c70d632

Choose a tag to compare

v0.2.1-preview.1 Pre-release
Pre-release

Change: ephemeral events no longer included in getMessages()

Following a runtime update to 1.0.12, events like session.idle are now truly ephemeral — they are only observable via live event listeners and are not returned by session.getMessages() / get_messages(). This makes session resume behave consistently whether the session was previously active in-process or is being resumed from disk. (#927)

If your code calls getMessages() and checks for a session.idle event to determine whether a turn is complete, switch to using a live event listener instead:

session.on("session.idle", () => {
  // turn is complete
});
session.OnSessionIdle += (e) => {
    // turn is complete
};

Other changes

  • improvement: [All] COPILOT_CLI_PATH env var is now read from the effective environment configured on the client (e.g. via options.env), not just the process environment — consistent across all SDKs (#925)

Generated by Release Changelog Generator

v0.2.1-preview.0

24 Mar 22:16
5b58582

Choose a tag to compare

v0.2.1-preview.0 Pre-release
Pre-release

Feature: commands and UI elicitation support for Node.js

The Node.js SDK now supports registering slash commands and prompting users with interactive dialogs. Pass commands in session config to handle CLI slash commands; use session.ui to show confirm, select, or text-input prompts. The feature was already available in other SDKs. (#906)

const session = await client.createSession({
  commands: [{
    name: "deploy",
    handler: async (params) => ({ text: `Deploying to \$\{params.args}...` })
  }]
});

const confirmed = await session.ui.confirm({ title: "Proceed?", message: "This will deploy to production." });
const env = await session.ui.select({ title: "Environment", options: [{ value: "prod" }, { value: "staging" }] });
const note = await session.ui.input({ title: "Release note" });

Feature: custom model listing for BYOK mode

All four SDKs now accept an onListModels callback in client options. When provided, client.listModels() calls your handler instead of querying the CLI — useful for BYOK setups where you want to expose your provider's available models. (#730)

const client = new CopilotClient({
  onListModels: async () => [{ id: "gpt-4o", displayName: "GPT-4o", vendor: "OpenAI" }]
});
var client = new CopilotClient(new CopilotClientOptions {
    OnListModels = async (ct) => [new ModelInfo { Id = "gpt-4o", DisplayName = "GPT-4o" }]
});
  • Python: on_list_models=lambda: [ModelInfo(id="gpt-4o", display_name="GPT-4o")]
  • Go: OnListModels: func(ctx context.Context) ([]copilot.ModelInfo, error) { ... }

Feature: blob attachments for inline image data

A new blob attachment type lets you send base64-encoded content directly to a session without writing it to disk first — useful when images are already in memory (screenshots, API responses, generated images). (#731)

await session.sendMessage("Describe this screenshot", {
  attachments: [{ type: "blob", data: base64Data, mimeType: "image/png", displayName: "screen.png" }]
});
await session.send_message("Describe this screenshot", attachments=[
    BlobAttachment(type="blob", data=base64_data, mime_type="image/png", display_name="screen.png")
])

Other changes

  • feature: [All] tools can now set skipPermission: true to bypass per-use permission prompts for safe tools (#808)
  • bugfix: [Node] add CJS compatibility so the SDK can be require()d in VS Code extensions and other CommonJS contexts (#546)
  • bugfix: [Node] cliPath is now ignored when cliUrl is already set (#787)
  • bugfix: [C#] fix SessionEvent.ToJson() failing for events with JsonElement-backed members (e.g. tool.execution_start, session.shutdown) (#868)
  • bugfix: [C#] unknown session event types no longer throw; they are returned as UnknownSessionEvent preserving the raw JSON (#881)
  • bugfix: [C#] fix AOT serialization crash when a CancellationToken fires during a JSON-RPC operation (#783)
  • improvement: [C#] optional RPC parameters are now optional method parameters, preventing source-breaking changes when new optional params are added by the runtime (#733)
  • bugfix: [Go] all enum constants are now consistently named using the TypeNameValue convention (e.g. SessionEventTypeSessionIdle, ModeInteractive) — breaking change: update any references using the old unprefixed names (#883)
  • improvement: [Go] Rpc suffix removed from struct names in the rpc package (e.g. ModelRpcApiModelApi) (#905)
  • bugfix: [Go] Session.SetModel now takes *SetModelOptions instead of a variadic argument (#904)
  • bugfix: [Python] workspace_path in CopilotSession now accepts any os.PathLike value, not just strings (#901)
  • improvement: [Python] telemetry, jsonrpc, and sdk_protocol_version modules are now marked as private (#884)

New contributors

  • @darthmolen made their first contribution in #546
  • @MackinnonBuck made their first contribution in #731
  • @kirankashyap made their first contribution in #740
  • @PureWeen made their first contribution in #783
  • @stefansedich made their first contribution in #784
  • @sergiou87 made their first contribution in #787
  • @MRayermannMSFT made their first contribution in #808
  • @xoofx made their first contribution in #868
  • @jamesmontemagno made their first contribution in #879
  • @Ron537 made their first contribution in #881
  • @edburns made their first contribution in #889

Generated by Release Changelog Generator

v0.2.0

20 Mar 19:50
1ff9e1b

Choose a tag to compare

This is a big update with a broad round of API refinements, new capabilities, and cross-SDK consistency improvements that have shipped incrementally through preview releases since v0.1.32.

Highlights

Fine-grained system prompt customization

A new "customize" mode for systemMessage lets you surgically edit individual sections of the Copilot system prompt — without replacing the entire thing. Ten sections are configurable: identity, tone, tool_efficiency, environment_context, code_change_rules, guidelines, safety, tool_instructions, custom_instructions, and last_instructions.

Each section supports four static actions (replace, remove, append, prepend) and a transform callback that receives the current rendered content and returns modified text — useful for regex mutations, conditional edits, or logging what the prompt contains. (#816)

const session = await client.createSession({
  onPermissionRequest: approveAll,
  systemMessage: {
    mode: "customize",
    sections: {
      identity: {
        action: (current) => current.replace("GitHub Copilot", "Acme Assistant"),
      },
      tone: { action: "replace", content: "Be concise and professional." },
      code_change_rules: { action: "remove" },
    },
  },
});
var session = await client.CreateSessionAsync(new SessionConfig {
    OnPermissionRequest = PermissionHandler.ApproveAll,
    SystemMessage = new SystemMessageConfig {
        Mode = SystemMessageMode.Customize,
        Sections = new Dictionary<string, SectionOverride> {
            ["identity"] = new() {
                Transform = current => Task.FromResult(current.Replace("GitHub Copilot", "Acme Assistant")),
            },
            ["tone"] = new() { Action = SectionOverrideAction.Replace, Content = "Be concise and professional." },
            ["code_change_rules"] = new() { Action = SectionOverrideAction.Remove },
        },
    },
});

OpenTelemetry support across all SDKs

All four SDK languages now support distributed tracing with the Copilot CLI. Set telemetry in your client options to configure an OTLP exporter; W3C trace context is automatically propagated on session.create, session.resume, and session.send, and restored in tool handlers so tool execution is linked to the originating trace. (#785)

const client = new CopilotClient({
  telemetry: {
    otlpEndpoint: "http://localhost:4318",
    sourceName: "my-app",
  },
});
var client = new CopilotClient(new CopilotClientOptions {
    Telemetry = new TelemetryConfig {
        OtlpEndpoint = "http://localhost:4318",
        SourceName = "my-app",
    },
});
  • Python: CopilotClient(SubprocessConfig(telemetry={"otlp_endpoint": "http://localhost:4318", "source_name": "my-app"}))
  • Go: copilot.NewClient(&copilot.ClientOptions{Telemetry: &copilot.TelemetryConfig{OTLPEndpoint: "http://localhost:4318", SourceName: "my-app"}})

Blob attachments for inline binary data

A new blob attachment type lets you send images or other binary content directly to a session without writing to disk — useful when data is already in memory (screenshots, API responses, generated images). (#731)

await session.send({
  prompt: "What's in this image?",
  attachments: [{ type: "blob", data: base64Str, mimeType: "image/png" }],
});
await session.SendAsync(new MessageOptions {
    Prompt = "What's in this image?",
    Attachments = [new UserMessageDataAttachmentsItemBlob { Data = base64Str, MimeType = "image/png" }],
});

Pre-select a custom agent at session creation

You can now specify which custom agent should be active when a session starts, eliminating the need for a separate session.rpc.agent.select() call. (#722)

const session = await client.createSession({
  customAgents: [
    { name: "researcher", prompt: "You are a research assistant." },
    { name: "editor", prompt: "You are a code editor." },
  ],
  agent: "researcher",
  onPermissionRequest: approveAll,
});
var session = await client.CreateSessionAsync(new SessionConfig {
    CustomAgents = [
        new CustomAgentConfig { Name = "researcher", Prompt = "You are a research assistant." },
        new CustomAgentConfig { Name = "editor", Prompt = "You are a code editor." },
    ],
    Agent = "researcher",
    OnPermissionRequest = PermissionHandler.ApproveAll,
});

New features

  • skipPermission on tool definitions — Tools can now be registered with skipPermission: true to bypass the confirmation prompt for low-risk operations like read-only queries. Available in all four SDKs. (#808)
  • reasoningEffort when switching models — All SDKs now accept an optional reasoningEffort parameter in setModel() for models that support it. (#712)
  • Custom model listing for BYOK — Applications using bring-your-own-key providers can supply onListModels in client options to override client.listModels() with their own model list. (#730)
  • no-result permission outcome — Permission handlers can now return "no-result" so extensions can attach to sessions without actively answering permission requests. (#802)
  • SessionConfig.onEvent catch-all — A new onEvent handler on session config is registered before the RPC is issued, guaranteeing that early events like session.start are never dropped. (#664)
  • Node.js CJS compatibility — The Node.js SDK now ships both ESM and CJS builds, fixing crashes in VS Code extensions and other tools bundled with esbuild's format: "cjs". No changes needed in consumer code. (#546)
  • Experimental API annotations — APIs marked experimental in the schema (agent, fleet, compaction groups) are now annotated in all four SDKs: [Experimental] in C#, /** @experimental */ in TypeScript, and comments in Python and Go. (#875)
  • System notifications and session log APIs — Updated to match the latest CLI runtime, adding system.notification events and a session log RPC API. (#737)

Improvements

  • [.NET, Go] Serialize event dispatch so handlers are invoked in registration order with no concurrent calls (#791)
  • [Go] Detach CLI process lifespan from the context passed to Client.Start so cancellation no longer kills the child process (#689)
  • [Go] Stop RPC client logging expected EOF errors (#609)
  • [.NET] Emit XML doc comments from schema descriptions in generated RPC code (#724)
  • [.NET] Use lazy property initialization in generated RPC classes (#725)
  • [.NET] Add DebuggerDisplay attribute to SessionEvent for easier debugging (#726)
  • [.NET] Optional RPC params are now represented as optional method params for forward-compatible generated code (#733)
  • [.NET] Replace Task.WhenAny + Task.Delay timeout pattern with .WaitAsync(TimeSpan) (#805)
  • [.NET] Add NuGet package icon (#688)
  • [Node] Don't resolve cliPath when cliUrl is already set (#787)

New RPC methods

We've added low-level RPC methods to control a lot more of what's going on in the session. These are emerging APIs that don't yet have friendly wrappers, and some may be flagged as experimental or subject to change.

  • session.rpc.skills.list(), .enable(name), .disable(name), .reload()
  • session.rpc.mcp.list(), .enable(name), .disable(name), .reload()
  • session.rpc.extensions.list(), .enable(name), .disable(name), .reload()
  • session.rpc.plugins.list()
  • session.rpc.ui.elicitation(...) — structured user input
  • session.rpc.shell.exec(command), .kill(pid)
  • session.log(message, level, ephemeral)

In an forthcoming update, we'll add friendlier wrappers for these.

Bug fixes

  • [.NET] Fix SessionEvent.ToJson() failing for events with JsonElement-backed payloads (assistant.message, tool.execution_start, etc.) (#868)
  • [.NET] Add fallback TypeInfoResolver for StreamJsonRpc.RequestId to fix NativeAOT compatibility (#783)
  • [.NET] Fix codegen for discriminated unions nested within other types (#736)
  • [.NET] Handle unknown session event types gracefully instead of throwing (#881)

⚠️ Breaking changes

All SDKs

  • autoRestart removed — The autoRestart option has been deprecated across all SDKs (it was never fully implemented). The property still exists but has no effect and will be removed in a future release. Remove any references to autoRestart from your client options. (#803)

Python

The Pyth...

Read more