Skip to content

v0.2.0

Latest

Choose a tag to compare

@github-actions github-actions released this 20 Mar 19:50
1ff9e1b

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 Python SDK received a significant API surface overhaul in this release, replacing loosely-typed TypedDict config objects with proper keyword arguments and dataclasses. These changes improve IDE autocompletion, type safety, and readability.

  • CopilotClient constructor redesigned — The CopilotClientOptions TypedDict has been replaced by two typed config dataclasses. (#793)

    # Before (v0.1.x)
    client = CopilotClient({"cli_url": "localhost:3000"})
    client = CopilotClient({"cli_path": "/usr/bin/copilot", "log_level": "debug"})
    
    # After (v0.2.0)
    client = CopilotClient(ExternalServerConfig(url="localhost:3000"))
    client = CopilotClient(SubprocessConfig(cli_path="/usr/bin/copilot", log_level="debug"))
  • create_session() and resume_session() now take keyword arguments instead of a SessionConfig / ResumeSessionConfig TypedDict. on_permission_request is now a required keyword argument. (#587)

    # Before
    session = await client.create_session({
        "on_permission_request": PermissionHandler.approve_all,
        "model": "gpt-4.1",
    })
    
    # After
    session = await client.create_session(
        on_permission_request=PermissionHandler.approve_all,
        model="gpt-4.1",
    )
  • send() and send_and_wait() take a positional prompt string instead of a MessageOptions TypedDict. Attachments and mode are now keyword arguments. (#814)

    # Before
    await session.send({"prompt": "Hello!"})
    await session.send_and_wait({"prompt": "What is 2+2?"})
    
    # After
    await session.send("Hello!")
    await session.send_and_wait("What is 2+2?")
  • MessageOptions, SessionConfig, and ResumeSessionConfig removed from public API — These TypedDicts are no longer exported. Use the new keyword-argument signatures directly. (#587, #814)

  • Internal modules renamed to privatecopilot.jsonrpc, copilot.sdk_protocol_version, and copilot.telemetry are now copilot._jsonrpc, copilot._sdk_protocol_version, and copilot._telemetry. If you were importing from these modules directly, update your imports. (#884)

  • 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 the context.Context passed to Start() would terminate the spawned CLI process (it used exec.CommandContext). Now the CLI process lifespan is independent of that context — call client.Stop() or client.ForceStop() to shut it down. (#689)

  • LogOptions.Ephemeral changed from bool to *bool — This enables proper three-state semantics (unset/true/false). Use copilot.Bool(true) instead of a bare true. (#827)

    // 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

Full Changelog: v0.1.32...v0.2.0