Skip to content

Commit 4fba3a4

Browse files
stephentoubCopilot
andauthored
Add typed context tier support (#1503)
* Add typed context tier support Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Trim context tier docs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 57b8dc6 commit 4fba3a4

6 files changed

Lines changed: 109 additions & 14 deletions

File tree

dotnet/src/Client.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2276,7 +2276,7 @@ internal record CreateSessionRequest(
22762276
string? ClientName,
22772277
string? ReasoningEffort,
22782278
ReasoningSummary? ReasoningSummary,
2279-
string? ContextTier,
2279+
ContextTier? ContextTier,
22802280
IList<ToolDefinition>? Tools,
22812281
SystemMessageConfig? SystemMessage,
22822282
IList<string>? AvailableTools,
@@ -2362,7 +2362,7 @@ internal record ResumeSessionRequest(
23622362
string? Model,
23632363
string? ReasoningEffort,
23642364
ReasoningSummary? ReasoningSummary,
2365-
string? ContextTier,
2365+
ContextTier? ContextTier,
23662366
IList<ToolDefinition>? Tools,
23672367
SystemMessageConfig? SystemMessage,
23682368
IList<string>? AvailableTools,

dotnet/src/Types.cs

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2390,6 +2390,65 @@ public sealed class CloudSessionOptions
23902390
public CloudSessionRepository? Repository { get; set; }
23912391
}
23922392

2393+
/// <summary>
2394+
/// Context window tier for models that support tiered context windows.
2395+
/// </summary>
2396+
[JsonConverter(typeof(ContextTier.Converter))]
2397+
[DebuggerDisplay("{Value,nq}")]
2398+
public readonly struct ContextTier : IEquatable<ContextTier>
2399+
{
2400+
private readonly string? _value;
2401+
2402+
/// <summary>Initializes a new instance of the <see cref="ContextTier"/> struct.</summary>
2403+
/// <param name="value">The value to associate with this <see cref="ContextTier"/>.</param>
2404+
[JsonConstructor]
2405+
public ContextTier(string value)
2406+
{
2407+
ArgumentException.ThrowIfNullOrWhiteSpace(value);
2408+
_value = value;
2409+
}
2410+
2411+
/// <summary>Gets the value associated with this <see cref="ContextTier"/>.</summary>
2412+
public string Value => _value ?? string.Empty;
2413+
2414+
/// <summary>Default context tier with standard context window size.</summary>
2415+
public static ContextTier Default { get; } = new("default");
2416+
2417+
/// <summary>Extended context tier with a larger context window.</summary>
2418+
public static ContextTier LongContext { get; } = new("long_context");
2419+
2420+
/// <summary>Returns a value indicating whether two <see cref="ContextTier"/> instances are equivalent.</summary>
2421+
public static bool operator ==(ContextTier left, ContextTier right) => left.Equals(right);
2422+
2423+
/// <summary>Returns a value indicating whether two <see cref="ContextTier"/> instances are not equivalent.</summary>
2424+
public static bool operator !=(ContextTier left, ContextTier right) => !left.Equals(right);
2425+
2426+
/// <inheritdoc/>
2427+
public override bool Equals([NotNullWhen(true)] object? obj) => obj is ContextTier other && Equals(other);
2428+
2429+
/// <inheritdoc/>
2430+
public bool Equals(ContextTier other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase);
2431+
2432+
/// <inheritdoc/>
2433+
public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value);
2434+
2435+
/// <inheritdoc/>
2436+
public override string ToString() => Value;
2437+
2438+
/// <summary>Provides a <see cref="JsonConverter{ContextTier}"/> for serializing <see cref="ContextTier"/> instances.</summary>
2439+
[EditorBrowsable(EditorBrowsableState.Never)]
2440+
public sealed class Converter : JsonConverter<ContextTier>
2441+
{
2442+
/// <inheritdoc/>
2443+
public override ContextTier Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
2444+
new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert));
2445+
2446+
/// <inheritdoc/>
2447+
public override void Write(Utf8JsonWriter writer, ContextTier value, JsonSerializerOptions options) =>
2448+
GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ContextTier));
2449+
}
2450+
}
2451+
23932452
/// <summary>
23942453
/// Shared configuration properties for creating or resuming a Copilot session.
23952454
/// Use <see cref="SessionConfig"/> when creating a new session, or
@@ -2497,9 +2556,10 @@ protected SessionConfigBase(SessionConfigBase? other)
24972556

