From 63a79ba4861599779647a577be9f685154dc1d8a Mon Sep 17 00:00:00 2001 From: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com> Date: Fri, 29 May 2026 15:03:40 -0700 Subject: [PATCH 1/2] Expose context tier in SDK set model APIs --- dotnet/src/Generated/Rpc.cs | 134 +----------------- dotnet/src/Session.cs | 32 ++++- dotnet/src/Types.cs | 28 ++++ dotnet/test/Unit/SerializationTests.cs | 21 ++- go/rpc/zrpc.go | 24 +--- go/session.go | 4 + go/types.go | 6 +- .../copilot/generated/rpc/ContextTier.java | 35 +++++ .../generated/rpc/SessionModelApi.java | 2 +- .../rpc/SessionModelGetCurrentResult.java | 6 +- .../rpc/SessionModelSwitchToParams.java | 6 +- .../com/github/copilot/CopilotSession.java | 42 +++++- .../com/github/copilot/RpcWrappersTest.java | 4 +- .../rpc/GeneratedRpcRecordsCoverageTest.java | 11 +- nodejs/src/generated/rpc.ts | 16 +-- nodejs/src/session.ts | 2 + nodejs/src/types.ts | 10 +- nodejs/test/client.test.ts | 2 + python/copilot/generated/rpc.py | 22 +-- python/copilot/session.py | 4 + python/test_client.py | 7 +- rust/src/generated/api_types.rs | 31 +--- rust/src/session.rs | 1 + rust/src/types.rs | 49 ++++--- rust/src/wire.rs | 6 +- rust/tests/session_test.rs | 5 +- 26 files changed, 260 insertions(+), 250 deletions(-) create mode 100644 java/src/generated/java/com/github/copilot/generated/rpc/ContextTier.java diff --git a/dotnet/src/Generated/Rpc.cs b/dotnet/src/Generated/Rpc.cs index 346177f63..660adc9f7 100644 --- a/dotnet/src/Generated/Rpc.cs +++ b/dotnet/src/Generated/Rpc.cs @@ -2491,7 +2491,7 @@ public sealed class CurrentModel { /// Context tier currently pinned for the session, when one is set. Reflects `Session.getContextTier()`, restored from the session journal on resume. [JsonPropertyName("contextTier")] - public ModelCurrentContextTier? ContextTier { get; set; } + public ContextTier? ContextTier { get; set; } /// Currently active model identifier. [JsonPropertyName("modelId")] @@ -2590,7 +2590,7 @@ internal sealed class ModelSwitchToRequest { /// Explicit context tier for the selected model. `"default"` / `"long_context"` pin the tier; `null` clears any previous explicit choice; `undefined` leaves the existing tier untouched. [JsonPropertyName("contextTier")] - public ModelSwitchToRequestContextTier? ContextTier { get; set; } + public ContextTier? ContextTier { get; set; } /// Override individual model capabilities resolved by the runtime. [JsonPropertyName("modelCapabilities")] @@ -9741,131 +9741,6 @@ public override void Write(Utf8JsonWriter writer, CanvasInstanceAvailability val } -/// Context tier currently pinned for the session, when one is set. Reflects `Session.getContextTier()`, restored from the session journal on resume. -[Experimental(Diagnostics.Experimental)] -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct ModelCurrentContextTier : IEquatable -{ - private readonly string? _value; - - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public ModelCurrentContextTier(string value) - { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; - } - - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// Use the model's default context window. - public static ModelCurrentContextTier Default { get; } = new("default"); - - /// Pin the session to the long-context tier when supported. - public static ModelCurrentContextTier LongContext { get; } = new("long_context"); - - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ModelCurrentContextTier left, ModelCurrentContextTier right) => left.Equals(right); - - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ModelCurrentContextTier left, ModelCurrentContextTier right) => !(left == right); - - /// - public override bool Equals(object? obj) => obj is ModelCurrentContextTier other && Equals(other); - - /// - public bool Equals(ModelCurrentContextTier other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - - /// - public override string ToString() => Value; - - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter - { - /// - public override ModelCurrentContextTier Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } - - /// - public override void Write(Utf8JsonWriter writer, ModelCurrentContextTier value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ModelCurrentContextTier)); - } - } -} - - -/// Defines the allowed values. -[JsonConverter(typeof(Converter))] -[DebuggerDisplay("{Value,nq}")] -public readonly struct ModelSwitchToRequestContextTier : IEquatable -{ - private readonly string? _value; - - /// Initializes a new instance of the struct. - /// The value to associate with this . - [JsonConstructor] - public ModelSwitchToRequestContextTier(string value) - { - ArgumentException.ThrowIfNullOrWhiteSpace(value); - _value = value; - } - - /// Gets the value associated with this . - public string Value => _value ?? string.Empty; - - /// Use the model's default context window. - public static ModelSwitchToRequestContextTier Default { get; } = new("default"); - - /// Pin the session to the long-context tier when supported. - public static ModelSwitchToRequestContextTier LongContext { get; } = new("long_context"); - - /// Returns a value indicating whether two instances are equivalent. - public static bool operator ==(ModelSwitchToRequestContextTier left, ModelSwitchToRequestContextTier right) => left.Equals(right); - - /// Returns a value indicating whether two instances are not equivalent. - public static bool operator !=(ModelSwitchToRequestContextTier left, ModelSwitchToRequestContextTier right) => !(left == right); - - /// - public override bool Equals(object? obj) => obj is ModelSwitchToRequestContextTier other && Equals(other); - - /// - public bool Equals(ModelSwitchToRequestContextTier other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase); - - /// - public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value); - - /// - public override string ToString() => Value; - - /// Provides a for serializing instances. - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class Converter : JsonConverter - { - /// - public override ModelSwitchToRequestContextTier Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert)); - } - - /// - public override void Write(Utf8JsonWriter writer, ModelSwitchToRequestContextTier value, JsonSerializerOptions options) - { - GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ModelSwitchToRequestContextTier)); - } - } -} - - /// Allowed values for the `WorkspacesWorkspaceDetailsHostType` enumeration. [Experimental(Diagnostics.Experimental)] [JsonConverter(typeof(Converter))] @@ -13917,7 +13792,7 @@ public async Task GetCurrentAsync(CancellationToken cancellationTo /// Explicit context tier for the selected model. `"default"` / `"long_context"` pin the tier; `null` clears any previous explicit choice; `undefined` leaves the existing tier untouched. /// The to monitor for cancellation requests. The default is . /// The model identifier active on the session after the switch. - public async Task SwitchToAsync(string modelId, string? reasoningEffort = null, ReasoningSummary? reasoningSummary = null, ModelCapabilitiesOverride? modelCapabilities = null, ModelSwitchToRequestContextTier? contextTier = null, CancellationToken cancellationToken = default) + public async Task SwitchToAsync(string modelId, string? reasoningEffort = null, ReasoningSummary? reasoningSummary = null, ModelCapabilitiesOverride? modelCapabilities = null, ContextTier? contextTier = null, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(modelId); _session.ThrowIfDisposed(); @@ -16359,6 +16234,7 @@ public static void RegisterClientSessionApiHandlers(JsonRpc rpc, Func /// await session.SetModelAsync("gpt-4.1"); /// await session.SetModelAsync("claude-sonnet-4.6", "high"); + /// await session.SetModelAsync("gpt-4.1", new SetModelOptions { ContextTier = ContextTier.LongContext }); /// /// - public async Task SetModelAsync(string model, string? reasoningEffort, ModelCapabilitiesOverride? modelCapabilities = null, CancellationToken cancellationToken = default) + public Task SetModelAsync(string model, string? reasoningEffort, ModelCapabilitiesOverride? modelCapabilities = null, CancellationToken cancellationToken = default) + { + return SetModelAsync( + model, + new SetModelOptions + { + ReasoningEffort = reasoningEffort, + ModelCapabilities = modelCapabilities, + }, + cancellationToken); + } + + /// + /// Changes the model for this session. + /// The new model takes effect for the next message. Conversation history is preserved. + /// + /// Model ID to switch to (e.g., "gpt-4.1"). + /// Settings for the new model. + /// Optional cancellation token. + public async Task SetModelAsync(string model, SetModelOptions options, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(model); ThrowIfDisposed(); - await Rpc.Model.SwitchToAsync(model, reasoningEffort, reasoningSummary: null, modelCapabilities: modelCapabilities, cancellationToken: cancellationToken); + await Rpc.Model.SwitchToAsync( + model, + options.ReasoningEffort, + options.ReasoningSummary, + options.ModelCapabilities, + options.ContextTier, + cancellationToken); } /// @@ -1593,7 +1619,7 @@ public Task SetModelAsync(string model, CancellationToken cancellationToken = de { ThrowIfDisposed(); - return SetModelAsync(model, reasoningEffort: null, modelCapabilities: null, cancellationToken); + return SetModelAsync(model, new SetModelOptions(), cancellationToken); } /// diff --git a/dotnet/src/Types.cs b/dotnet/src/Types.cs index e26391069..c32ecd545 100644 --- a/dotnet/src/Types.cs +++ b/dotnet/src/Types.cs @@ -2449,6 +2449,33 @@ public override void Write(Utf8JsonWriter writer, ContextTier value, JsonSeriali } } +/// +/// Optional settings for . +/// +public struct SetModelOptions +{ + /// + /// Reasoning effort level for the new model. + /// + public string? ReasoningEffort { get; set; } + + /// + /// Reasoning summary mode for models that support configurable reasoning summaries. + /// + /// + /// Use to suppress summary output regardless of whether reasoning is enabled. + /// + public ReasoningSummary? ReasoningSummary { get; set; } + + /// + /// Context window tier for models that support it. + /// + public ContextTier? ContextTier { get; set; } + + /// Per-property overrides for model capabilities, deep-merged over runtime defaults. + public ModelCapabilitiesOverride? ModelCapabilities { get; set; } +} + /// /// Shared configuration properties for creating or resuming a Copilot session. /// Use when creating a new session, or @@ -3556,6 +3583,7 @@ public sealed class SystemMessageTransformRpcResponse [JsonSerializable(typeof(SessionListFilter))] [JsonSerializable(typeof(SectionOverride))] [JsonSerializable(typeof(SessionMetadata))] +[JsonSerializable(typeof(SetModelOptions))] [JsonSerializable(typeof(SetForegroundSessionResponse))] [JsonSerializable(typeof(SystemMessageConfig))] [JsonSerializable(typeof(ToolBinaryResult))] diff --git a/dotnet/test/Unit/SerializationTests.cs b/dotnet/test/Unit/SerializationTests.cs index b0797d34b..fd0ab47c0 100644 --- a/dotnet/test/Unit/SerializationTests.cs +++ b/dotnet/test/Unit/SerializationTests.cs @@ -87,7 +87,7 @@ public void SendMessageRequest_CanSerializeRequestHeaders_WithSdkOptions() ("Mode", "enqueue"), ("RequestHeaders", new Dictionary { ["X-Trace"] = "trace-value" })); - var json = JsonSerializer.Serialize(request, requestType, options); + var json = JsonSerializer.Serialize(request, requestType!, options); using var document = JsonDocument.Parse(json); var root = document.RootElement; Assert.Equal("session-id", root.GetProperty("sessionId").GetString()); @@ -221,6 +221,25 @@ public void SessionRequests_CanSerializeContextTier_WithSdkOptions() Assert.Equal("default", resumeDocument.RootElement.GetProperty("contextTier").GetString()); } + [Fact] + public void ModelSwitchToRequest_CanSerializeContextTier_WithSdkOptions() + { + var options = GetSerializerOptions(); + var requestType = typeof(CopilotClient).Assembly.GetType("GitHub.Copilot.Rpc.ModelSwitchToRequest"); + Assert.NotNull(requestType); + var request = CreateInternalRequest( + requestType!, + ("ModelId", "gpt-4.1"), + ("ReasoningSummary", ReasoningSummary.Detailed), + ("ContextTier", ContextTier.LongContext)); + + var json = JsonSerializer.Serialize(request, requestType, options); + using var document = JsonDocument.Parse(json); + Assert.Equal("gpt-4.1", document.RootElement.GetProperty("modelId").GetString()); + Assert.Equal("detailed", document.RootElement.GetProperty("reasoningSummary").GetString()); + Assert.Equal("long_context", document.RootElement.GetProperty("contextTier").GetString()); + } + [Fact] public void SessionRequests_CanSerializePluginDirectoriesAndLargeOutput_WithSdkOptions() { diff --git a/go/rpc/zrpc.go b/go/rpc/zrpc.go index e2c735ada..6bc2c3eaf 100644 --- a/go/rpc/zrpc.go +++ b/go/rpc/zrpc.go @@ -909,7 +909,7 @@ type CopilotUserResponseQuotaSnapshotsPremiumInteractions struct { type CurrentModel struct { // Context tier currently pinned for the session, when one is set. Reflects // `Session.getContextTier()`, restored from the session journal on resume. - ContextTier *ModelCurrentContextTier `json:"contextTier,omitempty"` + ContextTier *ContextTier `json:"contextTier,omitempty"` // Currently active model identifier ModelID *string `json:"modelId,omitempty"` // Reasoning effort level currently applied to the active model, when one is set. Reads @@ -2468,7 +2468,7 @@ type ModelSwitchToRequest struct { // Explicit context tier for the selected model. `"default"` / `"long_context"` pin the // tier; `null` clears any previous explicit choice; `undefined` leaves the existing tier // untouched. - ContextTier *ModelSwitchToRequestContextTier `json:"contextTier,omitempty"` + ContextTier *ContextTier `json:"contextTier,omitempty"` // Override individual model capabilities resolved by the runtime ModelCapabilities *ModelCapabilitiesOverride `json:"modelCapabilities,omitempty"` // Model identifier to switch to @@ -7315,17 +7315,14 @@ const ( MetadataSnapshotRemoteMetadataTaskTypeCli MetadataSnapshotRemoteMetadataTaskType = "cli" ) -// Context tier currently pinned for the session, when one is set. Reflects -// `Session.getContextTier()`, restored from the session journal on resume. -// Experimental: ModelCurrentContextTier is part of an experimental API and may change or be -// removed. -type ModelCurrentContextTier string +// ContextTier identifies a context window tier for models that support tiered context windows. +type ContextTier string const ( // Use the model's default context window. - ModelCurrentContextTierDefault ModelCurrentContextTier = "default" + ContextTierDefault ContextTier = "default" // Pin the session to the long-context tier when supported. - ModelCurrentContextTierLongContext ModelCurrentContextTier = "long_context" + ContextTierLongContext ContextTier = "long_context" ) // Model capability category for grouping in the model picker @@ -7366,15 +7363,6 @@ const ( ModelPolicyStateUnconfigured ModelPolicyState = "unconfigured" ) -type ModelSwitchToRequestContextTier string - -const ( - // Use the model's default context window. - ModelSwitchToRequestContextTierDefault ModelSwitchToRequestContextTier = "default" - // Pin the session to the long-context tier when supported. - ModelSwitchToRequestContextTierLongContext ModelSwitchToRequestContextTier = "long_context" -) - // How env values are passed to MCP servers (`direct` inlines literal values; `indirect` // resolves at launch). // Experimental: OptionsUpdateEnvValueMode is part of an experimental API and may change or diff --git a/go/session.go b/go/session.go index fa03f5cc7..b2ca82755 100644 --- a/go/session.go +++ b/go/session.go @@ -1495,6 +1495,9 @@ type SetModelOptions struct { // ReasoningSummary sets the reasoning summary mode for the new model. // Use ReasoningSummaryNone to suppress summary output regardless of whether reasoning is enabled. ReasoningSummary *ReasoningSummary + // ContextTier pins the session to a context window tier for models that support it. + // Use ContextTierDefault or ContextTierLongContext for the currently known tiers. + ContextTier *ContextTier // ModelCapabilities overrides individual model capabilities resolved by the runtime. // Only non-nil fields are applied over the runtime-resolved capabilities. ModelCapabilities *rpc.ModelCapabilitiesOverride @@ -1516,6 +1519,7 @@ func (s *Session) SetModel(ctx context.Context, model string, opts *SetModelOpti if opts != nil { params.ReasoningEffort = opts.ReasoningEffort params.ReasoningSummary = opts.ReasoningSummary + params.ContextTier = opts.ContextTier params.ModelCapabilities = opts.ModelCapabilities } _, err := s.RPC.Model.SwitchTo(ctx, params) diff --git a/go/types.go b/go/types.go index 9dcb61602..465325f9d 100644 --- a/go/types.go +++ b/go/types.go @@ -860,13 +860,13 @@ type LargeToolOutputConfig struct { } // ContextTier identifies a context window tier for models that support tiered context windows. -type ContextTier string +type ContextTier = rpc.ContextTier const ( // ContextTierDefault is the default context tier with standard context window size. - ContextTierDefault ContextTier = "default" + ContextTierDefault ContextTier = rpc.ContextTierDefault // ContextTierLongContext is the extended context tier with a larger context window. - ContextTierLongContext ContextTier = "long_context" + ContextTierLongContext ContextTier = rpc.ContextTierLongContext ) // SessionFsCapabilities declares optional provider capabilities. diff --git a/java/src/generated/java/com/github/copilot/generated/rpc/ContextTier.java b/java/src/generated/java/com/github/copilot/generated/rpc/ContextTier.java new file mode 100644 index 000000000..4a6b8846e --- /dev/null +++ b/java/src/generated/java/com/github/copilot/generated/rpc/ContextTier.java @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// AUTO-GENERATED FILE - DO NOT EDIT +// Generated from: api.schema.json + +package com.github.copilot.generated.rpc; + +import javax.annotation.processing.Generated; + +/** + * Context window tier for models that support tiered context windows. + * + * @since 1.0.0 + */ +@javax.annotation.processing.Generated("copilot-sdk-codegen") +public enum ContextTier { + /** The {@code default} variant. */ + DEFAULT("default"), + /** The {@code long_context} variant. */ + LONG_CONTEXT("long_context"); + + private final String value; + ContextTier(String value) { this.value = value; } + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { return value; } + @com.fasterxml.jackson.annotation.JsonCreator + public static ContextTier fromValue(String value) { + for (ContextTier v : values()) { + if (v.value.equals(value)) return v; + } + throw new IllegalArgumentException("Unknown ContextTier value: " + value); + } +} diff --git a/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelApi.java b/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelApi.java index eda751b3e..d4c0a4e34 100644 --- a/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelApi.java +++ b/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelApi.java @@ -40,7 +40,7 @@ public CompletableFuture getCurrent() { } /** - * Target model identifier and optional reasoning effort, summary, and capability overrides. + * Target model identifier and optional reasoning effort, summary, capability overrides, and context tier. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetCurrentResult.java b/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetCurrentResult.java index 7bb2f8496..8ab022ac9 100644 --- a/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetCurrentResult.java +++ b/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetCurrentResult.java @@ -13,7 +13,7 @@ import javax.annotation.processing.Generated; /** - * The currently selected model and reasoning effort for the session. + * The currently selected model, reasoning effort, and context tier for the session. * * @since 1.0.0 */ @@ -24,6 +24,8 @@ public record SessionModelGetCurrentResult( /** Currently active model identifier */ @JsonProperty("modelId") String modelId, /** Reasoning effort level currently applied to the active model, when one is set. Reads `Session.getReasoningEffort()` synchronously after `getSelectedModel()` resolves so the two values are reported as a snapshot. */ - @JsonProperty("reasoningEffort") String reasoningEffort + @JsonProperty("reasoningEffort") String reasoningEffort, + /** Context tier currently pinned for the session, when one is set. Reflects `Session.getContextTier()`, restored from the session journal on resume. */ + @JsonProperty("contextTier") ContextTier contextTier ) { } diff --git a/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelSwitchToParams.java b/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelSwitchToParams.java index c5c1cbbe0..4cda275a2 100644 --- a/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelSwitchToParams.java +++ b/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelSwitchToParams.java @@ -13,7 +13,7 @@ import javax.annotation.processing.Generated; /** - * Target model identifier and optional reasoning effort, summary, and capability overrides. + * Target model identifier and optional reasoning effort, summary, capability overrides, and context tier. * * @since 1.0.0 */ @@ -30,6 +30,8 @@ public record SessionModelSwitchToParams( /** Reasoning summary mode to request for supported model clients */ @JsonProperty("reasoningSummary") ReasoningSummary reasoningSummary, /** Override individual model capabilities resolved by the runtime */ - @JsonProperty("modelCapabilities") ModelCapabilitiesOverride modelCapabilities + @JsonProperty("modelCapabilities") ModelCapabilitiesOverride modelCapabilities, + /** Explicit context tier for the selected model. `"default"` / `"long_context"` pin the tier; `null` clears any previous explicit choice; `undefined` leaves the existing tier untouched. */ + @JsonProperty("contextTier") ContextTier contextTier ) { } diff --git a/java/src/main/java/com/github/copilot/CopilotSession.java b/java/src/main/java/com/github/copilot/CopilotSession.java index 64c02d8b8..61bd6bbeb 100644 --- a/java/src/main/java/com/github/copilot/CopilotSession.java +++ b/java/src/main/java/com/github/copilot/CopilotSession.java @@ -31,6 +31,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.github.copilot.generated.AssistantMessageEvent; import com.github.copilot.generated.rpc.SessionCommandsHandlePendingCommandParams; +import com.github.copilot.generated.rpc.ContextTier; import com.github.copilot.generated.rpc.SessionLogParams; import com.github.copilot.generated.rpc.SessionLogLevel; import com.github.copilot.generated.rpc.ModelCapabilitiesOverride; @@ -1696,9 +1697,7 @@ public CompletableFuture abort() { * @since 1.2.0 */ public CompletableFuture setModel(String model, String reasoningEffort) { - ensureNotTerminated(); - return getRpc().model.switchTo(new SessionModelSwitchToParams(sessionId, model, reasoningEffort, null, null)) - .thenApply(r -> null); + return setModel(model, reasoningEffort, null, null, null); } /** @@ -1729,7 +1728,7 @@ public CompletableFuture setModel(String model, String reasoningEffort) { */ public CompletableFuture setModel(String model, String reasoningEffort, com.github.copilot.rpc.ModelCapabilitiesOverride modelCapabilities) { - return setModel(model, reasoningEffort, null, modelCapabilities); + return setModel(model, reasoningEffort, null, modelCapabilities, null); } /** @@ -1758,6 +1757,38 @@ public CompletableFuture setModel(String model, String reasoningEffort, */ public CompletableFuture setModel(String model, String reasoningEffort, String reasoningSummary, com.github.copilot.rpc.ModelCapabilitiesOverride modelCapabilities) { + return setModel(model, reasoningEffort, reasoningSummary, modelCapabilities, null); + } + + /** + * Changes the model for this session with optional reasoning effort, reasoning + * summary mode, capability overrides, and context tier. + *

+ * The new model takes effect for the next message. Conversation history is + * preserved. + * + * @param model + * the model ID to switch to (e.g., {@code "gpt-4.1"}) + * @param reasoningEffort + * reasoning effort level; {@code null} to use default + * @param reasoningSummary + * reasoning summary mode ({@code "none"}, {@code "concise"}, or + * {@code "detailed"}); {@code null} to use default. Use + * {@code "none"} to suppress summary output regardless of whether + * reasoning is enabled. + * @param modelCapabilities + * per-property overrides for model capabilities; {@code null} to use + * runtime defaults + * @param contextTier + * context window tier ({@code "default"} or + * {@code "long_context"}); {@code null} to use default + * @return a future that completes when the model switch is acknowledged + * @throws IllegalStateException + * if this session has been terminated + * @since 1.3.0 + */ + public CompletableFuture setModel(String model, String reasoningEffort, String reasoningSummary, + com.github.copilot.rpc.ModelCapabilitiesOverride modelCapabilities, String contextTier) { ensureNotTerminated(); ModelCapabilitiesOverride generatedCapabilities = null; if (modelCapabilities != null) { @@ -1777,8 +1808,9 @@ public CompletableFuture setModel(String model, String reasoningEffort, St var generatedReasoningSummary = reasoningSummary == null ? null : com.github.copilot.generated.rpc.ReasoningSummary.fromValue(reasoningSummary); + var generatedContextTier = contextTier == null ? null : ContextTier.fromValue(contextTier); return getRpc().model.switchTo(new SessionModelSwitchToParams(sessionId, model, reasoningEffort, - generatedReasoningSummary, generatedCapabilities)).thenApply(r -> null); + generatedReasoningSummary, generatedCapabilities, generatedContextTier)).thenApply(r -> null); } /** diff --git a/java/src/test/java/com/github/copilot/RpcWrappersTest.java b/java/src/test/java/com/github/copilot/RpcWrappersTest.java index 7b01e1d38..ff48d4897 100644 --- a/java/src/test/java/com/github/copilot/RpcWrappersTest.java +++ b/java/src/test/java/com/github/copilot/RpcWrappersTest.java @@ -183,7 +183,8 @@ void sessionRpc_model_switchTo_merges_sessionId_with_extra_params() { var session = new SessionRpc(stub, "sess-xyz"); // switchTo takes extra params beyond sessionId - var switchParams = new SessionModelSwitchToParams(null, "gpt-5", null, null, null); + var switchParams = new SessionModelSwitchToParams(null, "gpt-5", null, null, null, + ContextTier.LONG_CONTEXT); session.model.switchTo(switchParams); assertEquals(1, stub.calls.size()); @@ -195,6 +196,7 @@ void sessionRpc_model_switchTo_merges_sessionId_with_extra_params() { var node = (com.fasterxml.jackson.databind.node.ObjectNode) params; assertEquals("sess-xyz", node.get("sessionId").asText()); assertEquals("gpt-5", node.get("modelId").asText()); + assertEquals("long_context", node.get("contextTier").asText()); } @Test diff --git a/java/src/test/java/com/github/copilot/generated/rpc/GeneratedRpcRecordsCoverageTest.java b/java/src/test/java/com/github/copilot/generated/rpc/GeneratedRpcRecordsCoverageTest.java index d34fa76b1..4d2dc949a 100644 --- a/java/src/test/java/com/github/copilot/generated/rpc/GeneratedRpcRecordsCoverageTest.java +++ b/java/src/test/java/com/github/copilot/generated/rpc/GeneratedRpcRecordsCoverageTest.java @@ -321,12 +321,14 @@ void sessionModelGetCurrentParams_record() { @Test void sessionModelSwitchToParams_record() { - var params = new SessionModelSwitchToParams("sess-32", "claude-sonnet-4.5", "high", null, null); + var params = new SessionModelSwitchToParams("sess-32", "claude-sonnet-4.5", "high", null, null, + ContextTier.LONG_CONTEXT); assertEquals("sess-32", params.sessionId()); assertEquals("claude-sonnet-4.5", params.modelId()); assertEquals("high", params.reasoningEffort()); assertNull(params.reasoningSummary()); assertNull(params.modelCapabilities()); + assertEquals(ContextTier.LONG_CONTEXT, params.contextTier()); } @Test @@ -720,8 +722,9 @@ void sessionModeSetResult_enum() { @Test void sessionModelGetCurrentResult_record() { - var result = new SessionModelGetCurrentResult("claude-sonnet-4.5", null); + var result = new SessionModelGetCurrentResult("claude-sonnet-4.5", null, ContextTier.LONG_CONTEXT); assertEquals("claude-sonnet-4.5", result.modelId()); + assertEquals(ContextTier.LONG_CONTEXT, result.contextTier()); } @Test @@ -957,9 +960,11 @@ void sessionModelSwitchToParams_nested_records() { var limits = new ModelCapabilitiesOverrideLimits(100000L, 8192L, 128000L, limitsVision); var supports = new ModelCapabilitiesOverrideSupports(true, true); var capabilities = new ModelCapabilitiesOverride(supports, limits); - var params = new SessionModelSwitchToParams("sess-m", "gpt-5", null, null, capabilities); + var params = new SessionModelSwitchToParams("sess-m", "gpt-5", null, null, capabilities, + ContextTier.DEFAULT); assertEquals("gpt-5", params.modelId()); + assertEquals(ContextTier.DEFAULT, params.contextTier()); assertNotNull(params.modelCapabilities()); assertTrue(params.modelCapabilities().supports().vision()); assertTrue(params.modelCapabilities().supports().reasoningEffort()); diff --git a/nodejs/src/generated/rpc.ts b/nodejs/src/generated/rpc.ts index 602ee76a0..5c01060aa 100644 --- a/nodejs/src/generated/rpc.ts +++ b/nodejs/src/generated/rpc.ts @@ -266,13 +266,9 @@ export type ContentFilterMode = /** Remove characters that can hide directives. */ | "hidden_characters"; /** - * Context tier currently pinned for the session, when one is set. Reflects `Session.getContextTier()`, restored from the session journal on resume. - * - * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema - * via the `definition` "ModelCurrentContextTier". + * Context window tier for models that support tiered context windows. */ -/** @experimental */ -export type ModelCurrentContextTier = +export type ContextTier = /** Use the model's default context window. */ | "default" /** Pin the session to the long-context tier when supported. */ @@ -2841,7 +2837,7 @@ export interface CurrentModel { * Reasoning effort level currently applied to the active model, when one is set. Reads `Session.getReasoningEffort()` synchronously after `getSelectedModel()` resolves so the two values are reported as a snapshot. */ reasoningEffort?: string; - contextTier?: ModelCurrentContextTier; + contextTier?: ContextTier; } /** * Lightweight metadata for a currently initialized session tool @@ -4952,11 +4948,7 @@ export interface ModelSwitchToRequest { /** * Explicit context tier for the selected model. `"default"` / `"long_context"` pin the tier; `null` clears any previous explicit choice; `undefined` leaves the existing tier untouched. */ - contextTier?: /** Use the model's default context window. */ - | "default" - /** Pin the session to the long-context tier when supported. */ - | "long_context" - | null; + contextTier?: ContextTier | null; } /** * The model identifier active on the session after the switch. diff --git a/nodejs/src/session.ts b/nodejs/src/session.ts index b7b9c217a..854a1a0d4 100644 --- a/nodejs/src/session.ts +++ b/nodejs/src/session.ts @@ -30,6 +30,7 @@ import type { MessageOptions, PermissionHandler, PermissionRequest, + ContextTier, ReasoningEffort, ReasoningSummary, ModelCapabilitiesOverride, @@ -1210,6 +1211,7 @@ export class CopilotSession { options?: { reasoningEffort?: ReasoningEffort; reasoningSummary?: ReasoningSummary; + contextTier?: ContextTier; modelCapabilities?: ModelCapabilitiesOverride; } ): Promise { diff --git a/nodejs/src/types.ts b/nodejs/src/types.ts index 75aa5159f..2ba1a3660 100644 --- a/nodejs/src/types.ts +++ b/nodejs/src/types.ts @@ -14,10 +14,10 @@ import type { SessionEvent as GeneratedSessionEvent, } from "./generated/session-events.js"; import type { CopilotSession } from "./session.js"; -import type { RemoteSessionMode } from "./generated/rpc.js"; +import type { ContextTier, RemoteSessionMode } from "./generated/rpc.js"; import type { OpenCanvasInstance } from "./generated/rpc.js"; import type { ToolSet } from "./toolSet.js"; -export type { RemoteSessionMode } from "./generated/rpc.js"; +export type { ContextTier, RemoteSessionMode } from "./generated/rpc.js"; export type SessionEvent = GeneratedSessionEvent; export type { ReasoningSummary } from "./generated/session-events.js"; export type { SessionFsProvider } from "./sessionFsProvider.js"; @@ -1540,12 +1540,6 @@ export interface LargeToolOutputConfig { */ export type ReasoningEffort = "low" | "medium" | "high" | "xhigh"; -/** - * Context window tier for the session. "long_context" pins the session to the - * long-context tier when the selected model supports it. - */ -export type ContextTier = "default" | "long_context"; - /** * Stable extension identity for session participants that provide canvases. */ diff --git a/nodejs/test/client.test.ts b/nodejs/test/client.test.ts index 3a1e83460..657ec7c9c 100644 --- a/nodejs/test/client.test.ts +++ b/nodejs/test/client.test.ts @@ -1004,6 +1004,7 @@ describe("CopilotClient", () => { await session.setModel("claude-sonnet-4.6", { reasoningEffort: "high", reasoningSummary: "detailed", + contextTier: "long_context", }); expect(spy).toHaveBeenCalledWith("session.model.switchTo", { @@ -1011,6 +1012,7 @@ describe("CopilotClient", () => { modelId: "claude-sonnet-4.6", reasoningEffort: "high", reasoningSummary: "detailed", + contextTier: "long_context", }); spy.mockRestore(); diff --git a/python/copilot/generated/rpc.py b/python/copilot/generated/rpc.py index 694a6a267..5186a30a6 100644 --- a/python/copilot/generated/rpc.py +++ b/python/copilot/generated/rpc.py @@ -1051,13 +1051,15 @@ def to_dict(self) -> dict: return result # Experimental: this type is part of an experimental API and may change or be removed. -class ModelCurrentContextTier(Enum): +class ContextTier(Enum): """Context tier currently pinned for the session, when one is set. Reflects `Session.getContextTier()`, restored from the session journal on resume. """ DEFAULT = "default" LONG_CONTEXT = "long_context" +ModelCurrentContextTier = ContextTier + class DiscoveredMCPServerType(Enum): """Server transport type: stdio, http, sse (deprecated), or memory""" @@ -7467,7 +7469,7 @@ def to_dict(self) -> dict: class CurrentModel: """The currently selected model, reasoning effort, and context tier for the session.""" - context_tier: ModelCurrentContextTier | None = None + context_tier: ContextTier | None = None """Context tier currently pinned for the session, when one is set. Reflects `Session.getContextTier()`, restored from the session journal on resume. """ @@ -7483,7 +7485,7 @@ class CurrentModel: @staticmethod def from_dict(obj: Any) -> 'CurrentModel': assert isinstance(obj, dict) - context_tier = from_union([ModelCurrentContextTier, from_none], obj.get("contextTier")) + context_tier = from_union([ContextTier, from_none], obj.get("contextTier")) model_id = from_union([from_str, from_none], obj.get("modelId")) reasoning_effort = from_union([from_str, from_none], obj.get("reasoningEffort")) return CurrentModel(context_tier, model_id, reasoning_effort) @@ -7491,7 +7493,7 @@ def from_dict(obj: Any) -> 'CurrentModel': def to_dict(self) -> dict: result: dict = {} if self.context_tier is not None: - result["contextTier"] = from_union([lambda x: to_enum(ModelCurrentContextTier, x), from_none], self.context_tier) + result["contextTier"] = from_union([lambda x: to_enum(ContextTier, x), from_none], self.context_tier) if self.model_id is not None: result["modelId"] = from_union([from_str, from_none], self.model_id) if self.reasoning_effort is not None: @@ -15402,7 +15404,7 @@ class ModelSwitchToRequest: model_id: str """Model identifier to switch to""" - context_tier: ModelCurrentContextTier | None = None + context_tier: ContextTier | None = None """Explicit context tier for the selected model. `"default"` / `"long_context"` pin the tier; `null` clears any previous explicit choice; `undefined` leaves the existing tier untouched. @@ -15420,7 +15422,7 @@ class ModelSwitchToRequest: def from_dict(obj: Any) -> 'ModelSwitchToRequest': assert isinstance(obj, dict) model_id = from_str(obj.get("modelId")) - context_tier = from_union([ModelCurrentContextTier, from_none], obj.get("contextTier")) + context_tier = from_union([ContextTier, from_none], obj.get("contextTier")) model_capabilities = from_union([ModelCapabilitiesOverride.from_dict, from_none], obj.get("modelCapabilities")) reasoning_effort = from_union([from_str, from_none], obj.get("reasoningEffort")) reasoning_summary = from_union([ReasoningSummary, from_none], obj.get("reasoningSummary")) @@ -15430,7 +15432,7 @@ def to_dict(self) -> dict: result: dict = {} result["modelId"] = from_str(self.model_id) if self.context_tier is not None: - result["contextTier"] = from_union([lambda x: to_enum(ModelCurrentContextTier, x), from_none], self.context_tier) + result["contextTier"] = from_union([lambda x: to_enum(ContextTier, x), from_none], self.context_tier) if self.model_capabilities is not None: result["modelCapabilities"] = from_union([lambda x: to_class(ModelCapabilitiesOverride, x), from_none], self.model_capabilities) if self.reasoning_effort is not None: @@ -15850,7 +15852,7 @@ class RPC: model_capabilities_override_limits_vision: ModelCapabilitiesOverrideLimitsVision model_capabilities_override_supports: ModelCapabilitiesOverrideSupports model_capabilities_supports: ModelCapabilitiesSupports - model_current_context_tier: ModelCurrentContextTier + model_current_context_tier: ContextTier model_list: ModelList model_list_request: ModelListRequest model_picker_category: ModelPickerCategory @@ -16436,7 +16438,7 @@ def from_dict(obj: Any) -> 'RPC': model_capabilities_override_limits_vision = ModelCapabilitiesOverrideLimitsVision.from_dict(obj.get("ModelCapabilitiesOverrideLimitsVision")) model_capabilities_override_supports = ModelCapabilitiesOverrideSupports.from_dict(obj.get("ModelCapabilitiesOverrideSupports")) model_capabilities_supports = ModelCapabilitiesSupports.from_dict(obj.get("ModelCapabilitiesSupports")) - model_current_context_tier = ModelCurrentContextTier(obj.get("ModelCurrentContextTier")) + model_current_context_tier = ContextTier(obj.get("ModelCurrentContextTier")) model_list = ModelList.from_dict(obj.get("ModelList")) model_list_request = ModelListRequest.from_dict(obj.get("ModelListRequest")) model_picker_category = ModelPickerCategory(obj.get("ModelPickerCategory")) @@ -17022,7 +17024,7 @@ def to_dict(self) -> dict: result["ModelCapabilitiesOverrideLimitsVision"] = to_class(ModelCapabilitiesOverrideLimitsVision, self.model_capabilities_override_limits_vision) result["ModelCapabilitiesOverrideSupports"] = to_class(ModelCapabilitiesOverrideSupports, self.model_capabilities_override_supports) result["ModelCapabilitiesSupports"] = to_class(ModelCapabilitiesSupports, self.model_capabilities_supports) - result["ModelCurrentContextTier"] = to_enum(ModelCurrentContextTier, self.model_current_context_tier) + result["ModelCurrentContextTier"] = to_enum(ContextTier, self.model_current_context_tier) result["ModelList"] = to_class(ModelList, self.model_list) result["ModelListRequest"] = to_class(ModelListRequest, self.model_list_request) result["ModelPickerCategory"] = to_enum(ModelPickerCategory, self.model_picker_category) diff --git a/python/copilot/session.py b/python/copilot/session.py index f9bbb24c3..c61ca6add 100644 --- a/python/copilot/session.py +++ b/python/copilot/session.py @@ -39,6 +39,7 @@ ExternalToolTextResultForLlm, HandlePendingToolCallRequest, LogRequest, + ContextTier as _RpcContextTier, ModelSwitchToRequest, PermissionDecision, PermissionDecisionApproveOnce, @@ -2394,6 +2395,7 @@ async def set_model( *, reasoning_effort: str | None = None, reasoning_summary: ReasoningSummary | None = None, + context_tier: ContextTier | None = None, model_capabilities: ModelCapabilitiesOverride | None = None, ) -> None: """ @@ -2409,6 +2411,7 @@ async def set_model( reasoning_summary: Optional reasoning summary mode for supported models. Use "none" to suppress summary output regardless of whether reasoning is enabled. + context_tier: Optional context window tier for supported models. model_capabilities: Override individual model capabilities resolved by the runtime. Raises: @@ -2434,6 +2437,7 @@ async def set_model( if reasoning_summary is not None else None ), + context_tier=_RpcContextTier(context_tier) if context_tier is not None else None, model_capabilities=rpc_caps, ) ) diff --git a/python/test_client.py b/python/test_client.py index b1c687204..502d410ab 100644 --- a/python/test_client.py +++ b/python/test_client.py @@ -1132,10 +1132,15 @@ async def mock_request(method, params, **kwargs): return await original_request(method, params, **kwargs) client._client.request = mock_request - await session.set_model("gpt-4.1", reasoning_summary="detailed") + await session.set_model( + "gpt-4.1", + reasoning_summary="detailed", + context_tier="long_context", + ) assert captured["session.model.switchTo"]["sessionId"] == session.session_id assert captured["session.model.switchTo"]["modelId"] == "gpt-4.1" assert captured["session.model.switchTo"]["reasoningSummary"] == "detailed" + assert captured["session.model.switchTo"]["contextTier"] == "long_context" finally: await client.force_stop() diff --git a/rust/src/generated/api_types.rs b/rust/src/generated/api_types.rs index 39157f858..238eaae00 100644 --- a/rust/src/generated/api_types.rs +++ b/rust/src/generated/api_types.rs @@ -1796,7 +1796,7 @@ pub struct CopilotApiTokenAuthInfo { pub struct CurrentModel { /// Context tier currently pinned for the session, when one is set. Reflects `Session.getContextTier()`, restored from the session journal on resume. #[serde(skip_serializing_if = "Option::is_none")] - pub context_tier: Option, + pub context_tier: Option, /// Currently active model identifier #[serde(skip_serializing_if = "Option::is_none")] pub model_id: Option, @@ -4051,7 +4051,7 @@ pub struct ModelsListRequest { pub struct ModelSwitchToRequest { /// Explicit context tier for the selected model. `"default"` / `"long_context"` pin the tier; `null` clears any previous explicit choice; `undefined` leaves the existing tier untouched. #[serde(skip_serializing_if = "Option::is_none")] - pub context_tier: Option, + pub context_tier: Option, /// Override individual model capabilities resolved by the runtime #[serde(skip_serializing_if = "Option::is_none")] pub model_capabilities: Option, @@ -10117,7 +10117,7 @@ pub struct SessionModelGetCurrentParams { pub struct SessionModelGetCurrentResult { /// Context tier currently pinned for the session, when one is set. Reflects `Session.getContextTier()`, restored from the session journal on resume. #[serde(skip_serializing_if = "Option::is_none")] - pub context_tier: Option, + pub context_tier: Option, /// Currently active model identifier #[serde(skip_serializing_if = "Option::is_none")] pub model_id: Option, @@ -13155,16 +13155,9 @@ pub enum CopilotApiTokenAuthInfoType { CopilotApiToken, } -/// Context tier currently pinned for the session, when one is set. Reflects `Session.getContextTier()`, restored from the session journal on resume. -/// -///

-/// -/// **Experimental.** This type is part of an experimental wire-protocol surface -/// and may change or be removed in future SDK or CLI releases. -/// -///
+/// Context window tier for models that support tiered context windows. #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] -pub enum ModelCurrentContextTier { +pub enum ContextTier { /// Use the model's default context window. #[serde(rename = "default")] Default, @@ -13927,20 +13920,6 @@ pub enum ModelPolicyState { Unknown, } -#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] -pub enum ModelSwitchToRequestContextTier { - /// Use the model's default context window. - #[serde(rename = "default")] - Default, - /// Pin the session to the long-context tier when supported. - #[serde(rename = "long_context")] - LongContext, - /// Unknown variant for forward compatibility. - #[default] - #[serde(other)] - Unknown, -} - /// How env values are passed to MCP servers (`direct` inlines literal values; `indirect` resolves at launch). /// ///
diff --git a/rust/src/session.rs b/rust/src/session.rs index 6a1e4f92c..fc1999602 100644 --- a/rust/src/session.rs +++ b/rust/src/session.rs @@ -522,6 +522,7 @@ impl Session { let opts = opts.unwrap_or_default(); let request = ModelSwitchToRequest { model_id: model.to_string(), + context_tier: opts.context_tier, reasoning_effort: opts.reasoning_effort, reasoning_summary: opts.reasoning_summary, model_capabilities: opts.model_capabilities, diff --git a/rust/src/types.rs b/rust/src/types.rs index e4b9d48e2..df578f624 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -13,6 +13,8 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use crate::canvas::{CanvasDeclaration, CanvasHandler}; +/// Context window tier for models that support tiered context windows. +pub use crate::generated::api_types::ContextTier; use crate::generated::api_types::OpenCanvasInstance; use crate::generated::session_events::ReasoningSummary; use crate::handler::{ @@ -1157,9 +1159,8 @@ pub struct SessionConfig { /// reasoning summaries. Use [`ReasoningSummary::None`] to suppress /// summary output regardless of whether reasoning is enabled. pub reasoning_summary: Option, - /// Context window tier for models that support it. Use `"long_context"` - /// to pin the session to the long-context tier. - pub context_tier: Option, + /// Context window tier for models that support it. + pub context_tier: Option, /// Enable streaming token deltas via `assistant.message_delta` events. pub streaming: Option, /// Custom system message configuration. @@ -1828,9 +1829,9 @@ impl SessionConfig { self } - /// Set the context window tier (e.g. `"default"`, `"long_context"`). - pub fn with_context_tier(mut self, tier: impl Into) -> Self { - self.context_tier = Some(tier.into()); + /// Set [`context_tier`](Self::context_tier). + pub fn with_context_tier(mut self, tier: ContextTier) -> Self { + self.context_tier = Some(tier); self } @@ -2190,9 +2191,8 @@ pub struct ResumeSessionConfig { /// [`ReasoningSummary::None`] to suppress summary output regardless of /// whether reasoning is enabled. pub reasoning_summary: Option, - /// Context window tier to apply after resuming the session. Use - /// `"long_context"` to pin the session to the long-context tier. - pub context_tier: Option, + /// Context window tier to apply after resuming the session. + pub context_tier: Option, /// Enable streaming token deltas. pub streaming: Option, /// Re-supply the system message so the agent retains workspace context @@ -2755,10 +2755,9 @@ impl ResumeSessionConfig { self } - /// Set the context window tier to apply on resume (e.g. `"default"`, - /// `"long_context"`). - pub fn with_context_tier(mut self, tier: impl Into) -> Self { - self.context_tier = Some(tier.into()); + /// Set [`context_tier`](Self::context_tier). + pub fn with_context_tier(mut self, tier: ContextTier) -> Self { + self.context_tier = Some(tier); self } @@ -3267,6 +3266,8 @@ pub struct SetModelOptions { /// [`ReasoningSummary::None`] to suppress summary output regardless of /// whether reasoning is enabled. pub reasoning_summary: Option, + /// Context window tier for the new model. + pub context_tier: Option, /// Override individual model capabilities resolved by the runtime. Only /// fields set on the override are applied; the rest fall back to the /// runtime-resolved values for the model. @@ -3286,6 +3287,12 @@ impl SetModelOptions { self } + /// Set [`context_tier`](Self::context_tier). + pub fn with_context_tier(mut self, tier: ContextTier) -> Self { + self.context_tier = Some(tier); + self + } + /// Set [`model_capabilities`](Self::model_capabilities). pub fn with_model_capabilities( mut self, @@ -4259,10 +4266,10 @@ mod tests { use super::{ AgentMode, Attachment, AttachmentLineRange, AttachmentSelectionPosition, - AttachmentSelectionRange, ConnectionState, CustomAgentConfig, DeliveryMode, ExtensionInfo, - GitHubReferenceType, InfiniteSessionConfig, LargeToolOutputConfig, ProviderConfig, - ReasoningSummary, ResumeSessionConfig, SessionConfig, SessionEvent, SessionId, - SystemMessageConfig, Tool, ToolBinaryResult, ToolResult, ToolResultExpanded, + AttachmentSelectionRange, ConnectionState, ContextTier, CustomAgentConfig, DeliveryMode, + ExtensionInfo, GitHubReferenceType, InfiniteSessionConfig, LargeToolOutputConfig, + ProviderConfig, ReasoningSummary, ResumeSessionConfig, SessionConfig, SessionEvent, + SessionId, SystemMessageConfig, Tool, ToolBinaryResult, ToolResult, ToolResultExpanded, ToolResultResponse, ensure_attachment_display_names, }; use crate::generated::session_events::TypedSessionEvent; @@ -4606,7 +4613,7 @@ mod tests { .with_client_name("test-app") .with_reasoning_effort("medium") .with_reasoning_summary(ReasoningSummary::Concise) - .with_context_tier("long_context") + .with_context_tier(ContextTier::LongContext) .with_streaming(true) .with_tools([Tool::new("greet")]) .with_available_tools(["bash", "view"]) @@ -4630,7 +4637,7 @@ mod tests { assert_eq!(cfg.client_name.as_deref(), Some("test-app")); assert_eq!(cfg.reasoning_effort.as_deref(), Some("medium")); assert_eq!(cfg.reasoning_summary, Some(ReasoningSummary::Concise)); - assert_eq!(cfg.context_tier.as_deref(), Some("long_context")); + assert_eq!(cfg.context_tier, Some(ContextTier::LongContext)); assert_eq!(cfg.streaming, Some(true)); assert_eq!(cfg.tools.as_ref().map(|t| t.len()), Some(1)); assert_eq!( @@ -4672,7 +4679,7 @@ mod tests { let cfg = ResumeSessionConfig::new(SessionId::from("sess-2")) .with_client_name("test-app") .with_reasoning_summary(ReasoningSummary::None) - .with_context_tier("default") + .with_context_tier(ContextTier::Default) .with_streaming(true) .with_tools([Tool::new("greet")]) .with_available_tools(["bash", "view"]) @@ -4696,7 +4703,7 @@ mod tests { assert_eq!(cfg.session_id.as_str(), "sess-2"); assert_eq!(cfg.client_name.as_deref(), Some("test-app")); assert_eq!(cfg.reasoning_summary, Some(ReasoningSummary::None)); - assert_eq!(cfg.context_tier.as_deref(), Some("default")); + assert_eq!(cfg.context_tier, Some(ContextTier::Default)); assert_eq!(cfg.streaming, Some(true)); assert_eq!(cfg.tools.as_ref().map(|t| t.len()), Some(1)); assert_eq!( diff --git a/rust/src/wire.rs b/rust/src/wire.rs index de40720b2..42f511f82 100644 --- a/rust/src/wire.rs +++ b/rust/src/wire.rs @@ -24,7 +24,7 @@ use crate::generated::api_types::{ }; use crate::generated::session_events::ReasoningSummary; use crate::types::{ - CloudSessionOptions, CustomAgentConfig, DefaultAgentConfig, ExtensionInfo, + CloudSessionOptions, ContextTier, CustomAgentConfig, DefaultAgentConfig, ExtensionInfo, InfiniteSessionConfig, LargeToolOutputConfig, McpServerConfig, ProviderConfig, SessionId, SystemMessageConfig, Tool, }; @@ -55,7 +55,7 @@ pub(crate) struct SessionCreateWire { #[serde(skip_serializing_if = "Option::is_none")] pub reasoning_summary: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub context_tier: Option, + pub context_tier: Option, #[serde(skip_serializing_if = "Option::is_none")] pub streaming: Option, #[serde(skip_serializing_if = "Option::is_none")] @@ -161,7 +161,7 @@ pub(crate) struct SessionResumeWire { #[serde(skip_serializing_if = "Option::is_none")] pub reasoning_summary: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub context_tier: Option, + pub context_tier: Option, #[serde(skip_serializing_if = "Option::is_none")] pub streaming: Option, #[serde(skip_serializing_if = "Option::is_none")] diff --git a/rust/tests/session_test.rs b/rust/tests/session_test.rs index 786ba97de..b4cb1c52b 100644 --- a/rust/tests/session_test.rs +++ b/rust/tests/session_test.rs @@ -6,6 +6,7 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::time::Duration; use async_trait::async_trait; +use github_copilot_sdk::ContextTier; use github_copilot_sdk::canvas::{CanvasDeclaration, CanvasHandler, CanvasResult}; use github_copilot_sdk::generated::api_types::{ CanvasInstanceAvailability, CanvasProviderInvokeActionRequest, CanvasProviderOpenRequest, @@ -1290,7 +1291,8 @@ async fn set_model_sends_switch_to_request() { "claude-sonnet-4", Some( SetModelOptions::default() - .with_reasoning_summary(ReasoningSummary::Detailed), + .with_reasoning_summary(ReasoningSummary::Detailed) + .with_context_tier(ContextTier::LongContext), ), ) .await @@ -1302,6 +1304,7 @@ async fn set_model_sends_switch_to_request() { assert_eq!(request["method"], "session.model.switchTo"); assert_eq!(request["params"]["modelId"], "claude-sonnet-4"); assert_eq!(request["params"]["reasoningSummary"], "detailed"); + assert_eq!(request["params"]["contextTier"], "long_context"); server .respond( &request, From 62efeec1b7d986123268df1907dabc77970cbd1e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 29 May 2026 22:06:26 +0000 Subject: [PATCH 2/2] Regenerate Java codegen output Auto-committed by java-codegen-check workflow. --- .../com/github/copilot/generated/rpc/SessionModelApi.java | 2 +- .../copilot/generated/rpc/SessionModelGetCurrentResult.java | 6 ++---- .../copilot/generated/rpc/SessionModelSwitchToParams.java | 6 ++---- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelApi.java b/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelApi.java index d4c0a4e34..eda751b3e 100644 --- a/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelApi.java +++ b/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelApi.java @@ -40,7 +40,7 @@ public CompletableFuture getCurrent() { } /** - * Target model identifier and optional reasoning effort, summary, capability overrides, and context tier. + * Target model identifier and optional reasoning effort, summary, and capability overrides. *

* Note: the {@code sessionId} field in the params record is overridden * by the session-scoped wrapper; any value provided is ignored. diff --git a/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetCurrentResult.java b/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetCurrentResult.java index 8ab022ac9..7bb2f8496 100644 --- a/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetCurrentResult.java +++ b/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelGetCurrentResult.java @@ -13,7 +13,7 @@ import javax.annotation.processing.Generated; /** - * The currently selected model, reasoning effort, and context tier for the session. + * The currently selected model and reasoning effort for the session. * * @since 1.0.0 */ @@ -24,8 +24,6 @@ public record SessionModelGetCurrentResult( /** Currently active model identifier */ @JsonProperty("modelId") String modelId, /** Reasoning effort level currently applied to the active model, when one is set. Reads `Session.getReasoningEffort()` synchronously after `getSelectedModel()` resolves so the two values are reported as a snapshot. */ - @JsonProperty("reasoningEffort") String reasoningEffort, - /** Context tier currently pinned for the session, when one is set. Reflects `Session.getContextTier()`, restored from the session journal on resume. */ - @JsonProperty("contextTier") ContextTier contextTier + @JsonProperty("reasoningEffort") String reasoningEffort ) { } diff --git a/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelSwitchToParams.java b/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelSwitchToParams.java index 4cda275a2..c5c1cbbe0 100644 --- a/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelSwitchToParams.java +++ b/java/src/generated/java/com/github/copilot/generated/rpc/SessionModelSwitchToParams.java @@ -13,7 +13,7 @@ import javax.annotation.processing.Generated; /** - * Target model identifier and optional reasoning effort, summary, capability overrides, and context tier. + * Target model identifier and optional reasoning effort, summary, and capability overrides. * * @since 1.0.0 */ @@ -30,8 +30,6 @@ public record SessionModelSwitchToParams( /** Reasoning summary mode to request for supported model clients */ @JsonProperty("reasoningSummary") ReasoningSummary reasoningSummary, /** Override individual model capabilities resolved by the runtime */ - @JsonProperty("modelCapabilities") ModelCapabilitiesOverride modelCapabilities, - /** Explicit context tier for the selected model. `"default"` / `"long_context"` pin the tier; `null` clears any previous explicit choice; `undefined` leaves the existing tier untouched. */ - @JsonProperty("contextTier") ContextTier contextTier + @JsonProperty("modelCapabilities") ModelCapabilitiesOverride modelCapabilities ) { }