Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions dotnet/src/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -980,9 +980,11 @@ public async Task<CopilotSession> CreateSessionAsync(SessionConfig config, Cance
config.ReasoningSummary,
config.ContextTier,
config.Tools?.Select(ToolDefinition.FromAIFunction).ToList(),
config.EnableCitations,
wireSystemMessage,
toolFilter.AvailableTools,
toolFilter.ExcludedTools,
config.ExcludedBuiltInAgents,
config.Provider,
config.Capi,
config.EnableSessionTelemetry,
Expand Down Expand Up @@ -1013,6 +1015,7 @@ public async Task<CopilotSession> CreateSessionAsync(SessionConfig config, Cance
config.SkillDirectories,
config.DisabledSkills,
config.InfiniteSessions,
config.SessionLimits,
Commands: config.Commands?.Select(c => new CommandWireDefinition(c.Name, c.Description)).ToList(),
RequestElicitation: config.OnElicitationRequest != null,
RequestMcpApps: config.EnableMcpApps ? true : null,
Expand Down Expand Up @@ -1189,9 +1192,11 @@ public async Task<CopilotSession> ResumeSessionAsync(string sessionId, ResumeSes
config.ReasoningSummary,
config.ContextTier,
config.Tools?.Select(ToolDefinition.FromAIFunction).ToList(),
config.EnableCitations,
wireSystemMessage,
toolFilter.AvailableTools,
toolFilter.ExcludedTools,
config.ExcludedBuiltInAgents,
config.Provider,
config.Capi,
config.EnableSessionTelemetry,
Expand Down Expand Up @@ -1223,6 +1228,7 @@ public async Task<CopilotSession> ResumeSessionAsync(string sessionId, ResumeSes
config.SkillDirectories,
config.DisabledSkills,
config.InfiniteSessions,
config.SessionLimits,
Commands: config.Commands?.Select(c => new CommandWireDefinition(c.Name, c.Description)).ToList(),
RequestElicitation: config.OnElicitationRequest != null,
RequestMcpApps: config.EnableMcpApps ? true : null,
Expand Down Expand Up @@ -2431,9 +2437,11 @@ internal record CreateSessionRequest(
ReasoningSummary? ReasoningSummary,
ContextTier? ContextTier,
IList<ToolDefinition>? Tools,
bool? EnableCitations,
SystemMessageConfig? SystemMessage,
IList<string>? AvailableTools,
IList<string>? ExcludedTools,
[property: JsonPropertyName("excludedBuiltinAgents")] IList<string>? ExcludedBuiltInAgents,
ProviderConfig? Provider,
CapiSessionOptions? Capi,
bool? EnableSessionTelemetry,
Expand Down Expand Up @@ -2464,6 +2472,7 @@ internal record CreateSessionRequest(
IList<string>? SkillDirectories,
IList<string>? DisabledSkills,
InfiniteSessionConfig? InfiniteSessions,
SessionLimitsConfig? SessionLimits,
IList<CommandWireDefinition>? Commands = null,
bool? RequestElicitation = null,
bool? RequestMcpApps = null,
Expand Down Expand Up @@ -2525,9 +2534,11 @@ internal record ResumeSessionRequest(
ReasoningSummary? ReasoningSummary,
ContextTier? ContextTier,
IList<ToolDefinition>? Tools,
bool? EnableCitations,
SystemMessageConfig? SystemMessage,
IList<string>? AvailableTools,
IList<string>? ExcludedTools,
[property: JsonPropertyName("excludedBuiltinAgents")] IList<string>? ExcludedBuiltInAgents,
ProviderConfig? Provider,
CapiSessionOptions? Capi,
bool? EnableSessionTelemetry,
Expand Down Expand Up @@ -2559,6 +2570,7 @@ internal record ResumeSessionRequest(
IList<string>? SkillDirectories,
IList<string>? DisabledSkills,
InfiniteSessionConfig? InfiniteSessions,
SessionLimitsConfig? SessionLimits,
IList<CommandWireDefinition>? Commands = null,
bool? RequestElicitation = null,
bool? RequestMcpApps = null,
Expand Down Expand Up @@ -2660,6 +2672,7 @@ internal record HooksInvokeResponse(
[JsonSerializable(typeof(CapiSessionOptions))]
[JsonSerializable(typeof(NamedProviderConfig))]
[JsonSerializable(typeof(ProviderModelConfig))]
[JsonSerializable(typeof(SessionLimitsConfig))]
[JsonSerializable(typeof(ResumeSessionRequest))]
[JsonSerializable(typeof(ResumeSessionResponse))]
[JsonSerializable(typeof(SessionCapabilities))]
Expand Down
33 changes: 33 additions & 0 deletions dotnet/src/Types.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2758,6 +2758,7 @@ protected SessionConfigBase(SessionConfigBase? other)
DefaultAgent = other.DefaultAgent;
Agent = other.Agent;
DisabledSkills = other.DisabledSkills is not null ? [.. other.DisabledSkills] : null;
EnableCitations = other.EnableCitations;
EnableConfigDiscovery = other.EnableConfigDiscovery;
SkipEmbeddingRetrieval = other.SkipEmbeddingRetrieval;
EmbeddingCacheStorage = other.EmbeddingCacheStorage;
Expand All @@ -2768,6 +2769,7 @@ protected SessionConfigBase(SessionConfigBase? other)
EnableSessionStore = other.EnableSessionStore;
EnableSkills = other.EnableSkills;
EnableMcpApps = other.EnableMcpApps;
ExcludedBuiltInAgents = other.ExcludedBuiltInAgents is not null ? [.. other.ExcludedBuiltInAgents] : null;
ExcludedTools = other.ExcludedTools is not null ? [.. other.ExcludedTools] : null;
Hooks = other.Hooks;
InfiniteSessions = other.InfiniteSessions;
Expand Down Expand Up @@ -2815,6 +2817,7 @@ protected SessionConfigBase(SessionConfigBase? other)
SkillDirectories = other.SkillDirectories is not null ? [.. other.SkillDirectories] : null;
PluginDirectories = other.PluginDirectories is not null ? [.. other.PluginDirectories] : null;
InstructionDirectories = other.InstructionDirectories is not null ? [.. other.InstructionDirectories] : null;
SessionLimits = other.SessionLimits;
Streaming = other.Streaming;
IncludeSubAgentStreamingEvents = other.IncludeSubAgentStreamingEvents;
SystemMessage = other.SystemMessage;
Expand Down Expand Up @@ -2853,6 +2856,16 @@ protected SessionConfigBase(SessionConfigBase? other)
/// <summary>Per-property overrides for model capabilities, deep-merged over runtime defaults.</summary>
public ModelCapabilitiesOverride? ModelCapabilities { get; set; }

/// <summary>
/// Enables native model citations for models that support them.
/// </summary>
/// <remarks>
/// Citations are experimental, off by default, and currently available for Anthropic models.
/// This option may change or be removed while citation support is experimental.
/// </remarks>
[Experimental(Diagnostics.Experimental)]
public bool? EnableCitations { get; set; }

/// <summary>
/// Override the default configuration directory location.
/// When specified, the session will use this directory for storing config and state.
Expand Down Expand Up @@ -2945,6 +2958,16 @@ protected SessionConfigBase(SessionConfigBase? other)
/// <summary>List of tool names to exclude from the session.</summary>
public IList<string>? ExcludedTools { get; set; }

/// <summary>
/// Built-in subagent names to exclude from this session.
/// </summary>
/// <remarks>
/// Excluded built-ins are hidden from agent discovery and cannot be dispatched unless a
/// custom agent with the same name is available.
/// </remarks>
[JsonPropertyName("excludedBuiltinAgents")]
public IList<string>? ExcludedBuiltInAgents { get; set; }

/// <summary>Custom model provider configuration for the session.</summary>
public ProviderConfig? Provider { get; set; }

Expand Down Expand Up @@ -3137,6 +3160,16 @@ protected SessionConfigBase(SessionConfigBase? other)
/// </summary>
public InfiniteSessionConfig? InfiniteSessions { get; set; }

/// <summary>
/// Optional limits for the session's current accounting window.
/// </summary>
/// <remarks>
/// These settings only model the caller's configured limits. Enforcement and
/// limit-exhaustion behavior are handled by the runtime.
/// </remarks>
[Experimental(Diagnostics.Experimental)]
public SessionLimitsConfig? SessionLimits { get; set; }

/// <summary>
/// Configuration for handling large tool outputs. When a tool produces
/// output exceeding the configured size, the output is written to a temp
Expand Down
13 changes: 10 additions & 3 deletions dotnet/test/E2E/CopilotRequestE2EProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,14 @@ internal sealed class RecordingRequestHandler : CopilotRequestHandler
protected override async Task<HttpResponseMessage> SendRequestAsync(HttpRequestMessage request, CopilotRequestContext ctx)
{
var url = request.RequestUri!.ToString();
_records.Enqueue(new InterceptedRequest(url, ctx.SessionId));

var bodyText = request.Content is null
? string.Empty
#if NET8_0_OR_GREATER
: await request.Content.ReadAsStringAsync(ctx.CancellationToken).ConfigureAwait(false);
#else
: await request.Content.ReadAsStringAsync().ConfigureAwait(false);
#endif
_records.Enqueue(new InterceptedRequest(url, ctx.SessionId, bodyText));

return IsInferenceUrl(url)
? BuildInferenceResponse(url, bodyText)
Expand Down Expand Up @@ -95,6 +94,11 @@ private static HttpResponseMessage BuildInferenceResponse(string url, string bod
return Sse(string.Concat(ChatCompletionStreamEvents));
}

if (u.EndsWith("/messages", StringComparison.Ordinal))
{
return Json(BufferedAnthropicMessageJson);
}

// /chat/completions non-streaming (and any other inference url) — buffered JSON.
return Json(BufferedChatCompletionJson);
}
Expand Down Expand Up @@ -160,9 +164,12 @@ internal static HttpResponseMessage BuildNonInferenceResponse(string url)
private static readonly string BufferedChatCompletionJson =
"{\"id\":\"chatcmpl-stub-1\",\"object\":\"chat.completion\",\"created\":1,\"model\":\"claude-sonnet-4.5\",\"choices\":[{\"index\":0,\"message\":{\"role\":\"assistant\",\"content\":\"" + SyntheticText + "\"},\"finish_reason\":\"stop\"}],\"usage\":{\"prompt_tokens\":5,\"completion_tokens\":7,\"total_tokens\":12}}";

private static readonly string BufferedAnthropicMessageJson =
"{\"id\":\"msg_stub_1\",\"type\":\"message\",\"role\":\"assistant\",\"model\":\"claude-sonnet-4.5\",\"content\":[{\"type\":\"text\",\"text\":\"" + SyntheticText + "\"}],\"stop_reason\":\"end_turn\",\"stop_sequence\":null,\"usage\":{\"input_tokens\":5,\"output_tokens\":7}}";

private const string ModelCatalogJson =
"{\"data\":[{\"id\":\"claude-sonnet-4.5\",\"name\":\"Claude Sonnet 4.5\",\"object\":\"model\",\"vendor\":\"Anthropic\",\"version\":\"1\",\"preview\":false,\"model_picker_enabled\":true,\"capabilities\":{\"type\":\"chat\",\"family\":\"claude-sonnet-4.5\",\"tokenizer\":\"o200k_base\",\"limits\":{\"max_context_window_tokens\":200000,\"max_output_tokens\":8192},\"supports\":{\"streaming\":true,\"tool_calls\":true,\"parallel_tool_calls\":true,\"vision\":true}}}]}";
}

/// <summary>A single request the callback intercepted.</summary>
internal sealed record InterceptedRequest(string Url, string? SessionId);
internal sealed record InterceptedRequest(string Url, string? SessionId, string Body);
Loading
Loading