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
skipPermissionon tool definitions — Tools can now be registered withskipPermission: trueto bypass the confirmation prompt for low-risk operations like read-only queries. Available in all four SDKs. (#808)reasoningEffortwhen switching models — All SDKs now accept an optionalreasoningEffortparameter insetModel()for models that support it. (#712)- Custom model listing for BYOK — Applications using bring-your-own-key providers can supply
onListModelsin client options to overrideclient.listModels()with their own model list. (#730) no-resultpermission outcome — Permission handlers can now return"no-result"so extensions can attach to sessions without actively answering permission requests. (#802)SessionConfig.onEventcatch-all — A newonEventhandler on session config is registered before the RPC is issued, guaranteeing that early events likesession.startare 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.notificationevents 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.Startso 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
DebuggerDisplayattribute toSessionEventfor 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.Delaytimeout pattern with.WaitAsync(TimeSpan)(#805) - [.NET] Add NuGet package icon (#688)
- [Node] Don't resolve
cliPathwhencliUrlis 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 inputsession.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 withJsonElement-backed payloads (assistant.message,tool.execution_start, etc.) (#868) - [.NET] Add fallback
TypeInfoResolverforStreamJsonRpc.RequestIdto 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
autoRestartremoved — TheautoRestartoption 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 toautoRestartfrom your client options. (#803)
Python
The Python SDK received a significant API surface overhaul in this release, replacing loosely-typed TypedDict config objects with proper keyword arguments and dataclasses. These changes improve IDE autocompletion, type safety, and readability.
-
CopilotClientconstructor redesigned — TheCopilotClientOptionsTypedDict has been replaced by two typed config dataclasses. (#793)# Before (v0.1.x) client = CopilotClient({"cli_url": "localhost:3000"}) client = CopilotClient({"cli_path": "/usr/bin/copilot", "log_level": "debug"}) # After (v0.2.0) client = CopilotClient(ExternalServerConfig(url="localhost:3000")) client = CopilotClient(SubprocessConfig(cli_path="/usr/bin/copilot", log_level="debug"))
-
create_session()andresume_session()now take keyword arguments instead of aSessionConfig/ResumeSessionConfigTypedDict.on_permission_requestis now a required keyword argument. (#587)# Before session = await client.create_session({ "on_permission_request": PermissionHandler.approve_all, "model": "gpt-4.1", }) # After session = await client.create_session( on_permission_request=PermissionHandler.approve_all, model="gpt-4.1", )
-
send()andsend_and_wait()take a positionalpromptstring instead of aMessageOptionsTypedDict. Attachments and mode are now keyword arguments. (#814)# Before await session.send({"prompt": "Hello!"}) await session.send_and_wait({"prompt": "What is 2+2?"}) # After await session.send("Hello!") await session.send_and_wait("What is 2+2?")
-
MessageOptions,SessionConfig, andResumeSessionConfigremoved from public API — These TypedDicts are no longer exported. Use the new keyword-argument signatures directly. (#587, #814) -
Internal modules renamed to private —
copilot.jsonrpc,copilot.sdk_protocol_version, andcopilot.telemetryare nowcopilot._jsonrpc,copilot._sdk_protocol_version, andcopilot._telemetry. If you were importing from these modules directly, update your imports. (#884) -
Typed overloads for
CopilotClient.on()— Event registration now uses typed overloads for better autocomplete. This shouldn't break existing code but changes the type signature. (#589)
Go
-
Client.Start()context no longer kills the CLI process — Previously, canceling thecontext.Contextpassed toStart()would terminate the spawned CLI process (it usedexec.CommandContext). Now the CLI process lifespan is independent of that context — callclient.Stop()orclient.ForceStop()to shut it down. (#689) -
LogOptions.Ephemeralchanged fromboolto*bool— This enables proper three-state semantics (unset/true/false). Usecopilot.Bool(true)instead of a baretrue. (#827)// Before session.Log(ctx, copilot.LogOptions{Level: copilot.LevelInfo, Ephemeral: true}, "message") // After session.Log(ctx, copilot.LogOptions{Level: copilot.LevelInfo, Ephemeral: copilot.Bool(true)}, "message")
New Contributors
- @kirankashyap made their first contribution in #740
- @sergiou87 made their first contribution in #787
- @MRayermannMSFT made their first contribution in #808
- @stefansedich made their first contribution in #784
- @PureWeen made their first contribution in #783
- @jamesmontemagno made their first contribution in #879
- @MackinnonBuck made their first contribution in #731
- @xoofx made their first contribution in #868
- @edburns made their first contribution in #889
- @darthmolen made their first contribution in #546
- @Ron537 made their first contribution in #881
Full Changelog: v0.1.32...v0.2.0