24982557
/// <summary>
24992558
/// Context window tier for models that support it.
2500-
/// Valid values: "default", "long_context".
2559+
/// Use <see cref="ContextTier.Default"/> or <see cref="ContextTier.LongContext"/>
2560+
/// for the currently known tiers.
25012561
/// </summary>
2502-
public string? ContextTier { get; set; }
2562+
public ContextTier? ContextTier { get; set; }
25032563

25042564
/// <summary>Per-property overrides for model capabilities, deep-merged over runtime defaults.</summary>
25052565
public ModelCapabilitiesOverride? ModelCapabilities { get; set; }

dotnet/test/Unit/CloneTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public void SessionConfig_Clone_CopiesAllProperties()
6969
Model = "gpt-4",
7070
ReasoningEffort = "high",
7171
ReasoningSummary = ReasoningSummary.Detailed,
72-
ContextTier = "long_context",
72+
ContextTier = ContextTier.LongContext,
7373
ConfigDirectory = "/config",
7474
AvailableTools = ["tool1", "tool2"],
7575
ExcludedTools = ["tool3"],
@@ -386,7 +386,7 @@ public void ResumeSessionConfig_Clone_CopiesContextTier()
386386
{
387387
var original = new ResumeSessionConfig
388388
{
389-
ContextTier = "long_context",
389+
ContextTier = ContextTier.LongContext,
390390
};
391391

392392
var clone = original.Clone();

dotnet/test/Unit/SerializationTests.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,31 @@ public void SessionRequests_CanSerializeReasoningSummary_WithSdkOptions()
196196
Assert.Equal("none", resumeDocument.RootElement.GetProperty("reasoningSummary").GetString());
197197
}
198198

