diff --git a/dotnet/src/Client.cs b/dotnet/src/Client.cs index 11f8c90c9..3fab77c89 100644 --- a/dotnet/src/Client.cs +++ b/dotnet/src/Client.cs @@ -1636,6 +1636,20 @@ private async Task ConnectToServerAsync(Process? cliProcess, string? private static JsonSerializerOptions SerializerOptionsForMessageFormatter { get; } = CreateSerializerOptions(); + /// + /// Converts an arbitrary value into the representation that wire + /// DTOs use for opaque-JSON fields. Pass-through for , otherwise + /// serializes the runtime type using the shared JSON-RPC serializer options so that any + /// type registered in the SDK's source-generated contexts (e.g. primitives, + /// Dictionary<string, object>, generated DTOs) is supported. + /// + public static JsonElement? ToJsonElementForWire(object? value) => value switch + { + null => null, + JsonElement je => je, + _ => JsonSerializer.SerializeToElement(value, SerializerOptionsForMessageFormatter.GetTypeInfo(value.GetType())) + }; + private static JsonSerializerOptions CreateSerializerOptions() { var options = new JsonSerializerOptions(JsonSerializerDefaults.Web) @@ -1803,7 +1817,7 @@ public async ValueTask OnSystemMessageTransfo public async ValueTask OnToolCallV2(string sessionId, string toolCallId, string toolName, - object? arguments, + JsonElement? arguments, string? traceparent = null, string? tracestate = null) { @@ -1840,13 +1854,8 @@ public async ValueTask OnToolCallV2(string sessionId, } }; - if (arguments is not null) + if (arguments is JsonElement incomingJsonArgs) { - if (arguments is not JsonElement incomingJsonArgs) - { - throw new InvalidOperationException($"Incoming arguments must be a {nameof(JsonElement)}; received {arguments.GetType().Name}"); - } - foreach (var prop in incomingJsonArgs.EnumerateObject()) { aiFunctionArgs[prop.Name] = prop.Value; diff --git a/dotnet/src/Generated/Rpc.cs b/dotnet/src/Generated/Rpc.cs index db7ce9d4c..513eda7cd 100644 --- a/dotnet/src/Generated/Rpc.cs +++ b/dotnet/src/Generated/Rpc.cs @@ -247,7 +247,7 @@ public sealed class Tool /// JSON Schema for the tool's input parameters. [JsonPropertyName("parameters")] - public IDictionary? Parameters { get; set; } + public IDictionary? Parameters { get; set; } } /// Built-in tools available for the requested model, with their parameters and instructions. @@ -277,11 +277,11 @@ public sealed class AccountQuotaSnapshot [JsonPropertyName("isUnlimitedEntitlement")] public bool IsUnlimitedEntitlement { get; set; } - /// Number of overage requests made this period. + /// Number of additional usage requests made this period. [JsonPropertyName("overage")] public double Overage { get; set; } - /// Whether overage is allowed when quota is exhausted. + /// Whether additional usage is allowed when quota is exhausted. [JsonPropertyName("overageAllowedWithExhaustedQuota")] public bool OverageAllowedWithExhaustedQuota { get; set; } @@ -362,7 +362,7 @@ public sealed class McpConfigList { /// All MCP servers from user config, keyed by name. [JsonPropertyName("servers")] - public IDictionary Servers { get => field ??= new Dictionary(); set; } + public IDictionary Servers { get => field ??= new Dictionary(); set; } } /// MCP server name and configuration to add to user configuration. @@ -370,7 +370,7 @@ internal sealed class McpConfigAddRequest { /// MCP server configuration (stdio process or remote HTTP/SSE). [JsonPropertyName("config")] - public object Config { get; set; } = null!; + public JsonElement Config { get; set; } /// Unique name for the MCP server. [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] @@ -385,7 +385,7 @@ internal sealed class McpConfigUpdateRequest { /// MCP server configuration (stdio process or remote HTTP/SSE). [JsonPropertyName("config")] - public object Config { get; set; } = null!; + public JsonElement Config { get; set; } /// Name of the MCP server to update. [RegularExpression("^[^\\x00-\\x1f/\\x7f-\\x9f}]+(?:\\/[^\\x00-\\x1f/\\x7f-\\x9f}]+)*$")] @@ -1058,7 +1058,7 @@ public sealed class InstalledPlugin /// Source for direct repo installs (when marketplace is empty). [JsonPropertyName("source")] - public object? Source { get; set; } + public JsonElement? Source { get; set; } /// Version installed (if available). [JsonPropertyName("version")] @@ -1331,8 +1331,9 @@ internal sealed class SendRequest public string SessionId { get; set; } = string.Empty; /// Optional provenance tag copied to the resulting user.message event. Supported values are `system`, `command-*`, and `schedule-*`. + [JsonInclude] [JsonPropertyName("source")] - public object? Source { get; set; } + internal JsonElement? Source { get; set; } /// W3C Trace Context traceparent header for distributed tracing of this agent turn. [JsonPropertyName("traceparent")] @@ -2603,8 +2604,9 @@ public sealed class AgentInfo public string Id { get; set; } = string.Empty; /// MCP server configurations attached to this agent, keyed by server name. Server config shape mirrors the MCP `mcpServers` schema. + [Experimental(Diagnostics.Experimental)] [JsonPropertyName("mcpServers")] - public IDictionary? McpServers { get; set; } + public IDictionary? McpServers { get; set; } /// Preferred model id for this agent. When omitted, inherits the outer agent's model. [JsonPropertyName("model")] @@ -3460,7 +3462,7 @@ internal sealed class McpExecuteSamplingParams { /// The original MCP JSON-RPC request ID (string or number). Used by the runtime to correlate the inference with the originating MCP request for telemetry; this is distinct from `requestId` (which is the schema-level cancellation handle). [JsonPropertyName("mcpRequestId")] - public object McpRequestId { get; set; } = null!; + public JsonElement McpRequestId { get; set; } /// Raw MCP CreateMessageRequest params, as received in the `sampling.requested` event. Treated as opaque at the schema layer; the runtime converts the embedded MCP messages into the OpenAI chat-completion shape internally. [JsonPropertyName("request")] @@ -3654,7 +3656,7 @@ public sealed class SessionInstalledPlugin /// Source descriptor for direct repo installs (when marketplace is empty). [JsonPropertyName("source")] - public object? Source { get; set; } + public JsonElement? Source { get; set; } /// Installed version, if known. [JsonPropertyName("version")] @@ -3666,8 +3668,9 @@ public sealed class SessionInstalledPlugin internal sealed class SessionUpdateOptionsParams { /// Additional content-exclusion policies to merge into the session's policy set. Opaque shape; see `ContentExclusionApiResponse` in the runtime. + [Experimental(Diagnostics.Experimental)] [JsonPropertyName("additionalContentExclusionPolicies")] - public IList? AdditionalContentExclusionPolicies { get; set; } + public IList? AdditionalContentExclusionPolicies { get; set; } /// Runtime context discriminator (e.g., `cli`, `actions`). [JsonPropertyName("agentContext")] @@ -3770,8 +3773,9 @@ internal sealed class SessionUpdateOptionsParams public string? Model { get; set; } /// Custom model-provider configuration (BYOK). Opaque shape; see `ProviderConfig` in the runtime. + [Experimental(Diagnostics.Experimental)] [JsonPropertyName("provider")] - public object? Provider { get; set; } + public JsonElement? Provider { get; set; } /// Reasoning effort for the selected model (model-defined enum). [JsonPropertyName("reasoningEffort")] @@ -3782,8 +3786,9 @@ internal sealed class SessionUpdateOptionsParams public bool? RunningInInteractiveMode { get; set; } /// Sandbox configuration shape; opaque to SDK consumers. See `SandboxConfig` in the runtime. + [Experimental(Diagnostics.Experimental)] [JsonPropertyName("sandboxConfig")] - public object? SandboxConfig { get; set; } + public JsonElement? SandboxConfig { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] @@ -3936,7 +3941,7 @@ internal sealed class HandlePendingToolCallRequest /// Tool call result (string or expanded result object). [JsonPropertyName("result")] - public object? Result { get; set; } + public JsonElement? Result { get; set; } /// Target session identifier. [JsonPropertyName("sessionId")] @@ -4353,7 +4358,7 @@ public sealed class UIElicitationResponse /// The form values submitted by the user (present when action is 'accept'). [JsonPropertyName("content")] - public IDictionary? Content { get; set; } + public IDictionary? Content { get; set; } } /// JSON Schema describing the form fields to present to the user. @@ -4362,7 +4367,7 @@ public sealed class UIElicitationSchema { /// Form field definitions, keyed by field name. [JsonPropertyName("properties")] - public IDictionary Properties { get => field ??= new Dictionary(); set; } + public IDictionary Properties { get => field ??= new Dictionary(); set; } /// List of required field names. [JsonPropertyName("required")] @@ -4622,7 +4627,7 @@ public sealed class PermissionsConfigureAdditionalContentExclusionPolicy { /// Gets or sets the last_updated_at value. [JsonPropertyName("last_updated_at")] - public object LastUpdatedAt { get; set; } = null!; + public JsonElement LastUpdatedAt { get; set; } /// Gets or sets the rules value. [JsonPropertyName("rules")] @@ -6296,10 +6301,27 @@ public sealed class HistoryCompactResult public long TokensRemoved { get; set; } } -/// Identifies the target session. +/// Optional compaction parameters. +[Experimental(Diagnostics.Experimental)] +public sealed class HistoryCompactRequest +{ + /// Optional user-provided instructions to focus the compaction summary. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(4000)] + [JsonPropertyName("customInstructions")] + public string? CustomInstructions { get; set; } +} + +/// Optional compaction parameters. [Experimental(Diagnostics.Experimental)] -internal sealed class SessionHistoryCompactRequest +internal sealed class HistoryCompactRequestWithSession { + /// Optional user-provided instructions to focus the compaction summary. + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MaxLength(4000)] + [JsonPropertyName("customInstructions")] + public string? CustomInstructions { get; set; } + /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; @@ -6486,7 +6508,7 @@ internal sealed class EventLogReadRequest /// Either '*' to receive all event types, or a non-empty list of event types to receive. [JsonPropertyName("types")] - public object? Types { get; set; } + public JsonElement? Types { get; set; } /// Milliseconds to wait for new events when the cursor is at the tail of history. 0 (default) returns immediately even if no events are available. Capped at 30000ms. Ephemeral events that arrive during the wait are delivered in this batch but are NOT replayable on a subsequent read (use a non-zero waitMs in your next call to capture future ephemerals as they happen). [JsonConverter(typeof(MillisecondsTimeSpanConverter))] @@ -7108,7 +7130,7 @@ public sealed class SessionFsSqliteQueryResult /// For SELECT: array of row objects. For others: empty array. [JsonPropertyName("rows")] - public IList> Rows { get => field ??= []; set; } + public IList> Rows { get => field ??= []; set; } /// Number of rows affected (for INSERT/UPDATE/DELETE). [JsonPropertyName("rowsAffected")] @@ -7120,7 +7142,7 @@ public sealed class SessionFsSqliteQueryRequest { /// Optional named bind parameters. [JsonPropertyName("params")] - public IDictionary? Params { get; set; } + public IDictionary? Params { get; set; } /// SQL query to execute. [JsonPropertyName("query")] @@ -10294,7 +10316,7 @@ public async Task AddAsync(string name, object config, CancellationToken cancell ArgumentNullException.ThrowIfNull(name); ArgumentNullException.ThrowIfNull(config); - var request = new McpConfigAddRequest { Name = name, Config = config }; + var request = new McpConfigAddRequest { Name = name, Config = CopilotClient.ToJsonElementForWire(config)!.Value }; await CopilotClient.InvokeRpcAsync(_rpc, "mcp.config.add", [request], cancellationToken); } @@ -10307,7 +10329,7 @@ public async Task UpdateAsync(string name, object config, CancellationToken canc ArgumentNullException.ThrowIfNull(name); ArgumentNullException.ThrowIfNull(config); - var request = new McpConfigUpdateRequest { Name = name, Config = config }; + var request = new McpConfigUpdateRequest { Name = name, Config = CopilotClient.ToJsonElementForWire(config)!.Value }; await CopilotClient.InvokeRpcAsync(_rpc, "mcp.config.update", [request], cancellationToken); } @@ -10878,7 +10900,7 @@ public async Task SendAsync(string prompt, string? displayPrompt = n ArgumentNullException.ThrowIfNull(prompt); _session.ThrowIfDisposed(); - var request = new SendRequest { SessionId = _session.SessionId, Prompt = prompt, DisplayPrompt = displayPrompt, Attachments = attachments, Mode = mode, Prepend = prepend, Billable = billable, RequiredTool = requiredTool, Source = source, AgentMode = agentMode, RequestHeaders = requestHeaders, Traceparent = traceparent, Tracestate = tracestate, Wait = wait }; + var request = new SendRequest { SessionId = _session.SessionId, Prompt = prompt, DisplayPrompt = displayPrompt, Attachments = attachments, Mode = mode, Prepend = prepend, Billable = billable, RequiredTool = requiredTool, Source = CopilotClient.ToJsonElementForWire(source), AgentMode = agentMode, RequestHeaders = requestHeaders, Traceparent = traceparent, Tracestate = tracestate, Wait = wait }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.send", [request], cancellationToken); } @@ -11658,7 +11680,7 @@ public async Task ExecuteSamplingAsync(string reques ArgumentNullException.ThrowIfNull(request); _session.ThrowIfDisposed(); - var rpcRequest = new McpExecuteSamplingParams { SessionId = _session.SessionId, RequestId = requestId, ServerName = serverName, McpRequestId = mcpRequestId, Request = request }; + var rpcRequest = new McpExecuteSamplingParams { SessionId = _session.SessionId, RequestId = requestId, ServerName = serverName, McpRequestId = CopilotClient.ToJsonElementForWire(mcpRequestId)!.Value, Request = request }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.mcp.executeSampling", [rpcRequest], cancellationToken); } @@ -11806,11 +11828,11 @@ internal OptionsApi(CopilotSession session) /// Whether to expose the `manage_schedule` tool to the agent. The runtime always owns the per-session schedule registry; this flag only controls tool exposure (typically gated to staff users). /// The to monitor for cancellation requests. The default is . /// Indicates whether the session options patch was applied successfully. - public async Task UpdateAsync(string? model = null, string? reasoningEffort = null, string? clientName = null, string? lspClientName = null, string? integrationId = null, IDictionary? featureFlags = null, bool? isExperimentalMode = null, object? provider = null, string? workingDirectory = null, IList? availableTools = null, IList? excludedTools = null, bool? enableScriptSafety = null, string? shellInitProfile = null, IList? shellProcessFlags = null, object? sandboxConfig = null, bool? logInteractiveShells = null, OptionsUpdateEnvValueMode? envValueMode = null, IList? skillDirectories = null, IList? disabledSkills = null, bool? enableOnDemandInstructionDiscovery = null, IList? installedPlugins = null, bool? customAgentsLocalOnly = null, bool? skipCustomInstructions = null, IList? disabledInstructionSources = null, bool? coauthorEnabled = null, string? trajectoryFile = null, bool? enableStreaming = null, string? copilotUrl = null, bool? askUserDisabled = null, bool? continueOnAutoMode = null, bool? runningInInteractiveMode = null, bool? enableReasoningSummaries = null, string? agentContext = null, string? eventsLogDirectory = null, IList? additionalContentExclusionPolicies = null, bool? manageScheduleEnabled = null, CancellationToken cancellationToken = default) + public async Task UpdateAsync(string? model = null, string? reasoningEffort = null, string? clientName = null, string? lspClientName = null, string? integrationId = null, IDictionary? featureFlags = null, bool? isExperimentalMode = null, object? provider = null, string? workingDirectory = null, IList? availableTools = null, IList? excludedTools = null, bool? enableScriptSafety = null, string? shellInitProfile = null, IList? shellProcessFlags = null, object? sandboxConfig = null, bool? logInteractiveShells = null, OptionsUpdateEnvValueMode? envValueMode = null, IList? skillDirectories = null, IList? disabledSkills = null, bool? enableOnDemandInstructionDiscovery = null, IList? installedPlugins = null, bool? customAgentsLocalOnly = null, bool? skipCustomInstructions = null, IList? disabledInstructionSources = null, bool? coauthorEnabled = null, string? trajectoryFile = null, bool? enableStreaming = null, string? copilotUrl = null, bool? askUserDisabled = null, bool? continueOnAutoMode = null, bool? runningInInteractiveMode = null, bool? enableReasoningSummaries = null, string? agentContext = null, string? eventsLogDirectory = null, IList? additionalContentExclusionPolicies = null, bool? manageScheduleEnabled = null, CancellationToken cancellationToken = default) { _session.ThrowIfDisposed(); - var request = new SessionUpdateOptionsParams { SessionId = _session.SessionId, Model = model, ReasoningEffort = reasoningEffort, ClientName = clientName, LspClientName = lspClientName, IntegrationId = integrationId, FeatureFlags = featureFlags, IsExperimentalMode = isExperimentalMode, Provider = provider, WorkingDirectory = workingDirectory, AvailableTools = availableTools, ExcludedTools = excludedTools, EnableScriptSafety = enableScriptSafety, ShellInitProfile = shellInitProfile, ShellProcessFlags = shellProcessFlags, SandboxConfig = sandboxConfig, LogInteractiveShells = logInteractiveShells, EnvValueMode = envValueMode, SkillDirectories = skillDirectories, DisabledSkills = disabledSkills, EnableOnDemandInstructionDiscovery = enableOnDemandInstructionDiscovery, InstalledPlugins = installedPlugins, CustomAgentsLocalOnly = customAgentsLocalOnly, SkipCustomInstructions = skipCustomInstructions, DisabledInstructionSources = disabledInstructionSources, CoauthorEnabled = coauthorEnabled, TrajectoryFile = trajectoryFile, EnableStreaming = enableStreaming, CopilotUrl = copilotUrl, AskUserDisabled = askUserDisabled, ContinueOnAutoMode = continueOnAutoMode, RunningInInteractiveMode = runningInInteractiveMode, EnableReasoningSummaries = enableReasoningSummaries, AgentContext = agentContext, EventsLogDirectory = eventsLogDirectory, AdditionalContentExclusionPolicies = additionalContentExclusionPolicies, ManageScheduleEnabled = manageScheduleEnabled }; + var request = new SessionUpdateOptionsParams { SessionId = _session.SessionId, Model = model, ReasoningEffort = reasoningEffort, ClientName = clientName, LspClientName = lspClientName, IntegrationId = integrationId, FeatureFlags = featureFlags, IsExperimentalMode = isExperimentalMode, Provider = CopilotClient.ToJsonElementForWire(provider), WorkingDirectory = workingDirectory, AvailableTools = availableTools, ExcludedTools = excludedTools, EnableScriptSafety = enableScriptSafety, ShellInitProfile = shellInitProfile, ShellProcessFlags = shellProcessFlags, SandboxConfig = CopilotClient.ToJsonElementForWire(sandboxConfig), LogInteractiveShells = logInteractiveShells, EnvValueMode = envValueMode, SkillDirectories = skillDirectories, DisabledSkills = disabledSkills, EnableOnDemandInstructionDiscovery = enableOnDemandInstructionDiscovery, InstalledPlugins = installedPlugins, CustomAgentsLocalOnly = customAgentsLocalOnly, SkipCustomInstructions = skipCustomInstructions, DisabledInstructionSources = disabledInstructionSources, CoauthorEnabled = coauthorEnabled, TrajectoryFile = trajectoryFile, EnableStreaming = enableStreaming, CopilotUrl = copilotUrl, AskUserDisabled = askUserDisabled, ContinueOnAutoMode = continueOnAutoMode, RunningInInteractiveMode = runningInInteractiveMode, EnableReasoningSummaries = enableReasoningSummaries, AgentContext = agentContext, EventsLogDirectory = eventsLogDirectory, AdditionalContentExclusionPolicies = additionalContentExclusionPolicies, ManageScheduleEnabled = manageScheduleEnabled }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.options.update", [request], cancellationToken); } } @@ -11919,7 +11941,7 @@ public async Task HandlePendingToolCallAsync(string ArgumentNullException.ThrowIfNull(requestId); _session.ThrowIfDisposed(); - var request = new HandlePendingToolCallRequest { SessionId = _session.SessionId, RequestId = requestId, Result = result, Error = error }; + var request = new HandlePendingToolCallRequest { SessionId = _session.SessionId, RequestId = requestId, Result = CopilotClient.ToJsonElementForWire(result), Error = error }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.tools.handlePendingToolCall", [request], cancellationToken); } @@ -12651,14 +12673,15 @@ internal HistoryApi(CopilotSession session) } /// Compacts the session history to reduce context usage. + /// Optional compaction parameters. /// The to monitor for cancellation requests. The default is . /// Compaction outcome with the number of tokens and messages removed, summary text, and the resulting context window breakdown. - public async Task CompactAsync(CancellationToken cancellationToken = default) + public async Task CompactAsync(HistoryCompactRequest? request = null, CancellationToken cancellationToken = default) { _session.ThrowIfDisposed(); - var request = new SessionHistoryCompactRequest { SessionId = _session.SessionId }; - return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.history.compact", [request], cancellationToken); + var rpcRequest = new HistoryCompactRequestWithSession { SessionId = _session.SessionId, CustomInstructions = request?.CustomInstructions }; + return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.history.compact", [rpcRequest], cancellationToken); } /// Truncates persisted session history to a specific event. @@ -12775,7 +12798,7 @@ public async Task ReadAsync(string? cursor = null, int? max = { _session.ThrowIfDisposed(); - var request = new EventLogReadRequest { SessionId = _session.SessionId, Cursor = cursor, Max = max, Wait = waitMs, Types = types, AgentScope = agentScope }; + var request = new EventLogReadRequest { SessionId = _session.SessionId, Cursor = cursor, Max = max, Wait = waitMs, Types = CopilotClient.ToJsonElementForWire(types), AgentScope = agentScope }; return await CopilotClient.InvokeRpcAsync(_session.Rpc, "session.eventLog.read", [request], cancellationToken); } @@ -13362,6 +13385,8 @@ public static void RegisterClientSessionApiHandlers(JsonRpc rpc, FuncSession-wide accumulated nano-AI units cost. + [Experimental(Diagnostics.Experimental)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("totalNanoAiu")] public double? TotalNanoAiu { get; set; } /// Total number of premium API requests used during the session. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonInclude] [JsonPropertyName("totalPremiumRequests")] - public required double TotalPremiumRequests { get; set; } + internal double? TotalPremiumRequests { get; set; } } /// Working directory and git context at session start. @@ -1805,6 +1808,11 @@ public sealed partial class SessionCompactionCompleteData [JsonPropertyName("conversationTokens")] public long? ConversationTokens { get; set; } + /// User-supplied focus instructions provided to a manual `/compact` invocation. Omitted for automatic compaction and for manual compaction with no focus text. + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("customInstructions")] + public string? CustomInstructions { get; set; } + /// Error message if compaction failed. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("error")] @@ -1989,11 +1997,13 @@ public sealed partial class AssistantStreamingDeltaData public sealed partial class AssistantMessageData { /// Raw Anthropic content array with advisor blocks (server_tool_use, advisor_tool_result) for verbatim round-tripping. + [Experimental(Diagnostics.Experimental)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("anthropicAdvisorBlocks")] - public object[]? AnthropicAdvisorBlocks { get; set; } + public JsonElement[]? AnthropicAdvisorBlocks { get; set; } /// Anthropic advisor model ID used for this response, for timeline display on replay. + [Experimental(Diagnostics.Experimental)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("anthropicAdvisorModel")] public string? AnthropicAdvisorModel { get; set; } @@ -2133,6 +2143,7 @@ public sealed partial class AssistantUsageData public AssistantUsageCopilotUsage? CopilotUsage { get; set; } /// Model multiplier cost for billing purposes. + [Experimental(Diagnostics.Experimental)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("cost")] public double? Cost { get; set; } @@ -2182,8 +2193,9 @@ public sealed partial class AssistantUsageData /// Per-quota resource usage snapshots, keyed by quota identifier. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonInclude] [JsonPropertyName("quotaSnapshots")] - public IDictionary? QuotaSnapshots { get; set; } + internal IDictionary? QuotaSnapshots { get; set; } /// Reasoning effort level used for model calls, if applicable (e.g. "none", "low", "medium", "high", "xhigh", "max"). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -2260,7 +2272,7 @@ public sealed partial class ToolUserRequestedData /// Arguments for the tool invocation. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("arguments")] - public object? Arguments { get; set; } + public JsonElement? Arguments { get; set; } /// Unique identifier for this tool call. [JsonPropertyName("toolCallId")] @@ -2277,7 +2289,7 @@ public sealed partial class ToolExecutionStartData /// Arguments passed to the tool. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("arguments")] - public object? Arguments { get; set; } + public JsonElement? Arguments { get; set; } /// Name of the MCP server hosting this tool, when the tool is an MCP tool. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -2380,7 +2392,7 @@ public sealed partial class ToolExecutionCompleteData /// Tool-specific telemetry data (e.g., CodeQL check counts, grep match counts). [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("toolTelemetry")] - public IDictionary? ToolTelemetry { get; set; } + public IDictionary? ToolTelemetry { get; set; } /// Identifier for the agent loop turn this tool was invoked in, matching the corresponding assistant.turn_start event. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -2562,7 +2574,7 @@ public sealed partial class HookStartData /// Input data passed to the hook. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("input")] - public object? Input { get; set; } + public JsonElement? Input { get; set; } } /// Hook invocation completion details including output, success status, and error information. @@ -2584,7 +2596,7 @@ public sealed partial class HookEndData /// Output data produced by the hook. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("output")] - public object? Output { get; set; } + public JsonElement? Output { get; set; } /// Whether the hook completed successfully. [JsonPropertyName("success")] @@ -2757,7 +2769,7 @@ public sealed partial class ElicitationCompletedData /// The submitted form data when action is 'accept'; keys match the requested schema fields. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("content")] - public IDictionary? Content { get; set; } + public IDictionary? Content { get; set; } /// Request ID of the resolved elicitation request; clients should dismiss any UI for this request. [JsonPropertyName("requestId")] @@ -2769,7 +2781,7 @@ public sealed partial class SamplingRequestedData { /// The JSON-RPC request ID from the MCP protocol. [JsonPropertyName("mcpRequestId")] - public required object McpRequestId { get; set; } + public required JsonElement McpRequestId { get; set; } /// Unique identifier for this sampling request; used to respond via session.respondToSampling(). [JsonPropertyName("requestId")] @@ -2830,7 +2842,7 @@ public sealed partial class SessionCustomNotificationData /// Source-defined JSON payload for the custom notification. [JsonPropertyName("payload")] - public required object Payload { get; set; } + public required JsonElement Payload { get; set; } /// Namespace for the custom notification producer. [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] @@ -2855,7 +2867,7 @@ public sealed partial class ExternalToolRequestedData /// Arguments to pass to the external tool. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("arguments")] - public object? Arguments { get; set; } + public JsonElement? Arguments { get; set; } /// Unique identifier for this request; used to respond via session.respondToExternalTool(). [JsonPropertyName("requestId")] @@ -3180,12 +3192,16 @@ public sealed partial class ShutdownCodeChanges public sealed partial class ShutdownModelMetricRequests { /// Cumulative cost multiplier for requests to this model. + [Experimental(Diagnostics.Experimental)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("cost")] - public required double Cost { get; set; } + public double? Cost { get; set; } /// Total number of API requests made to this model. + [Experimental(Diagnostics.Experimental)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("count")] - public required long Count { get; set; } + public long? Count { get; set; } } /// Schema for the `ShutdownModelMetricTokenDetail` type. @@ -3237,6 +3253,7 @@ public sealed partial class ShutdownModelMetric public IDictionary? TokenDetails { get; set; } /// Accumulated nano-AI units cost for this model. + [Experimental(Diagnostics.Experimental)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("totalNanoAiu")] public double? TotalNanoAiu { get; set; } @@ -3525,7 +3542,7 @@ public sealed partial class AssistantMessageToolRequest /// Arguments to pass to the tool, format depends on the tool. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("arguments")] - public object? Arguments { get; set; } + public JsonElement? Arguments { get; set; } /// Resolved intention summary describing what this specific call does. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -3600,37 +3617,45 @@ public sealed partial class AssistantUsageCopilotUsage public sealed partial class AssistantUsageQuotaSnapshot { /// Total requests allowed by the entitlement. + [JsonInclude] [JsonPropertyName("entitlementRequests")] - public required long EntitlementRequests { get; set; } + internal required long EntitlementRequests { get; set; } /// Whether the user has an unlimited usage entitlement. + [JsonInclude] [JsonPropertyName("isUnlimitedEntitlement")] - public required bool IsUnlimitedEntitlement { get; set; } + internal required bool IsUnlimitedEntitlement { get; set; } - /// Number of requests over the entitlement limit. + /// Number of additional usage requests made this period. + [JsonInclude] [JsonPropertyName("overage")] - public required double Overage { get; set; } + internal required double Overage { get; set; } - /// Whether overage is allowed when quota is exhausted. + /// Whether additional usage is allowed when quota is exhausted. + [JsonInclude] [JsonPropertyName("overageAllowedWithExhaustedQuota")] - public required bool OverageAllowedWithExhaustedQuota { get; set; } + internal required bool OverageAllowedWithExhaustedQuota { get; set; } /// Percentage of quota remaining (0 to 100). + [JsonInclude] [JsonPropertyName("remainingPercentage")] - public required double RemainingPercentage { get; set; } + internal required double RemainingPercentage { get; set; } /// Date when the quota resets. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonInclude] [JsonPropertyName("resetDate")] - public DateTimeOffset? ResetDate { get; set; } + internal DateTimeOffset? ResetDate { get; set; } /// Whether usage is still permitted after quota exhaustion. + [JsonInclude] [JsonPropertyName("usageAllowedWithExhaustedQuota")] - public required bool UsageAllowedWithExhaustedQuota { get; set; } + internal required bool UsageAllowedWithExhaustedQuota { get; set; } /// Number of requests already consumed. + [JsonInclude] [JsonPropertyName("usedRequests")] - public required long UsedRequests { get; set; } + internal required long UsedRequests { get; set; } } /// Error details when the tool execution failed. @@ -3983,7 +4008,7 @@ public sealed partial class SystemMessageMetadata /// Template variables used when constructing the prompt. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("variables")] - public IDictionary? Variables { get; set; } + public IDictionary? Variables { get; set; } } /// Schema for the `SystemNotificationAgentCompleted` type. @@ -4289,7 +4314,7 @@ public sealed partial class PermissionRequestMcp : PermissionRequest /// Arguments to pass to the MCP tool. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("args")] - public object? Args { get; set; } + public JsonElement? Args { get; set; } /// Whether this MCP tool is read-only (no side effects). [JsonPropertyName("readOnly")] @@ -4391,7 +4416,7 @@ public sealed partial class PermissionRequestCustomTool : PermissionRequest /// Arguments to pass to the custom tool. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("args")] - public object? Args { get; set; } + public JsonElement? Args { get; set; } /// Tool call ID that triggered this permission request. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -4423,7 +4448,7 @@ public sealed partial class PermissionRequestHook : PermissionRequest /// Arguments of the tool call being gated. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("toolArgs")] - public object? ToolArgs { get; set; } + public JsonElement? ToolArgs { get; set; } /// Tool call ID that triggered this permission request. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -4606,7 +4631,7 @@ public sealed partial class PermissionPromptRequestMcp : PermissionPromptRequest /// Arguments to pass to the MCP tool. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("args")] - public object? Args { get; set; } + public JsonElement? Args { get; set; } /// Name of the MCP server providing the tool. [JsonPropertyName("serverName")] @@ -4704,7 +4729,7 @@ public sealed partial class PermissionPromptRequestCustomTool : PermissionPrompt /// Arguments to pass to the custom tool. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("args")] - public object? Args { get; set; } + public JsonElement? Args { get; set; } /// Tool call ID that triggered this permission request. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -4758,7 +4783,7 @@ public sealed partial class PermissionPromptRequestHook : PermissionPromptReques /// Arguments of the tool call being gated. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("toolArgs")] - public object? ToolArgs { get; set; } + public JsonElement? ToolArgs { get; set; } /// Tool call ID that triggered this permission request. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -5128,7 +5153,7 @@ public sealed partial class ElicitationRequestedSchema { /// Form field definitions, keyed by field name. [JsonPropertyName("properties")] - public required IDictionary Properties { get; set; } + public required IDictionary Properties { get; set; } /// List of required field names. [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] diff --git a/dotnet/src/Session.cs b/dotnet/src/Session.cs index fc7d82675..999ab7f60 100644 --- a/dotnet/src/Session.cs +++ b/dotnet/src/Session.cs @@ -640,7 +640,7 @@ private async Task HandleBroadcastEventAsync(SessionEvent sessionEvent) ? new ElicitationSchema { Type = data.RequestedSchema.Type, - Properties = data.RequestedSchema.Properties, + Properties = data.RequestedSchema.Properties.ToDictionary(kvp => kvp.Key, kvp => (object)kvp.Value), Required = data.RequestedSchema.Required?.ToList() } : null; @@ -690,7 +690,7 @@ await HandleElicitationRequestAsync( /// /// Executes a tool handler and sends the result back via the HandlePendingToolCall RPC. /// - private async Task ExecuteToolAndRespondAsync(string requestId, string toolName, string toolCallId, object? arguments, AIFunction tool) + private async Task ExecuteToolAndRespondAsync(string requestId, string toolName, string toolCallId, JsonElement? arguments, AIFunction tool) { try { @@ -710,13 +710,8 @@ private async Task ExecuteToolAndRespondAsync(string requestId, string toolName, } }; - if (arguments is not null) + if (arguments is JsonElement incomingJsonArgs) { - if (arguments is not JsonElement incomingJsonArgs) - { - throw new InvalidOperationException($"Incoming arguments must be a {nameof(JsonElement)}; received {arguments.GetType().Name}"); - } - foreach (var prop in incomingJsonArgs.EnumerateObject()) { aiFunctionArgs[prop.Name] = prop.Value; @@ -957,7 +952,9 @@ private async Task HandleElicitationRequestAsync(ElicitationContext context, str await Rpc.Ui.HandlePendingElicitationAsync(requestId, new UIElicitationResponse { Action = result.Action, - Content = result.Content + Content = result.Content?.ToDictionary( + kvp => kvp.Key, + kvp => CopilotClient.ToJsonElementForWire(kvp.Value)!.Value) }); LoggingHelpers.LogTiming(_logger, LogLevel.Debug, null, "CopilotSession.HandleElicitationRequestAsync response sent successfully. Elapsed={Elapsed}, SessionId={SessionId}, RequestId={RequestId}", @@ -1009,12 +1006,18 @@ public async Task ElicitAsync(ElicitationParams elicitationPa var schema = new UIElicitationSchema { Type = elicitationParams.RequestedSchema.Type, - Properties = elicitationParams.RequestedSchema.Properties, + Properties = elicitationParams.RequestedSchema.Properties.ToDictionary( + kvp => kvp.Key, + kvp => CopilotClient.ToJsonElementForWire(kvp.Value)!.Value), Required = elicitationParams.RequestedSchema.Required }; var result = await session.Rpc.Ui.ElicitationAsync(elicitationParams.Message, schema, cancellationToken); - return new ElicitationResult { Action = result.Action, Content = result.Content }; + return new ElicitationResult + { + Action = result.Action, + Content = result.Content?.ToDictionary(kvp => kvp.Key, kvp => (object)kvp.Value) + }; } public async Task ConfirmAsync(string message, CancellationToken cancellationToken) @@ -1026,9 +1029,9 @@ public async Task ConfirmAsync(string message, CancellationToken cancellat var schema = new UIElicitationSchema { Type = "object", - Properties = new Dictionary + Properties = new Dictionary { - ["confirmed"] = new Dictionary { ["type"] = "boolean", ["default"] = true } + ["confirmed"] = JsonDocument.Parse("""{"type":"boolean","default":true}""").RootElement.Clone() }, Required = ["confirmed"] }; @@ -1038,11 +1041,10 @@ public async Task ConfirmAsync(string message, CancellationToken cancellat && result.Content != null && result.Content.TryGetValue("confirmed", out var val)) { - return val switch + return val.ValueKind switch { - bool b => b, - JsonElement { ValueKind: JsonValueKind.True } => true, - JsonElement { ValueKind: JsonValueKind.False } => false, + JsonValueKind.True => true, + JsonValueKind.False => false, _ => false }; } @@ -1057,12 +1059,13 @@ public async Task ConfirmAsync(string message, CancellationToken cancellat session.ThrowIfDisposed(); session.AssertElicitation(); + var enumJson = JsonSerializer.Serialize(options, TypesJsonContext.Default.StringArray); var schema = new UIElicitationSchema { Type = "object", - Properties = new Dictionary + Properties = new Dictionary { - ["selection"] = new Dictionary { ["type"] = "string", ["enum"] = options } + ["selection"] = JsonDocument.Parse($$"""{"type":"string","enum":{{enumJson}}}""").RootElement.Clone() }, Required = ["selection"] }; @@ -1072,12 +1075,7 @@ public async Task ConfirmAsync(string message, CancellationToken cancellat && result.Content != null && result.Content.TryGetValue("selection", out var val)) { - return val switch - { - string s => s, - JsonElement { ValueKind: JsonValueKind.String } je => je.GetString(), - _ => val.ToString() - }; + return val.ValueKind == JsonValueKind.String ? val.GetString() : val.ToString(); } return null; @@ -1089,18 +1087,21 @@ public async Task ConfirmAsync(string message, CancellationToken cancellat session.ThrowIfDisposed(); session.AssertElicitation(); - var field = new Dictionary { ["type"] = "string" }; - if (options?.Title != null) field["title"] = options.Title; - if (options?.Description != null) field["description"] = options.Description; - if (options?.MinLength != null) field["minLength"] = options.MinLength; - if (options?.MaxLength != null) field["maxLength"] = options.MaxLength; - if (options?.Format != null) field["format"] = options.Format; - if (options?.Default != null) field["default"] = options.Default; + var fieldNode = new System.Text.Json.Nodes.JsonObject { ["type"] = "string" }; + if (options?.Title != null) fieldNode["title"] = options.Title; + if (options?.Description != null) fieldNode["description"] = options.Description; + if (options?.MinLength != null) fieldNode["minLength"] = options.MinLength; + if (options?.MaxLength != null) fieldNode["maxLength"] = options.MaxLength; + if (options?.Format != null) fieldNode["format"] = options.Format; + if (options?.Default != null) fieldNode["default"] = options.Default; var schema = new UIElicitationSchema { Type = "object", - Properties = new Dictionary { ["value"] = field }, + Properties = new Dictionary + { + ["value"] = JsonDocument.Parse(fieldNode.ToJsonString()).RootElement.Clone() + }, Required = ["value"] }; @@ -1109,12 +1110,7 @@ public async Task ConfirmAsync(string message, CancellationToken cancellat && result.Content != null && result.Content.TryGetValue("value", out var val)) { - return val switch - { - string s => s, - JsonElement { ValueKind: JsonValueKind.String } je => je.GetString(), - _ => val.ToString() - }; + return val.ValueKind == JsonValueKind.String ? val.GetString() : val.ToString(); } return null; diff --git a/dotnet/src/SessionFsProvider.cs b/dotnet/src/SessionFsProvider.cs index 12dfc8770..fbb8df507 100644 --- a/dotnet/src/SessionFsProvider.cs +++ b/dotnet/src/SessionFsProvider.cs @@ -3,6 +3,7 @@ *--------------------------------------------------------------------------------------------*/ using GitHub.Copilot.Rpc; +using System.Text.Json; namespace GitHub.Copilot; @@ -44,7 +45,7 @@ public interface ISessionFsSqliteProvider Task QueryAsync( SessionFsSqliteQueryType queryType, string query, - IDictionary? bindParams, + IDictionary? bindParams, CancellationToken cancellationToken); /// @@ -287,11 +288,16 @@ async Task ISessionFsHandler.SqliteQueryAsync(Sessio try { - var result = await sqliteProvider.QueryAsync(request.QueryType, request.Query, request.Params, cancellationToken).ConfigureAwait(false); + var bindParams = request.Params?.ToDictionary( + kvp => kvp.Key, + kvp => JsonElementToValue(kvp.Value)); + var result = await sqliteProvider.QueryAsync(request.QueryType, request.Query, bindParams, cancellationToken).ConfigureAwait(false); return new SessionFsSqliteQueryResult { - Rows = result?.Rows ?? [], + Rows = result?.Rows?.Select(row => (IDictionary)row.ToDictionary( + kvp => kvp.Key, + kvp => CopilotClient.ToJsonElementForWire(kvp.Value)!.Value)).ToList() ?? [], Columns = result?.Columns ?? [], RowsAffected = result?.RowsAffected ?? 0, LastInsertRowid = result?.LastInsertRowid, @@ -329,4 +335,14 @@ private static SessionFsError ToSessionFsError(Exception ex) : SessionFsErrorCode.UNKNOWN; return new SessionFsError { Code = code, Message = ex.Message }; } + + private static object? JsonElementToValue(JsonElement element) => element.ValueKind switch + { + JsonValueKind.Null => null, + JsonValueKind.True => true, + JsonValueKind.False => false, + JsonValueKind.String => element.GetString(), + JsonValueKind.Number => element.TryGetInt64(out var l) ? l : element.GetDouble(), + _ => element.GetRawText(), + }; } diff --git a/dotnet/src/Types.cs b/dotnet/src/Types.cs index 9cc070f78..e3569663e 100644 --- a/dotnet/src/Types.cs +++ b/dotnet/src/Types.cs @@ -671,7 +671,7 @@ public sealed class ToolInvocation /// /// Arguments passed to the tool by the language model. /// - public object? Arguments { get; set; } + public JsonElement? Arguments { get; set; } } /// Describes the kind of a permission request result. @@ -1227,7 +1227,7 @@ public sealed class PreToolUseHookInput /// Arguments that will be passed to the tool. /// [JsonPropertyName("toolArgs")] - public object? ToolArgs { get; set; } + public JsonElement? ToolArgs { get; set; } } /// @@ -1305,13 +1305,13 @@ public sealed class PostToolUseHookInput /// Arguments that were passed to the tool. /// [JsonPropertyName("toolArgs")] - public object? ToolArgs { get; set; } + public JsonElement? ToolArgs { get; set; } /// /// Result returned by the tool execution. /// [JsonPropertyName("toolResult")] - public object? ToolResult { get; set; } + public JsonElement? ToolResult { get; set; } } /// diff --git a/dotnet/test/E2E/InMemorySessionFsSqliteHandler.cs b/dotnet/test/E2E/InMemorySessionFsSqliteHandler.cs index 0ae9c9a7d..4e573ff5c 100644 --- a/dotnet/test/E2E/InMemorySessionFsSqliteHandler.cs +++ b/dotnet/test/E2E/InMemorySessionFsSqliteHandler.cs @@ -43,7 +43,7 @@ private SqliteConnection GetOrCreateDb() public Task QueryAsync( SessionFsSqliteQueryType queryType, string query, - IDictionary? bindParams, + IDictionary? bindParams, CancellationToken cancellationToken) { sqliteCalls.Add(new SqliteCall(sessionId, queryType.Value, query)); @@ -125,7 +125,7 @@ public Task ExistsAsync(CancellationToken cancellationToken) return Task.FromResult(_db is not null); } - private static void AddParams(SqliteCommand cmd, IDictionary? bindParams) + private static void AddParams(SqliteCommand cmd, IDictionary? bindParams) { if (bindParams is null) return; foreach (var (key, value) in bindParams) diff --git a/dotnet/test/E2E/PendingWorkResumeE2ETests.cs b/dotnet/test/E2E/PendingWorkResumeE2ETests.cs index 889dc0050..ffd214de1 100644 --- a/dotnet/test/E2E/PendingWorkResumeE2ETests.cs +++ b/dotnet/test/E2E/PendingWorkResumeE2ETests.cs @@ -5,6 +5,7 @@ using GitHub.Copilot.Test.Harness; using Microsoft.Extensions.AI; using System.ComponentModel; +using System.Text.Json; using Xunit; using Xunit.Abstractions; using RpcPermissionDecisionApproveOnce = GitHub.Copilot.Rpc.PermissionDecisionApproveOnce; @@ -141,7 +142,7 @@ await session1.SendAsync(new MessageOptions var toolResult = await session2.Rpc.Tools.HandlePendingToolCallAsync( toolEvent.Data.RequestId, - result: "EXTERNAL_RESUMED_BETA"); + result: JsonDocument.Parse("\"EXTERNAL_RESUMED_BETA\"").RootElement.Clone()); Assert.True(toolResult.Success); var answer = await TestHelper.GetFinalAssistantMessageAsync(session2, PendingWorkTimeout); @@ -210,7 +211,7 @@ await session1.SendAsync(new MessageOptions var resumedResult = await session2.Rpc.Tools.HandlePendingToolCallAsync( toolEvent.Data.RequestId, - result: "EXTERNAL_RESUMED_BETA"); + result: JsonDocument.Parse("\"EXTERNAL_RESUMED_BETA\"").RootElement.Clone()); Assert.True(resumedResult.Success); // continuePendingWork=false may interrupt agent continuation before this response, @@ -287,11 +288,11 @@ await Task.WhenAll( var toolB = toolEvents["pending_lookup_b"]; var resultB = await session2.Rpc.Tools.HandlePendingToolCallAsync( toolB.Data.RequestId, - result: "PARALLEL_B_BETA"); + result: JsonDocument.Parse("\"PARALLEL_B_BETA\"").RootElement.Clone()); Assert.True(resultB.Success); var resultA = await session2.Rpc.Tools.HandlePendingToolCallAsync( toolA.Data.RequestId, - result: "PARALLEL_A_ALPHA"); + result: JsonDocument.Parse("\"PARALLEL_A_ALPHA\"").RootElement.Clone()); Assert.True(resultA.Success); await session2.DisposeAsync(); diff --git a/dotnet/test/E2E/RpcMcpConfigE2ETests.cs b/dotnet/test/E2E/RpcMcpConfigE2ETests.cs index d26e5535d..1b4de0ca1 100644 --- a/dotnet/test/E2E/RpcMcpConfigE2ETests.cs +++ b/dotnet/test/E2E/RpcMcpConfigE2ETests.cs @@ -34,11 +34,11 @@ public async Task Should_Call_Server_Mcp_Config_Rpcs() try { - await Client.Rpc.Mcp.Config.AddAsync(serverName, config); + await Client.Rpc.Mcp.Config.AddAsync(serverName, JsonSerializer.SerializeToElement(config, TestSharedJsonContext.Default.DictionaryStringObject)); var afterAdd = await Client.Rpc.Mcp.Config.ListAsync(); Assert.Contains(serverName, afterAdd.Servers.Keys); - await Client.Rpc.Mcp.Config.UpdateAsync(serverName, updatedConfig); + await Client.Rpc.Mcp.Config.UpdateAsync(serverName, JsonSerializer.SerializeToElement(updatedConfig, TestSharedJsonContext.Default.DictionaryStringObject)); var afterUpdate = await Client.Rpc.Mcp.Config.ListAsync(); var updated = GetServerConfig(afterUpdate, serverName); Assert.Equal("node", updated.GetProperty("command").GetString()); @@ -84,7 +84,7 @@ public async Task Should_RoundTrip_Http_Mcp_Oauth_Config_Rpc() try { - await Client.Rpc.Mcp.Config.AddAsync(serverName, config); + await Client.Rpc.Mcp.Config.AddAsync(serverName, JsonSerializer.SerializeToElement(config, TestSharedJsonContext.Default.McpServerConfig)); var afterAdd = await Client.Rpc.Mcp.Config.ListAsync(); var added = GetServerConfig(afterAdd, serverName); Assert.Equal("http", added.GetProperty("type").GetString()); @@ -94,7 +94,7 @@ public async Task Should_RoundTrip_Http_Mcp_Oauth_Config_Rpc() Assert.False(added.GetProperty("oauthPublicClient").GetBoolean()); Assert.Equal("client_credentials", added.GetProperty("oauthGrantType").GetString()); - await Client.Rpc.Mcp.Config.UpdateAsync(serverName, updatedConfig); + await Client.Rpc.Mcp.Config.UpdateAsync(serverName, JsonSerializer.SerializeToElement(updatedConfig, TestSharedJsonContext.Default.McpServerConfig)); var afterUpdate = await Client.Rpc.Mcp.Config.ListAsync(); var updated = GetServerConfig(afterUpdate, serverName); Assert.Equal("https://example.com/updated-mcp", updated.GetProperty("url").GetString()); diff --git a/dotnet/test/E2E/RpcTasksAndHandlersE2ETests.cs b/dotnet/test/E2E/RpcTasksAndHandlersE2ETests.cs index 2ed338129..61c8d5878 100644 --- a/dotnet/test/E2E/RpcTasksAndHandlersE2ETests.cs +++ b/dotnet/test/E2E/RpcTasksAndHandlersE2ETests.cs @@ -4,6 +4,7 @@ using GitHub.Copilot.Rpc; using GitHub.Copilot.Test.Harness; +using System.Text.Json; using Xunit; using Xunit.Abstractions; @@ -143,7 +144,7 @@ public async Task Should_Return_Expected_Results_For_Missing_Pending_Handler_Req var tool = await session.Rpc.Tools.HandlePendingToolCallAsync( requestId: "missing-tool-request", - result: "tool result"); + result: JsonDocument.Parse("\"tool result\"").RootElement.Clone()); Assert.False(tool.Success); var command = await session.Rpc.Commands.HandlePendingCommandAsync( diff --git a/dotnet/test/E2E/SessionFsE2ETests.cs b/dotnet/test/E2E/SessionFsE2ETests.cs index 7986cddcf..e550babf7 100644 --- a/dotnet/test/E2E/SessionFsE2ETests.cs +++ b/dotnet/test/E2E/SessionFsE2ETests.cs @@ -609,7 +609,7 @@ protected override Task RemoveAsync(string path, bool recursive, bool force, Can protected override Task RenameAsync(string src, string dest, CancellationToken cancellationToken) => Task.FromException(exception); - Task ISessionFsSqliteProvider.QueryAsync(SessionFsSqliteQueryType queryType, string query, IDictionary? bindParams, CancellationToken cancellationToken) => + Task ISessionFsSqliteProvider.QueryAsync(SessionFsSqliteQueryType queryType, string query, IDictionary? bindParams, CancellationToken cancellationToken) => Task.FromException(exception); Task ISessionFsSqliteProvider.ExistsAsync(CancellationToken cancellationToken) => diff --git a/dotnet/test/E2E/ToolResultsE2ETests.cs b/dotnet/test/E2E/ToolResultsE2ETests.cs index 75fd9488e..103c7ffe2 100644 --- a/dotnet/test/E2E/ToolResultsE2ETests.cs +++ b/dotnet/test/E2E/ToolResultsE2ETests.cs @@ -113,8 +113,8 @@ static ToolResultAIContent AnalyzeCode([Description("File to analyze")] string f ResultType = "success", ToolTelemetry = new Dictionary { - ["metrics"] = new Dictionary { ["analysisTimeMs"] = 150 }, - ["properties"] = new Dictionary { ["analyzer"] = "eslint" }, + ["metrics"] = JsonDocument.Parse("""{"analysisTimeMs":150}""").RootElement.Clone(), + ["properties"] = JsonDocument.Parse("""{"analyzer":"eslint"}""").RootElement.Clone(), }, }); } diff --git a/dotnet/test/TestJsonContext.cs b/dotnet/test/TestJsonContext.cs new file mode 100644 index 000000000..12a576510 --- /dev/null +++ b/dotnet/test/TestJsonContext.cs @@ -0,0 +1,16 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +using System.Text.Json.Serialization; + +namespace GitHub.Copilot.Test; + +[JsonSourceGenerationOptions(System.Text.Json.JsonSerializerDefaults.Web)] +[JsonSerializable(typeof(string[]))] +[JsonSerializable(typeof(Dictionary))] +[JsonSerializable(typeof(Dictionary))] +[JsonSerializable(typeof(McpServerConfig))] +[JsonSerializable(typeof(McpHttpServerConfig))] +[JsonSerializable(typeof(McpStdioServerConfig))] +internal partial class TestSharedJsonContext : JsonSerializerContext; diff --git a/dotnet/test/Unit/SessionEventSerializationTests.cs b/dotnet/test/Unit/SessionEventSerializationTests.cs index 3e6d4661f..608b47458 100644 --- a/dotnet/test/Unit/SessionEventSerializationTests.cs +++ b/dotnet/test/Unit/SessionEventSerializationTests.cs @@ -66,7 +66,7 @@ public class SessionEventSerializationTests Content = "ok", DetailedContent = "ok", }, - ToolTelemetry = new Dictionary + ToolTelemetry = new Dictionary { ["properties"] = ParseJsonElement("""{"command":"view"}"""), ["metrics"] = ParseJsonElement("""{"resultLength":2}"""), diff --git a/go/rpc/zrpc.go b/go/rpc/zrpc.go index eea56b4ba..97ab8d760 100644 --- a/go/rpc/zrpc.go +++ b/go/rpc/zrpc.go @@ -46,9 +46,9 @@ type AccountQuotaSnapshot struct { EntitlementRequests int64 `json:"entitlementRequests"` // Whether the user has an unlimited usage entitlement IsUnlimitedEntitlement bool `json:"isUnlimitedEntitlement"` - // Number of overage requests made this period + // Number of additional usage requests made this period Overage float64 `json:"overage"` - // Whether overage is allowed when quota is exhausted + // Whether additional usage is allowed when quota is exhausted OverageAllowedWithExhaustedQuota bool `json:"overageAllowedWithExhaustedQuota"` // Percentage of entitlement remaining RemainingPercentage float64 `json:"remainingPercentage"` @@ -81,6 +81,7 @@ type AgentInfo struct { ID string `json:"id"` // MCP server configurations attached to this agent, keyed by server name. Server config // shape mirrors the MCP `mcpServers` schema. + // Experimental: McpServers is part of an experimental API and may change or be removed. McpServers map[string]any `json:"mcpServers,omitempty"` // Preferred model id for this agent. When omitted, inherits the outer agent's model. Model *string `json:"model,omitempty"` @@ -1035,6 +1036,14 @@ type HistoryCompactContextWindow struct { ToolDefinitionsTokens *int64 `json:"toolDefinitionsTokens,omitempty"` } +// Optional compaction parameters. +// Experimental: HistoryCompactRequest is part of an experimental API and may change or be +// removed. +type HistoryCompactRequest struct { + // Optional user-provided instructions to focus the compaction summary + CustomInstructions *string `json:"customInstructions,omitempty"` +} + // Compaction outcome with the number of tokens and messages removed, summary text, and the // resulting context window breakdown. // Experimental: HistoryCompactResult is part of an experimental API and may change or be @@ -1100,6 +1109,8 @@ type InstalledPlugin struct { // Source for direct repo installs (when marketplace is empty) // Experimental: InstalledPluginSource is part of an experimental API and may change or be // removed. +// Experimental: InstalledPluginSource is part of an experimental API and may change or be +// removed. type InstalledPluginSource struct { InstalledPluginSourceGithub *InstalledPluginSourceGithub InstalledPluginSourceLocal *InstalledPluginSourceLocal @@ -1351,6 +1362,8 @@ type McpExecuteSamplingRequest struct { // construct/consume it per the MCP CreateMessageResult shape. // Experimental: McpExecuteSamplingResult is part of an experimental API and may change or // be removed. +// Experimental: McpExecuteSamplingResult is part of an experimental API and may change or +// be removed. type McpExecuteSamplingResult struct { } @@ -3383,6 +3396,8 @@ type SendRequest struct { RequiredTool *string `json:"requiredTool,omitempty"` // Optional provenance tag copied to the resulting user.message event. Supported values are // `system`, `command-*`, and `schedule-*`. + // Internal: Source is part of the SDK's internal API surface and is not intended for + // external use. Source any `json:"source,omitempty"` // W3C Trace Context traceparent header for distributed tracing of this agent turn Traceparent *string `json:"traceparent,omitempty"` @@ -3777,6 +3792,8 @@ type SessionInstalledPlugin struct { // Source descriptor for direct repo installs (when marketplace is empty) // Experimental: SessionInstalledPluginSource is part of an experimental API and may change // or be removed. +// Experimental: SessionInstalledPluginSource is part of an experimental API and may change +// or be removed. type SessionInstalledPluginSource struct { SessionInstalledPluginSourceGithub *SessionInstalledPluginSourceGithub SessionInstalledPluginSourceLocal *SessionInstalledPluginSourceLocal @@ -4302,6 +4319,8 @@ type SessionTelemetrySetFeatureOverridesResult struct { type SessionUpdateOptionsParams struct { // Additional content-exclusion policies to merge into the session's policy set. Opaque // shape; see `ContentExclusionApiResponse` in the runtime. + // Experimental: AdditionalContentExclusionPolicies is part of an experimental API and may + // change or be removed. AdditionalContentExclusionPolicies []any `json:"additionalContentExclusionPolicies,omitempty"` // Runtime context discriminator (e.g., `cli`, `actions`). AgentContext *string `json:"agentContext,omitempty"` @@ -4362,12 +4381,14 @@ type SessionUpdateOptionsParams struct { Model *string `json:"model,omitempty"` // Custom model-provider configuration (BYOK). Opaque shape; see `ProviderConfig` in the // runtime. + // Experimental: Provider is part of an experimental API and may change or be removed. Provider any `json:"provider,omitempty"` // Reasoning effort for the selected model (model-defined enum). ReasoningEffort *string `json:"reasoningEffort,omitempty"` // Whether the session is running in an interactive UI. RunningInInteractiveMode *bool `json:"runningInInteractiveMode,omitempty"` // Sandbox configuration shape; opaque to SDK consumers. See `SandboxConfig` in the runtime. + // Experimental: SandboxConfig is part of an experimental API and may change or be removed. SandboxConfig any `json:"sandboxConfig,omitempty"` // Shell init profile (`None` or `NonInteractive`). ShellInitProfile *string `json:"shellInitProfile,omitempty"` @@ -8178,10 +8199,21 @@ func (a *HistoryApi) CancelBackgroundCompaction(ctx context.Context) (*HistoryCa // // RPC method: session.history.compact. // +// Parameters: Optional compaction parameters. +// // Returns: Compaction outcome with the number of tokens and messages removed, summary text, // and the resulting context window breakdown. -func (a *HistoryApi) Compact(ctx context.Context) (*HistoryCompactResult, error) { +func (a *HistoryApi) Compact(ctx context.Context, params ...*HistoryCompactRequest) (*HistoryCompactResult, error) { + var requestParams *HistoryCompactRequest + if len(params) > 0 { + requestParams = params[0] + } req := map[string]any{"sessionId": a.sessionID} + if requestParams != nil { + if requestParams.CustomInstructions != nil { + req["customInstructions"] = *requestParams.CustomInstructions + } + } raw, err := a.client.Request("session.history.compact", req) if err != nil { return nil, err diff --git a/go/rpc/zsession_events.go b/go/rpc/zsession_events.go index 568794119..0ab4e074d 100644 --- a/go/rpc/zsession_events.go +++ b/go/rpc/zsession_events.go @@ -170,8 +170,10 @@ func (*AssistantReasoningData) Type() SessionEventType { return SessionEventType // Assistant response containing text content, optional tool requests, and interaction metadata type AssistantMessageData struct { // Raw Anthropic content array with advisor blocks (server_tool_use, advisor_tool_result) for verbatim round-tripping + // Experimental: AnthropicAdvisorBlocks is part of an experimental API and may change or be removed. AnthropicAdvisorBlocks []any `json:"anthropicAdvisorBlocks,omitempty"` // Anthropic advisor model ID used for this response, for timeline display on replay + // Experimental: AnthropicAdvisorModel is part of an experimental API and may change or be removed. AnthropicAdvisorModel *string `json:"anthropicAdvisorModel,omitempty"` // The assistant's text response content Content string `json:"content"` @@ -258,6 +260,8 @@ type SessionCompactionCompleteData struct { CompactionTokensUsed *CompactionCompleteCompactionTokensUsed `json:"compactionTokensUsed,omitempty"` // Token count from non-system messages (user, assistant, tool) after compaction ConversationTokens *int64 `json:"conversationTokens,omitempty"` + // User-supplied focus instructions provided to a manual `/compact` invocation. Omitted for automatic compaction and for manual compaction with no focus text. + CustomInstructions *string `json:"customInstructions,omitempty"` // Error message if compaction failed Error *string `json:"error,omitempty"` // Number of messages removed during compaction @@ -532,6 +536,7 @@ type AssistantUsageData struct { // Per-request cost and usage data from the CAPI copilot_usage response field CopilotUsage *AssistantUsageCopilotUsage `json:"copilotUsage,omitempty"` // Model multiplier cost for billing purposes + // Experimental: Cost is part of an experimental API and may change or be removed. Cost *float64 `json:"cost,omitempty"` // Duration of the API call in milliseconds Duration *int64 `json:"duration,omitempty"` @@ -551,6 +556,7 @@ type AssistantUsageData struct { // GitHub request tracing ID (x-github-request-id header) for server-side log correlation ProviderCallID *string `json:"providerCallId,omitempty"` // Per-quota resource usage snapshots, keyed by quota identifier + // Internal: QuotaSnapshots is part of the SDK's internal API surface and is not intended for external use. QuotaSnapshots map[string]AssistantUsageQuotaSnapshot `json:"quotaSnapshots,omitempty"` // Reasoning effort level used for model calls, if applicable (e.g. "none", "low", "medium", "high", "xhigh", "max") ReasoningEffort *string `json:"reasoningEffort,omitempty"` @@ -1050,9 +1056,11 @@ type SessionShutdownData struct { // Cumulative time spent in API calls during the session, in milliseconds TotalAPIDurationMs int64 `json:"totalApiDurationMs"` // Session-wide accumulated nano-AI units cost + // Experimental: TotalNanoAiu is part of an experimental API and may change or be removed. TotalNanoAiu *float64 `json:"totalNanoAiu,omitempty"` // Total number of premium API requests used during the session - TotalPremiumRequests float64 `json:"totalPremiumRequests"` + // Internal: TotalPremiumRequests is part of the SDK's internal API surface and is not intended for external use. + TotalPremiumRequests *float64 `json:"totalPremiumRequests,omitempty"` } func (*SessionShutdownData) sessionEventData() {} @@ -1483,20 +1491,28 @@ type AssistantUsageCopilotUsageTokenDetail struct { // Schema for the `AssistantUsageQuotaSnapshot` type. type AssistantUsageQuotaSnapshot struct { // Total requests allowed by the entitlement + // Internal: EntitlementRequests is part of the SDK's internal API surface and is not intended for external use. EntitlementRequests int64 `json:"entitlementRequests"` // Whether the user has an unlimited usage entitlement + // Internal: IsUnlimitedEntitlement is part of the SDK's internal API surface and is not intended for external use. IsUnlimitedEntitlement bool `json:"isUnlimitedEntitlement"` - // Number of requests over the entitlement limit + // Number of additional usage requests made this period + // Internal: Overage is part of the SDK's internal API surface and is not intended for external use. Overage float64 `json:"overage"` - // Whether overage is allowed when quota is exhausted + // Whether additional usage is allowed when quota is exhausted + // Internal: OverageAllowedWithExhaustedQuota is part of the SDK's internal API surface and is not intended for external use. OverageAllowedWithExhaustedQuota bool `json:"overageAllowedWithExhaustedQuota"` // Percentage of quota remaining (0 to 100) + // Internal: RemainingPercentage is part of the SDK's internal API surface and is not intended for external use. RemainingPercentage float64 `json:"remainingPercentage"` // Date when the quota resets + // Internal: ResetDate is part of the SDK's internal API surface and is not intended for external use. ResetDate *time.Time `json:"resetDate,omitempty"` // Whether usage is still permitted after quota exhaustion + // Internal: UsageAllowedWithExhaustedQuota is part of the SDK's internal API surface and is not intended for external use. UsageAllowedWithExhaustedQuota bool `json:"usageAllowedWithExhaustedQuota"` // Number of requests already consumed + // Internal: UsedRequests is part of the SDK's internal API surface and is not intended for external use. UsedRequests int64 `json:"usedRequests"` } @@ -2225,6 +2241,7 @@ type ShutdownModelMetric struct { // Token count details per type TokenDetails map[string]ShutdownModelMetricTokenDetail `json:"tokenDetails,omitempty"` // Accumulated nano-AI units cost for this model + // Experimental: TotalNanoAiu is part of an experimental API and may change or be removed. TotalNanoAiu *float64 `json:"totalNanoAiu,omitempty"` // Token usage breakdown Usage ShutdownModelMetricUsage `json:"usage"` @@ -2233,9 +2250,11 @@ type ShutdownModelMetric struct { // Request count and cost metrics type ShutdownModelMetricRequests struct { // Cumulative cost multiplier for requests to this model - Cost float64 `json:"cost"` + // Experimental: Cost is part of an experimental API and may change or be removed. + Cost *float64 `json:"cost,omitempty"` // Total number of API requests made to this model - Count int64 `json:"count"` + // Experimental: Count is part of an experimental API and may change or be removed. + Count *int64 `json:"count,omitempty"` } // Schema for the `ShutdownModelMetricTokenDetail` type. diff --git a/nodejs/src/generated/rpc.ts b/nodejs/src/generated/rpc.ts index 02d2222d3..dd965d56f 100644 --- a/nodejs/src/generated/rpc.ts +++ b/nodejs/src/generated/rpc.ts @@ -1118,11 +1118,11 @@ export interface AccountQuotaSnapshot { */ remainingPercentage: number; /** - * Number of overage requests made this period + * Number of additional usage requests made this period */ overage: number; /** - * Whether overage is allowed when quota is exhausted + * Whether additional usage is allowed when quota is exhausted */ overageAllowedWithExhaustedQuota: boolean; /** @@ -2492,6 +2492,19 @@ export interface HistoryCompactContextWindow { */ toolDefinitionsTokens?: number; } +/** + * Optional compaction parameters. + * + * This interface was referenced by `_RpcSchemaRoot`'s JSON-Schema + * via the `definition` "HistoryCompactRequest". + */ +/** @experimental */ +export interface HistoryCompactRequest { + /** + * Optional user-provided instructions to focus the compaction summary + */ + customInstructions?: string; +} /** * Compaction outcome with the number of tokens and messages removed, summary text, and the resulting context window breakdown. * @@ -9997,10 +10010,12 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin /** * Compacts the session history to reduce context usage. * + * @param params Optional compaction parameters. + * * @returns Compaction outcome with the number of tokens and messages removed, summary text, and the resulting context window breakdown. */ - compact: async (): Promise => - connection.sendRequest("session.history.compact", { sessionId }), + compact: async (params?: HistoryCompactRequest): Promise => + connection.sendRequest("session.history.compact", { sessionId, ...params }), /** * Truncates persisted session history to a specific event. * diff --git a/nodejs/src/generated/session-events.ts b/nodejs/src/generated/session-events.ts index cf376c3db..e466d1337 100644 --- a/nodejs/src/generated/session-events.ts +++ b/nodejs/src/generated/session-events.ts @@ -1469,7 +1469,7 @@ export interface ShutdownData { /** * Total number of premium API requests used during the session */ - totalPremiumRequests: number; + totalPremiumRequests?: number; } /** * Aggregate code change metrics for the session @@ -1512,11 +1512,11 @@ export interface ShutdownModelMetricRequests { /** * Cumulative cost multiplier for requests to this model */ - cost: number; + cost?: number; /** * Total number of API requests made to this model */ - count: number; + count?: number; } /** * Schema for the `ShutdownModelMetricTokenDetail` type. @@ -1748,6 +1748,10 @@ export interface CompactionCompleteData { * Token count from non-system messages (user, assistant, tool) after compaction */ conversationTokens?: number; + /** + * User-supplied focus instructions provided to a manual `/compact` invocation. Omitted for automatic compaction and for manual compaction with no focus text. + */ + customInstructions?: string; /** * Error message if compaction failed */ @@ -2776,11 +2780,11 @@ export interface AssistantUsageQuotaSnapshot { */ isUnlimitedEntitlement: boolean; /** - * Number of requests over the entitlement limit + * Number of additional usage requests made this period */ overage: number; /** - * Whether overage is allowed when quota is exhausted + * Whether additional usage is allowed when quota is exhausted */ overageAllowedWithExhaustedQuota: boolean; /** diff --git a/python/copilot/generated/rpc.py b/python/copilot/generated/rpc.py index bb9092b47..327a41344 100644 --- a/python/copilot/generated/rpc.py +++ b/python/copilot/generated/rpc.py @@ -149,10 +149,10 @@ class AccountQuotaSnapshot: """Whether the user has an unlimited usage entitlement""" overage: float - """Number of overage requests made this period""" + """Number of additional usage requests made this period""" overage_allowed_with_exhausted_quota: bool - """Whether overage is allowed when quota is exhausted""" + """Whether additional usage is allowed when quota is exhausted""" remaining_percentage: float """Percentage of entitlement remaining""" @@ -1211,6 +1211,26 @@ def to_dict(self) -> dict: result["toolDefinitionsTokens"] = from_union([from_int, from_none], self.tool_definitions_tokens) return result +# Experimental: this type is part of an experimental API and may change or be removed. +@dataclass +class HistoryCompactRequest: + """Optional compaction parameters.""" + + custom_instructions: str | None = None + """Optional user-provided instructions to focus the compaction summary""" + + @staticmethod + def from_dict(obj: Any) -> 'HistoryCompactRequest': + assert isinstance(obj, dict) + custom_instructions = from_union([from_str, from_none], obj.get("customInstructions")) + return HistoryCompactRequest(custom_instructions) + + def to_dict(self) -> dict: + result: dict = {} + if self.custom_instructions is not None: + result["customInstructions"] = from_union([from_str, from_none], self.custom_instructions) + return result + # Experimental: this type is part of an experimental API and may change or be removed. @dataclass class HistorySummarizeForHandoffResult: @@ -14985,6 +15005,7 @@ class RPC: history_abort_manual_compaction_result: HistoryAbortManualCompactionResult history_cancel_background_compaction_result: HistoryCancelBackgroundCompactionResult history_compact_context_window: HistoryCompactContextWindow + history_compact_request: HistoryCompactRequest history_compact_result: HistoryCompactResult history_summarize_for_handoff_result: HistorySummarizeForHandoffResult history_truncate_request: HistoryTruncateRequest @@ -15501,6 +15522,7 @@ def from_dict(obj: Any) -> 'RPC': history_abort_manual_compaction_result = HistoryAbortManualCompactionResult.from_dict(obj.get("HistoryAbortManualCompactionResult")) history_cancel_background_compaction_result = HistoryCancelBackgroundCompactionResult.from_dict(obj.get("HistoryCancelBackgroundCompactionResult")) history_compact_context_window = HistoryCompactContextWindow.from_dict(obj.get("HistoryCompactContextWindow")) + history_compact_request = HistoryCompactRequest.from_dict(obj.get("HistoryCompactRequest")) history_compact_result = HistoryCompactResult.from_dict(obj.get("HistoryCompactResult")) history_summarize_for_handoff_result = HistorySummarizeForHandoffResult.from_dict(obj.get("HistorySummarizeForHandoffResult")) history_truncate_request = HistoryTruncateRequest.from_dict(obj.get("HistoryTruncateRequest")) @@ -15930,7 +15952,7 @@ def from_dict(obj: Any) -> 'RPC': session_context_info = from_union([SessionContextInfo.from_dict, from_none], obj.get("SessionContextInfo")) task_progress = from_union([TaskProgress.from_dict, from_none], obj.get("TaskProgress")) workspace_summary = from_union([WorkspaceSummary.from_dict, from_none], obj.get("WorkspaceSummary")) - return RPC(abort_request, abort_result, account_get_quota_request, account_get_quota_result, account_quota_snapshot, agent_get_current_result, agent_info, agent_info_source, agent_list, agent_reload_result, agent_select_request, agent_select_result, api_key_auth_info, auth_info, auth_info_type, command_list, commands_handle_pending_command_request, commands_handle_pending_command_result, commands_invoke_request, commands_list_request, commands_respond_to_queued_command_request, commands_respond_to_queued_command_result, connected_remote_session_metadata, connected_remote_session_metadata_kind, connected_remote_session_metadata_repository, connect_remote_session_params, connect_request, connect_result, content_filter_mode, copilot_api_token_auth_info, copilot_user_response, copilot_user_response_endpoints, copilot_user_response_quota_snapshots, copilot_user_response_quota_snapshots_chat, copilot_user_response_quota_snapshots_completions, copilot_user_response_quota_snapshots_premium_interactions, current_model, discovered_mcp_server, discovered_mcp_server_type, enqueue_command_params, enqueue_command_result, env_auth_info, event_log_read_request, event_log_release_interest_result, event_log_tail_result, event_log_types, events_agent_scope, events_cursor_status, events_read_result, execute_command_params, execute_command_result, extension, extension_list, extensions_disable_request, extensions_enable_request, extension_source, extension_status, external_tool_result, external_tool_text_result_for_llm, external_tool_text_result_for_llm_binary_results_for_llm, external_tool_text_result_for_llm_binary_results_for_llm_type, external_tool_text_result_for_llm_content, external_tool_text_result_for_llm_content_audio, external_tool_text_result_for_llm_content_image, external_tool_text_result_for_llm_content_resource, external_tool_text_result_for_llm_content_resource_details, external_tool_text_result_for_llm_content_resource_link, external_tool_text_result_for_llm_content_resource_link_icon, external_tool_text_result_for_llm_content_resource_link_icon_theme, external_tool_text_result_for_llm_content_terminal, external_tool_text_result_for_llm_content_text, filter_mapping, fleet_start_request, fleet_start_result, folder_trust_add_params, folder_trust_check_params, folder_trust_check_result, gh_cli_auth_info, handle_pending_tool_call_request, handle_pending_tool_call_result, history_abort_manual_compaction_result, history_cancel_background_compaction_result, history_compact_context_window, history_compact_result, history_summarize_for_handoff_result, history_truncate_request, history_truncate_result, hmac_auth_info, installed_plugin, installed_plugin_source, installed_plugin_source_github, installed_plugin_source_local, installed_plugin_source_url, instructions_get_sources_result, instructions_sources, instructions_sources_location, instructions_sources_type, log_request, log_result, lsp_initialize_request, mcp_cancel_sampling_execution_params, mcp_cancel_sampling_execution_result, mcp_config_add_request, mcp_config_disable_request, mcp_config_enable_request, mcp_config_list, mcp_config_remove_request, mcp_config_update_request, mcp_disable_request, mcp_discover_request, mcp_discover_result, mcp_enable_request, mcp_execute_sampling_params, mcp_execute_sampling_request, mcp_execute_sampling_result, mcp_oauth_login_request, mcp_oauth_login_result, mcp_remove_git_hub_result, mcp_sampling_execution_action, mcp_sampling_execution_result, mcp_server, mcp_server_config, mcp_server_config_http, mcp_server_config_http_auth, mcp_server_config_http_oauth_grant_type, mcp_server_config_http_type, mcp_server_config_stdio, mcp_server_list, mcp_set_env_value_mode_details, mcp_set_env_value_mode_params, mcp_set_env_value_mode_result, metadata_context_info_request, metadata_context_info_result, metadata_is_processing_result, metadata_recompute_context_tokens_request, metadata_recompute_context_tokens_result, metadata_record_context_change_request, metadata_record_context_change_result, metadata_set_working_directory_request, metadata_set_working_directory_result, metadata_snapshot_current_mode, metadata_snapshot_remote_metadata, metadata_snapshot_remote_metadata_repository, metadata_snapshot_remote_metadata_task_type, model, model_billing, model_billing_token_prices, model_capabilities, model_capabilities_limits, model_capabilities_limits_vision, model_capabilities_override, model_capabilities_override_limits, model_capabilities_override_limits_vision, model_capabilities_override_supports, model_capabilities_supports, model_list, model_picker_category, model_picker_price_category, model_policy, model_policy_state, model_set_reasoning_effort_request, model_set_reasoning_effort_result, models_list_request, model_switch_to_request, model_switch_to_result, mode_set_request, name_get_result, name_set_auto_request, name_set_auto_result, name_set_request, options_update_env_value_mode, pending_permission_request, pending_permission_request_list, permission_decision, permission_decision_approved, permission_decision_approved_for_location, permission_decision_approved_for_session, permission_decision_approve_for_location, permission_decision_approve_for_location_approval, permission_decision_approve_for_location_approval_commands, permission_decision_approve_for_location_approval_custom_tool, permission_decision_approve_for_location_approval_extension_management, permission_decision_approve_for_location_approval_extension_permission_access, permission_decision_approve_for_location_approval_mcp, permission_decision_approve_for_location_approval_mcp_sampling, permission_decision_approve_for_location_approval_memory, permission_decision_approve_for_location_approval_read, permission_decision_approve_for_location_approval_write, permission_decision_approve_for_session, permission_decision_approve_for_session_approval, permission_decision_approve_for_session_approval_commands, permission_decision_approve_for_session_approval_custom_tool, permission_decision_approve_for_session_approval_extension_management, permission_decision_approve_for_session_approval_extension_permission_access, permission_decision_approve_for_session_approval_mcp, permission_decision_approve_for_session_approval_mcp_sampling, permission_decision_approve_for_session_approval_memory, permission_decision_approve_for_session_approval_read, permission_decision_approve_for_session_approval_write, permission_decision_approve_once, permission_decision_approve_permanently, permission_decision_cancelled, permission_decision_denied_by_content_exclusion_policy, permission_decision_denied_by_permission_request_hook, permission_decision_denied_by_rules, permission_decision_denied_interactively_by_user, permission_decision_denied_no_approval_rule_and_could_not_request_from_user, permission_decision_reject, permission_decision_request, permission_decision_user_not_available, permission_location_add_tool_approval_params, permission_location_apply_params, permission_location_apply_result, permission_location_resolve_params, permission_location_resolve_result, permission_location_type, permission_paths_add_params, permission_paths_allowed_check_params, permission_paths_allowed_check_result, permission_paths_config, permission_paths_list, permission_paths_update_primary_params, permission_paths_workspace_check_params, permission_paths_workspace_check_result, permission_prompt_shown_notification, permission_request_result, permission_rules_set, permissions_configure_additional_content_exclusion_policy, permissions_configure_additional_content_exclusion_policy_rule, permissions_configure_additional_content_exclusion_policy_rule_source, permissions_configure_additional_content_exclusion_policy_scope, permissions_configure_params, permissions_configure_result, permissions_folder_trust_add_trusted_result, permissions_locations_add_tool_approval_details, permissions_locations_add_tool_approval_details_commands, permissions_locations_add_tool_approval_details_custom_tool, permissions_locations_add_tool_approval_details_extension_management, permissions_locations_add_tool_approval_details_extension_permission_access, permissions_locations_add_tool_approval_details_mcp, permissions_locations_add_tool_approval_details_mcp_sampling, permissions_locations_add_tool_approval_details_memory, permissions_locations_add_tool_approval_details_read, permissions_locations_add_tool_approval_details_write, permissions_locations_add_tool_approval_result, permissions_modify_rules_params, permissions_modify_rules_result, permissions_modify_rules_scope, permissions_notify_prompt_shown_result, permissions_paths_add_result, permissions_paths_list_request, permissions_paths_update_primary_result, permissions_pending_requests_request, permissions_reset_session_approvals_request, permissions_reset_session_approvals_result, permissions_set_approve_all_request, permissions_set_approve_all_result, permissions_set_approve_all_source, permissions_set_required_request, permissions_set_required_result, permissions_urls_set_unrestricted_mode_result, permission_urls_config, permission_urls_set_unrestricted_mode_params, ping_request, ping_result, plan_read_result, plan_update_request, plugin, plugin_list, queued_command_handled, queued_command_not_handled, queued_command_result, queue_pending_items, queue_pending_items_kind, queue_pending_items_result, queue_remove_most_recent_result, register_event_interest_params, register_event_interest_result, release_event_interest_params, remote_enable_request, remote_enable_result, remote_notify_steerable_changed_request, remote_notify_steerable_changed_result, remote_session_connection_result, remote_session_mode, schedule_entry, schedule_list, schedule_stop_request, schedule_stop_result, send_agent_mode, send_attachment, send_attachment_blob, send_attachment_directory, send_attachment_file, send_attachment_file_line_range, send_attachment_github_reference, send_attachment_github_reference_type, send_attachment_selection, send_attachment_selection_details, send_attachment_selection_details_end, send_attachment_selection_details_start, send_mode, send_request, send_result, server_skill, server_skill_list, session_auth_status, session_bulk_delete_result, session_context, session_context_host_type, session_enrich_metadata_result, session_fs_append_file_request, session_fs_error, session_fs_error_code, session_fs_exists_request, session_fs_exists_result, session_fs_mkdir_request, session_fs_readdir_request, session_fs_readdir_result, session_fs_readdir_with_types_entry, session_fs_readdir_with_types_entry_type, session_fs_readdir_with_types_request, session_fs_readdir_with_types_result, session_fs_read_file_request, session_fs_read_file_result, session_fs_rename_request, session_fs_rm_request, session_fs_set_provider_capabilities, session_fs_set_provider_conventions, session_fs_set_provider_request, session_fs_set_provider_result, session_fs_sqlite_exists_request, session_fs_sqlite_exists_result, session_fs_sqlite_query_request, session_fs_sqlite_query_result, session_fs_sqlite_query_type, session_fs_stat_request, session_fs_stat_result, session_fs_write_file_request, session_installed_plugin, session_installed_plugin_source, session_installed_plugin_source_github, session_installed_plugin_source_local, session_installed_plugin_source_url, session_list, session_list_filter, session_load_deferred_repo_hooks_result, session_log_level, session_metadata, session_metadata_snapshot, session_mode, session_prune_result, sessions_bulk_delete_request, sessions_check_in_use_request, sessions_check_in_use_result, sessions_close_request, sessions_close_result, sessions_enrich_metadata_request, session_set_credentials_params, session_set_credentials_result, sessions_find_by_prefix_request, sessions_find_by_prefix_result, sessions_find_by_task_id_request, sessions_find_by_task_id_result, sessions_fork_request, sessions_fork_result, sessions_get_event_file_path_request, sessions_get_event_file_path_result, sessions_get_last_for_context_request, sessions_get_last_for_context_result, sessions_get_persisted_remote_steerable_request, sessions_get_persisted_remote_steerable_result, session_sizes, sessions_list_request, sessions_load_deferred_repo_hooks_request, sessions_prune_old_request, sessions_release_lock_request, sessions_release_lock_result, sessions_reload_plugin_hooks_request, sessions_reload_plugin_hooks_result, sessions_save_request, sessions_save_result, sessions_set_additional_plugins_request, sessions_set_additional_plugins_result, session_update_options_params, session_update_options_result, session_working_directory_context, session_working_directory_context_host_type, shell_exec_request, shell_exec_result, shell_kill_request, shell_kill_result, shell_kill_signal, shutdown_request, skill, skill_list, skills_config_set_disabled_skills_request, skills_disable_request, skills_discover_request, skills_enable_request, skills_get_invoked_result, skills_invoked_skill, skills_load_diagnostics, slash_command_agent_prompt_result, slash_command_completed_result, slash_command_info, slash_command_input, slash_command_input_completion, slash_command_invocation_result, slash_command_kind, slash_command_select_subcommand_option, slash_command_select_subcommand_result, slash_command_text_result, task_agent_info, task_agent_progress, task_execution_mode, task_info, task_list, task_progress_line, tasks_cancel_request, tasks_cancel_result, tasks_get_current_promotable_result, tasks_get_progress_request, tasks_get_progress_result, task_shell_info, task_shell_info_attachment_mode, task_shell_progress, tasks_promote_current_to_background_result, tasks_promote_to_background_request, tasks_promote_to_background_result, tasks_refresh_result, tasks_remove_request, tasks_remove_result, tasks_send_message_request, tasks_send_message_result, tasks_start_agent_request, tasks_start_agent_result, task_status, tasks_wait_for_pending_result, telemetry_set_feature_overrides_request, token_auth_info, tool, tool_list, tools_initialize_and_validate_result, tools_list_request, ui_auto_mode_switch_response, ui_elicitation_array_any_of_field, ui_elicitation_array_any_of_field_items, ui_elicitation_array_any_of_field_items_any_of, ui_elicitation_array_enum_field, ui_elicitation_array_enum_field_items, ui_elicitation_field_value, ui_elicitation_request, ui_elicitation_response, ui_elicitation_response_action, ui_elicitation_response_content, ui_elicitation_result, ui_elicitation_schema, ui_elicitation_schema_property, ui_elicitation_schema_property_boolean, ui_elicitation_schema_property_number, ui_elicitation_schema_property_number_type, ui_elicitation_schema_property_string, ui_elicitation_schema_property_string_format, ui_elicitation_string_enum_field, ui_elicitation_string_one_of_field, ui_elicitation_string_one_of_field_one_of, ui_exit_plan_mode_action, ui_exit_plan_mode_response, ui_handle_pending_auto_mode_switch_request, ui_handle_pending_elicitation_request, ui_handle_pending_exit_plan_mode_request, ui_handle_pending_result, ui_handle_pending_sampling_request, ui_handle_pending_sampling_response, ui_handle_pending_user_input_request, ui_register_direct_auto_mode_switch_handler_result, ui_unregister_direct_auto_mode_switch_handler_request, ui_unregister_direct_auto_mode_switch_handler_result, ui_user_input_response, usage_get_metrics_result, usage_metrics_code_changes, usage_metrics_model_metric, usage_metrics_model_metric_requests, usage_metrics_model_metric_token_detail, usage_metrics_model_metric_usage, usage_metrics_token_detail, user_auth_info, user_tool_session_approval_commands, user_tool_session_approval_custom_tool, user_tool_session_approval_extension_management, user_tool_session_approval_extension_permission_access, user_tool_session_approval_mcp, user_tool_session_approval_memory, user_tool_session_approval_read, user_tool_session_approval_write, workspaces_checkpoints, workspaces_create_file_request, workspaces_get_workspace_result, workspaces_list_checkpoints_result, workspaces_list_files_result, workspaces_read_checkpoint_request, workspaces_read_checkpoint_result, workspaces_read_file_request, workspaces_read_file_result, workspaces_save_large_paste_request, workspaces_save_large_paste_result, workspace_summary_host_type, workspaces_workspace_details_host_type, session_context_info, task_progress, workspace_summary) + return RPC(abort_request, abort_result, account_get_quota_request, account_get_quota_result, account_quota_snapshot, agent_get_current_result, agent_info, agent_info_source, agent_list, agent_reload_result, agent_select_request, agent_select_result, api_key_auth_info, auth_info, auth_info_type, command_list, commands_handle_pending_command_request, commands_handle_pending_command_result, commands_invoke_request, commands_list_request, commands_respond_to_queued_command_request, commands_respond_to_queued_command_result, connected_remote_session_metadata, connected_remote_session_metadata_kind, connected_remote_session_metadata_repository, connect_remote_session_params, connect_request, connect_result, content_filter_mode, copilot_api_token_auth_info, copilot_user_response, copilot_user_response_endpoints, copilot_user_response_quota_snapshots, copilot_user_response_quota_snapshots_chat, copilot_user_response_quota_snapshots_completions, copilot_user_response_quota_snapshots_premium_interactions, current_model, discovered_mcp_server, discovered_mcp_server_type, enqueue_command_params, enqueue_command_result, env_auth_info, event_log_read_request, event_log_release_interest_result, event_log_tail_result, event_log_types, events_agent_scope, events_cursor_status, events_read_result, execute_command_params, execute_command_result, extension, extension_list, extensions_disable_request, extensions_enable_request, extension_source, extension_status, external_tool_result, external_tool_text_result_for_llm, external_tool_text_result_for_llm_binary_results_for_llm, external_tool_text_result_for_llm_binary_results_for_llm_type, external_tool_text_result_for_llm_content, external_tool_text_result_for_llm_content_audio, external_tool_text_result_for_llm_content_image, external_tool_text_result_for_llm_content_resource, external_tool_text_result_for_llm_content_resource_details, external_tool_text_result_for_llm_content_resource_link, external_tool_text_result_for_llm_content_resource_link_icon, external_tool_text_result_for_llm_content_resource_link_icon_theme, external_tool_text_result_for_llm_content_terminal, external_tool_text_result_for_llm_content_text, filter_mapping, fleet_start_request, fleet_start_result, folder_trust_add_params, folder_trust_check_params, folder_trust_check_result, gh_cli_auth_info, handle_pending_tool_call_request, handle_pending_tool_call_result, history_abort_manual_compaction_result, history_cancel_background_compaction_result, history_compact_context_window, history_compact_request, history_compact_result, history_summarize_for_handoff_result, history_truncate_request, history_truncate_result, hmac_auth_info, installed_plugin, installed_plugin_source, installed_plugin_source_github, installed_plugin_source_local, installed_plugin_source_url, instructions_get_sources_result, instructions_sources, instructions_sources_location, instructions_sources_type, log_request, log_result, lsp_initialize_request, mcp_cancel_sampling_execution_params, mcp_cancel_sampling_execution_result, mcp_config_add_request, mcp_config_disable_request, mcp_config_enable_request, mcp_config_list, mcp_config_remove_request, mcp_config_update_request, mcp_disable_request, mcp_discover_request, mcp_discover_result, mcp_enable_request, mcp_execute_sampling_params, mcp_execute_sampling_request, mcp_execute_sampling_result, mcp_oauth_login_request, mcp_oauth_login_result, mcp_remove_git_hub_result, mcp_sampling_execution_action, mcp_sampling_execution_result, mcp_server, mcp_server_config, mcp_server_config_http, mcp_server_config_http_auth, mcp_server_config_http_oauth_grant_type, mcp_server_config_http_type, mcp_server_config_stdio, mcp_server_list, mcp_set_env_value_mode_details, mcp_set_env_value_mode_params, mcp_set_env_value_mode_result, metadata_context_info_request, metadata_context_info_result, metadata_is_processing_result, metadata_recompute_context_tokens_request, metadata_recompute_context_tokens_result, metadata_record_context_change_request, metadata_record_context_change_result, metadata_set_working_directory_request, metadata_set_working_directory_result, metadata_snapshot_current_mode, metadata_snapshot_remote_metadata, metadata_snapshot_remote_metadata_repository, metadata_snapshot_remote_metadata_task_type, model, model_billing, model_billing_token_prices, model_capabilities, model_capabilities_limits, model_capabilities_limits_vision, model_capabilities_override, model_capabilities_override_limits, model_capabilities_override_limits_vision, model_capabilities_override_supports, model_capabilities_supports, model_list, model_picker_category, model_picker_price_category, model_policy, model_policy_state, model_set_reasoning_effort_request, model_set_reasoning_effort_result, models_list_request, model_switch_to_request, model_switch_to_result, mode_set_request, name_get_result, name_set_auto_request, name_set_auto_result, name_set_request, options_update_env_value_mode, pending_permission_request, pending_permission_request_list, permission_decision, permission_decision_approved, permission_decision_approved_for_location, permission_decision_approved_for_session, permission_decision_approve_for_location, permission_decision_approve_for_location_approval, permission_decision_approve_for_location_approval_commands, permission_decision_approve_for_location_approval_custom_tool, permission_decision_approve_for_location_approval_extension_management, permission_decision_approve_for_location_approval_extension_permission_access, permission_decision_approve_for_location_approval_mcp, permission_decision_approve_for_location_approval_mcp_sampling, permission_decision_approve_for_location_approval_memory, permission_decision_approve_for_location_approval_read, permission_decision_approve_for_location_approval_write, permission_decision_approve_for_session, permission_decision_approve_for_session_approval, permission_decision_approve_for_session_approval_commands, permission_decision_approve_for_session_approval_custom_tool, permission_decision_approve_for_session_approval_extension_management, permission_decision_approve_for_session_approval_extension_permission_access, permission_decision_approve_for_session_approval_mcp, permission_decision_approve_for_session_approval_mcp_sampling, permission_decision_approve_for_session_approval_memory, permission_decision_approve_for_session_approval_read, permission_decision_approve_for_session_approval_write, permission_decision_approve_once, permission_decision_approve_permanently, permission_decision_cancelled, permission_decision_denied_by_content_exclusion_policy, permission_decision_denied_by_permission_request_hook, permission_decision_denied_by_rules, permission_decision_denied_interactively_by_user, permission_decision_denied_no_approval_rule_and_could_not_request_from_user, permission_decision_reject, permission_decision_request, permission_decision_user_not_available, permission_location_add_tool_approval_params, permission_location_apply_params, permission_location_apply_result, permission_location_resolve_params, permission_location_resolve_result, permission_location_type, permission_paths_add_params, permission_paths_allowed_check_params, permission_paths_allowed_check_result, permission_paths_config, permission_paths_list, permission_paths_update_primary_params, permission_paths_workspace_check_params, permission_paths_workspace_check_result, permission_prompt_shown_notification, permission_request_result, permission_rules_set, permissions_configure_additional_content_exclusion_policy, permissions_configure_additional_content_exclusion_policy_rule, permissions_configure_additional_content_exclusion_policy_rule_source, permissions_configure_additional_content_exclusion_policy_scope, permissions_configure_params, permissions_configure_result, permissions_folder_trust_add_trusted_result, permissions_locations_add_tool_approval_details, permissions_locations_add_tool_approval_details_commands, permissions_locations_add_tool_approval_details_custom_tool, permissions_locations_add_tool_approval_details_extension_management, permissions_locations_add_tool_approval_details_extension_permission_access, permissions_locations_add_tool_approval_details_mcp, permissions_locations_add_tool_approval_details_mcp_sampling, permissions_locations_add_tool_approval_details_memory, permissions_locations_add_tool_approval_details_read, permissions_locations_add_tool_approval_details_write, permissions_locations_add_tool_approval_result, permissions_modify_rules_params, permissions_modify_rules_result, permissions_modify_rules_scope, permissions_notify_prompt_shown_result, permissions_paths_add_result, permissions_paths_list_request, permissions_paths_update_primary_result, permissions_pending_requests_request, permissions_reset_session_approvals_request, permissions_reset_session_approvals_result, permissions_set_approve_all_request, permissions_set_approve_all_result, permissions_set_approve_all_source, permissions_set_required_request, permissions_set_required_result, permissions_urls_set_unrestricted_mode_result, permission_urls_config, permission_urls_set_unrestricted_mode_params, ping_request, ping_result, plan_read_result, plan_update_request, plugin, plugin_list, queued_command_handled, queued_command_not_handled, queued_command_result, queue_pending_items, queue_pending_items_kind, queue_pending_items_result, queue_remove_most_recent_result, register_event_interest_params, register_event_interest_result, release_event_interest_params, remote_enable_request, remote_enable_result, remote_notify_steerable_changed_request, remote_notify_steerable_changed_result, remote_session_connection_result, remote_session_mode, schedule_entry, schedule_list, schedule_stop_request, schedule_stop_result, send_agent_mode, send_attachment, send_attachment_blob, send_attachment_directory, send_attachment_file, send_attachment_file_line_range, send_attachment_github_reference, send_attachment_github_reference_type, send_attachment_selection, send_attachment_selection_details, send_attachment_selection_details_end, send_attachment_selection_details_start, send_mode, send_request, send_result, server_skill, server_skill_list, session_auth_status, session_bulk_delete_result, session_context, session_context_host_type, session_enrich_metadata_result, session_fs_append_file_request, session_fs_error, session_fs_error_code, session_fs_exists_request, session_fs_exists_result, session_fs_mkdir_request, session_fs_readdir_request, session_fs_readdir_result, session_fs_readdir_with_types_entry, session_fs_readdir_with_types_entry_type, session_fs_readdir_with_types_request, session_fs_readdir_with_types_result, session_fs_read_file_request, session_fs_read_file_result, session_fs_rename_request, session_fs_rm_request, session_fs_set_provider_capabilities, session_fs_set_provider_conventions, session_fs_set_provider_request, session_fs_set_provider_result, session_fs_sqlite_exists_request, session_fs_sqlite_exists_result, session_fs_sqlite_query_request, session_fs_sqlite_query_result, session_fs_sqlite_query_type, session_fs_stat_request, session_fs_stat_result, session_fs_write_file_request, session_installed_plugin, session_installed_plugin_source, session_installed_plugin_source_github, session_installed_plugin_source_local, session_installed_plugin_source_url, session_list, session_list_filter, session_load_deferred_repo_hooks_result, session_log_level, session_metadata, session_metadata_snapshot, session_mode, session_prune_result, sessions_bulk_delete_request, sessions_check_in_use_request, sessions_check_in_use_result, sessions_close_request, sessions_close_result, sessions_enrich_metadata_request, session_set_credentials_params, session_set_credentials_result, sessions_find_by_prefix_request, sessions_find_by_prefix_result, sessions_find_by_task_id_request, sessions_find_by_task_id_result, sessions_fork_request, sessions_fork_result, sessions_get_event_file_path_request, sessions_get_event_file_path_result, sessions_get_last_for_context_request, sessions_get_last_for_context_result, sessions_get_persisted_remote_steerable_request, sessions_get_persisted_remote_steerable_result, session_sizes, sessions_list_request, sessions_load_deferred_repo_hooks_request, sessions_prune_old_request, sessions_release_lock_request, sessions_release_lock_result, sessions_reload_plugin_hooks_request, sessions_reload_plugin_hooks_result, sessions_save_request, sessions_save_result, sessions_set_additional_plugins_request, sessions_set_additional_plugins_result, session_update_options_params, session_update_options_result, session_working_directory_context, session_working_directory_context_host_type, shell_exec_request, shell_exec_result, shell_kill_request, shell_kill_result, shell_kill_signal, shutdown_request, skill, skill_list, skills_config_set_disabled_skills_request, skills_disable_request, skills_discover_request, skills_enable_request, skills_get_invoked_result, skills_invoked_skill, skills_load_diagnostics, slash_command_agent_prompt_result, slash_command_completed_result, slash_command_info, slash_command_input, slash_command_input_completion, slash_command_invocation_result, slash_command_kind, slash_command_select_subcommand_option, slash_command_select_subcommand_result, slash_command_text_result, task_agent_info, task_agent_progress, task_execution_mode, task_info, task_list, task_progress_line, tasks_cancel_request, tasks_cancel_result, tasks_get_current_promotable_result, tasks_get_progress_request, tasks_get_progress_result, task_shell_info, task_shell_info_attachment_mode, task_shell_progress, tasks_promote_current_to_background_result, tasks_promote_to_background_request, tasks_promote_to_background_result, tasks_refresh_result, tasks_remove_request, tasks_remove_result, tasks_send_message_request, tasks_send_message_result, tasks_start_agent_request, tasks_start_agent_result, task_status, tasks_wait_for_pending_result, telemetry_set_feature_overrides_request, token_auth_info, tool, tool_list, tools_initialize_and_validate_result, tools_list_request, ui_auto_mode_switch_response, ui_elicitation_array_any_of_field, ui_elicitation_array_any_of_field_items, ui_elicitation_array_any_of_field_items_any_of, ui_elicitation_array_enum_field, ui_elicitation_array_enum_field_items, ui_elicitation_field_value, ui_elicitation_request, ui_elicitation_response, ui_elicitation_response_action, ui_elicitation_response_content, ui_elicitation_result, ui_elicitation_schema, ui_elicitation_schema_property, ui_elicitation_schema_property_boolean, ui_elicitation_schema_property_number, ui_elicitation_schema_property_number_type, ui_elicitation_schema_property_string, ui_elicitation_schema_property_string_format, ui_elicitation_string_enum_field, ui_elicitation_string_one_of_field, ui_elicitation_string_one_of_field_one_of, ui_exit_plan_mode_action, ui_exit_plan_mode_response, ui_handle_pending_auto_mode_switch_request, ui_handle_pending_elicitation_request, ui_handle_pending_exit_plan_mode_request, ui_handle_pending_result, ui_handle_pending_sampling_request, ui_handle_pending_sampling_response, ui_handle_pending_user_input_request, ui_register_direct_auto_mode_switch_handler_result, ui_unregister_direct_auto_mode_switch_handler_request, ui_unregister_direct_auto_mode_switch_handler_result, ui_user_input_response, usage_get_metrics_result, usage_metrics_code_changes, usage_metrics_model_metric, usage_metrics_model_metric_requests, usage_metrics_model_metric_token_detail, usage_metrics_model_metric_usage, usage_metrics_token_detail, user_auth_info, user_tool_session_approval_commands, user_tool_session_approval_custom_tool, user_tool_session_approval_extension_management, user_tool_session_approval_extension_permission_access, user_tool_session_approval_mcp, user_tool_session_approval_memory, user_tool_session_approval_read, user_tool_session_approval_write, workspaces_checkpoints, workspaces_create_file_request, workspaces_get_workspace_result, workspaces_list_checkpoints_result, workspaces_list_files_result, workspaces_read_checkpoint_request, workspaces_read_checkpoint_result, workspaces_read_file_request, workspaces_read_file_result, workspaces_save_large_paste_request, workspaces_save_large_paste_result, workspace_summary_host_type, workspaces_workspace_details_host_type, session_context_info, task_progress, workspace_summary) def to_dict(self) -> dict: result: dict = {} @@ -16017,6 +16039,7 @@ def to_dict(self) -> dict: result["HistoryAbortManualCompactionResult"] = to_class(HistoryAbortManualCompactionResult, self.history_abort_manual_compaction_result) result["HistoryCancelBackgroundCompactionResult"] = to_class(HistoryCancelBackgroundCompactionResult, self.history_cancel_background_compaction_result) result["HistoryCompactContextWindow"] = to_class(HistoryCompactContextWindow, self.history_compact_context_window) + result["HistoryCompactRequest"] = to_class(HistoryCompactRequest, self.history_compact_request) result["HistoryCompactResult"] = to_class(HistoryCompactResult, self.history_compact_result) result["HistorySummarizeForHandoffResult"] = to_class(HistorySummarizeForHandoffResult, self.history_summarize_for_handoff_result) result["HistoryTruncateRequest"] = to_class(HistoryTruncateRequest, self.history_truncate_request) @@ -17489,9 +17512,11 @@ def __init__(self, client: "JsonRpcClient", session_id: str): self._client = client self._session_id = session_id - async def compact(self, *, timeout: float | None = None) -> HistoryCompactResult: - "Compacts the session history to reduce context usage.\n\nReturns:\n Compaction outcome with the number of tokens and messages removed, summary text, and the resulting context window breakdown." - return HistoryCompactResult.from_dict(await self._client.request("session.history.compact", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + async def compact(self, params: HistoryCompactRequest | None = None, *, timeout: float | None = None) -> HistoryCompactResult: + "Compacts the session history to reduce context usage.\n\nArgs:\n params: Optional compaction parameters.\n\nReturns:\n Compaction outcome with the number of tokens and messages removed, summary text, and the resulting context window breakdown." + params_dict: dict[str, Any] = {k: v for k, v in params.to_dict().items() if v is not None} if params is not None else {} + params_dict["sessionId"] = self._session_id + return HistoryCompactResult.from_dict(await self._client.request("session.history.compact", params_dict, **_timeout_kwargs(timeout))) async def truncate(self, params: HistoryTruncateRequest, *, timeout: float | None = None) -> HistoryTruncateResult: "Truncates persisted session history to a specific event.\n\nArgs:\n params: Identifier of the event to truncate to; this event and all later events are removed.\n\nReturns:\n Number of events that were removed by the truncation." diff --git a/python/copilot/generated/session_events.py b/python/copilot/generated/session_events.py index 83d9cb9ed..706ec8086 100644 --- a/python/copilot/generated/session_events.py +++ b/python/copilot/generated/session_events.py @@ -320,7 +320,9 @@ class AssistantMessageData: "Assistant response containing text content, optional tool requests, and interaction metadata" content: str message_id: str + # Experimental: this field is part of an experimental API and may change or be removed. anthropic_advisor_blocks: list[Any] | None = None + # Experimental: this field is part of an experimental API and may change or be removed. anthropic_advisor_model: str | None = None encrypted_content: str | None = None interaction_id: str | None = None @@ -681,6 +683,7 @@ class AssistantUsageData: cache_read_tokens: int | None = None cache_write_tokens: int | None = None copilot_usage: AssistantUsageCopilotUsage | None = None + # Experimental: this field is part of an experimental API and may change or be removed. cost: float | None = None duration: timedelta | None = None initiator: str | None = None @@ -690,6 +693,7 @@ class AssistantUsageData: # Deprecated: this field is deprecated. parent_tool_call_id: str | None = None provider_call_id: str | None = None + # Internal: this field is an internal SDK API and is not part of the public surface. quota_snapshots: dict[str, AssistantUsageQuotaSnapshot] | None = None reasoning_effort: str | None = None reasoning_tokens: int | None = None @@ -780,13 +784,21 @@ def to_dict(self) -> dict: @dataclass class AssistantUsageQuotaSnapshot: "Schema for the `AssistantUsageQuotaSnapshot` type." + # Internal: this field is an internal SDK API and is not part of the public surface. entitlement_requests: int + # Internal: this field is an internal SDK API and is not part of the public surface. is_unlimited_entitlement: bool + # Internal: this field is an internal SDK API and is not part of the public surface. overage: float + # Internal: this field is an internal SDK API and is not part of the public surface. overage_allowed_with_exhausted_quota: bool + # Internal: this field is an internal SDK API and is not part of the public surface. remaining_percentage: float + # Internal: this field is an internal SDK API and is not part of the public surface. usage_allowed_with_exhausted_quota: bool + # Internal: this field is an internal SDK API and is not part of the public surface. used_requests: int + # Internal: this field is an internal SDK API and is not part of the public surface. reset_date: datetime | None = None @staticmethod @@ -2406,6 +2418,7 @@ class SessionCompactionCompleteData: checkpoint_path: str | None = None compaction_tokens_used: CompactionCompleteCompactionTokensUsed | None = None conversation_tokens: int | None = None + custom_instructions: str | None = None error: str | None = None messages_removed: int | None = None post_compaction_tokens: int | None = None @@ -2425,6 +2438,7 @@ def from_dict(obj: Any) -> "SessionCompactionCompleteData": checkpoint_path = from_union([from_none, from_str], obj.get("checkpointPath")) compaction_tokens_used = from_union([from_none, CompactionCompleteCompactionTokensUsed.from_dict], obj.get("compactionTokensUsed")) conversation_tokens = from_union([from_none, from_int], obj.get("conversationTokens")) + custom_instructions = from_union([from_none, from_str], obj.get("customInstructions")) error = from_union([from_none, from_str], obj.get("error")) messages_removed = from_union([from_none, from_int], obj.get("messagesRemoved")) post_compaction_tokens = from_union([from_none, from_int], obj.get("postCompactionTokens")) @@ -2441,6 +2455,7 @@ def from_dict(obj: Any) -> "SessionCompactionCompleteData": checkpoint_path=checkpoint_path, compaction_tokens_used=compaction_tokens_used, conversation_tokens=conversation_tokens, + custom_instructions=custom_instructions, error=error, messages_removed=messages_removed, post_compaction_tokens=post_compaction_tokens, @@ -2464,6 +2479,8 @@ def to_dict(self) -> dict: result["compactionTokensUsed"] = from_union([from_none, lambda x: to_class(CompactionCompleteCompactionTokensUsed, x)], self.compaction_tokens_used) if self.conversation_tokens is not None: result["conversationTokens"] = from_union([from_none, to_int], self.conversation_tokens) + if self.custom_instructions is not None: + result["customInstructions"] = from_union([from_none, from_str], self.custom_instructions) if self.error is not None: result["error"] = from_union([from_none, from_str], self.error) if self.messages_removed is not None: @@ -3087,7 +3104,6 @@ class SessionShutdownData: session_start_time: int shutdown_type: ShutdownType total_api_duration: timedelta - total_premium_requests: float conversation_tokens: int | None = None current_model: str | None = None current_tokens: int | None = None @@ -3095,7 +3111,10 @@ class SessionShutdownData: system_tokens: int | None = None token_details: dict[str, ShutdownTokenDetail] | None = None tool_definitions_tokens: int | None = None + # Experimental: this field is part of an experimental API and may change or be removed. total_nano_aiu: float | None = None + # Internal: this field is an internal SDK API and is not part of the public surface. + total_premium_requests: float | None = None @staticmethod def from_dict(obj: Any) -> "SessionShutdownData": @@ -3105,7 +3124,6 @@ def from_dict(obj: Any) -> "SessionShutdownData": session_start_time = from_int(obj.get("sessionStartTime")) shutdown_type = parse_enum(ShutdownType, obj.get("shutdownType")) total_api_duration = from_timedelta(obj.get("totalApiDurationMs")) - total_premium_requests = from_float(obj.get("totalPremiumRequests")) conversation_tokens = from_union([from_none, from_int], obj.get("conversationTokens")) current_model = from_union([from_none, from_str], obj.get("currentModel")) current_tokens = from_union([from_none, from_int], obj.get("currentTokens")) @@ -3114,13 +3132,13 @@ def from_dict(obj: Any) -> "SessionShutdownData": token_details = from_union([from_none, lambda x: from_dict(ShutdownTokenDetail.from_dict, x)], obj.get("tokenDetails")) tool_definitions_tokens = from_union([from_none, from_int], obj.get("toolDefinitionsTokens")) total_nano_aiu = from_union([from_none, from_float], obj.get("totalNanoAiu")) + total_premium_requests = from_union([from_none, from_float], obj.get("totalPremiumRequests")) return SessionShutdownData( code_changes=code_changes, model_metrics=model_metrics, session_start_time=session_start_time, shutdown_type=shutdown_type, total_api_duration=total_api_duration, - total_premium_requests=total_premium_requests, conversation_tokens=conversation_tokens, current_model=current_model, current_tokens=current_tokens, @@ -3129,6 +3147,7 @@ def from_dict(obj: Any) -> "SessionShutdownData": token_details=token_details, tool_definitions_tokens=tool_definitions_tokens, total_nano_aiu=total_nano_aiu, + total_premium_requests=total_premium_requests, ) def to_dict(self) -> dict: @@ -3138,7 +3157,6 @@ def to_dict(self) -> dict: result["sessionStartTime"] = to_int(self.session_start_time) result["shutdownType"] = to_enum(ShutdownType, self.shutdown_type) result["totalApiDurationMs"] = to_timedelta_int(self.total_api_duration) - result["totalPremiumRequests"] = to_float(self.total_premium_requests) if self.conversation_tokens is not None: result["conversationTokens"] = from_union([from_none, to_int], self.conversation_tokens) if self.current_model is not None: @@ -3155,6 +3173,8 @@ def to_dict(self) -> dict: result["toolDefinitionsTokens"] = from_union([from_none, to_int], self.tool_definitions_tokens) if self.total_nano_aiu is not None: result["totalNanoAiu"] = from_union([from_none, to_float], self.total_nano_aiu) + if self.total_premium_requests is not None: + result["totalPremiumRequests"] = from_union([from_none, to_float], self.total_premium_requests) return result @@ -3511,6 +3531,7 @@ class ShutdownModelMetric: requests: ShutdownModelMetricRequests usage: ShutdownModelMetricUsage token_details: dict[str, ShutdownModelMetricTokenDetail] | None = None + # Experimental: this field is part of an experimental API and may change or be removed. total_nano_aiu: float | None = None @staticmethod @@ -3541,14 +3562,16 @@ def to_dict(self) -> dict: @dataclass class ShutdownModelMetricRequests: "Request count and cost metrics" - cost: float - count: int + # Experimental: this field is part of an experimental API and may change or be removed. + cost: float | None = None + # Experimental: this field is part of an experimental API and may change or be removed. + count: int | None = None @staticmethod def from_dict(obj: Any) -> "ShutdownModelMetricRequests": assert isinstance(obj, dict) - cost = from_float(obj.get("cost")) - count = from_int(obj.get("count")) + cost = from_union([from_none, from_float], obj.get("cost")) + count = from_union([from_none, from_int], obj.get("count")) return ShutdownModelMetricRequests( cost=cost, count=count, @@ -3556,8 +3579,10 @@ def from_dict(obj: Any) -> "ShutdownModelMetricRequests": def to_dict(self) -> dict: result: dict = {} - result["cost"] = to_float(self.cost) - result["count"] = to_int(self.count) + if self.cost is not None: + result["cost"] = from_union([from_none, to_float], self.cost) + if self.count is not None: + result["count"] = from_union([from_none, to_int], self.count) return result diff --git a/rust/src/generated/api_types.rs b/rust/src/generated/api_types.rs index b7ebd6c48..b0ef34ff6 100644 --- a/rust/src/generated/api_types.rs +++ b/rust/src/generated/api_types.rs @@ -10,7 +10,8 @@ use super::session_events::{ AbortReason, McpServerSource, McpServerStatus, PermissionPromptRequest, PermissionRule, ReasoningSummary, SessionMode, ShutdownType, SkillSource, UserToolSessionApproval, }; -use crate::types::{RequestId, SessionEvent, SessionId}; +use crate::types::SessionEvent; +use crate::types::{RequestId, SessionId}; /// JSON-RPC method name constants. pub mod rpc_methods { @@ -429,9 +430,9 @@ pub struct AccountQuotaSnapshot { pub entitlement_requests: i64, /// Whether the user has an unlimited usage entitlement pub is_unlimited_entitlement: bool, - /// Number of overage requests made this period + /// Number of additional usage requests made this period pub overage: f64, - /// Whether overage is allowed when quota is exhausted + /// Whether additional usage is allowed when quota is exhausted pub overage_allowed_with_exhausted_quota: bool, /// Percentage of entitlement remaining pub remaining_percentage: f64, @@ -470,6 +471,13 @@ pub struct AgentInfo { /// Stable identifier for selection. For most agents this is the same as `name`; for plugin/builtin agents it may differ. Always populated; defaults to `name` when no distinct id was assigned. pub id: String, /// MCP server configurations attached to this agent, keyed by server name. Server config shape mirrors the MCP `mcpServers` schema. + /// + ///
+ /// + /// **Experimental.** This type is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. + /// + ///
#[serde(default)] pub mcp_servers: HashMap, /// Preferred model id for this agent. When omitted, inherits the outer agent's model. @@ -1812,6 +1820,22 @@ pub struct HistoryCompactContextWindow { pub tool_definitions_tokens: Option, } +/// Optional compaction parameters. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct HistoryCompactRequest { + /// Optional user-provided instructions to focus the compaction summary + #[serde(skip_serializing_if = "Option::is_none")] + pub custom_instructions: Option, +} + /// Compaction outcome with the number of tokens and messages removed, summary text, and the resulting context window breakdown. /// ///
@@ -5126,6 +5150,7 @@ pub struct SendRequest { #[serde(skip_serializing_if = "Option::is_none")] pub required_tool: Option, /// Optional provenance tag copied to the resulting user.message event. Supported values are `system`, `command-*`, and `schedule-*`. + #[doc(hidden)] #[serde(skip_serializing_if = "Option::is_none")] pub source: Option, /// W3C Trace Context traceparent header for distributed tracing of this agent turn @@ -6363,6 +6388,13 @@ pub struct SessionsSetAdditionalPluginsResult {} #[serde(rename_all = "camelCase")] pub struct SessionUpdateOptionsParams { /// Additional content-exclusion policies to merge into the session's policy set. Opaque shape; see `ContentExclusionApiResponse` in the runtime. + /// + ///
+ /// + /// **Experimental.** This type is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. + /// + ///
#[serde(default)] pub additional_content_exclusion_policies: Vec, /// Runtime context discriminator (e.g., `cli`, `actions`). @@ -6441,6 +6473,13 @@ pub struct SessionUpdateOptionsParams { #[serde(skip_serializing_if = "Option::is_none")] pub model: Option, /// Custom model-provider configuration (BYOK). Opaque shape; see `ProviderConfig` in the runtime. + /// + ///
+ /// + /// **Experimental.** This type is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. + /// + ///
#[serde(skip_serializing_if = "Option::is_none")] pub provider: Option, /// Reasoning effort for the selected model (model-defined enum). @@ -6450,6 +6489,13 @@ pub struct SessionUpdateOptionsParams { #[serde(skip_serializing_if = "Option::is_none")] pub running_in_interactive_mode: Option, /// Sandbox configuration shape; opaque to SDK consumers. See `SandboxConfig` in the runtime. + /// + ///
+ /// + /// **Experimental.** This type is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. + /// + ///
#[serde(skip_serializing_if = "Option::is_none")] pub sandbox_config: Option, /// Shell init profile (`None` or `NonInteractive`). @@ -10517,21 +10563,6 @@ pub struct SessionShellKillResult { pub killed: bool, } -/// Identifies the target session. -/// -///
-/// -/// **Experimental.** This type is part of an experimental wire-protocol surface -/// and may change or be removed in future SDK or CLI releases. -/// -///
-#[derive(Debug, Clone, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct SessionHistoryCompactParams { - /// Target session identifier - pub session_id: SessionId, -} - /// Compaction outcome with the number of tokens and messages removed, summary text, and the resulting context window breakdown. /// ///
diff --git a/rust/src/generated/rpc.rs b/rust/src/generated/rpc.rs index 5831a4553..f73d1bc00 100644 --- a/rust/src/generated/rpc.rs +++ b/rust/src/generated/rpc.rs @@ -2174,6 +2174,39 @@ impl<'a> SessionRpcHistory<'a> { Ok(serde_json::from_value(_value)?) } + /// Compacts the session history to reduce context usage. + /// + /// Wire method: `session.history.compact`. + /// + /// # Parameters + /// + /// * `params` - Optional compaction parameters. + /// + /// # Returns + /// + /// Compaction outcome with the number of tokens and messages removed, summary text, and the resulting context window breakdown. + /// + ///
+ /// + /// **Experimental.** This API is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. Pin both the + /// SDK and CLI versions if your code depends on it. + /// + ///
+ pub async fn compact_with_params( + &self, + params: HistoryCompactRequest, + ) -> Result { + let mut wire_params = serde_json::to_value(params)?; + wire_params["sessionId"] = serde_json::Value::String(self.session.id().to_string()); + let _value = self + .session + .client() + .call(rpc_methods::SESSION_HISTORY_COMPACT, Some(wire_params)) + .await?; + Ok(serde_json::from_value(_value)?) + } + /// Truncates persisted session history to a specific event. /// /// Wire method: `session.history.truncate`. diff --git a/rust/src/generated/session_events.rs b/rust/src/generated/session_events.rs index 053c4f8f8..8b16291c4 100644 --- a/rust/src/generated/session_events.rs +++ b/rust/src/generated/session_events.rs @@ -723,9 +723,25 @@ pub struct ShutdownCodeChanges { #[serde(rename_all = "camelCase")] pub struct ShutdownModelMetricRequests { /// Cumulative cost multiplier for requests to this model - pub cost: f64, + /// + ///
+ /// + /// **Experimental.** This type is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. + /// + ///
+ #[serde(skip_serializing_if = "Option::is_none")] + pub cost: Option, /// Total number of API requests made to this model - pub count: i64, + /// + ///
+ /// + /// **Experimental.** This type is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. + /// + ///
+ #[serde(skip_serializing_if = "Option::is_none")] + pub count: Option, } /// Schema for the `ShutdownModelMetricTokenDetail` type. @@ -763,6 +779,13 @@ pub struct ShutdownModelMetric { #[serde(default)] pub token_details: HashMap, /// Accumulated nano-AI units cost for this model + /// + ///
+ /// + /// **Experimental.** This type is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. + /// + ///
#[serde(skip_serializing_if = "Option::is_none")] pub total_nano_aiu: Option, /// Token usage breakdown @@ -813,10 +836,19 @@ pub struct SessionShutdownData { /// Cumulative time spent in API calls during the session, in milliseconds pub total_api_duration_ms: i64, /// Session-wide accumulated nano-AI units cost + /// + ///
+ /// + /// **Experimental.** This type is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. + /// + ///
#[serde(skip_serializing_if = "Option::is_none")] pub total_nano_aiu: Option, /// Total number of premium API requests used during the session - pub total_premium_requests: f64, + #[doc(hidden)] + #[serde(skip_serializing_if = "Option::is_none")] + pub total_premium_requests: Option, } /// Session event "session.context_changed". Updated working directory and git context after the change @@ -954,6 +986,9 @@ pub struct SessionCompactionCompleteData { /// Token count from non-system messages (user, assistant, tool) after compaction #[serde(skip_serializing_if = "Option::is_none")] pub conversation_tokens: Option, + /// User-supplied focus instructions provided to a manual `/compact` invocation. Omitted for automatic compaction and for manual compaction with no focus text. + #[serde(skip_serializing_if = "Option::is_none")] + pub custom_instructions: Option, /// Error message if compaction failed #[serde(skip_serializing_if = "Option::is_none")] pub error: Option, @@ -1120,9 +1155,23 @@ pub struct AssistantMessageToolRequest { #[serde(rename_all = "camelCase")] pub struct AssistantMessageData { /// Raw Anthropic content array with advisor blocks (server_tool_use, advisor_tool_result) for verbatim round-tripping + /// + ///
+ /// + /// **Experimental.** This type is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. + /// + ///
#[serde(default)] pub anthropic_advisor_blocks: Vec, /// Anthropic advisor model ID used for this response, for timeline display on replay + /// + ///
+ /// + /// **Experimental.** This type is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. + /// + ///
#[serde(skip_serializing_if = "Option::is_none")] pub anthropic_advisor_model: Option, /// The assistant's text response content @@ -1229,21 +1278,29 @@ pub struct AssistantUsageCopilotUsage { #[serde(rename_all = "camelCase")] pub struct AssistantUsageQuotaSnapshot { /// Total requests allowed by the entitlement + #[doc(hidden)] pub entitlement_requests: i64, /// Whether the user has an unlimited usage entitlement + #[doc(hidden)] pub is_unlimited_entitlement: bool, - /// Number of requests over the entitlement limit + /// Number of additional usage requests made this period + #[doc(hidden)] pub overage: f64, - /// Whether overage is allowed when quota is exhausted + /// Whether additional usage is allowed when quota is exhausted + #[doc(hidden)] pub overage_allowed_with_exhausted_quota: bool, /// Percentage of quota remaining (0 to 100) + #[doc(hidden)] pub remaining_percentage: f64, /// Date when the quota resets + #[doc(hidden)] #[serde(skip_serializing_if = "Option::is_none")] pub reset_date: Option, /// Whether usage is still permitted after quota exhaustion + #[doc(hidden)] pub usage_allowed_with_exhausted_quota: bool, /// Number of requests already consumed + #[doc(hidden)] pub used_requests: i64, } @@ -1267,6 +1324,13 @@ pub struct AssistantUsageData { #[serde(skip_serializing_if = "Option::is_none")] pub copilot_usage: Option, /// Model multiplier cost for billing purposes + /// + ///
+ /// + /// **Experimental.** This type is part of an experimental wire-protocol surface + /// and may change or be removed in future SDK or CLI releases. + /// + ///
#[serde(skip_serializing_if = "Option::is_none")] pub cost: Option, /// Duration of the API call in milliseconds @@ -1295,6 +1359,7 @@ pub struct AssistantUsageData { #[serde(skip_serializing_if = "Option::is_none")] pub provider_call_id: Option, /// Per-quota resource usage snapshots, keyed by quota identifier + #[doc(hidden)] #[serde(default)] pub quota_snapshots: HashMap, /// Reasoning effort level used for model calls, if applicable (e.g. "none", "low", "medium", "high", "xhigh", "max") diff --git a/scripts/codegen/csharp.ts b/scripts/codegen/csharp.ts index f35c0a52b..9c2825ab1 100644 --- a/scripts/codegen/csharp.ts +++ b/scripts/codegen/csharp.ts @@ -36,6 +36,8 @@ import { isNodeFullyDeprecated, isSchemaDeprecated, isSchemaExperimental, + isSchemaInternal, + isOpaqueJson, isObjectSchema, isVoidSchema, getNullableInner, @@ -275,9 +277,30 @@ function isNonNullableCSharpValueType(typeName: string): boolean { "long", "DateTimeOffset", "TimeSpan", + "JsonElement", ].includes(typeName) || generatedEnums.has(typeName) || emittedRpcEnumResultTypes.has(typeName) || externalRpcValueTypes.has(typeName); } +/** + * Schemas marked `.asOpaqueJson()` on the runtime side carry + * `x-opaque-json: true`. These are the only shapes that legitimately surface + * as opaque JSON in the SDK (mapped to `JsonElement` in C#). Anything else + * that lacks an idiomatic mapping (untyped fields, non-discriminated unions, + * etc.) is rejected by the runtime's schema-shape lint, so the codegen + * treats reaching an unmappable schema here as a bug. + * + * The predicate itself lives in {@link "./utils".isOpaqueJson} for reuse. + */ +function failUnmappable(context: string, schema: JSONSchema7): never { + const summary = JSON.stringify(schema, (key, value) => (key === "description" ? undefined : value)).slice(0, 200); + throw new Error( + `C# codegen: cannot map schema to an idiomatic C# type (${context}). ` + + `On the runtime side, either tighten the Zod schema to a typed shape, or — if it is genuinely free-form JSON — ` + + `mark it \`.asOpaqueJson()\` so the schema emits \`x-opaque-json: true\` and the codegen maps it to JsonElement. ` + + `Offending schema (truncated): ${summary}`, + ); +} + function requiresArgumentNullCheck(typeName: string, isRequired: boolean): boolean { return isRequired && !typeName.endsWith("?") && !isNonNullableCSharpValueType(typeName); } @@ -309,6 +332,9 @@ function localRequestVariableName(paramEntries: [string, JSONSchema7Definition][ } function schemaTypeToCSharp(schema: JSONSchema7, required: boolean, knownTypes: Map, propName?: string): string { + if (isOpaqueJson(schema)) { + return required ? "JsonElement" : "JsonElement?"; + } const nullableInner = getNullableInner(schema); if (nullableInner) { // Pass required=true to get the base type, then add "?" for nullable @@ -361,7 +387,8 @@ function schemaTypeToCSharp(schema: JSONSchema7, required: boolean, knownTypes: if (type === "boolean") return required ? "bool" : "bool?"; if (type === "array") { const items = schema.items as JSONSchema7 | undefined; - const itemType = items ? schemaTypeToCSharp(items, true, knownTypes) : "object"; + if (!items) failUnmappable(`array without items (propName=${propName ?? "?"})`, schema); + const itemType = schemaTypeToCSharp(items, true, knownTypes); return required ? `${itemType}[]` : `${itemType}[]?`; } if (type === "object") { @@ -369,9 +396,9 @@ function schemaTypeToCSharp(schema: JSONSchema7, required: boolean, knownTypes: const valueType = schemaTypeToCSharp(schema.additionalProperties as JSONSchema7, true, knownTypes); return required ? `IDictionary` : `IDictionary?`; } - return required ? "object" : "object?"; + failUnmappable(`object without properties or typed additionalProperties (propName=${propName ?? "?"})`, schema); } - return required ? "object" : "object?"; + failUnmappable(`unknown/missing type (propName=${propName ?? "?"})`, schema); } /** Tracks whether any TimeSpan property was emitted so the converter can be generated. */ @@ -489,6 +516,20 @@ function pushObsoleteAttributes(lines: string[], indent = ""): void { lines.push(...obsoleteAttributes(indent)); } +/** + * Emit the `[JsonInclude]` attribute for an internally-marked property and + * return the C# access modifier to use for the property declaration. + * + * `[JsonInclude]` is required because System.Text.Json only auto-(de)serialises + * public members by default; without it, the `internal` setter would silently + * be skipped. + */ +function pushCSharpInternalAttribute(lines: string[], schema: JSONSchema7, indent = " "): "public" | "internal" { + const propInternal = isSchemaInternal(schema); + if (propInternal) lines.push(`${indent}[JsonInclude]`); + return propInternal ? "internal" : "public"; +} + // ══════════════════════════════════════════════════════════════════════════════ // SESSION EVENTS // ══════════════════════════════════════════════════════════════════════════════ @@ -747,11 +788,13 @@ function generateFlattenedBooleanDiscriminatedClass( lines.push(...xmlDocPropertyComment(info.schema.description, propName, " ")); lines.push(...emitDataAnnotations(info.schema, " ", csharpType)); if (isSchemaDeprecated(info.schema)) pushObsoleteAttributes(lines, " "); + if (isSchemaExperimental(info.schema)) pushExperimentalAttribute(lines, " "); if (isMillisecondsDurationProperty(propName, info.schema)) lines.push(` [JsonConverter(typeof(MillisecondsTimeSpanConverter))]`); if (!isReq) lines.push(` [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]`); + const propVisibility = pushCSharpInternalAttribute(lines, info.schema); lines.push(` [JsonPropertyName("${propName}")]`); const reqMod = isReq && !csharpType.endsWith("?") ? "required " : ""; - lines.push(` public ${reqMod}${csharpType} ${csharpName} { get; set; }`); + lines.push(` ${propVisibility} ${reqMod}${csharpType} ${csharpName} { get; set; }`); } lines.push(`}`); @@ -850,11 +893,13 @@ function generateDerivedClass( lines.push(...xmlDocPropertyComment(prop.description, propName, " ")); lines.push(...emitDataAnnotations(prop, " ", csharpType)); if (isSchemaDeprecated(prop)) pushObsoleteAttributes(lines, " "); + if (isSchemaExperimental(prop)) pushExperimentalAttribute(lines, " "); if (isMillisecondsDurationProperty(propName, prop)) lines.push(` [JsonConverter(typeof(MillisecondsTimeSpanConverter))]`); if (!isReq) lines.push(` [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]`); + const propVisibility = pushCSharpInternalAttribute(lines, prop); lines.push(` [JsonPropertyName("${propName}")]`); const reqMod = isReq && !csharpType.endsWith("?") ? "required " : ""; - lines.push(` public ${reqMod}${csharpType} ${csharpName} { get; set; }`, ""); + lines.push(` ${propVisibility} ${reqMod}${csharpType} ${csharpName} { get; set; }`, ""); } } @@ -1075,11 +1120,13 @@ function generateNestedClass( lines.push(...xmlDocPropertyComment(prop.description, propName, " ")); lines.push(...emitDataAnnotations(prop, " ", csharpType)); if (isSchemaDeprecated(prop)) pushObsoleteAttributes(lines, " "); + if (isSchemaExperimental(prop)) pushExperimentalAttribute(lines, " "); if (isMillisecondsDurationProperty(propName, prop)) lines.push(` [JsonConverter(typeof(MillisecondsTimeSpanConverter))]`); if (!isReq) lines.push(` [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]`); + const propVisibility = pushCSharpInternalAttribute(lines, prop); lines.push(` [JsonPropertyName("${propName}")]`); const reqMod = isReq && !csharpType.endsWith("?") ? "required " : ""; - lines.push(` public ${reqMod}${csharpType} ${csharpName} { get; set; }`, ""); + lines.push(` ${propVisibility} ${reqMod}${csharpType} ${csharpName} { get; set; }`, ""); } if (lines[lines.length - 1] === "") lines.pop(); lines.push(`}`); @@ -1095,6 +1142,9 @@ function resolveSessionPropertyType( nestedClasses: Map, enumOutput: string[] ): string { + if (isOpaqueJson(propSchema)) { + return isRequired ? "JsonElement" : "JsonElement?"; + } // Handle $ref by resolving against schema definitions if (propSchema.$ref) { const className = typeToClassName(refTypeName(propSchema.$ref, sessionDefinitions)); @@ -1145,12 +1195,12 @@ function resolveSessionPropertyType( } const unionType = tryGenerateSessionJsonUnionType(propSchema, parentClassName, propName, knownTypes, nestedClasses, enumOutput); if (unionType) return isRequired ? unionType : `${unionType}?`; - return !isRequired ? "object?" : "object"; + failUnmappable(`anyOf without discriminator (${parentClassName}.${propName})`, propSchema); } if (propSchema.oneOf) { const unionType = tryGenerateSessionJsonUnionType(propSchema, parentClassName, propName, knownTypes, nestedClasses, enumOutput); if (unionType) return isRequired ? unionType : `${unionType}?`; - return !isRequired ? "object?" : "object"; + failUnmappable(`oneOf without discriminator (${parentClassName}.${propName})`, propSchema); } if (propSchema.enum && Array.isArray(propSchema.enum)) { const enumName = getOrCreateEnum(parentClassName, propName, propSchema.enum as string[], enumOutput, propSchema.description, getEnumValueDescriptions(propSchema), propSchema.title as string | undefined, isSchemaDeprecated(propSchema), isSchemaExperimental(propSchema)); @@ -1218,11 +1268,13 @@ function generateDataClass(variant: EventVariant, knownTypes: Map=12" }, diff --git a/scripts/codegen/python.ts b/scripts/codegen/python.ts index 52b11ed59..45071e2db 100644 --- a/scripts/codegen/python.ts +++ b/scripts/codegen/python.ts @@ -25,6 +25,7 @@ import { isNodeFullyDeprecated, isSchemaDeprecated, isSchemaExperimental, + isSchemaInternal, postProcessSchema, stripBooleanLiterals, writeGeneratedFile, @@ -271,6 +272,24 @@ function pushPyExperimentalApiGroupComment(lines: string[]): void { lines.push("# Experimental: this API group is experimental and may change or be removed."); } +/** + * Emit `# Deprecated:` / `# Experimental:` / `# Internal:` comments above a + * dataclass field. Order matches our other codegens (deprecated, experimental, + * internal) and keeps the comments out of the field declaration itself. + */ +function pushPyFieldMarkers(lines: string[], propSchema: JSONSchema7 | null | undefined): void { + if (!propSchema) return; + if (isSchemaDeprecated(propSchema)) { + lines.push(` # Deprecated: this field is deprecated.`); + } + if (isSchemaExperimental(propSchema)) { + lines.push(` # Experimental: this field is part of an experimental API and may change or be removed.`); + } + if (isSchemaInternal(propSchema)) { + lines.push(` # Internal: this field is an internal SDK API and is not part of the public surface.`); + } +} + /** * Modernize quicktype's Python 3.7 output to Python 3.11+ syntax: * - Optional[T] → T | None @@ -1561,9 +1580,8 @@ function emitPyClass( for (const field of fieldInfos) { const suffix = field.isRequired ? "" : " = None"; - if (isSchemaDeprecated(orderedFieldEntries.find(([n]) => n === field.jsonName)?.[1] as JSONSchema7)) { - lines.push(` # Deprecated: this field is deprecated.`); - } + const propSchema = orderedFieldEntries.find(([n]) => n === field.jsonName)?.[1] as JSONSchema7 | undefined; + pushPyFieldMarkers(lines, propSchema); lines.push(` ${field.fieldName}: ${field.resolved.annotation}${suffix}`); } @@ -1703,10 +1721,8 @@ function emitPyFlatDiscriminatedUnion( } for (const field of fieldInfos) { const suffix = field.isRequired ? "" : " = None"; - const fieldSchema = orderedFieldEntries.find(([n]) => n === field.jsonName)?.[1]; - if (fieldSchema && isSchemaDeprecated(fieldSchema)) { - lines.push(` # Deprecated: this field is deprecated.`); - } + const fieldSchema = orderedFieldEntries.find(([n]) => n === field.jsonName)?.[1] as JSONSchema7 | undefined; + pushPyFieldMarkers(lines, fieldSchema); lines.push(` ${field.fieldName}: ${field.resolved.annotation}${suffix}`); } lines.push(``); diff --git a/scripts/codegen/rust.ts b/scripts/codegen/rust.ts index f2056c35c..0f1ae1d06 100644 --- a/scripts/codegen/rust.ts +++ b/scripts/codegen/rust.ts @@ -38,6 +38,7 @@ import { isRpcMethod, isSchemaDeprecated, isSchemaExperimental, + isSchemaInternal, isVoidSchema, parseExternalSchemaRef, postProcessSchema, @@ -818,6 +819,10 @@ function emitRustStruct( lines.push(` /// ${line}`); } } + pushRustExperimentalDocs(lines, isSchemaExperimental(prop), " "); + if (isSchemaInternal(prop)) { + lines.push(` #[doc(hidden)]`); + } if (isSchemaDeprecated(prop)) { lines.push(...rustDeprecatedAttributes(" ")); } diff --git a/scripts/codegen/typescript.ts b/scripts/codegen/typescript.ts index 3afaec395..ee9936de3 100644 --- a/scripts/codegen/typescript.ts +++ b/scripts/codegen/typescript.ts @@ -37,6 +37,7 @@ import { isVoidSchema, isSchemaExperimental, getEnumValueDescriptions, + stripOpaqueJsonMarker, type ApiSchema, type DefinitionCollections, type RpcMethod, @@ -280,6 +281,13 @@ export function normalizeSchemaForTypeScript(schema: JSONSchema7): JSONSchema7 { Object.entries(value as Record).map(([key, child]) => [key, rewrite(child)]) ) as Record; + // The TypeScript codegen doesn't distinguish opaque JSON from any + // other unconstrained value, so drop the marker before feeding the + // schema to json-schema-to-typescript. C# codegen reads the marker + // from its own (un-normalized) view of the schema and emits + // `JsonElement` instead. + stripOpaqueJsonMarker(rewritten); + const enumValueDescriptions = getEnumValueDescriptions(rewritten as JSONSchema7); if (enumValueDescriptions && Array.isArray(rewritten.enum) && rewritten.enum.every((entry) => typeof entry === "string")) { rewritten.tsType = (rewritten.enum as string[]) diff --git a/scripts/codegen/utils.ts b/scripts/codegen/utils.ts index a06be7607..c2e3f7b7e 100644 --- a/scripts/codegen/utils.ts +++ b/scripts/codegen/utils.ts @@ -501,6 +501,78 @@ export function isSchemaExperimental(schema: JSONSchema7 | null | undefined): bo return typeof schema === "object" && schema !== null && (schema as Record).stability === "experimental"; } +/** Returns true when a JSON Schema node is marked as visibility:"internal" (set via `.asInternal()` on the Zod source). */ +export function isSchemaInternal(schema: JSONSchema7 | null | undefined): boolean { + return typeof schema === "object" && schema !== null && (schema as Record).visibility === "internal"; +} + +/** + * Returns true when a JSON Schema node is marked `x-opaque-json: true` (set via + * `.asOpaqueJson()` on the Zod source). These are the only shapes that legitimately + * surface as opaque JSON in the SDK; everything else with an underspecified type + * is rejected by the runtime's schema lint pass. + */ +export function isOpaqueJson(schema: JSONSchema7 | null | undefined): boolean { + return typeof schema === "object" && schema !== null && (schema as Record)["x-opaque-json"] === true; +} + +/** + * Removes the `x-opaque-json` marker from a schema node in place. Useful for + * codegens (e.g. TypeScript) that don't distinguish opaque JSON from any other + * unconstrained value and would otherwise have the marker confuse downstream + * tooling. Codegens that *do* care (e.g. C#, which maps opaque JSON to + * `JsonElement`) should call `isOpaqueJson` *before* this point. + */ +export function stripOpaqueJsonMarker(schema: Record): void { + delete schema["x-opaque-json"]; +} + +/** + * Append `@internal` and/or `@experimental` JSDoc-style tags to the `description` + * of every property that carries `visibility: "internal"` or `stability: "experimental"` + * inline. Used by codegens whose output mechanism (e.g. `json-schema-to-typescript`) + * renders `description` verbatim as JSDoc; downstream tooling then picks the tags + * up automatically. + * + * Mutates `schema` in place and returns it. Callers that don't want their input + * mutated should clone first. + */ +export function appendPropertyMarkerTagsToDescriptions(schema: JSONSchema7): JSONSchema7 { + const seen = new WeakSet(); + const visit = (node: unknown): void => { + if (!node || typeof node !== "object") return; + if (seen.has(node)) return; + seen.add(node); + + if (Array.isArray(node)) { + for (const item of node) visit(item); + return; + } + + const record = node as Record; + const props = record.properties; + if (props && typeof props === "object" && !Array.isArray(props)) { + for (const propSchema of Object.values(props as Record)) { + if (!propSchema || typeof propSchema !== "object") continue; + const tags: string[] = []; + if (isSchemaInternal(propSchema as JSONSchema7)) tags.push("@internal"); + if (isSchemaExperimental(propSchema as JSONSchema7)) tags.push("@experimental"); + if (tags.length === 0) continue; + const propRecord = propSchema as Record; + const existing = typeof propRecord.description === "string" ? propRecord.description : ""; + const suffix = tags.join("\n"); + propRecord.description = existing.length > 0 ? `${existing}\n\n${suffix}` : suffix; + } + } + + for (const value of Object.values(record)) { + if (value && typeof value === "object") visit(value); + } + }; + visit(schema); + return schema; +} + // ── $ref resolution ───────────────────────────────────────────────────────── /** Extract the generated type name from a `$ref` path (e.g. "#/definitions/Model" → "Model"). */