199+
[Fact]
200+
public void SessionRequests_CanSerializeContextTier_WithSdkOptions()
201+
{
202+
var options = GetSerializerOptions();
203+
var createRequestType = GetNestedType(typeof(CopilotClient), "CreateSessionRequest");
204+
var createRequest = CreateInternalRequest(
205+
createRequestType,
206+
("SessionId", "session-id"),
207+
("ContextTier", ContextTier.LongContext));
208+
209+
var createJson = JsonSerializer.Serialize(createRequest, createRequestType, options);
210+
using var createDocument = JsonDocument.Parse(createJson);
211+
Assert.Equal("long_context", createDocument.RootElement.GetProperty("contextTier").GetString());
212+
213+
var resumeRequestType = GetNestedType(typeof(CopilotClient), "ResumeSessionRequest");
214+
var resumeRequest = CreateInternalRequest(
215+
resumeRequestType,
216+
("SessionId", "session-id"),
217+
("ContextTier", ContextTier.Default));
218+
219+
var resumeJson = JsonSerializer.Serialize(resumeRequest, resumeRequestType, options);
220+
using var resumeDocument = JsonDocument.Parse(resumeJson);
221+
Assert.Equal("default", resumeDocument.RootElement.GetProperty("contextTier").GetString());
222+
}
223+
199224
[Fact]
200225
public void SessionRequests_CanSerializePluginDirectoriesAndLargeOutput_WithSdkOptions()
201226
{

go/client_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ func TestSessionRequests_ReasoningSummary(t *testing.T) {
436436

437437
func TestSessionRequests_ContextTier(t *testing.T) {
438438
t.Run("create includes contextTier in JSON when set", func(t *testing.T) {
439-
req := createSessionRequest{ContextTier: "long_context"}
439+
req := createSessionRequest{ContextTier: ContextTierLongContext}
440440
data, err := json.Marshal(req)
441441
if err != nil {
442442
t.Fatalf("Failed to marshal: %v", err)
@@ -451,7 +451,7 @@ func TestSessionRequests_ContextTier(t *testing.T) {
451451
})
452452

453453
t.Run("resume includes contextTier in JSON when set", func(t *testing.T) {
454-
req := resumeSessionRequest{SessionID: "s1", ContextTier: "default"}
454+
req := resumeSessionRequest{SessionID: "s1", ContextTier: ContextTierDefault}
455455
data, err := json.Marshal(req)
456456
if err != nil {
457457
t.Fatalf("Failed to marshal: %v", err)

go/types.go

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,16 @@ type LargeToolOutputConfig struct {
859859
OutputDirectory string `json:"outputDir,omitempty"`
860860
}
861861

862+
// ContextTier identifies a context window tier for models that support tiered context windows.
863+
type ContextTier string
864+
865+
const (
866+
// ContextTierDefault is the default context tier with standard context window size.
867+
ContextTierDefault ContextTier = "default"
868+
// ContextTierLongContext is the extended context tier with a larger context window.
869+
ContextTierLongContext ContextTier = "long_context"
870+
)
871+
862872
// SessionFsCapabilities declares optional provider capabilities.
863873
type SessionFsCapabilities struct {
864874
// Sqlite indicates whether the provider supports SQLite query/exists operations.
@@ -895,8 +905,8 @@ type SessionConfig struct {
895905
// Use ReasoningSummaryNone to suppress summary output regardless of whether reasoning is enabled.
896906
ReasoningSummary ReasoningSummary
897907
// ContextTier pins the session to a context window tier for models that support it.
898-
// Valid values: "default", "long_context".
899-
ContextTier string
908+
// Use ContextTierDefault or ContextTierLongContext for the currently known tiers.
909+
ContextTier ContextTier
900910
// ConfigDirectory overrides the default configuration directory location.
901911
// When specified, the session will use this directory for storing config and state.
902912
ConfigDirectory string
@@ -1298,8 +1308,8 @@ type ResumeSessionConfig struct {
12981308
// Use ReasoningSummaryNone to suppress summary output regardless of whether reasoning is enabled.
12991309
ReasoningSummary ReasoningSummary
13001310
// ContextTier pins the session to a context window tier for models that support it.
1301-
// Valid values: "default", "long_context".
1302-
ContextTier string
1311+
// Use ContextTierDefault or ContextTierLongContext for the currently known tiers.
1312+
ContextTier ContextTier
13031313
// OnPermissionRequest is an optional handler for permission requests from the server.
13041314
// When nil, permission requests are surfaced as events and left pending for the
13051315
// consumer to resolve via pending permission RPCs.
@@ -1660,7 +1670,7 @@ type createSessionRequest struct {
16601670
ClientName string `json:"clientName,omitempty"`
16611671
ReasoningEffort string `json:"reasoningEffort,omitempty"`
16621672
ReasoningSummary ReasoningSummary `json:"reasoningSummary,omitempty"`
1663-
ContextTier string `json:"contextTier,omitempty"`
1673+
ContextTier ContextTier `json:"contextTier,omitempty"`
16641674
Tools []Tool `json:"tools,omitempty"`
16651675
SystemMessage *SystemMessageConfig `json:"systemMessage,omitempty"`
16661676
AvailableTools []string `json:"availableTools"`
@@ -1738,7 +1748,7 @@ type resumeSessionRequest struct {
17381748
Model string `json:"model,omitempty"`
17391749
ReasoningEffort string `json:"reasoningEffort,omitempty"`
17401750
ReasoningSummary ReasoningSummary `json:"reasoningSummary,omitempty"`
1741-
ContextTier string `json:"contextTier,omitempty"`
1751+
ContextTier ContextTier `json:"contextTier,omitempty"`
17421752
Tools []Tool `json:"tools,omitempty"`
17431753
SystemMessage *SystemMessageConfig `json:"systemMessage,omitempty"`
17441754
AvailableTools []string `json:"availableTools"`

0 commit comments

Comments
 (0)